🎨 代码格式化

This commit is contained in:
BTMuli
2023-06-25 16:15:15 +08:00
parent 7982649bbc
commit 7567bba147
174 changed files with 29970 additions and 29840 deletions

View File

@@ -6,7 +6,7 @@ Update: 2023-06-20
--- ---
> 本文档 [`Front-matter`](https://github.com/BTMuli/Mucli#FrontMatter) 由 [MuCli](https://github.com/BTMuli/Mucli) 自动生成于 `2023-06-18 15:03:42 ` > 本文档 [`Front-matter`](https://github.com/BTMuli/Mucli#FrontMatter) 由 [MuCli](https://github.com/BTMuli/Mucli) 自动生成于 `2023-06-18 15:03:42 `
> >
> 更新于 `2023-06-20 08:53:56` > 更新于 `2023-06-20 08:53:56`
# CHANGELOG # CHANGELOG
@@ -36,4 +36,4 @@ Update: 2023-06-20
- 资源:成就系列图标目录变更 - 资源:成就系列图标目录变更
- 资源:字体文件变更 [`2ee48566`](https://github.com/BTMuli/Tauri.Genshin/commit/2ee48566) - 资源:字体文件变更 [`2ee48566`](https://github.com/BTMuli/Tauri.Genshin/commit/2ee48566)
FullCommits: [`v0.1.6...v0.2.0`](https://github.com/BTMuli/Tauri.Genshin/compare/v0.1.6...v0.2.0) FullCommits: [`v0.1.6...v0.2.0`](https://github.com/BTMuli/Tauri.Genshin/compare/v0.1.6...v0.2.0)

View File

@@ -6,10 +6,10 @@ Update: 2023-06-21
--- ---
> 本文档 [`Front-matter`](https://github.com/BTMuli/Mucli#FrontMatter) 由 [MuCli](https://github.com/BTMuli/Mucli) 自动生成于 `2023-03-05 14:41:55` > 本文档 [`Front-matter`](https://github.com/BTMuli/Mucli#FrontMatter) 由 [MuCli](https://github.com/BTMuli/Mucli) 自动生成于 `2023-03-05 14:41:55`
> >
> 更新于 `2023-06-21 10:28:11` > 更新于 `2023-06-21 10:28:11`
![](https://img.shields.io/github/last-commit/BTMuli/Tauri.Genshin?style=for-the-badge) ![](https://img.shields.io/github/commits-since/BTMuli/Tauri.Genshin/latest?include_prereleases&style=for-the-badge) ![](https://img.shields.io/github/license/BTMuli/Tauri.Genshin?style=for-the-badge) ![](https://img.shields.io/github/last-commit/BTMuli/Tauri.Genshin?style=for-the-badge) ![](https://img.shields.io/github/commits-since/BTMuli/Tauri.Genshin/latest?include_prereleases&style=for-the-badge) ![](https://img.shields.io/github/license/BTMuli/Tauri.Genshin?style=for-the-badge)
# Tauri.Genshin # Tauri.Genshin
@@ -43,7 +43,7 @@ Tauri 练手项目,子模块:[TGAssistant](https://github.com/BTMuli/TGAssis
- [x] 用户 Cookie 获取、备份、恢复、刷新 - [x] 用户 Cookie 获取、备份、恢复、刷新
- [x] 原神战绩数据获取、渲染、分享 - [x] 原神战绩数据获取、渲染、分享
- [x] 角色列表数据获取、渲染、分享 - [x] 角色列表数据获取、渲染、分享
- [x] 深渊挑战数据获取、渲染、分享、备份、恢复 - [x] 深渊挑战数据获取、渲染、分享、备份、恢复
### 计划中 ### 计划中
@@ -70,10 +70,10 @@ Tauri 练手项目,子模块:[TGAssistant](https://github.com/BTMuli/TGAssis
## 相关文档 ## 相关文档
+ 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[UIGF v2.3](docs/UIGF.md)
## Contributors ## Contributors

View File

@@ -6,7 +6,7 @@ Update: 2023-06-18
--- ---
> 本文档 [`Front-matter`](https://github.com/BTMuli/Mucli#FrontMatter) 由 [MuCli](https://github.com/BTMuli/Mucli) 自动生成于 `2023-03-30 15:39:49` > 本文档 [`Front-matter`](https://github.com/BTMuli/Mucli#FrontMatter) 由 [MuCli](https://github.com/BTMuli/Mucli) 自动生成于 `2023-03-30 15:39:49`
> >
> 更新于 `2023-06-18 15:02:31` > 更新于 `2023-06-18 15:02:31`
# CHANGELOG v0.1.x # CHANGELOG v0.1.x
@@ -113,7 +113,6 @@ FullCommits: [`v0.1.2 ~ v0.1.3`](https://github.com/BTMuli/Tauri.Genshin/compare
- 咨讯:支持多种游戏咨讯查看 - 咨讯:支持多种游戏咨讯查看
- 米游社解析:添加 `mention` 类型解析 - 米游社解析:添加 `mention` 类型解析
### Fix ### Fix
- 首页:近期活动、限时祈愿结束处理 - 首页:近期活动、限时祈愿结束处理

View File

@@ -6,7 +6,7 @@ Update: 2023-03-07
--- ---
> 本文档 [`Front-matter`](https://github.com/BTMuli/Mucli#FrontMatter) 由 [MuCli](https://github.com/BTMuli/Mucli) 自动生成于`2023-03-07 14:17:11` > 本文档 [`Front-matter`](https://github.com/BTMuli/Mucli#FrontMatter) 由 [MuCli](https://github.com/BTMuli/Mucli) 自动生成于`2023-03-07 14:17:11`
> >
> 更新于 `2023-03-07 14:17:11` > 更新于 `2023-03-07 14:17:11`
> 本文档为 [`UIAF`](https://github.com/DGP-Studio/Snap.Genshin.Docs/blob/main/docs/development/UIAF.md) 的备份。 > 本文档为 [`UIAF`](https://github.com/DGP-Studio/Snap.Genshin.Docs/blob/main/docs/development/UIAF.md) 的备份。
@@ -14,18 +14,19 @@ Update: 2023-03-07
# 统一可交换成就标准 v1.1 # 统一可交换成就标准 v1.1
> Uniformed Interchangeable Achievement Format standard (UIAF) > Uniformed Interchangeable Achievement Format standard (UIAF)
## 前言 ## 前言
由于原神的第三方成就识别、导出、记录软件越来越多,在有了 UIGF 的经验后, 由于原神的第三方成就识别、导出、记录软件越来越多,在有了 UIGF 的经验后,
我们 我们
* [babalae/genshin achievement toy](https://github.com/babalae/genshin-achievement-toy) - [babalae/genshin achievement toy](https://github.com/babalae/genshin-achievement-toy)
* [DGP Studio/Snap.Genshin](https://github.com/DGP-Studio/Snap.Genshin) - [DGP Studio/Snap.Genshin](https://github.com/DGP-Studio/Snap.Genshin)
* [HolographicHat/genshin achievement export](https://github.com/HolographicHat/genshin-achievement-export) - [HolographicHat/genshin achievement export](https://github.com/HolographicHat/genshin-achievement-export)
* [YuehaiTeam/cocogoat](https://github.com/YuehaiTeam/cocogoat) - [YuehaiTeam/cocogoat](https://github.com/YuehaiTeam/cocogoat)
(上述名称以字典顺序排序,不代表其他任何意义) (上述名称以字典顺序排序,不代表其他任何意义)
在此一起制定了此项标准旨在加强各个原神相关的App间的数据可交换性。 在此一起,制定了此项标准,旨在加强各个原神相关的 App 间的数据可交换性。
## 注意事项 ## 注意事项
@@ -61,10 +62,7 @@ Update: 2023-03-07
"description": "导出UNIX时间戳" "description": "导出UNIX时间戳"
} }
}, },
"required": [ "required": ["export_app", "uiaf_version"],
"export_app",
"uiaf_version"
],
"description": "包含导出方定义的基本信息" "description": "包含导出方定义的基本信息"
}, },
"list": { "list": {
@@ -83,12 +81,7 @@ Update: 2023-03-07
"status": { "status": {
"type": "number", "type": "number",
"description": "完成状态", "description": "完成状态",
"enum": [ "enum": [0, 1, 2, 3],
0,
1,
2,
3
],
"enumDesc": "ACHIEVEMENT_INVALID = 0; ACHIEVEMENT_UNFINISHED = 1; ACHIEVEMENT_FINISHED = 2;ACHIEVEMENT_POINT_TAKEN = 3;" "enumDesc": "ACHIEVEMENT_INVALID = 0; ACHIEVEMENT_UNFINISHED = 1; ACHIEVEMENT_FINISHED = 2;ACHIEVEMENT_POINT_TAKEN = 3;"
}, },
"timestamp": { "timestamp": {
@@ -96,21 +89,13 @@ Update: 2023-03-07
"description": "完成的时间" "description": "完成的时间"
} }
}, },
"required": [ "required": ["id", "current", "status", "timestamp"],
"id",
"current",
"status",
"timestamp"
],
"description": "表示一个成就" "description": "表示一个成就"
}, },
"description": "包含完成或未完成的成就" "description": "包含完成或未完成的成就"
} }
}, },
"required": [ "required": ["info", "list"]
"info",
"list"
]
} }
``` ```
@@ -118,46 +103,48 @@ Update: 2023-03-07
可以包含我们认可的以下字段 可以包含我们认可的以下字段
|字段名|值|说明| | 字段名 | 值 | 说明 |
|-|-|-| | -------------------- | --------------------------------------------------------------------------- | ---- |
|`export_timestamp`|导出UNIX时间戳|| | `export_timestamp` | 导出 UNIX 时间戳 | |
|`export_app_version`|导出此份记录的App版本号|| | `export_app_version` | 导出此份记录的 App 版本号 | |
|`uiaf_version`|所应用的 `UIAF` 的版本,包含此字段以防 `UIAF` 出现中断性变更时App无法处理|| | `uiaf_version` | 所应用的 `UIAF` 的版本,包含此字段以防 `UIAF` 出现中断性变更时App 无法处理 | |
#### `uiaf_version` #### `uiaf_version`
合法值 合法值
|值|说明|向下兼容的最低版本| | 值 | 说明 | 向下兼容的最低版本 |
|-|-|-| | ------ | ----------------------------------------------------------- | ------------------ |
|`v1.0`|首个正式版本|v1.0| | `v1.0` | 首个正式版本 | v1.0 |
|`v1.1`|`achievement` 中引入了 `status` 字段,指示成就的完成情况|v1.1| | `v1.1` | `achievement` 中引入了 `status` 字段,指示成就的完成情况 | v1.1 |
#### `export_app` #### `export_app`
未实现导出支持的以 `-` 代替 未实现导出支持的以 `-` 代替
|导出 App|`export_app` 的值| | 导出 App | `export_app` 的值 |
|-|-| | -------- | ----------------- |
|Empty|Empty| | Empty | Empty |
### `achievement` ### `achievement`
#### `id` #### `id`
原神的成就在游戏内部带有Id对于扫描类导出软件在取得成就的外在表现形式呈现文本便可对应到内部的Id 原神的成就在游戏内部带有 Id对于扫描类导出软件在取得成就的外在表现形式呈现文本便可对应到内部的 Id
> 导入/导出软件应自行负责Id与呈现文本间的转换 > 导入/导出软件应自行负责 Id 与呈现文本间的转换
> 成就的信息可以从 [Dimbreath/GenshinData](https://github.com/Dimbreath/GenshinData) 库中获取 > 成就的信息可以从 [Dimbreath/GenshinData](https://github.com/Dimbreath/GenshinData) 库中获取
#### `timestamp` #### `timestamp`
* 对于识别成功的值直接将时间转换为对应的UNIX 时间戳(秒) - 对于识别成功的值,直接将时间转换为对应的 UNIX 时间戳(秒)
* 对于识别失败的值,直接将时间设置为 `9999-12-31 23:59:59`253402271999 - 对于识别失败的值,直接将时间设置为 `9999-12-31 23:59:59`253402271999
#### `current` #### `current`
* 对于识别成功的值,如 30/40 `current` 的值应设置为30 - 对于识别成功的值,如 30/40 `current` 的值应设置为 30
> 因为始终可以从原神的数据中找到目标达成值 > 因为始终可以从原神的数据中找到目标达成值
* 对于识别失败的值,请将该字段的值设为 `0`
- 对于识别失败的值,请将该字段的值设为 `0`

View File

@@ -6,7 +6,7 @@ Update: 2023-04-07
--- ---
> 本文档 [`Front-matter`](https://github.com/BTMuli/Mucli#FrontMatter) 由 [MuCli](https://github.com/BTMuli/Mucli) 自动生成于`2023-04-07 19:51:40` > 本文档 [`Front-matter`](https://github.com/BTMuli/Mucli#FrontMatter) 由 [MuCli](https://github.com/BTMuli/Mucli) 自动生成于`2023-04-07 19:51:40`
> >
> 更新于 `2023-04-07 19:51:40` > 更新于 `2023-04-07 19:51:40`
> 本文档为 [`UIGF`](https://github.com/UIGF-org/UIGF-org.github.io/blob/main/docs/zh/standards/UIGF-pre-release.md) 的备份。 > 本文档为 [`UIGF`](https://github.com/UIGF-org/UIGF-org.github.io/blob/main/docs/zh/standards/UIGF-pre-release.md) 的备份。
@@ -17,24 +17,26 @@ Update: 2023-04-07
## 更新记录 ## 更新记录
|版本|说明|兼容| | 版本 | 说明 | 兼容 |
|-|-|-| | ------ | ------------------------------------------------ | -------------- |
|`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` | 新增 `info.export_timestamp` 填充 UNIX 时间戳 | v2.2 and lower |
|`v2.3`| 扩充至非中文语境,使用 Json Schema 表述 | v2.3 and lower | | `v2.3` | 扩充至非中文语境,使用 Json Schema 表述 | v2.3 and lower |
## Id ## Id
原神的祈愿记录物品内包含了一项较为特殊的字段: `id` ,该值在 1.3版本后加入 原神的祈愿记录物品内包含了一项较为特殊的字段: `id` ,该值在 1.3 版本后加入
所以**先前查询出的物品**若无特殊兼容性修改则不会包含相应的 `id` 所以**先前查询出的物品**若无特殊兼容性修改则不会包含相应的 `id`
App 导出 UIGF 时 App 导出 UIGF 时
* 需要确保每个物品的 `id` 的有效性。
* 从最后一个自带有效 `id` 的物品开始,向前(相对于时间)依次递减 `id` 的值,每次递减的值应保持为 `1` - 需要确保每个物品的 `id` 的有效性。
- 从最后一个自带有效 `id` 的物品开始,向前(相对于时间)依次递减 `id` 的值,每次递减的值应保持为 `1`
导入 UIGF 到 App 时 导入 UIGF 到 App 时
* App不应假设所有的 `gacha_item` 都有有效的 `id`
* App应具有处理 `id` 字段为 `null`或 `` 空字符串的能力 - App 不应假设所有的 `gacha_item` 都有有效的 `id`
- App 应具有处理 `id` 字段为 `null`或 `` 空字符串的能力
## GachaType ## GachaType
@@ -44,19 +46,19 @@ App 导出 UIGF 时
### 映射关系 ### 映射关系
|`uigf_gacha_type`|`gacha_type`| | `uigf_gacha_type` | `gacha_type` |
|-|-| | ----------------- | -------------- |
|`100`|`100`| | `100` | `100` |
|`200`|`200`| | `200` | `200` |
|`301`|`301` or `400`| | `301` | `301` or `400` |
|`302`|`302`| | `302` | `302` |
## Json 格式 ## Json 格式
> Uniformed Interchangeable GachaLog Format standard of Json (UIGF.J) > Uniformed Interchangeable GachaLog Format standard of Json (UIGF.J)
Json 格式 由于 与从官方接口获取到的格式一致 > Json 格式 由于 与从官方接口获取到的格式一致
更便于各App的导入与导出我们也在此做出规范 > 更便于各 App 的导入与导出,我们也在此做出规范
该格式应仅用于各App间的数据互通 > 该格式应仅用于各 App 间的数据互通
### 导出的格式 ### 导出的格式
@@ -107,11 +109,7 @@ Json 格式 由于 与从官方接口获取到的格式一致
} }
}, },
"title": "Infomation", "title": "Infomation",
"required": [ "required": ["uid", "lang", "uigf_version"],
"uid",
"lang",
"uigf_version"
],
"description": "包含导出方定义的基本信息" "description": "包含导出方定义的基本信息"
}, },
"list": { "list": {
@@ -166,13 +164,7 @@ Json 格式 由于 与从官方接口获取到的格式一致
"description": "向接口查询时需要的 gacha_type" "description": "向接口查询时需要的 gacha_type"
} }
}, },
"required": [ "required": ["gacha_type", "name", "id", "uigf_gacha_type", "time"],
"gacha_type",
"name",
"id",
"uigf_gacha_type",
"time"
],
"title": "Gacha Item", "title": "Gacha Item",
"description": "祈愿物品" "description": "祈愿物品"
}, },
@@ -180,10 +172,7 @@ Json 格式 由于 与从官方接口获取到的格式一致
"description": "物品列表" "description": "物品列表"
} }
}, },
"required": [ "required": ["info", "list"],
"info",
"list"
],
"description": "UIGF 根对象" "description": "UIGF 根对象"
} }
``` ```
@@ -194,95 +183,95 @@ Json 格式 由于 与从官方接口获取到的格式一致
### 单元格的格式 ### 单元格的格式
* 在填充单元格内的数据时,应统一转换到 `String` 字符串类型后填入 - 在填充单元格内的数据时,应统一转换到 `String` 字符串类型后填入
### 表名及内容 ### 表名及内容
|表名|内容|类型|是否必要| | 表名 | 内容 | 类型 | 是否必要 |
|-|-|-|-| | ------------ | -------------------------------------- | ------ | ------------------------------ |
|统计分析|统计分析内容等|任意|否| | 统计分析 | 统计分析内容等 | 任意 | 否 |
|角色活动祈愿|`gacha_type` : `301 or 400` 的祈愿数据|祈愿表|否,但是应该导出| | 角色活动祈愿 | `gacha_type` : `301 or 400` 的祈愿数据 | 祈愿表 | 否,但是应该导出 |
|武器活动祈愿|`gacha_type` : `302` 的祈愿数据|祈愿表|否,但是应该导出| | 武器活动祈愿 | `gacha_type` : `302` 的祈愿数据 | 祈愿表 | 否,但是应该导出 |
|常驻祈愿|`gacha_type` : `200` 的祈愿数据|祈愿表|否,但是应该导出| | 常驻祈愿 | `gacha_type` : `200` 的祈愿数据 | 祈愿表 | 否,但是应该导出 |
|新手祈愿|`gacha_type` : `100` 的祈愿数据|祈愿表|否,但是应该导出| | 新手祈愿 | `gacha_type` : `100` 的祈愿数据 | 祈愿表 | 否,但是应该导出 |
|原始数据|全部祈愿数据|数据表|**详见下方原始数据表结构说明**| | 原始数据 | 全部祈愿数据 | 数据表 | **详见下方原始数据表结构说明** |
* 表的顺序可以是任意的 - 表的顺序可以是任意的
* 可以隐藏部分表,防止用户随意篡改数据 - 可以隐藏部分表,防止用户随意篡改数据
* Sheet 的名称应与游戏内祈愿记录页面显示的名称保持一致 - Sheet 的名称应与游戏内祈愿记录页面显示的名称保持一致
> App间应依据 `原始数据表` 的内容,来进行数据互通 > App 间应依据 `原始数据表` 的内容,来进行数据互通
### 祈愿表结构 ### 祈愿表结构
本节内容是为了规范兼容分析类App 本节内容是为了规范兼容分析类 App
* 表头对应的内容填充**顺序需要严格按照下方说明**排布 - 表头对应的内容填充**顺序需要严格按照下方说明**排布
* **共享保底的卡池**按祈愿类型 (`gacha_type`) 区分 - **共享保底的卡池**按祈愿类型 (`gacha_type`) 区分
* 此类 `Sheet` 存在的目的,是为了便于用户观看与祈愿分析工具的分析 - 此类 `Sheet` 存在的目的,是为了便于用户观看与祈愿分析工具的分析
|表头|内容|是否必要| | 表头 | 内容 | 是否必要 |
|-|-|-| | -------- | ---------------------------------------- | ---------------------------- |
|时间|`yyyy-MM-dd HH:mm:ss` 格式的 `time` 时间|是| | 时间 | `yyyy-MM-dd HH:mm:ss` 格式的 `time` 时间 | 是 |
|名称|`name`物品名称|是| | 名称 | `name`物品名称 | 是 |
|物品类型|`item_type`|是| | 物品类型 | `item_type` | 是 |
|星级|`rank_type`|是| | 星级 | `rank_type` | 是 |
|祈愿类型|`gacha_type` 的转义名称|是,尽管部分工具不会分析此项| | 祈愿类型 | `gacha_type` 的转义名称 | 是,尽管部分工具不会分析此项 |
|...|...|否| | ... | ... | 否 |
> 如果你认为有必要的话,可以额外增加其他表头,但请确保表头的前几列为上表规范的内容 > 如果你认为有必要的话,可以额外增加其他表头,但请确保表头的前几列为上表规范的内容
> 表内的数据通常按祈愿Id升序或降序排列分析App不应假设表内的顺序为特定的升序与降序 > 表内的数据通常按祈愿 Id 升序或降序排列,分析 App 不应假设表内的顺序为特定的升序与降序
#### `gacha_type` 转义名称 #### `gacha_type` 转义名称
|gacha_type|名称| | gacha_type | 名称 |
|-|-| | ---------- | -------------- |
|100|新手祈愿| | 100 | 新手祈愿 |
|200|常驻祈愿| | 200 | 常驻祈愿 |
|301|角色活动祈愿| | 301 | 角色活动祈愿 |
|400|角色活动祈愿-2| | 400 | 角色活动祈愿-2 |
|302|武器活动祈愿| | 302 | 武器活动祈愿 |
#### 示例 #### 示例
|时间|名称|类别|星级|祈愿类型|...| | 时间 | 名称 | 类别 | 星级 | 祈愿类型 | ... |
|-|-|-|-|-|-| | ------------------- | -------- | ---- | ---- | -------------- | --- |
|2021-02-17 18:45:09|以理服人|武器|3|角色活动祈愿-2|...| | 2021-02-17 18:45:09 | 以理服人 | 武器 | 3 | 角色活动祈愿-2 | ... |
|...|...|...|...|...|...| | ... | ... | ... | ... | ... | ... |
### 原始数据表结构 ### 原始数据表结构
导出时 导出时
* App 在导出时应尽可能询问用户是否应包含原始数据表 - App 在导出时应尽可能询问用户是否应包含原始数据表
* 一旦在工作簿内包含了名为 `原始数据` 的表,即表示支持本格式 - 一旦在工作簿内包含了名为 `原始数据` 的表,即表示支持本格式
* 该表内的内容应严格按照本格式所述填充 - 该表内的内容应严格按照本格式所述填充
* **表头的顺序需严格按照下表设置**。 - **表头的顺序需严格按照下表设置**。
* 现有的字段采用**字典顺序**递增排序,后续新增的字段依添加的顺序排在后侧。 - 现有的字段采用**字典顺序**递增排序,后续新增的字段依添加的顺序排在后侧。
* 若无特殊需求我们建议导出所有json 数据内包含的字段 - 若无特殊需求,我们建议导出所有 json 数据内包含的字段
导入时 导入时
* 强烈建议您编写不依赖于列的顺序位置便可实现导入的程序,以达到最大化的兼容。 - 强烈建议您编写不依赖于列的顺序位置便可实现导入的程序,以达到最大化的兼容。
* 如果省略了其中某些非必要字段的值,请保持表头存在,对应的列则空置。 - 如果省略了其中某些非必要字段的值,请保持表头存在,对应的列则空置。
|表头|是否必要| | 表头 | 是否必要 |
|-|-| | ----------------- | ---------------------------------------------------- |
|`count`|否,但是建议保留,不排除后续会有`count`不为1的情况| | `count` | 否,但是建议保留,不排除后续会有`count`不为 1 的情况 |
|`gacha_type`|是| | `gacha_type` | 是 |
|`id`|且大部分App按此字段排序数据| | `id` | 是,且大部分 App 按此字段排序数据 |
|`item_id`|否,目前官方已经弃用了此字段| | `item_id` | 否,目前官方已经弃用了此字段 |
|`item_type`|是| | `item_type` | 是 |
|`lang`|否,但建议保留,以便国际化| | `lang` | 否,但建议保留,以便国际化 |
|`name`|是| | `name` | 是 |
|`rank_type`|否,但建议保留,以便分析| | `rank_type` | 否,但建议保留,以便分析 |
|`time`|否,但建议保留,以便分析| | `time` | 否,但建议保留,以便分析 |
|`uid`|否,但建议将选择权交予用户,保留以便分析| | `uid` | 否,但建议将选择权交予用户,保留以便分析 |
|`uigf_gacha_type`|是| | `uigf_gacha_type` | 是 |
#### 示例 #### 示例
|count|gacha_type|id|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| | 1 | 301 | 1613556360008291100 | | 武器 | zh-cn | 以理服人 | 3 | 2021-02-17 18:45:09 | 123456789 | 301 |
|...|...|...|...|...|...|...|...|...|...|...| | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |

View File

@@ -6,7 +6,7 @@ Update: 2023-05-19
--- ---
> 本文档 [`Front-matter`](https://github.com/BTMuli/Mucli#FrontMatter) 由 [MuCli](https://github.com/BTMuli/Mucli) 自动生成于`2023-03-10 22:05:44` > 本文档 [`Front-matter`](https://github.com/BTMuli/Mucli#FrontMatter) 由 [MuCli](https://github.com/BTMuli/Mucli) 自动生成于`2023-03-10 22:05:44`
> >
> 更新于 `2023-05-19 23:02:49` > 更新于 `2023-05-19 23:02:49`
## 说明 ## 说明
@@ -16,7 +16,7 @@ Update: 2023-05-19
相关仓库:[TGAssistant](https://github.com/BTMuli/TGAssistant)。 相关仓库:[TGAssistant](https://github.com/BTMuli/TGAssistant)。
> 如下 JSON 均经过处理,并未直接作为项目 JSON 数据使用。 > 如下 JSON 均经过处理,并未直接作为项目 JSON 数据使用。
> >
> 如下图像均经过 Sharp 处理转换为 webp 格式,并未直接作为项目图像资源使用。 > 如下图像均经过 Sharp 处理转换为 webp 格式,并未直接作为项目图像资源使用。
## 侧边栏图标 ## 侧边栏图标
@@ -48,7 +48,7 @@ Update: 2023-05-19
### 图像资源 ### 图像资源
- [36691244|米游社](https://www.miyoushe.com/ys/article/36691244) - [36691244|米游社](https://www.miyoushe.com/ys/article/36691244)
- [成就系统|原神WIKI](https://wiki.biligame.com/ys/%E6%88%90%E5%B0%B1%E7%B3%BB%E7%BB%9F) - [成就系统|原神 WIKI](https://wiki.biligame.com/ys/%E6%88%90%E5%B0%B1%E7%B3%BB%E7%BB%9F)
- [HoneyHunterWorld](https://genshin.honeyhunterworld.com/?lang=EN) - [HoneyHunterWorld](https://genshin.honeyhunterworld.com/?lang=EN)
### 格式说明 ### 格式说明
@@ -57,8 +57,8 @@ Update: 2023-05-19
关于图像资源格式,涉及到的图像类型及格式如下: 关于图像资源格式,涉及到的图像类型及格式如下:
- 原石图标:`source/material/原石.webp`256x25632位深度 - 原石图标:`source/material/原石.webp`256x25632 位深度
- 成就系列图标:`source/achievementSeries/${series_id}.webp`256x25632位深度 - 成就系列图标:`source/achievementSeries/${series_id}.webp`256x25632 位深度
- 成就系列对应名片图标:见 [名片相关](#名片相关) - 成就系列对应名片图标:见 [名片相关](#名片相关)
## 名片相关 ## 名片相关
@@ -70,7 +70,7 @@ Update: 2023-05-19
参考: 参考:
- [HoneyHunterWorld](https://genshin.honeyhunterworld.com/?lang=CHS) - [HoneyHunterWorld](https://genshin.honeyhunterworld.com/?lang=CHS)
- [原神WIKI|名片](https://wiki.biligame.com/ys/%E5%90%8D%E7%89%87) - [原神 WIKI|名片](https://wiki.biligame.com/ys/%E5%90%8D%E7%89%87)
### 图像资源 ### 图像资源
@@ -78,13 +78,13 @@ Update: 2023-05-19
### 格式说明 ### 格式说明
- 名片图标:`source/nameCard/icon/${card.name}.webp`250x16532位深度 - 名片图标:`source/nameCard/icon/${card.name}.webp`250x16532 位深度
- 名片bg`source/nameCard/bg/${card.name}.webp`880x14032位深度 - 名片 bg`source/nameCard/bg/${card.name}.webp`880x14032 位深度
- 名片profile`source/nameCard/profile/${card.name}.webp`840x40032位深度 - 名片 profile`source/nameCard/profile/${card.name}.webp`840x40032 位深度
### 格式说明 ### 格式说明
- 卡牌图标:`source/gcg/card/${cardType}/${cardName}.webp`420x72032位深度 - 卡牌图标:`source/gcg/card/${cardType}/${cardName}.webp`420x72032 位深度
## 素材日历相关 ## 素材日历相关
@@ -101,9 +101,9 @@ Update: 2023-05-19
> 角色&武器资源见 [Wiki](#wiki)。 > 角色&武器资源见 [Wiki](#wiki)。
- 素材图标:`source/calendar/material/${sourceName}.webp`128x12832位深度 - 素材图标:`source/calendar/material/${sourceName}.webp`128x12832 位深度
- 星级图标:`icon/star/${star}.webp`133x2932位深度 - 星级图标:`icon/star/${star}.webp`133x2932 位深度
- 地区图标: `icon/nation/${nation}.webp`256x25632位深度 - 地区图标: `icon/nation/${nation}.webp`256x25632 位深度
## Wiki ## Wiki
@@ -131,9 +131,8 @@ Update: 2023-05-19
> >
> iconType 为 `normal` 或 `special`,目前只有 `normal`。 > iconType 为 `normal` 或 `special`,目前只有 `normal`。
- 角色图鉴:`WIKI/character/icon/${avatarId}.webp`256x25632位深度 - 角色图鉴:`WIKI/character/icon/${avatarId}.webp`256x25632 位深度
- 武器图鉴:`WIKI/weapon/icon/${weaponId}.webp`256x25632位深度 - 武器图鉴:`WIKI/weapon/icon/${weaponId}.webp`256x25632 位深度
- 卡牌图鉴: - 卡牌图鉴:
- 卡牌背景:`WIKI/GCG/${iconType}/${cardName}.webp`420x72032位深度 - 卡牌背景:`WIKI/GCG/${iconType}/${cardName}.webp`420x72032 位深度
- 卡牌图标:`WIKI/GCG/bg.${bgType}.webp`420x72032位深度 - 卡牌图标:`WIKI/GCG/bg.${bgType}.webp`420x72032 位深度

View File

@@ -1,14 +1,14 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/icon.svg" /> <link rel="icon" type="image/svg+xml" href="/icon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Tauri.Genshin</title> <title>Tauri.Genshin</title>
</head> </head>
<body> <body>
<div id="app"></div> <div id="app"></div>
<script type="module" src="/src/main.ts"></script> <script type="module" src="/src/main.ts"></script>
</body> </body>
</html> </html>

View File

@@ -1,11 +1,11 @@
{ {
"version": "0.2.0", "version": "0.2.0",
"notes": "https://github.com/BTMuli/Tauri.Genshin/releases/tag/v0.2.0", "notes": "https://github.com/BTMuli/Tauri.Genshin/releases/tag/v0.2.0",
"pub_date": "2023-06-19T07:08:41.112Z", "pub_date": "2023-06-19T07:08:41.112Z",
"platforms": { "platforms": {
"windows-x86_64": { "windows-x86_64": {
"signature": "dW50cnVzdGVkIGNvbW1lbnQ6IHNpZ25hdHVyZSBmcm9tIHRhdXJpIHNlY3JldCBrZXkKUlVSWkdzekNNZjh1aGpkUzdSRHAvMnQ0M1hIRVAwOFZxOTNqOTIyQ0dyWlY4YVFVRjNMTyttNWp6SndvK0RnVGgvOFBBNFhCSjZHeVpGUEE2elZzWmlVeFZUSVRqUllPdXdvPQp0cnVzdGVkIGNvbW1lbnQ6IHRpbWVzdGFtcDoxNjg3MTU4NTAzCWZpbGU6dGF1cmktZ2Vuc2hpbl8wLjIuMF94NjRfemgtQ04ubXNpLnppcApmK3hKeWh4WE91SFFmWnFOeTd0aTlJMnlXakFNSVBPRnREY1pUbmcybngwdFNTa1FtZGF4czU5Qm04YjN6RllvRXUxM3c1ZTQxUlZVZE5nYzNKY0JEUT09Cg==", "signature": "dW50cnVzdGVkIGNvbW1lbnQ6IHNpZ25hdHVyZSBmcm9tIHRhdXJpIHNlY3JldCBrZXkKUlVSWkdzekNNZjh1aGpkUzdSRHAvMnQ0M1hIRVAwOFZxOTNqOTIyQ0dyWlY4YVFVRjNMTyttNWp6SndvK0RnVGgvOFBBNFhCSjZHeVpGUEE2elZzWmlVeFZUSVRqUllPdXdvPQp0cnVzdGVkIGNvbW1lbnQ6IHRpbWVzdGFtcDoxNjg3MTU4NTAzCWZpbGU6dGF1cmktZ2Vuc2hpbl8wLjIuMF94NjRfemgtQ04ubXNpLnppcApmK3hKeWh4WE91SFFmWnFOeTd0aTlJMnlXakFNSVBPRnREY1pUbmcybngwdFNTa1FtZGF4czU5Qm04YjN6RllvRXUxM3c1ZTQxUlZVZE5nYzNKY0JEUT09Cg==",
"url": "https://github.com/BTMuli/Tauri.Genshin/releases/download/v0.2.0/tauri-genshin_0.2.0_x64_zh-CN.msi.zip" "url": "https://github.com/BTMuli/Tauri.Genshin/releases/download/v0.2.0/tauri-genshin_0.2.0_x64_zh-CN.msi.zip"
} }
} }
} }

View File

@@ -1,76 +1,76 @@
{ {
"build": { "build": {
"beforeDevCommand": "npm run vite:dev", "beforeDevCommand": "npm run vite:dev",
"beforeBuildCommand": "npm run vite:build", "beforeBuildCommand": "npm run vite:build",
"devPath": "http://localhost:3000", "devPath": "http://localhost:3000",
"distDir": "../dist", "distDir": "../dist",
"withGlobalTauri": true "withGlobalTauri": true
}, },
"package": { "package": {
"productName": "tauri-genshin", "productName": "tauri-genshin",
"version": "0.2.1" "version": "0.2.1"
}, },
"tauri": { "tauri": {
"allowlist": { "allowlist": {
"all": true, "all": true,
"fs": { "fs": {
"all": true, "all": true,
"scope": ["**", "**/*"] "scope": ["**", "**/*"]
}, },
"http": { "http": {
"all": true, "all": true,
"request": true, "request": true,
"scope": [ "scope": [
"https://api-takumi.mihoyo.com/*", "https://api-takumi.mihoyo.com/*",
"https://api-takumi-record.mihoyo.com/*", "https://api-takumi-record.mihoyo.com/*",
"https://api-static.mihoyo.com/*", "https://api-static.mihoyo.com/*",
"https://bbs-api.mihoyo.com/*", "https://bbs-api.mihoyo.com/*",
"https://bbs-api.miyoushe.com/*", "https://bbs-api.miyoushe.com/*",
"https://bbs.mihoyo.com/*", "https://bbs.mihoyo.com/*",
"https://hk4e-api.mihoyo.com/*", "https://hk4e-api.mihoyo.com/*",
"https://passport-api.mihoyo.com/*", "https://passport-api.mihoyo.com/*",
"https://passport-api-v4.mihoyo.com/*", "https://passport-api-v4.mihoyo.com/*",
"https://act-webstatic.mihoyo.com/*", "https://act-webstatic.mihoyo.com/*",
"https://sdk-webstatic.mihoyo.com/*", "https://sdk-webstatic.mihoyo.com/*",
"https://homa.snapgenshin.com/*" "https://homa.snapgenshin.com/*"
] ]
}, },
"shell": { "shell": {
"all": false, "all": false,
"open": true "open": true
} }
}, },
"bundle": { "bundle": {
"active": true, "active": true,
"icon": ["icons/icon.png", "icons/icon.ico"], "icon": ["icons/icon.png", "icons/icon.ico"],
"identifier": "tauri-genshin", "identifier": "tauri-genshin",
"targets": "all", "targets": "all",
"windows": { "windows": {
"wix": { "wix": {
"language": "zh-CN" "language": "zh-CN"
} }
} }
}, },
"security": { "security": {
"csp": null "csp": null
}, },
"updater": { "updater": {
"active": true, "active": true,
"dialog": true, "dialog": true,
"endpoints": ["https://raw.fastgit.org/BTMuli/Tauri.Genshin/master/latest.json"], "endpoints": ["https://raw.fastgit.org/BTMuli/Tauri.Genshin/master/latest.json"],
"pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDg2MkVGRjMxQzJDQzFBNTkKUldSWkdzekNNZjh1aHJGRXBEOGtwbUxLaU1wdWNVeUJaeGhoV2ZlZ3VlYmQ0b2tYZWQwODdnTHkK" "pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDg2MkVGRjMxQzJDQzFBNTkKUldSWkdzekNNZjh1aHJGRXBEOGtwbUxLaU1wdWNVeUJaeGhoV2ZlZ3VlYmQ0b2tYZWQwODdnTHkK"
}, },
"windows": [ "windows": [
{ {
"fullscreen": false, "fullscreen": false,
"resizable": true, "resizable": true,
"title": "Tauri.Genshin", "title": "Tauri.Genshin",
"label": "tauri-genshin", "label": "tauri-genshin",
"width": 1600, "width": 1600,
"height": 900, "height": 900,
"center": true, "center": true,
"transparent": true "transparent": true
} }
] ]
} }
} }

View File

@@ -42,7 +42,7 @@ onMounted(async () => {
}); });
// 监听主题变化 // 监听主题变化
async function listenOnTheme () { async function listenOnTheme() {
await event.listen("readTheme", (e) => { await event.listen("readTheme", (e) => {
const themeGet = e.payload as string; const themeGet = e.payload as string;
if (theme.value !== themeGet) { if (theme.value !== themeGet) {
@@ -52,7 +52,7 @@ async function listenOnTheme () {
}); });
} }
async function checkLoad () { async function checkLoad() {
if (appStore.loading) { if (appStore.loading) {
console.info("数据已加载!"); console.info("数据已加载!");
return; return;
@@ -63,13 +63,13 @@ async function checkLoad () {
} }
// 创建数据文件夹 // 创建数据文件夹
async function createDataDir () { async function createDataDir() {
console.info("开始创建数据文件夹..."); console.info("开始创建数据文件夹...");
// 如果不存在则创建 // 如果不存在则创建
if (!await fs.exists("userData", { dir: fs.BaseDirectory.AppLocalData })) { if (!(await fs.exists("userData", { dir: fs.BaseDirectory.AppLocalData }))) {
await fs.createDir("userData", { dir: fs.BaseDirectory.AppLocalData, recursive: true }); await fs.createDir("userData", { dir: fs.BaseDirectory.AppLocalData, recursive: true });
} }
if (!await fs.exists("tempData", { dir: fs.BaseDirectory.AppLocalData })) { if (!(await fs.exists("tempData", { dir: fs.BaseDirectory.AppLocalData }))) {
await fs.createDir("tempData", { dir: fs.BaseDirectory.AppLocalData, recursive: true }); await fs.createDir("tempData", { dir: fs.BaseDirectory.AppLocalData, recursive: true });
} }
console.info("数据文件夹创建完成!"); console.info("数据文件夹创建完成!");

View File

@@ -6,21 +6,21 @@
*/ */
@font-face { @font-face {
font-family: "Genshin"; font-family: "Genshin";
src: url("./汉仪文黑-85W.ttf") format("truetype"); src: url("./汉仪文黑-85W.ttf") format("truetype");
} }
@font-face { @font-face {
font-family: "Genshin-Light"; font-family: "Genshin-Light";
src: url("./汉仪文黑-55W.ttf") format("truetype"); src: url("./汉仪文黑-55W.ttf") format("truetype");
} }
@font-face { @font-face {
font-family: "JetBrians mono"; font-family: "JetBrians mono";
src: url("./JetBrainsMono-Regular.ttf") format("truetype"); src: url("./JetBrainsMono-Regular.ttf") format("truetype");
} }
@font-face { @font-face {
font-family: "JetBrians mono Bold"; font-family: "JetBrians mono Bold";
src: url("./JetBrainsMono-Bold.ttf") format("truetype"); src: url("./JetBrainsMono-Bold.ttf") format("truetype");
} }

View File

@@ -10,65 +10,64 @@
@import url("themes/dark.css"); @import url("themes/dark.css");
:root { :root {
/* font */ /* font */
--font-text: "JetBrians mono", "Genshin-Light", sans-serif; --font-text: "JetBrians mono", "Genshin-Light", sans-serif;
--font-title: "JetBrians mono Bold", "Genshin", serif; --font-title: "JetBrians mono Bold", "Genshin", serif;
/* color */ /* color */
--common-color-white: #faf7e8; --common-color-white: #faf7e8;
--common-color-black: #333333; --common-color-black: #333333;
--common-color-blue: #485466; --common-color-blue: #485466;
--common-color-blue-2: #546d8b; --common-color-blue-2: #546d8b;
--common-color-blue-3: #5b738f; --common-color-blue-3: #5b738f;
--common-color-yellow: #fec90b; --common-color-yellow: #fec90b;
--common-color-grey: #96979a; --common-color-grey: #96979a;
--common-color-grey-2: #b3b3b3; --common-color-grey-2: #b3b3b3;
} }
html { html {
font-family: var(--font-text); font-family: var(--font-text);
font-size: 16px; font-size: 16px;
} }
/* /*
* @description 侧边滚动条样式 * @description 侧边滚动条样式
* @since Alpha v0.2.1 * @since Alpha v0.2.1
*/ */
::-webkit-scrollbar { ::-webkit-scrollbar {
width: 8px; width: 8px;
border-radius: 5px; border-radius: 5px;
} }
::-webkit-scrollbar-track { ::-webkit-scrollbar-track {
background: #847c74; /* 夜灰 */ background: #847c74; /* 夜灰 */
border-radius: 5px; border-radius: 5px;
} }
::-webkit-scrollbar-thumb { ::-webkit-scrollbar-thumb {
background: #c7d2d4; /* 鸥蓝 */ background: #c7d2d4; /* 鸥蓝 */
border-radius: 5px; border-radius: 5px;
} }
/* card action 内的按钮 */ /* card action 内的按钮 */
.card-btn { .card-btn {
background: #4a5366; background: #4a5366;
color: #ece5d8; color: #ece5d8;
border-radius: 50px; border-radius: 50px;
margin-left: 5px; margin-left: 5px;
} }
.card-btn img { .card-btn img {
width: 20px; width: 20px;
height: 20px; height: 20px;
margin: 5px; margin: 5px;
} }
.card-dev-btn { .card-dev-btn {
background: #546d8b; background: #546d8b;
color: #faf7e8; color: #faf7e8;
} }
.card-dev-btn img { .card-dev-btn img {
width: 18px; width: 18px;
height: 18px; height: 18px;
} }

View File

@@ -28,11 +28,11 @@ html.dark {
--content-text-1: #1e1e1e; --content-text-1: #1e1e1e;
--content-text-2: #faf7e8; --content-text-2: #faf7e8;
--content-text-3: #e1e1e1; --content-text-3: #e1e1e1;
--btn-bg-1: #3b3d3b; --btn-bg-1: #3b3d3b;
--btn-bg-2: #e1e1e1; --btn-bg-2: #e1e1e1;
--btn-bg-3: #1e1e1e; --btn-bg-3: #1e1e1e;
--btn-text-1: #393b40; --btn-text-1: #393b40;
--card-text-1: #393b40; --card-text-1: #393b40;
} }

View File

@@ -12,7 +12,7 @@ html.default {
--common-bg-4: rgb(0 0 0 / 40%); --common-bg-4: rgb(0 0 0 / 40%);
--common-bg-8: rgb(0 0 0 / 80%); --common-bg-8: rgb(0 0 0 / 80%);
--common-text: var(--common-color-blue); /* title */ --common-text: var(--common-color-blue); /* title */
--common-text-2: var(--common-color-blue-2); /* text */ --common-text-2: var(--common-color-blue-2); /* text */
--common-text-3: var(--common-color-blue-3); /* quote */ --common-text-3: var(--common-color-blue-3); /* quote */
@@ -35,4 +35,4 @@ html.default {
--btn-text-1: #faf7e8; --btn-text-1: #faf7e8;
--card-text-1: #485466; --card-text-1: #485466;
} }

View File

@@ -29,7 +29,7 @@ const visible = computed({
set: (value) => emits("update:modelValue", value), set: (value) => emits("update:modelValue", value),
}); });
function onCancel () { function onCancel() {
visible.value = false; visible.value = false;
} }
</script> </script>

View File

@@ -7,7 +7,7 @@ import { computed } from "vue";
import TItemBox, { TItemBoxData } from "../main/t-itembox.vue"; import TItemBox, { TItemBoxData } from "../main/t-itembox.vue";
interface TibCalendarAvatarProps { interface TibCalendarAvatarProps {
modelValue: TGApp.App.Calendar.Item modelValue: TGApp.App.Calendar.Item;
} }
const props = defineProps<TibCalendarAvatarProps>(); const props = defineProps<TibCalendarAvatarProps>();

View File

@@ -7,19 +7,17 @@ import { onMounted, ref } from "vue";
import TItemBox, { TItemBoxData } from "../main/t-itembox.vue"; import TItemBox, { TItemBoxData } from "../main/t-itembox.vue";
interface TibUrAvatarProps { interface TibUrAvatarProps {
modelValue: TGApp.Sqlite.Record.Avatar modelValue: TGApp.Sqlite.Record.Avatar;
} }
const props = defineProps<TibUrAvatarProps>(); const props = defineProps<TibUrAvatarProps>();
const box = ref({} as TItemBoxData); const box = ref({} as TItemBoxData);
const getName = () => { const getName = () => {
return ( return props.modelValue.id === 10000005
props.modelValue.id === 10000005 ? "旅行者-空"
? "旅行者-空" : props.modelValue.id === 10000007
: props.modelValue.id === 10000007 ? "旅行者-荧"
? "旅行者-荧" : props.modelValue.name;
: props.modelValue.name
);
}; };
onMounted(async () => { onMounted(async () => {
@@ -38,7 +36,7 @@ onMounted(async () => {
}; };
}); });
function showData () { function showData() {
// todo @click 应该出来的是一个弹窗,而不是 console // todo @click 应该出来的是一个弹窗,而不是 console
console.log(props.modelValue); console.log(props.modelValue);
} }

View File

@@ -1,5 +1,5 @@
<template> <template>
<TItemBox :model-value="box" style="cursor: pointer;" /> <TItemBox :model-value="box" style="cursor: pointer" />
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
// vue // vue
@@ -7,7 +7,7 @@ import { computed } from "vue";
import TItemBox, { TItemBoxData } from "../main/t-itembox.vue"; import TItemBox, { TItemBoxData } from "../main/t-itembox.vue";
interface TibCalendarWeaponProps { interface TibCalendarWeaponProps {
modelValue: TGApp.App.Weapon.WikiBriefInfo modelValue: TGApp.App.Weapon.WikiBriefInfo;
} }
const props = defineProps<TibCalendarWeaponProps>(); const props = defineProps<TibCalendarWeaponProps>();

View File

@@ -1,7 +1,7 @@
<template> <template>
<transition name="fade"> <transition name="fade">
<div v-show="canTop" class="back-top" @click="handleScrollTop"> <div v-show="canTop" class="back-top" @click="handleScrollTop">
<img src="../../assets/icons/arrow-top.svg" alt="back-icon"> <img src="../../assets/icons/arrow-top.svg" alt="back-icon" />
</div> </div>
</transition> </transition>
</template> </template>
@@ -13,7 +13,7 @@ const scrollTop = ref(0); // 滚动条距离顶部的距离
const canTop = ref(false); // 默认不显示 const canTop = ref(false); // 默认不显示
// 监听滚动事件 // 监听滚动事件
function handleScroll () { function handleScroll() {
scrollTop.value = document.documentElement.scrollTop || document.body.scrollTop; scrollTop.value = document.documentElement.scrollTop || document.body.scrollTop;
// 超过500px显示回到顶部按钮 // 超过500px显示回到顶部按钮
canTop.value = scrollTop.value > 500; canTop.value = scrollTop.value > 500;
@@ -26,10 +26,10 @@ function handleScroll () {
} }
// 点击回到顶部 // 点击回到顶部
function handleScrollTop () { function handleScrollTop() {
let timer = 0; let timer = 0;
cancelAnimationFrame(timer); cancelAnimationFrame(timer);
timer = requestAnimationFrame(function fn () { timer = requestAnimationFrame(function fn() {
if (scrollTop.value > 0) { if (scrollTop.value > 0) {
scrollTop.value -= 50; scrollTop.value -= 50;
document.body.scrollTop = document.documentElement.scrollTop = scrollTop.value; document.body.scrollTop = document.documentElement.scrollTop = scrollTop.value;

View File

@@ -2,9 +2,7 @@
<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"> <v-icon size="small"> mdi-calendar-clock </v-icon>
mdi-calendar-clock
</v-icon>
<span>今日素材</span> <span>今日素材</span>
<span>{{ dateNow }}</span> <span>{{ dateNow }}</span>
</div> </div>
@@ -119,7 +117,7 @@ defineExpose({
}); });
onMounted(() => { onMounted(() => {
const dayNow = (new Date().getDay()) === 0 ? 7 : (new Date().getDay()); const dayNow = new Date().getDay() === 0 ? 7 : new Date().getDay();
weekNow.value = dayNow; weekNow.value = dayNow;
btnNow.value = dayNow; btnNow.value = dayNow;
calendarNow.value = getCalendar(dayNow); calendarNow.value = getCalendar(dayNow);
@@ -129,17 +127,17 @@ onMounted(() => {
}); });
// 获取当前日历 // 获取当前日历
function getCalendar (day: number) { function getCalendar(day: number) {
return calendarData.value.filter((item) => item.dropDays.includes(day)); return calendarData.value.filter((item) => item.dropDays.includes(day));
} }
function selectContent (item: TGApp.App.Calendar.Item, type: string) { function selectContent(item: TGApp.App.Calendar.Item, type: string) {
selectedItem.value = item; selectedItem.value = item;
selectedType.value = type; selectedType.value = type;
showItem.value = true; showItem.value = true;
} }
function getContents (day: number) { function getContents(day: number) {
btnNow.value = day; btnNow.value = day;
calendarNow.value = getCalendar(day); calendarNow.value = getCalendar(day);
characterCards.value = calendarNow.value.filter((item) => item.itemType === "character"); characterCards.value = calendarNow.value.filter((item) => item.itemType === "character");
@@ -159,7 +157,7 @@ function getContents (day: number) {
height: 45px; height: 45px;
font-size: 20px; font-size: 20px;
display: flex; display: flex;
color:rgb(255 255 255 / 80%); color: rgb(255 255 255 / 80%);
} }
.calendar-title-left { .calendar-title-left {
@@ -182,8 +180,8 @@ function getContents (day: number) {
} }
.calendar-title-btn { .calendar-title-btn {
margin-left: 10px; margin-left: 10px;
border-radius: 5px; border-radius: 5px;
} }
.calendar-divider { .calendar-divider {
@@ -194,12 +192,12 @@ function getContents (day: number) {
} }
.calendar-sub { .calendar-sub {
margin: 5px; margin: 5px;
} }
.cards-grid { .cards-grid {
display: grid; display: grid;
grid-template-columns: repeat(auto-fill, minmax(100px, 1fr)); grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
grid-gap: 8px; grid-gap: 8px;
} }
</style> </style>

View File

@@ -3,13 +3,13 @@
<div class="tib2-left"> <div class="tib2-left">
<slot name="left"> <slot name="left">
<div v-if="props.modelValue.bg !== undefined" class="tib2-bg"> <div v-if="props.modelValue.bg !== undefined" class="tib2-bg">
<img :src="props.modelValue.bg" alt="bg"> <img :src="props.modelValue.bg" alt="bg" />
</div> </div>
<div class="tib2-icon"> <div class="tib2-icon">
<img :src="props.modelValue.icon" alt="icon"> <img :src="props.modelValue.icon" alt="icon" />
</div> </div>
<div v-if="props.modelValue.star !== undefined" class="tib2-star"> <div v-if="props.modelValue.star !== undefined" class="tib2-star">
<img :src="props.modelValue.star" alt="element"> <img :src="props.modelValue.star" alt="element" />
</div> </div>
</slot> </slot>
</div> </div>
@@ -19,18 +19,17 @@
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
export interface TItemBox2Data { export interface TItemBox2Data {
width: string, width: string;
height: string, height: string;
bg?: string, bg?: string;
icon: string, icon: string;
star?: string, star?: string;
name: string, name: string;
} }
interface TItemBox2Props { interface TItemBox2Props {
modelValue: TItemBox2Data, modelValue: TItemBox2Data;
} }
const props = defineProps<TItemBox2Props>(); const props = defineProps<TItemBox2Props>();
@@ -38,16 +37,16 @@ const props = defineProps<TItemBox2Props>();
<style lang="css" scoped> <style lang="css" scoped>
.tib2-box { .tib2-box {
position: relative; position: relative;
height: v-bind(props["modelValue"]["height"]); height: v-bind(props[ "modelValue"][ "height"]);
width: v-bind(props["modelValue"]["width"]); width: v-bind(props[ "modelValue"][ "width"]);
display: flex; display: flex;
border-radius: 5px; border-radius: 5px;
background: rgb(20 20 20 / 30%); background: rgb(20 20 20 / 30%);
} }
.tib2-left { .tib2-left {
width: v-bind(props["modelValue"]["height"]); width: v-bind(props[ "modelValue"][ "height"]);
height: v-bind(props["modelValue"]["height"]); height: v-bind(props[ "modelValue"][ "height"]);
border-top-left-radius: 5px; border-top-left-radius: 5px;
border-bottom-left-radius: 5px; border-bottom-left-radius: 5px;
overflow: hidden; overflow: hidden;
@@ -57,8 +56,8 @@ const props = defineProps<TItemBox2Props>();
.tib2-icon { .tib2-icon {
position: absolute; position: absolute;
top: 0; top: 0;
width: v-bind(props["modelValue"]["height"]); width: v-bind(props[ "modelValue"][ "height"]);
height: v-bind(props["modelValue"]["height"]); height: v-bind(props[ "modelValue"][ "height"]);
border-top-left-radius: 5px; border-top-left-radius: 5px;
border-bottom-left-radius: 5px; border-bottom-left-radius: 5px;
overflow: hidden; overflow: hidden;
@@ -74,7 +73,7 @@ const props = defineProps<TItemBox2Props>();
.tib2-star { .tib2-star {
position: absolute; position: absolute;
bottom: -5px; bottom: -5px;
width: v-bind(props["modelValue"]["height"]); width: v-bind(props[ "modelValue"][ "height"]);
height: auto; height: auto;
} }
@@ -87,7 +86,7 @@ const props = defineProps<TItemBox2Props>();
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
font-size: calc(0.2 * v-bind(props["modelValue"]["height"])); font-size: calc(0.2 * v-bind(props[ "modelValue"][ "height"]));
color: var(--common-color-white); color: var(--common-color-white);
overflow: hidden; overflow: hidden;
} }

View File

@@ -2,31 +2,31 @@
<div class="tib-box"> <div class="tib-box">
<div class="tib-bg"> <div class="tib-bg">
<slot name="bg"> <slot name="bg">
<img :src="modelValue.bg" alt="bg"> <img :src="modelValue.bg" alt="bg" />
</slot> </slot>
</div> </div>
<div class="tib-icon"> <div class="tib-icon">
<slot name="icon"> <slot name="icon">
<img :src="modelValue.icon" alt="icon"> <img :src="modelValue.icon" alt="icon" />
</slot> </slot>
</div> </div>
<div class="tib-cover"> <div class="tib-cover">
<div class="tib-lt"> <div class="tib-lt">
<img :src="modelValue.lt" alt="lt"> <img :src="modelValue.lt" alt="lt" />
</div> </div>
<div v-show="modelValue.rt" class="tib-rt"> <div v-show="modelValue.rt" class="tib-rt">
{{ modelValue.rt }} {{ modelValue.rt }}
</div> </div>
<div class="tib-inner"> <div class="tib-inner">
<slot name="inner-icon"> <slot name="inner-icon">
<img v-show="modelValue.innerIcon" :src="modelValue.innerIcon" alt="inner-icon"> <img v-show="modelValue.innerIcon" :src="modelValue.innerIcon" alt="inner-icon" />
</slot> </slot>
<slot name="inner-text"> <slot name="inner-text">
<span>{{ modelValue.innerText }}</span> <span>{{ modelValue.innerText }}</span>
</slot> </slot>
</div> </div>
</div> </div>
<div v-if="modelValue.display==='outer'" class="tib-outer"> <div v-if="modelValue.display === 'outer'" class="tib-outer">
<slot name="outer-text"> <slot name="outer-text">
<span>{{ modelValue.outerText }}</span> <span>{{ modelValue.outerText }}</span>
</slot> </slot>
@@ -37,24 +37,24 @@
import { computed } from "vue"; import { computed } from "vue";
export interface TItemBoxData { export interface TItemBoxData {
bg: string, bg: string;
icon: string, icon: string;
size: string, size: string;
height: string, height: string;
display: "inner" | "outer", display: "inner" | "outer";
lt: string, lt: string;
ltSize: string, ltSize: string;
rt?: string, rt?: string;
rtSize?: string, rtSize?: string;
innerHeight?: number, innerHeight?: number;
innerIcon?: string, innerIcon?: string;
innerText: string, innerText: string;
outerHeight?: number, outerHeight?: number;
outerText?: string, outerText?: string;
} }
interface TItemBoxProps { interface TItemBoxProps {
modelValue: TItemBoxData, modelValue: TItemBoxData;
} }
const props = withDefaults(defineProps<TItemBoxProps>(), { const props = withDefaults(defineProps<TItemBoxProps>(), {
@@ -78,16 +78,16 @@ const getOuterFont = computed(() => `${props.modelValue.outerHeight / 2}px`);
<style lang="css" scoped> <style lang="css" scoped>
.tib-box { .tib-box {
position: relative; position: relative;
width: v-bind(props["modelValue"]["size"]); width: v-bind(props[ "modelValue"][ "size"]);
height: v-bind(props["modelValue"]["height"]); height: v-bind(props[ "modelValue"][ "height"]);
} }
.tib-bg { .tib-bg {
position: absolute; position: absolute;
top: 0; top: 0;
left: 0; left: 0;
width: v-bind(props["modelValue"]["size"]); width: v-bind(props[ "modelValue"][ "size"]);
height: v-bind(props["modelValue"]["size"]); height: v-bind(props[ "modelValue"][ "size"]);
border-radius: 5px; border-radius: 5px;
overflow: hidden; overflow: hidden;
} }
@@ -100,8 +100,8 @@ const getOuterFont = computed(() => `${props.modelValue.outerHeight / 2}px`);
.tib-icon { .tib-icon {
position: relative; position: relative;
width: v-bind(props["modelValue"]["size"]); width: v-bind(props[ "modelValue"][ "size"]);
height: v-bind(props["modelValue"]["size"]); height: v-bind(props[ "modelValue"][ "size"]);
overflow: hidden; overflow: hidden;
border-radius: 5px; border-radius: 5px;
} }
@@ -116,8 +116,8 @@ const getOuterFont = computed(() => `${props.modelValue.outerHeight / 2}px`);
position: absolute; position: absolute;
top: 0; top: 0;
left: 0; left: 0;
width: v-bind(props["modelValue"]["size"]); width: v-bind(props[ "modelValue"][ "size"]);
height: v-bind(props["modelValue"]["size"]); height: v-bind(props[ "modelValue"][ "size"]);
border-radius: 5px; border-radius: 5px;
display: flex; display: flex;
justify-content: center; justify-content: center;
@@ -130,8 +130,8 @@ const getOuterFont = computed(() => `${props.modelValue.outerHeight / 2}px`);
top: 0; top: 0;
left: 0; left: 0;
padding: 5px; padding: 5px;
width: v-bind(props["modelValue"]["ltSize"]); width: v-bind(props[ "modelValue"][ "ltSize"]);
height: v-bind(props["modelValue"]["ltSize"]); height: v-bind(props[ "modelValue"][ "ltSize"]);
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
@@ -147,8 +147,8 @@ const getOuterFont = computed(() => `${props.modelValue.outerHeight / 2}px`);
position: absolute; position: absolute;
top: 0; top: 0;
right: 0; right: 0;
width: v-bind(props["modelValue"]["rtSize"]); width: v-bind(props[ "modelValue"][ "rtSize"]);
height: v-bind(props["modelValue"]["rtSize"]); height: v-bind(props[ "modelValue"][ "rtSize"]);
background: rgb(0 0 0 / 40%); background: rgb(0 0 0 / 40%);
border-top-right-radius: 5px; border-top-right-radius: 5px;
border-bottom-left-radius: 5px; border-bottom-left-radius: 5px;

View File

@@ -26,19 +26,21 @@ const props = withDefaults(defineProps<TolProps>(), {
blurVal: "20px", blurVal: "20px",
}); });
watch(() => props.modelValue, () => { watch(
if (props.modelValue) { () => props.modelValue,
showTolo.value = true; () => {
showToli.value = true; if (props.modelValue) {
} else { showTolo.value = true;
setTimeout(() => { showToli.value = true;
showToli.value = false; } else {
}, 100); setTimeout(() => {
setTimeout(() => { showToli.value = false;
showTolo.value = false; }, 100);
}, 300); setTimeout(() => {
} showTolo.value = false;
}, }, 300);
}
},
); );
</script> </script>
<style lang="css" scoped> <style lang="css" scoped>

View File

@@ -1,19 +1,15 @@
<template> <template>
<div class="pool-box"> <div class="pool-box">
<div class="pool-title"> <div class="pool-title">
<img src="../../assets/icons/icon-wish.svg" alt="wish"> <img src="../../assets/icons/icon-wish.svg" alt="wish" />
限时祈愿 限时祈愿
</div> </div>
<div v-if="!loading" class="pool-grid"> <div v-if="!loading" class="pool-grid">
<v-card <v-card v-for="pool in poolCards" :key="pool.post_id" class="pool-card">
v-for="pool in poolCards"
:key="pool.post_id"
class="pool-card"
>
<v-list class="pool-list"> <v-list class="pool-list">
<v-list-item :title="pool.title" :subtitle="pool.subtitle"> <v-list-item :title="pool.title" :subtitle="pool.subtitle">
<template #prepend> <template #prepend>
<img :src="pool.voice.icon" class="pool-sideIcon" alt="icon"> <img :src="pool.voice.icon" class="pool-sideIcon" alt="icon" />
</template> </template>
<template v-if="pool.voice.url" #append> <template v-if="pool.voice.url" #append>
<audio :src="pool.voice.url" controls /> <audio :src="pool.voice.url" controls />
@@ -21,7 +17,7 @@
</v-list-item> </v-list-item>
</v-list> </v-list>
<div class="pool-cover" @click="toPost(pool)"> <div class="pool-cover" @click="toPost(pool)">
<img :src="pool.cover" alt="cover"> <img :src="pool.cover" alt="cover" />
</div> </div>
<div class="pool-character"> <div class="pool-character">
<div class="pool-icon-grid"> <div class="pool-icon-grid">
@@ -31,11 +27,16 @@
class="pool-icon" class="pool-icon"
@click="toOuter(character.url, pool.title)" @click="toOuter(character.url, pool.title)"
> >
<img :src="character.icon" alt="character"> <img :src="character.icon" alt="character" />
</div> </div>
</div> </div>
<div class="pool-clock"> <div class="pool-clock">
<v-progress-circular :model-value="poolTimePass[pool.post_id]" size="100" width="10" :color="poolColor[pool.post_id]"> <v-progress-circular
:model-value="poolTimePass[pool.post_id]"
size="100"
width="10"
:color="poolColor[pool.post_id]"
>
{{ poolTimeGet[pool.post_id] }} {{ poolTimeGet[pool.post_id] }}
</v-progress-circular> </v-progress-circular>
</div> </div>
@@ -92,7 +93,7 @@ defineExpose({
loading, loading,
}); });
function poolLastInterval (postId: number) { function poolLastInterval(postId: number) {
const pool = poolCards.value.find((pool) => pool.post_id === postId); const pool = poolCards.value.find((pool) => pool.post_id === postId);
if (!pool) return; if (!pool) return;
if (poolTimeGet.value[postId] === "未开始") { if (poolTimeGet.value[postId] === "未开始") {
@@ -105,7 +106,7 @@ function poolLastInterval (postId: number) {
const isEnd = pool.time.end_stamp - Date.now(); const isEnd = pool.time.end_stamp - Date.now();
poolTimeGet.value[postId] = getLastPoolTime(isEnd); poolTimeGet.value[postId] = getLastPoolTime(isEnd);
poolTimePass.value[postId] = poolTimePass.value[postId] =
((pool.time.end_stamp - Date.now()) / (pool.time.end_stamp - pool.time.start_stamp)) * 100; ((pool.time.end_stamp - Date.now()) / (pool.time.end_stamp - pool.time.start_stamp)) * 100;
if (isEnd >= 0) return; if (isEnd >= 0) return;
clearInterval(timer.value[postId]); clearInterval(timer.value[postId]);
timer.value[postId] = null; timer.value[postId] = null;
@@ -156,7 +157,7 @@ onMounted(async () => {
}); });
// 检测是否有新的限时祈愿 // 检测是否有新的限时祈愿
function checkCover (data: GachaData[]) { function checkCover(data: GachaData[]) {
// 如果没有缓存 // 如果没有缓存
if (!homeStore.poolCover || Object.keys(homeStore.poolCover).length === 0) { if (!homeStore.poolCover || Object.keys(homeStore.poolCover).length === 0) {
return false; return false;
@@ -180,7 +181,7 @@ function checkCover (data: GachaData[]) {
}); });
} }
async function toOuter (url: string, title: string) { async function toOuter(url: string, title: string) {
if (!url) { if (!url) {
barText.value = "链接为空!"; barText.value = "链接为空!";
barColor.value = "error"; barColor.value = "error";
@@ -190,14 +191,14 @@ async function toOuter (url: string, title: string) {
createTGWindow(url, "祈愿", title, 1200, 800, true, true); createTGWindow(url, "祈愿", title, 1200, 800, true, true);
} }
function getLastPoolTime (time: number) { function getLastPoolTime(time: number) {
const hour = Math.floor(time / 1000 / 60 / 60); const hour = Math.floor(time / 1000 / 60 / 60);
const minute = Math.floor((time / 1000 / 60 / 60 - hour) * 60); const minute = Math.floor((time / 1000 / 60 / 60 - hour) * 60);
const second = Math.floor(((time / 1000 / 60 / 60 - hour) * 60 - minute) * 60); const second = Math.floor(((time / 1000 / 60 / 60 - hour) * 60 - minute) * 60);
return `${hour}:${minute.toFixed(0).padStart(2, "0")}:${second.toFixed(0).padStart(2, "0")}`; return `${hour}:${minute.toFixed(0).padStart(2, "0")}:${second.toFixed(0).padStart(2, "0")}`;
} }
function toPost (pool: GachaCard) { function toPost(pool: GachaCard) {
const path = router.resolve({ const path = router.resolve({
name: "帖子详情", name: "帖子详情",
params: { params: {
@@ -225,7 +226,7 @@ onUnmounted(() => {
.pool-title { .pool-title {
color: var(--common-text); color: var(--common-text);
font-family: var(--font-title); font-family: var(--font-title);
font-size: 20px; font-size: 20px;
display: flex; display: flex;
} }
@@ -235,7 +236,7 @@ onUnmounted(() => {
height: 25px; height: 25px;
transform: translate(0, 2px); transform: translate(0, 2px);
margin-right: 10px; margin-right: 10px;
border-radius: 50%; border-radius: 50%;
background: var(--common-bg-2); background: var(--common-bg-2);
} }
@@ -247,19 +248,19 @@ onUnmounted(() => {
} }
.pool-card { .pool-card {
background: #45b787; /* 蛙绿 */ background: #45b787; /* 蛙绿 */
color: #eef7f2; /* 丹白 */ color: #eef7f2; /* 丹白 */
border-radius: 5px; border-radius: 5px;
} }
.dark .pool-card { .dark .pool-card {
background: #1f2623; /* 苷蓝绿 */ background: #1f2623; /* 苷蓝绿 */
} }
.pool-list { .pool-list {
font-family: var(--font-title); font-family: var(--font-title);
background: inherit; background: inherit;
color: inherit; color: inherit;
} }
.pool-sideIcon { .pool-sideIcon {
@@ -267,7 +268,7 @@ onUnmounted(() => {
width: 40px; width: 40px;
height: 40px; height: 40px;
border-radius: 50%; border-radius: 50%;
background: var(--common-bg-2); background: var(--common-bg-2);
} }
.pool-cover { .pool-cover {
@@ -282,7 +283,7 @@ onUnmounted(() => {
} }
.pool-cover img { .pool-cover img {
width: 100%; width: 100%;
transition: all 0.5s; transition: all 0.5s;
border-radius: 10px; border-radius: 10px;
} }
@@ -301,22 +302,22 @@ onUnmounted(() => {
} }
.pool-icon-grid { .pool-icon-grid {
display: grid; display: grid;
grid-template-columns: repeat(4,70px); grid-template-columns: repeat(4, 70px);
grid-column-gap: 10px; grid-column-gap: 10px;
} }
.pool-icon { .pool-icon {
width: 70px; width: 70px;
height: 70px; height: 70px;
border-radius: 5px; border-radius: 5px;
} }
.pool-icon img { .pool-icon img {
width: 100%; width: 100%;
height: 100%; height: 100%;
border-radius: 5px; border-radius: 5px;
cursor: pointer; cursor: pointer;
} }
.pool-clock { .pool-clock {

View File

@@ -1,15 +1,11 @@
<template> <template>
<div class="position-box"> <div class="position-box">
<div class="position-title"> <div class="position-title">
<img src="../../assets/icons/board.svg" alt="act"> <img src="../../assets/icons/board.svg" alt="act" />
<span>近期活动</span> <span>近期活动</span>
</div> </div>
<div v-if="!loading" class="position-grid"> <div v-if="!loading" class="position-grid">
<v-card <v-card v-for="card in positionCards" :key="card.post_id" class="position-card">
v-for="card in positionCards"
:key="card.post_id"
class="position-card"
>
<v-list class="position-list"> <v-list class="position-list">
<v-list-item :title="card.title" :subtitle="card.abstract"> <v-list-item :title="card.title" :subtitle="card.abstract">
<template #prepend> <template #prepend>
@@ -18,9 +14,7 @@
</v-avatar> </v-avatar>
</template> </template>
<template #append> <template #append>
<v-btn variant="outlined" @click="toPost(card)"> <v-btn variant="outlined" @click="toPost(card)"> 查看 </v-btn>
查看
</v-btn>
</template> </template>
</v-list-item> </v-list-item>
</v-list> </v-list>
@@ -38,7 +32,9 @@
positionTimeGet[card.post_id] positionTimeGet[card.post_id]
}}</span> }}</span>
<!-- 粉红 --> <!-- 粉红 -->
<span v-if="positionTimeGet[card.post_id] === '已结束'" style="color: #f2b9b2">已结束</span> <span v-if="positionTimeGet[card.post_id] === '已结束'" style="color: #f2b9b2"
>已结束</span
>
</div> </div>
</v-card-text> </v-card-text>
</v-card> </v-card>
@@ -74,7 +70,7 @@ defineExpose({
loading, loading,
}); });
function positionLastInterval (postId: number) { function positionLastInterval(postId: number) {
const timeGet = positionTimeGet.value[postId]; const timeGet = positionTimeGet.value[postId];
if (timeGet === "未知" || timeGet === "已结束") { if (timeGet === "未知" || timeGet === "已结束") {
clearInterval(positionTimer.value[postId]); clearInterval(positionTimer.value[postId]);
@@ -110,17 +106,17 @@ onMounted(async () => {
loading.value = false; loading.value = false;
}); });
function getLastPositionTime (time: number) { function getLastPositionTime(time: number) {
const day = Math.floor(time / (24 * 3600 * 1000)); const day = Math.floor(time / (24 * 3600 * 1000));
const hour = Math.floor((time % (24 * 3600 * 1000)) / (3600 * 1000)); const hour = Math.floor((time % (24 * 3600 * 1000)) / (3600 * 1000));
const minute = Math.floor((time % (3600 * 1000)) / (60 * 1000)); const minute = Math.floor((time % (3600 * 1000)) / (60 * 1000));
const second = Math.floor((time % (60 * 1000)) / 1000); const second = Math.floor((time % (60 * 1000)) / 1000);
return `${day}${hour.toFixed(0).padStart(2, "0")}:${minute.toFixed(0).padStart(2, "0")}:${second return `${day}${hour.toFixed(0).padStart(2, "0")}:${minute
.toFixed(0) .toFixed(0)
.padStart(2, "0")}`; .padStart(2, "0")}:${second.toFixed(0).padStart(2, "0")}`;
} }
async function toPost (card: PositionCard) { async function toPost(card: PositionCard) {
// 获取路由路径 // 获取路由路径
const path = router.resolve({ const path = router.resolve({
name: "帖子详情", name: "帖子详情",
@@ -173,7 +169,7 @@ onUnmounted(() => {
.position-card { .position-card {
background: #45b787; /* 蛙绿 */ background: #45b787; /* 蛙绿 */
color: #eef7f2; /* 月白 */ color: #eef7f2; /* 月白 */
border-radius: 5px border-radius: 5px;
} }
.dark .position-card { .dark .position-card {

View File

@@ -1,9 +1,7 @@
<template> <template>
<div class="share-box"> <div class="share-box">
<div class="share-btn" @click="shareContent()"> <div class="share-btn" @click="shareContent()">
<v-icon style="color:var(--theme-switch-icon)"> <v-icon style="color: var(--theme-switch-icon)"> mdi-share-variant </v-icon>
mdi-share-variant
</v-icon>
</div> </div>
</div> </div>
</template> </template>
@@ -18,7 +16,7 @@ interface TShareBtnProps {
const props = defineProps<TShareBtnProps>(); const props = defineProps<TShareBtnProps>();
async function shareContent () { async function shareContent() {
await generateShareImg(props.title, props.modelValue); await generateShareImg(props.title, props.modelValue);
} }
</script> </script>

View File

@@ -17,38 +17,38 @@
<!-- 菜单项 --> <!-- 菜单项 -->
<v-list-item value="home" title="首页" :link="true" href="/"> <v-list-item value="home" title="首页" :link="true" href="/">
<template #prepend> <template #prepend>
<img src="/source/UI/paimon.webp" alt="homeIcon" class="side-icon"> <img src="/source/UI/paimon.webp" alt="homeIcon" class="side-icon" />
</template> </template>
</v-list-item> </v-list-item>
<v-list-item title="公告" value="announcements" :link="true" href="/announcements"> <v-list-item title="公告" value="announcements" :link="true" href="/announcements">
<template #prepend> <template #prepend>
<img src="../../assets/icons/board.svg" alt="annoIcon" class="side-icon"> <img src="../../assets/icons/board.svg" alt="annoIcon" class="side-icon" />
</template> </template>
</v-list-item> </v-list-item>
<v-list-item title="咨讯" value="news" :link="true" href="/news/2"> <v-list-item title="咨讯" value="news" :link="true" href="/news/2">
<template #prepend> <template #prepend>
<img src="/platforms/mhy/mys.webp" alt="mihoyo" class="side-icon"> <img src="/platforms/mhy/mys.webp" alt="mihoyo" class="side-icon" />
</template> </template>
</v-list-item> </v-list-item>
<v-list-item title="成就" value="achievements" :link="true" href="/achievements"> <v-list-item title="成就" value="achievements" :link="true" href="/achievements">
<template #prepend> <template #prepend>
<img src="../../assets/icons/achievements.svg" alt="achievementsIcon" class="side-icon"> <img src="../../assets/icons/achievements.svg" alt="achievementsIcon" class="side-icon" />
</template> </template>
</v-list-item> </v-list-item>
<v-divider /> <v-divider />
<v-list-item title="原神战绩" value="record" :link="true" href="/user/record"> <v-list-item title="原神战绩" value="record" :link="true" href="/user/record">
<template #prepend> <template #prepend>
<img src="/source/UI/userRecord.webp" alt="record" class="side-icon"> <img src="/source/UI/userRecord.webp" alt="record" class="side-icon" />
</template> </template>
</v-list-item> </v-list-item>
<v-list-item title="我的角色" value="character" :link="true" href="/user/characters"> <v-list-item title="我的角色" value="character" :link="true" href="/user/characters">
<template #prepend> <template #prepend>
<img src="/source/UI/userAvatar.webp" alt="characters" class="side-icon"> <img src="/source/UI/userAvatar.webp" alt="characters" class="side-icon" />
</template> </template>
</v-list-item> </v-list-item>
<v-list-item title="深渊记录" value="abyss" :link="true" href="/user/abyss"> <v-list-item title="深渊记录" value="abyss" :link="true" href="/user/abyss">
<template #prepend> <template #prepend>
<img src="/source/UI/userAbyss.webp" alt="abyss" class="side-icon"> <img src="/source/UI/userAbyss.webp" alt="abyss" class="side-icon" />
</template> </template>
</v-list-item> </v-list-item>
<!-- todo --> <!-- todo -->
@@ -68,35 +68,35 @@
<template #activator="{ props }"> <template #activator="{ props }">
<v-list-item title="图鉴" v-bind="props"> <v-list-item title="图鉴" v-bind="props">
<template #prepend> <template #prepend>
<img src="/source/UI/guideMini.webp" alt="wikiIcon" class="side-icon-mini"> <img src="/source/UI/guideMini.webp" alt="wikiIcon" class="side-icon-mini" />
</template> </template>
</v-list-item> </v-list-item>
</template> </template>
<v-list-item title="深渊数据库" value="wiki-abyss" :link="true" href="/wiki/abyss"> <v-list-item title="深渊数据库" value="wiki-abyss" :link="true" href="/wiki/abyss">
<template #prepend> <template #prepend>
<img src="/icon/star/Abyss.webp" alt="abyssIcon" class="side-icon"> <img src="/icon/star/Abyss.webp" alt="abyssIcon" class="side-icon" />
</template> </template>
</v-list-item> </v-list-item>
<v-list-item title="GCG" value="wiki-GCG" :link="true" href="/wiki/GCG"> <v-list-item title="GCG" value="wiki-GCG" :link="true" href="/wiki/GCG">
<template #prepend> <template #prepend>
<img src="../../assets/icons/GCG.svg" alt="gcgIcon" class="side-icon"> <img src="../../assets/icons/GCG.svg" alt="gcgIcon" class="side-icon" />
</template> </template>
</v-list-item> </v-list-item>
<v-list-item title="角色图鉴" value="wiki-character" :link="true" href="/wiki/character"> <v-list-item title="角色图鉴" value="wiki-character" :link="true" href="/wiki/character">
<template #prepend> <template #prepend>
<img src="/source/UI/avatarMini.webp" alt="characterIcon" class="side-icon-mini"> <img src="/source/UI/avatarMini.webp" alt="characterIcon" class="side-icon-mini" />
</template> </template>
</v-list-item> </v-list-item>
<v-list-item title="武器图鉴" value="wiki-weapon" :link="true" href="/wiki/weapon"> <v-list-item title="武器图鉴" value="wiki-weapon" :link="true" href="/wiki/weapon">
<template #prepend> <template #prepend>
<img src="/source/UI/weaponMini.webp" alt="weaponIcon" class="side-icon-mini"> <img src="/source/UI/weaponMini.webp" alt="weaponIcon" class="side-icon-mini" />
</template> </template>
</v-list-item> </v-list-item>
</v-list-group> </v-list-group>
<div class="bottom-menu"> <div class="bottom-menu">
<v-list-item> <v-list-item>
<template #prepend> <template #prepend>
<img :src="userInfo.avatar" alt="userIcon" class="side-icon"> <img :src="userInfo.avatar" alt="userIcon" class="side-icon" />
</template> </template>
<template #default> <template #default>
<v-list-item-title> <v-list-item-title>
@@ -113,7 +113,7 @@
</v-list-item> </v-list-item>
<v-list-item title="设置" value="config" :link="true" href="/config"> <v-list-item title="设置" value="config" :link="true" href="/config">
<template #prepend> <template #prepend>
<img src="../../assets/icons/setting.svg" alt="setting" class="side-icon"> <img src="../../assets/icons/setting.svg" alt="setting" class="side-icon" />
</template> </template>
</v-list-item> </v-list-item>
</div> </div>
@@ -143,10 +143,10 @@ const userInfo = computed(() => {
const rail = ref(appStore.sidebar.collapse); const rail = ref(appStore.sidebar.collapse);
// theme // theme
const themeGet = computed({ const themeGet = computed({
get () { get() {
return appStore.theme; return appStore.theme;
}, },
set (value: string) { set(value: string) {
appStore.theme = value; appStore.theme = value;
}, },
}); });
@@ -155,15 +155,15 @@ const themeTitle = computed(() => {
}); });
const open = computed({ const open = computed({
get () { get() {
return appStore.getSubmenu(); return appStore.getSubmenu();
}, },
set (value: string[]) { set(value: string[]) {
appStore.sidebar.submenu.wiki = value.includes("wiki"); appStore.sidebar.submenu.wiki = value.includes("wiki");
}, },
}); });
function collapse () { function collapse() {
rail.value = !rail.value; rail.value = !rail.value;
appStore.sidebar.collapse = rail.value; appStore.sidebar.collapse = rail.value;
} }
@@ -172,14 +172,14 @@ onMounted(async () => {
await listenOnTheme(); await listenOnTheme();
}); });
async function listenOnTheme () { async function listenOnTheme() {
await event.listen("readTheme", (e) => { await event.listen("readTheme", (e) => {
const theme = e.payload as string; const theme = e.payload as string;
themeGet.value = theme === "default" ? "default" : "dark"; themeGet.value = theme === "default" ? "default" : "dark";
}); });
} }
async function switchTheme () { async function switchTheme() {
await event.emit("readTheme", themeGet.value === "default" ? "dark" : "default"); await event.emit("readTheme", themeGet.value === "default" ? "dark" : "default");
} }
</script> </script>

View File

@@ -1,6 +1,6 @@
<template> <template>
<div class="tsl-box"> <div class="tsl-box">
<img src="/src/assets/icons/arrow-right.svg" alt="right"> <img src="/src/assets/icons/arrow-right.svg" alt="right" />
<slot> <slot>
{{ title }} {{ title }}
</slot> </slot>

View File

@@ -1,8 +1,8 @@
<template> <template>
<div class="switch-box"> <div class="switch-box">
<div class="switch-btn" @click="switchTheme()"> <div class="switch-btn" @click="switchTheme()">
<v-icon style="color:var(--theme-switch-icon)"> <v-icon style="color: var(--theme-switch-icon)">
{{ themeGet === 'default' ? 'mdi-weather-night' : 'mdi-weather-sunny' }} {{ themeGet === "default" ? "mdi-weather-night" : "mdi-weather-sunny" }}
</v-icon> </v-icon>
</div> </div>
</div> </div>
@@ -19,10 +19,10 @@ import { useAppStore } from "../../store/modules/app";
const appStore = useAppStore(); const appStore = useAppStore();
// theme // theme
const themeGet = computed({ const themeGet = computed({
get () { get() {
return appStore.theme; return appStore.theme;
}, },
set (value: string) { set(value: string) {
appStore.theme = value; appStore.theme = value;
}, },
}); });
@@ -31,12 +31,12 @@ onMounted(async () => {
await listenOnTheme(); await listenOnTheme();
}); });
async function switchTheme () { async function switchTheme() {
appStore.changeTheme(); appStore.changeTheme();
await event.emit("readTheme", themeGet.value); await event.emit("readTheme", themeGet.value);
} }
async function listenOnTheme () { async function listenOnTheme() {
await event.listen("readTheme", (e) => { await event.listen("readTheme", (e) => {
const theme = e.payload as string; const theme = e.payload as string;
themeGet.value = theme === "default" ? "default" : "dark"; themeGet.value = theme === "default" ? "default" : "dark";

View File

@@ -4,27 +4,33 @@
<div class="box-div"> <div class="box-div">
<div class="toc-top"> <div class="toc-top">
<div class="toc-icon"> <div class="toc-icon">
<TibCalendarAvatar v-if="itemType=== 'character'" v-model="itemVal" size="100px" style="cursor: default" /> <TibCalendarAvatar
<TibCalendarWeapon v-if="itemType=== 'weapon'" v-model="itemVal" size="100px" style="cursor: default" /> v-if="itemType === 'character'"
v-model="itemVal"
size="100px"
style="cursor: default"
/>
<TibCalendarWeapon
v-if="itemType === 'weapon'"
v-model="itemVal"
size="100px"
style="cursor: default"
/>
</div> </div>
<div class="toc-material-grid"> <div class="toc-material-grid">
<TibCalendarMaterial v-for="item in itemVal.materials" :item="item" /> <TibCalendarMaterial v-for="item in itemVal.materials" :item="item" />
</div> </div>
</div> </div>
<img src="/source/UI/item-line.webp" alt="line" class="toc-line"> <img src="/source/UI/item-line.webp" alt="line" class="toc-line" />
<div class="toc-bottom"> <div class="toc-bottom">
<div class="toc-src-box"> <div class="toc-src-box">
<div class="toc-src-text"> <div class="toc-src-text">来源</div>
来源 <img :src="`/icon/nation/${itemVal.source.area}.webp`" alt="icon" />
</div> <div class="toc-src-text">{{ itemVal.source.area }} - {{ itemVal.source.name }}</div>
<img :src="`/icon/nation/${itemVal.source.area}.webp`" alt="icon">
<div class="toc-src-text">
{{ itemVal.source.area }} - {{ itemVal.source.name }}
</div>
</div> </div>
<v-btn variant="outlined" @click="toDetail(itemVal)"> <v-btn variant="outlined" @click="toDetail(itemVal)">
<template #append> <template #append>
<img src="../../assets/icons/arrow-right.svg" alt="right" class="toc-btn-img"> <img src="../../assets/icons/arrow-right.svg" alt="right" class="toc-btn-img" />
</template> </template>
详情 详情
</v-btn> </v-btn>
@@ -83,7 +89,7 @@ const onCancel = () => {
emits("cancel"); emits("cancel");
}; };
function toDetail (item: TGApp.App.Calendar.Item) { function toDetail(item: TGApp.App.Calendar.Item) {
if (item.contentId === 0) { if (item.contentId === 0) {
snackbar.value = true; snackbar.value = true;
return; return;

View File

@@ -2,12 +2,10 @@
<TOverlay v-model="visible" hide :to-click="onCancel" blur-val="20px"> <TOverlay v-model="visible" hide :to-click="onCancel" blur-val="20px">
<div class="toc-box"> <div class="toc-box">
<div class="toc-top"> <div class="toc-top">
<div class="toc-title"> <div class="toc-title">请选择要跳转的频道</div>
请选择要跳转的频道
</div>
<div class="toc-list"> <div class="toc-list">
<div v-for="item in channelList" class="toc-list-item" @click="toChannel(item.link)"> <div v-for="item in channelList" class="toc-list-item" @click="toChannel(item.link)">
<img :src="item.icon" alt="icon"> <img :src="item.icon" alt="icon" />
<span>{{ item.title }}</span> <span>{{ item.title }}</span>
</div> </div>
</div> </div>
@@ -86,13 +84,14 @@ const channelList: ToChannelItem[] = [
title: "大别野", title: "大别野",
icon: "/platforms/mhy/dby.webp", icon: "/platforms/mhy/dby.webp",
link: "/news/5", link: "/news/5",
}]; },
];
function onCancel () { function onCancel() {
visible.value = false; visible.value = false;
} }
function toChannel (link: string) { function toChannel(link: string) {
visible.value = false; visible.value = false;
router.push(link); router.push(link);
setTimeout(() => { setTimeout(() => {

View File

@@ -5,21 +5,26 @@
<div class="confirm-title"> <div class="confirm-title">
{{ title }} {{ title }}
</div> </div>
<div v-show="subtitle!=='' && !isInput" class="confirm-subtitle"> <div v-show="subtitle !== '' && !isInput" class="confirm-subtitle">
{{ subtitle }} {{ subtitle }}
</div> </div>
<div v-show="isInput" class="confirm-input"> <div v-show="isInput" class="confirm-input">
<v-text-field v-model="inputVal" :label="subtitle||''" hide-details="auto" @keyup.enter="onConfirm" /> <v-text-field
v-model="inputVal"
:label="subtitle || ''"
hide-details="auto"
@keyup.enter="onConfirm"
/>
</div> </div>
<div class="confirm-btn-box"> <div class="confirm-btn-box">
<button class="confirm-btn" @click="onCancel"> <button class="confirm-btn" @click="onCancel">
<img class="btn-icon" src="../../assets/icons/circle-cancel.svg" alt="cancel"> <img class="btn-icon" src="../../assets/icons/circle-cancel.svg" alt="cancel" />
<span class="btn-text"> <span class="btn-text">
{{ cancel }} {{ cancel }}
</span> </span>
</button> </button>
<button class="confirm-btn" @click="onConfirm"> <button class="confirm-btn" @click="onConfirm">
<img class="btn-icon" src="../../assets/icons/circle-check.svg" alt="confirm"> <img class="btn-icon" src="../../assets/icons/circle-check.svg" alt="confirm" />
<span class="btn-text"> <span class="btn-text">
{{ confirm }} {{ confirm }}
</span> </span>

View File

@@ -15,8 +15,8 @@
</div> </div>
<div class="tol-img"> <div class="tol-img">
<slot name="img"> <slot name="img">
<img v-if="!empty" src="/source/UI/loading.webp" alt="loading"> <img v-if="!empty" src="/source/UI/loading.webp" alt="loading" />
<img v-else src="/source/UI/empty.webp" alt="empty"> <img v-else src="/source/UI/empty.webp" alt="empty" />
</slot> </slot>
</div> </div>
</div> </div>
@@ -43,9 +43,12 @@ const props = withDefaults(defineProps<LoadingProps>(), {
empty: false, empty: false,
}); });
watch(() => props.modelValue, (v) => { watch(
show.value = v; () => props.modelValue,
}); (v) => {
show.value = v;
},
);
</script> </script>
<style lang="css" scoped> <style lang="css" scoped>
.tol-div { .tol-div {

View File

@@ -5,7 +5,8 @@
<div class="tud-db-icons-grid"> <div class="tud-db-icons-grid">
<TibAbyssDetail <TibAbyssDetail
v-for="avatar in props.modelValue.characters" v-for="avatar in props.modelValue.characters"
:key="avatar.id" :model-value="avatar" :key="avatar.id"
:model-value="avatar"
/> />
</div> </div>
</template> </template>

View File

@@ -6,7 +6,7 @@
</slot> </slot>
</div> </div>
<div class="tud-t-val"> <div class="tud-t-val">
<img src="/icon/star/Abyss.webp" alt="Abyss"> <img src="/icon/star/Abyss.webp" alt="Abyss" />
<slot name="val"> <slot name="val">
<span>{{ props.val }}</span> <span>{{ props.val }}</span>
</slot> </slot>
@@ -53,7 +53,7 @@ const getFontSize: ComputedRef<string> = computed(() => {
display: flex; display: flex;
align-items: center; align-items: center;
font-family: var(--font-text); font-family: var(--font-text);
font-size: v-bind(getFontSize); font-size: v-bind(getFontSize);
color: var(--common-color-white); color: var(--common-color-white);
text-shadow: 0 0 10px var(--common-color-yellow); text-shadow: 0 0 10px var(--common-color-yellow);
} }

View File

@@ -1,18 +1,25 @@
<template> <template>
<div class="tuad-box"> <div class="tuad-box">
<TuaDetailTitle :val="props.modelValue.winStar" :name="`第${props.modelValue.id}层`" mode="floor" /> <TuaDetailTitle
:val="props.modelValue.winStar"
:name="`第${props.modelValue.id}层`"
mode="floor"
/>
<div class="tuad-index-box"> <div class="tuad-index-box">
<TuaDetailLevel v-for="level in props.modelValue.levels" :key="level.id" :model-value="level" /> <TuaDetailLevel
v-for="level in props.modelValue.levels"
:key="level.id"
:model-value="level"
/>
</div> </div>
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import TuaDetailTitle from "./tua-detail-title.vue"; import TuaDetailTitle from "./tua-detail-title.vue";
import TuaDetailLevel from "./tua-detail-level.vue"; import TuaDetailLevel from "./tua-detail-level.vue";
interface TuaDetailProps { interface TuaDetailProps {
modelValue: TGApp.Sqlite.Abyss.Floor modelValue: TGApp.Sqlite.Abyss.Floor;
} }
const props = defineProps<TuaDetailProps>(); const props = defineProps<TuaDetailProps>();

View File

@@ -14,7 +14,8 @@
<slot name="val-icons"> <slot name="val-icons">
<TibAbyssOverview <TibAbyssOverview
v-for="avatar in JSON.parse(props.valIcons) as TGApp.Sqlite.Abyss.Character[]" v-for="avatar in JSON.parse(props.valIcons) as TGApp.Sqlite.Abyss.Character[]"
:key="avatar.id" :model-value="avatar" :key="avatar.id"
:model-value="avatar"
/> />
</slot> </slot>
</div> </div>
@@ -25,10 +26,10 @@
import TibAbyssOverview from "../itembox/tib-abyss-overview.vue"; import TibAbyssOverview from "../itembox/tib-abyss-overview.vue";
interface TAOProps { interface TAOProps {
title: string, title: string;
valText?: string | number, valText?: string | number;
valIcons?: string, valIcons?: string;
iconNum: number, iconNum: number;
} }
const props = withDefaults(defineProps<TAOProps>(), { const props = withDefaults(defineProps<TAOProps>(), {

View File

@@ -1,18 +1,16 @@
<template> <template>
<div class="tuc-dc-box"> <div class="tuc-dc-box">
<div v-if="!modelValue.active" class="tuc-dc-lock"> <div v-if="!modelValue.active" class="tuc-dc-lock">
<v-icon color="white"> <v-icon color="white"> mdi-lock </v-icon>
mdi-lock
</v-icon>
</div> </div>
<div class="tuc-dc-icon"> <div class="tuc-dc-icon">
<img :src="modelValue.icon" alt="constellation"> <img :src="modelValue.icon" alt="constellation" />
</div> </div>
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
interface TucDetailConstellationProps { interface TucDetailConstellationProps {
modelValue: TGApp.Sqlite.Character.RoleConstellation modelValue: TGApp.Sqlite.Character.RoleConstellation;
} }
defineProps<TucDetailConstellationProps>(); defineProps<TucDetailConstellationProps>();

View File

@@ -34,7 +34,7 @@ interface TucDetailDescConstellationProps {
const props = defineProps<TucDetailDescConstellationProps>(); const props = defineProps<TucDetailDescConstellationProps>();
// 解析描述 // 解析描述
function parseDesc (desc: string): string { function parseDesc(desc: string): string {
const reg = /<color=(.*?)>(.*?)<\/color>/g; const reg = /<color=(.*?)>(.*?)<\/color>/g;
let match = reg.exec(desc); let match = reg.exec(desc);
while (match) { while (match) {

View File

@@ -12,14 +12,12 @@
<span>{{ props.modelValue.level }}</span> <span>{{ props.modelValue.level }}</span>
</div> </div>
<div class="tuc-ddrc-bottom"> <div class="tuc-ddrc-bottom">
<img :src="`/icon/star/${props.modelValue.star}.webp`" alt="star"> <img :src="`/icon/star/${props.modelValue.star}.webp`" alt="star" />
</div> </div>
</div> </div>
</template> </template>
<template #desc> <template #desc>
<div class="tuc-ddrd-title"> <div class="tuc-ddrd-title">{{ props.modelValue.set.name }}</div>
{{ props.modelValue.set.name }}
</div>
<div v-for="desc in props.modelValue.set.effect" class="tuc-ddrc-desc"> <div v-for="desc in props.modelValue.set.effect" class="tuc-ddrc-desc">
<span>{{ desc.active }}件套</span> <span>{{ desc.active }}件套</span>
<span>{{ desc.description }}</span> <span>{{ desc.description }}</span>

View File

@@ -14,7 +14,7 @@
<span></span> <span></span>
</div> </div>
<div class="tuc-ddwc-bottom"> <div class="tuc-ddwc-bottom">
<img :src="`/icon/star/${props.modelValue.star}.webp`" alt="star"> <img :src="`/icon/star/${props.modelValue.star}.webp`" alt="star" />
</div> </div>
</div> </div>
</template> </template>

View File

@@ -1,19 +1,18 @@
<template> <template>
<div class="tuc-dib-box"> <div class="tuc-dib-box">
<div v-if="modelValue.bg" class="tuc-dib-bg"> <div v-if="modelValue.bg" class="tuc-dib-bg">
<img :src="modelValue.bg" alt="bg"> <img :src="modelValue.bg" alt="bg" />
</div> </div>
<div v-if="modelValue.icon" class="tuc-dib-icon"> <div v-if="modelValue.icon" class="tuc-dib-icon">
<img :src="modelValue.icon" alt="icon"> <img :src="modelValue.icon" alt="icon" />
</div> </div>
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
interface TucDetailItemBoxProps { interface TucDetailItemBoxProps {
modelValue: { modelValue: {
icon?: string, icon?: string;
bg?: string, bg?: string;
}; };
} }

View File

@@ -2,13 +2,11 @@
<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-box">
<div class="tuc-do-bg"> <div class="tuc-do-bg">
<img :src="data.bg" alt="role"> <img :src="data.bg" alt="role" />
</div>
<div class="tuc-do-quote">
* 所有数据以游戏内为准此处仅供参考
</div> </div>
<div class="tuc-do-quote">* 所有数据以游戏内为准此处仅供参考</div>
<!-- 衣装 --> <!-- 衣装 -->
<div v-if="data.costume.length>0" class="tuc-do-costume"> <div v-if="data.costume.length > 0" class="tuc-do-costume">
<v-switch v-model="showCostumeSwitch" color="#faf7e8" @click="switchBg"> <v-switch v-model="showCostumeSwitch" color="#faf7e8" @click="switchBg">
<template #label> <template #label>
<v-icon>mdi-tshirt-crew-outline</v-icon> <v-icon>mdi-tshirt-crew-outline</v-icon>
@@ -26,7 +24,7 @@
:style="{ :style="{
border: selected.pos === 0 ? '2px solid var(--common-color-yellow)' : '', border: selected.pos === 0 ? '2px solid var(--common-color-yellow)' : '',
}" }"
@click="showDetail(data.weapon,'武器',0)" @click="showDetail(data.weapon, '武器', 0)"
> >
<TucDetailItemBox v-model="weaponBox" /> <TucDetailItemBox v-model="weaponBox" />
</div> </div>
@@ -37,7 +35,7 @@
cursor: item ? 'pointer' : 'default', cursor: item ? 'pointer' : 'default',
border: selected.pos === index + 1 ? '2px solid var(--common-color-yellow)' : '', border: selected.pos === index + 1 ? '2px solid var(--common-color-yellow)' : '',
}" }"
@click="showDetail(item,'圣遗物',index + 1)" @click="showDetail(item, '圣遗物', index + 1)"
> >
<TucDetailRelic :model-value="item" :pos="index.toString()" /> <TucDetailRelic :model-value="item" :pos="index.toString()" />
</div> </div>
@@ -50,9 +48,9 @@
class="tuc-dor-item" class="tuc-dor-item"
:model-value="item" :model-value="item"
:style="{ :style="{
border: selected.pos === item.pos+5 ? '2px solid var(--common-color-yellow)' : '', border: selected.pos === item.pos + 5 ? '2px solid var(--common-color-yellow)' : '',
}" }"
@click="showDetail(item, '命座', item.pos+5)" @click="showDetail(item, '命座', item.pos + 5)"
/> />
</div> </div>
</div> </div>
@@ -123,18 +121,21 @@ const data = ref({
bg: "" as string, bg: "" as string,
}); });
const selected = ref({ const selected = ref({
data: {} as TGApp.Sqlite.Character.RoleConstellation data: {} as
| TGApp.Sqlite.Character.RoleWeapon | TGApp.Sqlite.Character.RoleConstellation
| TGApp.Sqlite.Character.RoleReliquary, | TGApp.Sqlite.Character.RoleWeapon
| TGApp.Sqlite.Character.RoleReliquary,
type: "武器" || "命之座" || "圣遗物", type: "武器" || "命之座" || "圣遗物",
pos: 0, // 用于标记选中的是哪个位置 pos: 0, // 用于标记选中的是哪个位置
}); });
// 加载数据 // 加载数据
function loadData () { function loadData() {
if (!props.modelValue) return; if (!props.modelValue) return;
data.value.weapon = JSON.parse(props.dataVal.weapon) as TGApp.Sqlite.Character.RoleWeapon; data.value.weapon = JSON.parse(props.dataVal.weapon) as TGApp.Sqlite.Character.RoleWeapon;
data.value.constellation = JSON.parse(props.dataVal.constellation) as TGApp.Sqlite.Character.RoleConstellation[]; data.value.constellation = JSON.parse(
props.dataVal.constellation,
) as TGApp.Sqlite.Character.RoleConstellation[];
if (props.dataVal.reliquary !== "") { if (props.dataVal.reliquary !== "") {
const relics = JSON.parse(props.dataVal.reliquary) as TGApp.Sqlite.Character.RoleReliquary[]; const relics = JSON.parse(props.dataVal.reliquary) as TGApp.Sqlite.Character.RoleReliquary[];
relics.map((item) => { relics.map((item) => {
@@ -173,12 +174,12 @@ const onCancel = () => {
emits("cancel"); emits("cancel");
}; };
function showDetail ( function showDetail(
item: item:
TGApp.Sqlite.Character.RoleConstellation | | TGApp.Sqlite.Character.RoleConstellation
TGApp.Sqlite.Character.RoleWeapon | | TGApp.Sqlite.Character.RoleWeapon
TGApp.Sqlite.Character.RoleReliquary | | TGApp.Sqlite.Character.RoleReliquary
false, | false,
type: string, type: string,
pos: number = 0, pos: number = 0,
) { ) {
@@ -190,7 +191,7 @@ function showDetail (
}; };
} }
function switchBg () { function switchBg() {
if (data.value.bg === props.dataVal.img) { if (data.value.bg === props.dataVal.img) {
data.value.bg = data.value.costume[0].icon; data.value.bg = data.value.costume[0].icon;
} else { } else {

View File

@@ -1,13 +1,13 @@
<template> <template>
<div class="tuc-dr-box"> <div class="tuc-dr-box">
<div class="tuc-dr-bg"> <div class="tuc-dr-bg">
<img :src="`/icon/relic/${props.pos}.webp`" alt="relic"> <img :src="`/icon/relic/${props.pos}.webp`" alt="relic" />
</div> </div>
<div v-if="props.modelValue" class="tuc-dr-bg"> <div v-if="props.modelValue" class="tuc-dr-bg">
<img :src="`/icon/bg/${props.modelValue.star}-Star.webp`" alt="bg"> <img :src="`/icon/bg/${props.modelValue.star}-Star.webp`" alt="bg" />
</div> </div>
<div v-if="props.modelValue" class="tuc-dr-icon"> <div v-if="props.modelValue" class="tuc-dr-icon">
<img :src="props.modelValue.icon" alt="relic"> <img :src="props.modelValue.icon" alt="relic" />
</div> </div>
</div> </div>
</template> </template>

View File

@@ -6,21 +6,19 @@
</div> </div>
<div class="tuc-rb-bottom"> <div class="tuc-rb-bottom">
<!-- bg 好感名片 --> <!-- bg 好感名片 -->
<div v-if="nameCard!==false" class="tuc-rbb-bg"> <div v-if="nameCard !== false" class="tuc-rbb-bg">
<img :src="nameCard" alt="nameCard"> <img :src="nameCard" alt="nameCard" />
</div> </div>
<!-- 表面 lock --> <!-- 表面 lock -->
<div v-if="props.modelValue.fetter!==10" class="tuc-rbb-lock"> <div v-if="props.modelValue.fetter !== 10" class="tuc-rbb-lock">
<v-icon size="20" color="var(--page-bg)"> <v-icon size="20" color="var(--page-bg)"> mdi-lock </v-icon>
mdi-lock
</v-icon>
</div> </div>
<!-- 左上角好感等级 --> <!-- 左上角好感等级 -->
<div class="tuc-rbb-fetter"> <div class="tuc-rbb-fetter">
<img src="/icon/material/105.webp" alt="fetter"> <img src="/icon/material/105.webp" alt="fetter" />
<span>{{ props.modelValue.fetter }}</span> <span>{{ props.modelValue.fetter }}</span>
<!-- 衣装 icon --> <!-- 衣装 icon -->
<span v-if="props.modelValue.costume!=='[]'"> <span v-if="props.modelValue.costume !== '[]'">
<v-icon>mdi-tshirt-crew-outline</v-icon> <v-icon>mdi-tshirt-crew-outline</v-icon>
</span> </span>
</div> </div>
@@ -83,14 +81,12 @@ onMounted(async () => {
nameCard.value = `/source/nameCard/profile/${role.nameCard}.webp`; nameCard.value = `/source/nameCard/profile/${role.nameCard}.webp`;
}); });
function getAvatarName () { function getAvatarName() {
return ( return props.modelValue.cid === 10000005
props.modelValue.cid === 10000005 ? "旅行者-空"
? "旅行者-空" : props.modelValue.cid === 10000007
: props.modelValue.cid === 10000007 ? "旅行者-荧"
? "旅行者-荧" : props.modelValue.name;
: props.modelValue.name
);
} }
</script> </script>
<style lang="css" scoped> <style lang="css" scoped>

View File

@@ -1,7 +1,5 @@
<template> <template>
<div v-if="props.modelValue===undefined"> <div v-if="props.modelValue === undefined">暂无数据</div>
暂无数据
</div>
<div v-else class="tur-ag-box"> <div v-else class="tur-ag-box">
<TibUrAvatar v-for="avatar in data" :key="avatar.id" :model-value="avatar" /> <TibUrAvatar v-for="avatar in data" :key="avatar.id" :model-value="avatar" />
</div> </div>

View File

@@ -1,7 +1,5 @@
<template> <template>
<div v-if="props.modelValue===undefined"> <div v-if="props.modelValue === undefined">暂无数据</div>
暂无数据
</div>
<div v-else class="tur-hg-box"> <div v-else class="tur-hg-box">
<TurHomeSub v-for="home in homes" :data="home" /> <TurHomeSub v-for="home in homes" :data="home" />
</div> </div>

View File

@@ -11,7 +11,7 @@
</div> </div>
<div class="tur-hs-title"> <div class="tur-hs-title">
<!-- canvas --> <!-- canvas -->
<img :src="getUrl.icon" alt="comfort"> <img :src="getUrl.icon" alt="comfort" />
{{ data.comfortName }} {{ data.comfortName }}
</div> </div>
<div class="tur-hs-text-grid"> <div class="tur-hs-text-grid">

View File

@@ -1,7 +1,5 @@
<template> <template>
<div v-if="props.modelValue===undefined"> <div v-if="props.modelValue === undefined">暂无数据</div>
暂无数据
</div>
<div v-else class="tur-og-box"> <div v-else class="tur-og-box">
<TurOverviewSub title="活跃天数" :text="data.activeDays" /> <TurOverviewSub title="活跃天数" :text="data.activeDays" />
<TurOverviewSub title="成就达成数" :text="data.achievementNumber" /> <TurOverviewSub title="成就达成数" :text="data.achievementNumber" />
@@ -26,13 +24,11 @@ import { computed } from "vue";
import TurOverviewSub from "./tur-overview-sub.vue"; import TurOverviewSub from "./tur-overview-sub.vue";
interface TurOverviewGridProps { interface TurOverviewGridProps {
modelValue?: string modelValue?: string;
} }
const props = defineProps<TurOverviewGridProps>(); const props = defineProps<TurOverviewGridProps>();
const data = computed(() => const data = computed(() => JSON.parse(<string>props.modelValue) as TGApp.Sqlite.Record.Stats);
JSON.parse(<string>props.modelValue) as TGApp.Sqlite.Record.Stats,
);
</script> </script>
<style lang="css" scoped> <style lang="css" scoped>
.tur-og-box { .tur-og-box {

View File

@@ -14,8 +14,8 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
interface TAOProps { interface TAOProps {
title: string, title: string;
text: string | number, text: string | number;
} }
defineProps<TAOProps>(); defineProps<TAOProps>();

View File

@@ -1,7 +1,5 @@
<template> <template>
<div v-if="props.modelValue===undefined"> <div v-if="props.modelValue === undefined">暂无数据</div>
暂无数据
</div>
<div v-else class="tur-wg-box"> <div v-else class="tur-wg-box">
<TurWorldSub v-for="area in getData()" :data="area" :theme="theme" /> <TurWorldSub v-for="area in getData()" :data="area" :theme="theme" />
</div> </div>
@@ -25,7 +23,7 @@ const theme = computed(() => {
} }
}); });
function getData () { function getData() {
return JSON.parse(<string>props.modelValue) as TGApp.Sqlite.Record.WorldExplore[]; return JSON.parse(<string>props.modelValue) as TGApp.Sqlite.Record.WorldExplore[];
} }
</script> </script>

View File

@@ -5,11 +5,11 @@
backgroundImage: `url('${getUrl.bg}')`, backgroundImage: `url('${getUrl.bg}')`,
backgroundPositionX: 'right', backgroundPositionX: 'right',
backgroundSize: 'cover', backgroundSize: 'cover',
backgroundRepeat: 'no-repeat' backgroundRepeat: 'no-repeat',
}" }"
> >
<div class="tur-ws-icon"> <div class="tur-ws-icon">
<img :src="getUrl.icon" alt="icon"> <img :src="getUrl.icon" alt="icon" />
</div> </div>
<div class="tur-ws-content"> <div class="tur-ws-content">
<div class="tur-ws-title"> <div class="tur-ws-title">
@@ -20,13 +20,13 @@
<span>{{ data.exploration / 10 }}</span> <span>{{ data.exploration / 10 }}</span>
<span>%</span> <span>%</span>
</div> </div>
<div v-if="data.type==='Reputation'" class="tur-ws-sub"> <div v-if="data.type === 'Reputation'" class="tur-ws-sub">
<span>声望等级</span> <span>声望等级</span>
<span>{{ data.level }}</span> <span>{{ data.level }}</span>
<span></span> <span></span>
</div> </div>
<div v-if="data.offerings.length>0" class="tur-ws-sub"> <div v-if="data.offerings.length > 0" class="tur-ws-sub">
<img :src="getUrl.offer" alt="offer"> <img :src="getUrl.offer" alt="offer" />
<span>{{ data.offerings[0].name }}等级</span> <span>{{ data.offerings[0].name }}等级</span>
<span>{{ data.offerings[0].level }}</span> <span>{{ data.offerings[0].level }}</span>
<span></span> <span></span>
@@ -35,7 +35,6 @@
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
// vue // vue
import { onMounted, ref } from "vue"; import { onMounted, ref } from "vue";
// tauri // tauri
@@ -44,8 +43,8 @@ import { event } from "@tauri-apps/api";
import { saveImgLocal } from "../../utils/TGShare"; import { saveImgLocal } from "../../utils/TGShare";
interface TurWorldSubProps { interface TurWorldSubProps {
theme: "default" | "dark", theme: "default" | "dark";
data: TGApp.Sqlite.Record.WorldExplore data: TGApp.Sqlite.Record.WorldExplore;
} }
const props = defineProps<TurWorldSubProps>(); const props = defineProps<TurWorldSubProps>();
@@ -66,11 +65,11 @@ onMounted(async () => {
getUrl.value.offer = await saveImgLocal(props.data.offerings[0].icon); getUrl.value.offer = await saveImgLocal(props.data.offerings[0].icon);
} }
props.theme === "dark" props.theme === "dark"
? getUrl.value.icon = getUrl.value.iconLight ? (getUrl.value.icon = getUrl.value.iconLight)
: getUrl.value.icon = getUrl.value.iconDark; : (getUrl.value.icon = getUrl.value.iconDark);
}); });
async function listenOnTheme () { async function listenOnTheme() {
await event.listen("readTheme", (e) => { await event.listen("readTheme", (e) => {
const theme = e.payload as string; const theme = e.payload as string;
if (theme === "dark") { if (theme === "dark") {

File diff suppressed because it is too large Load Diff

View File

@@ -1,330 +1,330 @@
[ [
{ {
"id": 0, "id": 0,
"order": 1, "order": 1,
"name": "天地万象", "name": "天地万象",
"version": "3.6", "version": "3.6",
"card": "", "card": "",
"icon": "/source/achievementSeries/0.webp" "icon": "/source/achievementSeries/0.webp"
}, },
{ {
"id": 17, "id": 17,
"order": 2, "order": 2,
"name": "心跳的记忆", "name": "心跳的记忆",
"version": "3.7", "version": "3.7",
"card": "", "card": "",
"icon": "/source/achievementSeries/17.webp" "icon": "/source/achievementSeries/17.webp"
}, },
{ {
"id": 1, "id": 1,
"order": 3, "order": 3,
"name": "尘世巡游·第一辑", "name": "尘世巡游·第一辑",
"version": "1.0", "version": "1.0",
"card": "成就·游遍", "card": "成就·游遍",
"icon": "/source/achievementSeries/1.webp" "icon": "/source/achievementSeries/1.webp"
}, },
{ {
"id": 22, "id": 22,
"order": 4, "order": 4,
"name": "尘世巡游·第二辑", "name": "尘世巡游·第二辑",
"version": "2.0", "version": "2.0",
"card": "成就·遍历", "card": "成就·遍历",
"icon": "/source/achievementSeries/22.webp" "icon": "/source/achievementSeries/22.webp"
}, },
{ {
"id": 32, "id": 32,
"order": 5, "order": 5,
"name": "尘世巡游·第三辑", "name": "尘世巡游·第三辑",
"version": "3.0", "version": "3.0",
"card": "成就·漫行", "card": "成就·漫行",
"icon": "/source/achievementSeries/32.webp" "icon": "/source/achievementSeries/32.webp"
}, },
{ {
"id": 2, "id": 2,
"order": 6, "order": 6,
"name": "冒险手艺", "name": "冒险手艺",
"version": "1.0", "version": "1.0",
"card": "成就·殊技", "card": "成就·殊技",
"icon": "/source/achievementSeries/2.webp" "icon": "/source/achievementSeries/2.webp"
}, },
{ {
"id": 3, "id": 3,
"order": 7, "order": 7,
"name": "英雄之旅", "name": "英雄之旅",
"version": "1.0", "version": "1.0",
"card": "成就·侠行", "card": "成就·侠行",
"icon": "/source/achievementSeries/3.webp" "icon": "/source/achievementSeries/3.webp"
}, },
{ {
"id": 4, "id": 4,
"order": 8, "order": 8,
"name": "蒙德·风与牧歌的城邦", "name": "蒙德·风与牧歌的城邦",
"version": "1.0", "version": "1.0",
"card": "蒙德·风吟", "card": "蒙德·风吟",
"icon": "/source/achievementSeries/4.webp" "icon": "/source/achievementSeries/4.webp"
}, },
{ {
"id": 5, "id": 5,
"order": 9, "order": 9,
"name": "璃月·岩与契约的海港", "name": "璃月·岩与契约的海港",
"version": "1.0", "version": "1.0",
"card": "璃月·岩寂", "card": "璃月·岩寂",
"icon": "/source/achievementSeries/5.webp" "icon": "/source/achievementSeries/5.webp"
}, },
{ {
"id": 6, "id": 6,
"order": 10, "order": 10,
"name": "元素专家·第一辑", "name": "元素专家·第一辑",
"version": "1.0", "version": "1.0",
"card": "成就·虹色", "card": "成就·虹色",
"icon": "/source/achievementSeries/6.webp" "icon": "/source/achievementSeries/6.webp"
}, },
{ {
"id": 36, "id": 36,
"order": 11, "order": 11,
"name": "元素专家·第二辑", "name": "元素专家·第二辑",
"version": "3.1", "version": "3.1",
"card": "成就·七芒", "card": "成就·七芒",
"icon": "/source/achievementSeries/36.webp" "icon": "/source/achievementSeries/36.webp"
}, },
{ {
"id": 7, "id": 7,
"order": 12, "order": 12,
"name": "神射手", "name": "神射手",
"version": "1.0", "version": "1.0",
"card": "成就·强弓", "card": "成就·强弓",
"icon": "/source/achievementSeries/7.webp" "icon": "/source/achievementSeries/7.webp"
}, },
{ {
"id": 8, "id": 8,
"order": 13, "order": 13,
"name": "挑战者·第一辑", "name": "挑战者·第一辑",
"version": "1.0", "version": "1.0",
"card": "成就·挑战", "card": "成就·挑战",
"icon": "/source/achievementSeries/8.webp" "icon": "/source/achievementSeries/8.webp"
}, },
{ {
"id": 14, "id": 14,
"order": 14, "order": 14,
"name": "挑战者·第二辑", "name": "挑战者·第二辑",
"version": "1.1", "version": "1.1",
"card": "成就·挑战·其二", "card": "成就·挑战·其二",
"icon": "/source/achievementSeries/14.webp" "icon": "/source/achievementSeries/14.webp"
}, },
{ {
"id": 15, "id": 15,
"order": 15, "order": 15,
"name": "挑战者·第三辑", "name": "挑战者·第三辑",
"version": "1.2", "version": "1.2",
"card": "成就·挑战·其三", "card": "成就·挑战·其三",
"icon": "/source/achievementSeries/15.webp" "icon": "/source/achievementSeries/15.webp"
}, },
{ {
"id": 20, "id": 20,
"order": 16, "order": 16,
"name": "挑战者·第四辑", "name": "挑战者·第四辑",
"version": "2.0", "version": "2.0",
"card": "成就·石龙", "card": "成就·石龙",
"icon": "/source/achievementSeries/20.webp" "icon": "/source/achievementSeries/20.webp"
}, },
{ {
"id": 29, "id": 29,
"order": 17, "order": 17,
"name": "挑战者·第五辑", "name": "挑战者·第五辑",
"version": "2.6", "version": "2.6",
"card": "成就·雷音", "card": "成就·雷音",
"icon": "/source/achievementSeries/29.webp" "icon": "/source/achievementSeries/29.webp"
}, },
{ {
"id": 34, "id": 34,
"order": 18, "order": 18,
"name": "挑战者·第六辑", "name": "挑战者·第六辑",
"version": "3.1", "version": "3.1",
"card": "成就·镜梦", "card": "成就·镜梦",
"icon": "/source/achievementSeries/34.webp" "icon": "/source/achievementSeries/34.webp"
}, },
{ {
"id": 39, "id": 39,
"order": 19, "order": 19,
"name": "挑战者·第七辑", "name": "挑战者·第七辑",
"version": "3.6", "version": "3.6",
"card": "成就·槿暮", "card": "成就·槿暮",
"icon": "/source/achievementSeries/39.webp" "icon": "/source/achievementSeries/39.webp"
}, },
{ {
"id": 9, "id": 9,
"order": 20, "order": 20,
"name": "秘境与深境螺旋·第一辑", "name": "秘境与深境螺旋·第一辑",
"version": "1.0", "version": "1.0",
"card": "成就·深秘", "card": "成就·深秘",
"icon": "/source/achievementSeries/9.webp" "icon": "/source/achievementSeries/9.webp"
}, },
{ {
"id": 10, "id": 10,
"order": 21, "order": 21,
"name": "Olah第一辑", "name": "Olah第一辑",
"version": "1.0", "version": "1.0",
"card": "成就·山民", "card": "成就·山民",
"icon": "/source/achievementSeries/10.webp" "icon": "/source/achievementSeries/10.webp"
}, },
{ {
"id": 11, "id": 11,
"order": 22, "order": 22,
"name": "至冬国不相信眼泪·第一辑", "name": "至冬国不相信眼泪·第一辑",
"version": "1.0", "version": "1.0",
"card": "成就·雪乡", "card": "成就·雪乡",
"icon": "/source/achievementSeries/11.webp" "icon": "/source/achievementSeries/11.webp"
}, },
{ {
"id": 12, "id": 12,
"order": 23, "order": 23,
"name": "岩港往事·第一辑", "name": "岩港往事·第一辑",
"version": "1.0", "version": "1.0",
"card": "成就·合扇", "card": "成就·合扇",
"icon": "/source/achievementSeries/12.webp" "icon": "/source/achievementSeries/12.webp"
}, },
{ {
"id": 13, "id": 13,
"order": 24, "order": 24,
"name": "异世相逢·第一辑", "name": "异世相逢·第一辑",
"version": "1.0", "version": "1.0",
"card": "成就·相逢", "card": "成就·相逢",
"icon": "/source/achievementSeries/13.webp" "icon": "/source/achievementSeries/13.webp"
}, },
{ {
"id": 21, "id": 21,
"order": 25, "order": 25,
"name": "异世相逢·第二辑", "name": "异世相逢·第二辑",
"version": "2.1", "version": "2.1",
"card": "成就·门扉", "card": "成就·门扉",
"icon": "/source/achievementSeries/21.webp" "icon": "/source/achievementSeries/21.webp"
}, },
{ {
"id": 33, "id": 33,
"order": 26, "order": 26,
"name": "异世相逢·第三辑", "name": "异世相逢·第三辑",
"version": "3.0", "version": "3.0",
"card": "成就·逢缘", "card": "成就·逢缘",
"icon": "/source/achievementSeries/33.webp" "icon": "/source/achievementSeries/33.webp"
}, },
{ {
"id": 16, "id": 16,
"order": 27, "order": 27,
"name": "雪山上的来客", "name": "雪山上的来客",
"version": "1.2", "version": "1.2",
"card": "成就·雪峰", "card": "成就·雪峰",
"icon": "/source/achievementSeries/16.webp" "icon": "/source/achievementSeries/16.webp"
}, },
{ {
"id": 18, "id": 18,
"order": 28, "order": 28,
"name": "世外洞天·第一辑", "name": "世外洞天·第一辑",
"version": "1.5", "version": "1.5",
"card": "成就·壶歌", "card": "成就·壶歌",
"icon": "/source/achievementSeries/18.webp" "icon": "/source/achievementSeries/18.webp"
}, },
{ {
"id": 19, "id": 19,
"order": 29, "order": 29,
"name": "世外洞天·第二辑", "name": "世外洞天·第二辑",
"version": "1.6", "version": "1.6",
"card": "成就·旅居", "card": "成就·旅居",
"icon": "/source/achievementSeries/19.webp" "icon": "/source/achievementSeries/19.webp"
}, },
{ {
"id": 23, "id": 23,
"order": 30, "order": 30,
"name": "世外洞天·第三辑", "name": "世外洞天·第三辑",
"version": "2.0", "version": "2.0",
"card": "成就·繁花", "card": "成就·繁花",
"icon": "/source/achievementSeries/23.webp" "icon": "/source/achievementSeries/23.webp"
}, },
{ {
"id": 24, "id": 24,
"order": 31, "order": 31,
"name": "稻妻·雷与永恒的群岛·其之一", "name": "稻妻·雷与永恒的群岛·其之一",
"version": "2.0", "version": "2.0",
"card": "稻妻·九条之纹", "card": "稻妻·九条之纹",
"icon": "/source/achievementSeries/24.webp" "icon": "/source/achievementSeries/24.webp"
}, },
{ {
"id": 26, "id": 26,
"order": 32, "order": 32,
"name": "稻妻·雷与永恒的群岛·其之二", "name": "稻妻·雷与永恒的群岛·其之二",
"version": "2.1", "version": "2.1",
"card": "稻妻·珊瑚宫之纹", "card": "稻妻·珊瑚宫之纹",
"icon": "/source/achievementSeries/26.webp" "icon": "/source/achievementSeries/26.webp"
}, },
{ {
"id": 27, "id": 27,
"order": 33, "order": 33,
"name": "雾海纪行", "name": "雾海纪行",
"version": "2.2", "version": "2.2",
"card": "稻妻·鹫羽", "card": "稻妻·鹫羽",
"icon": "/source/achievementSeries/27.webp" "icon": "/source/achievementSeries/27.webp"
}, },
{ {
"id": 25, "id": 25,
"order": 34, "order": 34,
"name": "提瓦特钓鱼指南·第一辑", "name": "提瓦特钓鱼指南·第一辑",
"version": "2.1", "version": "2.1",
"card": "成就·敲针", "card": "成就·敲针",
"icon": "/source/achievementSeries/25.webp" "icon": "/source/achievementSeries/25.webp"
}, },
{ {
"id": 28, "id": 28,
"order": 35, "order": 35,
"name": "白昼之光", "name": "白昼之光",
"version": "2.4", "version": "2.4",
"card": "稻妻·常世", "card": "稻妻·常世",
"icon": "/source/achievementSeries/28.webp" "icon": "/source/achievementSeries/28.webp"
}, },
{ {
"id": 30, "id": 30,
"order": 36, "order": 36,
"name": "岩窟流明", "name": "岩窟流明",
"version": "2.6", "version": "2.6",
"card": "成就·层岩", "card": "成就·层岩",
"icon": "/source/achievementSeries/30.webp" "icon": "/source/achievementSeries/30.webp"
}, },
{ {
"id": 31, "id": 31,
"order": 37, "order": 37,
"name": "须弥·玄识深藏的雨林", "name": "须弥·玄识深藏的雨林",
"version": "3.0", "version": "3.0",
"card": "须弥·瑶林", "card": "须弥·瑶林",
"icon": "/source/achievementSeries/31.webp" "icon": "/source/achievementSeries/31.webp"
}, },
{ {
"id": 35, "id": 35,
"order": 38, "order": 38,
"name": "须弥·饰金砂原·其之一", "name": "须弥·饰金砂原·其之一",
"version": "3.1", "version": "3.1",
"card": "须弥·踏沙", "card": "须弥·踏沙",
"icon": "/source/achievementSeries/35.webp" "icon": "/source/achievementSeries/35.webp"
}, },
{ {
"id": 38, "id": 38,
"order": 39, "order": 39,
"name": "须弥·饰金砂原·其之二", "name": "须弥·饰金砂原·其之二",
"version": "3.4", "version": "3.4",
"card": "须弥·砂岚", "card": "须弥·砂岚",
"icon": "/source/achievementSeries/38.webp" "icon": "/source/achievementSeries/38.webp"
}, },
{ {
"id": 37, "id": 37,
"order": 40, "order": 40,
"name": "七圣召唤", "name": "七圣召唤",
"version": "3.3", "version": "3.3",
"card": "成就·七圣", "card": "成就·七圣",
"icon": "/source/achievementSeries/37.webp" "icon": "/source/achievementSeries/37.webp"
}, },
{ {
"id": 41, "id": 41,
"order": 41, "order": 41,
"name": "佑灵砾漠", "name": "佑灵砾漠",
"version": "3.6", "version": "3.6",
"card": "成就·万种", "card": "成就·万种",
"icon": "/source/achievementSeries/41.webp" "icon": "/source/achievementSeries/41.webp"
} }
] ]

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -33,6 +33,6 @@ const wikiFiles = import.meta.glob("./wiki/**/*.json");
* @param {string} name 文件名 * @param {string} name 文件名
* @returns {Promise<any>} 文件内容 * @returns {Promise<any>} 文件内容
*/ */
export async function getWikiData (dir: string, name: string) { export async function getWikiData(dir: string, name: string): Promise<any> {
return await wikiFiles[`./wiki/${dir}/${name}.json`](); return await wikiFiles[`./wiki/${dir}/${name}.json`]();
} }

View File

@@ -14,30 +14,35 @@
@keyup.enter="searchCard" @keyup.enter="searchCard"
/> />
<template #append> <template #append>
<v-btn prepend-icon="mdi-import" class="ms-2 top-btn" @click="importJson"> <v-btn prepend-icon="mdi-import" class="ms-2 top-btn" @click="importJson"> 导入 </v-btn>
导入 <v-btn prepend-icon="mdi-export" class="ms-2 top-btn" @click="exportJson"> 导出 </v-btn>
</v-btn>
<v-btn prepend-icon="mdi-export" class="ms-2 top-btn" @click="exportJson">
导出
</v-btn>
</template> </template>
</v-app-bar> </v-app-bar>
<TOLoading v-model="loading" :title="loadingTitle" /> <TOLoading v-model="loading" :title="loadingTitle" />
<div class="wrap"> <div class="wrap">
<!-- 左侧菜单 --> <!-- 左侧菜单 -->
<div class="left-wrap"> <div class="left-wrap">
<v-list v-for="series in seriesList" :key="series.id" class="card-left" @click="selectSeries(series.id)"> <v-list
<div class="version-icon-series"> v-for="series in seriesList"
v{{ series.version }} :key="series.id"
</div> class="card-left"
@click="selectSeries(series.id)"
>
<div class="version-icon-series">v{{ series.version }}</div>
<v-list-item> <v-list-item>
<template #prepend> <template #prepend>
<v-img width="40px" style="margin-right: 10px" :src="`/source/achievement/${series.id}.webp`" /> <v-img
width="40px"
style="margin-right: 10px"
:src="`/source/achievement/${series.id}.webp`"
/>
</template> </template>
<v-list-item-title> <v-list-item-title>
{{ series.name }} {{ series.name }}
</v-list-item-title> </v-list-item-title>
<v-list-item-subtitle> {{ series.finCount }} / {{ series.totalCount }} </v-list-item-subtitle> <v-list-item-subtitle>
{{ series.finCount }} / {{ series.totalCount }}
</v-list-item-subtitle>
</v-list-item> </v-list-item>
</v-list> </v-list>
</div> </div>
@@ -65,11 +70,13 @@
</template> </template>
</v-list-item> </v-list-item>
</v-list> </v-list>
<div <div class="list-empty" :style="{ height: `${emptyHeight}px` }">
class="list-empty" <v-list
:style="{height: `${emptyHeight}px`}" v-for="achievement in renderAchievement"
> :key="achievement.id"
<v-list v-for="achievement in renderAchievement" :key="achievement.id" class="card-right" :style="{Transform:`translateY(${translateY})`}"> class="card-right"
:style="{ Transform: `translateY(${translateY})` }"
>
<div v-if="achievement.progress !== 0" class="achievement-progress"> <div v-if="achievement.progress !== 0" class="achievement-progress">
{{ achievement.progress }} {{ achievement.progress }}
</div> </div>
@@ -86,7 +93,9 @@
</v-list-item-title> </v-list-item-title>
<v-list-item-subtitle>{{ achievement.description }}</v-list-item-subtitle> <v-list-item-subtitle>{{ achievement.description }}</v-list-item-subtitle>
<template #append> <template #append>
<span v-show="achievement.isCompleted" class="right-time">{{ achievement.completedTime }}</span> <span v-show="achievement.isCompleted" class="right-time">{{
achievement.completedTime
}}</span>
<v-card class="reward-card"> <v-card class="reward-card">
<v-img src="/icon/material/201.webp" sizes="32" /> <v-img src="/icon/material/201.webp" sizes="32" />
<div class="reward-num"> <div class="reward-num">
@@ -172,9 +181,12 @@ onMounted(async () => {
loading.value = false; loading.value = false;
}); });
function handleScroll (e: Event) { function handleScroll(e: Event) {
// 如果 scrollTop 到底部了 // 如果 scrollTop 到底部了
if ((e.target as HTMLElement).scrollTop + (e.target as HTMLElement).offsetHeight >= (e.target as HTMLElement).scrollHeight) { if (
(e.target as HTMLElement).scrollTop + (e.target as HTMLElement).offsetHeight >=
(e.target as HTMLElement).scrollHeight
) {
// 如果 selectedAchievement 的长度小于 itemCount不进行偏移 // 如果 selectedAchievement 的长度小于 itemCount不进行偏移
if (selectedAchievement.value.length <= itemCount.value) { if (selectedAchievement.value.length <= itemCount.value) {
window.requestAnimationFrame(() => { window.requestAnimationFrame(() => {
@@ -210,7 +222,7 @@ function handleScroll (e: Event) {
} }
// 渲染选中的成就系列 // 渲染选中的成就系列
async function selectSeries (index: number) { async function selectSeries(index: number) {
// 如果选中的是已经选中的系列,则不进行操作 // 如果选中的是已经选中的系列,则不进行操作
if (selectedSeries.value === index) { if (selectedSeries.value === index) {
snackbarText.value = "已经选中该系列"; snackbarText.value = "已经选中该系列";
@@ -229,11 +241,11 @@ async function selectSeries (index: number) {
} }
// 打开图片 // 打开图片
function openImg () { function openImg() {
createTGWindow(getCardImg.value.profile, "nameCard", getCardInfo.value.name, 840, 400, false); createTGWindow(getCardImg.value.profile, "nameCard", getCardInfo.value.name, 840, 400, false);
} }
async function searchCard () { async function searchCard() {
if (search.value === "") { if (search.value === "") {
snackbarColor.value = "#F5810A"; snackbarColor.value = "#F5810A";
snackbarText.value = "请输入搜索内容"; snackbarText.value = "请输入搜索内容";
@@ -252,7 +264,7 @@ async function searchCard () {
loading.value = false; loading.value = false;
} }
// 导入 UIAF 数据,进行数据合并、刷新 // 导入 UIAF 数据,进行数据合并、刷新
async function importJson () { async function importJson() {
const selectedFile = await dialog.open({ const selectedFile = await dialog.open({
multiple: false, multiple: false,
filters: [ filters: [
@@ -281,7 +293,7 @@ async function importJson () {
} }
// 导出 // 导出
async function exportJson () { async function exportJson() {
// 判断是否有数据 // 判断是否有数据
if (achievementsStore.finAchievements === 0) { if (achievementsStore.finAchievements === 0) {
snackbarColor.value = "#F5810A"; snackbarColor.value = "#F5810A";
@@ -398,7 +410,7 @@ async function exportJson () {
top: 0; top: 0;
text-align: center; text-align: center;
width: 65px; width: 65px;
background: #8BA5C5; background: #8ba5c5;
border-bottom-right-radius: 20px; border-bottom-right-radius: 20px;
border-bottom: #fff 2px solid; border-bottom: #fff 2px solid;
border-right: #fff 2px solid; border-right: #fff 2px solid;

View File

@@ -1,12 +1,8 @@
<template> <template>
<TLoading v-model="loading" :title="loadingTitle" /> <TLoading v-model="loading" :title="loadingTitle" />
<v-tabs v-model="tab" align-tabs="start" class="anno-tab"> <v-tabs v-model="tab" align-tabs="start" class="anno-tab">
<v-tab value="activity"> <v-tab value="activity"> 活动公告 </v-tab>
活动公告 <v-tab value="game"> 游戏公告 </v-tab>
</v-tab>
<v-tab value="game">
游戏公告
</v-tab>
<v-spacer /> <v-spacer />
<v-btn class="switch-btn" @click="switchNews"> <v-btn class="switch-btn" @click="switchNews">
<template #prepend> <template #prepend>
@@ -20,7 +16,7 @@
<div class="anno-grid"> <div class="anno-grid">
<v-card v-for="item in annoCards.activity" :key="item.id" class="anno-card" width="340"> <v-card v-for="item in annoCards.activity" :key="item.id" class="anno-card" width="340">
<div class="anno-cover" @click="toPost(item)"> <div class="anno-cover" @click="toPost(item)">
<img :src="item.banner" alt="cover"> <img :src="item.banner" alt="cover" />
</div> </div>
<v-card-title> <v-card-title>
{{ item.title }} {{ item.title }}
@@ -29,7 +25,7 @@
<v-card-actions> <v-card-actions>
<v-btn class="anno-btn" @click="toPost(item)"> <v-btn class="anno-btn" @click="toPost(item)">
<template #prepend> <template #prepend>
<img :src="item.tagIcon || '../assets/icons/arrow-right.svg'" alt="right"> <img :src="item.tagIcon || '../assets/icons/arrow-right.svg'" alt="right" />
</template> </template>
查看 查看
</v-btn> </v-btn>
@@ -38,12 +34,10 @@
{{ item.startTime.split(" ")[0] }} - {{ item.startTime.split(" ")[0] }} -
{{ item.endTime.split(" ")[0] }} {{ item.endTime.split(" ")[0] }}
</v-card-subtitle> </v-card-subtitle>
<v-card-subtitle v-show="appStore.devMode"> <v-card-subtitle v-show="appStore.devMode"> id: {{ item.id }} </v-card-subtitle>
id: {{ item.id }}
</v-card-subtitle>
<v-btn v-show="appStore.devMode" class="card-dev-btn" @click="toJson(item)"> <v-btn v-show="appStore.devMode" class="card-dev-btn" @click="toJson(item)">
<template #prepend> <template #prepend>
<img src="../assets/icons/arrow-right.svg" alt="right"> <img src="../assets/icons/arrow-right.svg" alt="right" />
</template> </template>
查看数据 查看数据
</v-btn> </v-btn>
@@ -55,14 +49,14 @@
<div class="anno-grid"> <div class="anno-grid">
<v-card v-for="item in annoCards.game" :key="item.id" class="anno-card" width="340"> <v-card v-for="item in annoCards.game" :key="item.id" class="anno-card" width="340">
<div class="anno-cover" @click="toPost(item)"> <div class="anno-cover" @click="toPost(item)">
<img :src="item.banner" alt="cover"> <img :src="item.banner" alt="cover" />
</div> </div>
<v-card-title>{{ item.title }}</v-card-title> <v-card-title>{{ item.title }}</v-card-title>
<v-card-subtitle>{{ item.subtitle }}</v-card-subtitle> <v-card-subtitle>{{ item.subtitle }}</v-card-subtitle>
<v-card-actions> <v-card-actions>
<v-btn class="anno-btn" @click="toPost(item)"> <v-btn class="anno-btn" @click="toPost(item)">
<template #prepend> <template #prepend>
<img :src="item.tagIcon || '../assets/icons/arrow-right.svg'" alt="right"> <img :src="item.tagIcon || '../assets/icons/arrow-right.svg'" alt="right" />
</template> </template>
查看 查看
</v-btn> </v-btn>
@@ -71,12 +65,10 @@
{{ item.startTime.split(" ")[0] }} - {{ item.startTime.split(" ")[0] }} -
{{ item.endTime.split(" ")[0] }} {{ item.endTime.split(" ")[0] }}
</v-card-subtitle> </v-card-subtitle>
<v-card-subtitle v-show="appStore.devMode"> <v-card-subtitle v-show="appStore.devMode"> id: {{ item.id }} </v-card-subtitle>
id: {{ item.id }}
</v-card-subtitle>
<v-btn v-show="appStore.devMode" class="card-dev-btn" @click="toJson(item)"> <v-btn v-show="appStore.devMode" class="card-dev-btn" @click="toJson(item)">
<template #prepend> <template #prepend>
<img src="../assets/icons/arrow-right.svg" alt="right"> <img src="../assets/icons/arrow-right.svg" alt="right" />
</template> </template>
查看数据 查看数据
</v-btn> </v-btn>
@@ -131,11 +123,11 @@ onMounted(async () => {
loading.value = false; loading.value = false;
}); });
async function switchNews () { async function switchNews() {
await router.push("/news/2"); await router.push("/news/2");
} }
async function toPost (item: TGApp.App.Announcement.ListCard) { async function toPost(item: TGApp.App.Announcement.ListCard) {
const path = router.resolve({ const path = router.resolve({
name: "游戏内公告", name: "游戏内公告",
params: { params: {
@@ -146,7 +138,7 @@ async function toPost (item: TGApp.App.Announcement.ListCard) {
createTGWindow(path, "游戏内公告", item.title, 960, 720, false, false); createTGWindow(path, "游戏内公告", item.title, 960, 720, false, false);
} }
async function toJson (item: TGApp.App.Announcement.ListCard) { async function toJson(item: TGApp.App.Announcement.ListCard) {
const path = router.resolve({ const path = router.resolve({
name: "游戏内公告JSON", name: "游戏内公告JSON",
params: { params: {
@@ -162,7 +154,7 @@ async function toJson (item: TGApp.App.Announcement.ListCard) {
.anno-tab { .anno-tab {
font-family: Genshin, serif; font-family: Genshin, serif;
margin-bottom: 20px; margin-bottom: 20px;
color: var(--content-text-3) color: var(--content-text-3);
} }
.anno-grid { .anno-grid {

View File

@@ -1,13 +1,11 @@
<template> <template>
<TOLoading v-model="loading" :title="loadingTitle" /> <TOLoading v-model="loading" :title="loadingTitle" />
<v-list class="config-list"> <v-list class="config-list">
<v-list-subheader inset class="config-header"> <v-list-subheader inset class="config-header"> 应用信息 </v-list-subheader>
应用信息
</v-list-subheader>
<v-divider inset class="border-opacity-75" /> <v-divider inset class="border-opacity-75" />
<v-list-item title="Tauri 版本" @click="toOuter('https://next--tauri.netlify.app/')"> <v-list-item title="Tauri 版本" @click="toOuter('https://next--tauri.netlify.app/')">
<template #prepend> <template #prepend>
<img class="config-icon" src="/platforms/tauri.webp" alt="Tauri"> <img class="config-icon" src="/platforms/tauri.webp" alt="Tauri" />
</template> </template>
<template #append> <template #append>
<v-list-item-subtitle>{{ versionTauri }}</v-list-item-subtitle> <v-list-item-subtitle>{{ versionTauri }}</v-list-item-subtitle>
@@ -15,12 +13,13 @@
</v-list-item> </v-list-item>
<v-list-item> <v-list-item>
<template #prepend> <template #prepend>
<img class="config-icon" src="/icon.webp" alt="App"> <img class="config-icon" src="/icon.webp" alt="App" />
</template> </template>
<v-list-item-title> <v-list-item-title>
应用版本 应用版本
<v-btn <v-btn
class="card-btn" size="small" class="card-btn"
size="small"
@click="toOuter('https://github.com/BTMuli/Tauri.Genshin/releases/latest')" @click="toOuter('https://github.com/BTMuli/Tauri.Genshin/releases/latest')"
> >
Alpha Alpha
@@ -32,34 +31,32 @@
</v-list-item> </v-list-item>
<v-list-item title="成就版本"> <v-list-item title="成就版本">
<template #prepend> <template #prepend>
<img class="config-icon" src="../assets/icons/achievements.svg" alt="Achievements"> <img class="config-icon" src="../assets/icons/achievements.svg" alt="Achievements" />
</template> </template>
<template #append> <template #append>
<v-list-item-subtitle>{{ achievementsStore.lastVersion }}</v-list-item-subtitle> <v-list-item-subtitle>{{ achievementsStore.lastVersion }}</v-list-item-subtitle>
</template> </template>
</v-list-item> </v-list-item>
<v-list-item title="登录信息"> <v-list-item title="登录信息">
<v-list-item-subtitle v-show="userInfo.nickname!=='未登录'"> <v-list-item-subtitle v-show="userInfo.nickname !== '未登录'">
{{ userInfo.nickname }} uid:{{ userInfo.uid }} {{ userInfo.nickname }} uid:{{ userInfo.uid }}
</v-list-item-subtitle> </v-list-item-subtitle>
<v-list-item-subtitle v-show="userInfo.nickname==='未登录'"> <v-list-item-subtitle v-show="userInfo.nickname === '未登录'">
未登录请输入 Cookie 登录 未登录请输入 Cookie 登录
</v-list-item-subtitle> </v-list-item-subtitle>
<template #prepend> <template #prepend>
<img class="config-icon" :src="userInfo.avatar" alt="Login"> <img class="config-icon" :src="userInfo.avatar" alt="Login" />
</template> </template>
<template #append> <template #append>
<v-btn class="card-btn" @click="tryConfirm('refreshUser')"> <v-btn class="card-btn" @click="tryConfirm('refreshUser')">
<template #prepend> <template #prepend>
<img src="../assets/icons/circle-check.svg" alt="check"> <img src="../assets/icons/circle-check.svg" alt="check" />
刷新数据 刷新数据
</template> </template>
</v-btn> </v-btn>
</template> </template>
</v-list-item> </v-list-item>
<v-list-subheader inset class="config-header"> <v-list-subheader inset class="config-header"> 系统信息 </v-list-subheader>
系统信息
</v-list-subheader>
<v-divider inset class="border-opacity-75" /> <v-divider inset class="border-opacity-75" />
<v-list-item title="系统平台"> <v-list-item title="系统平台">
<template #prepend> <template #prepend>
@@ -79,29 +76,43 @@
</v-list-item> </v-list-item>
<v-list-item title="数据库更新时间" prepend-icon="mdi-database"> <v-list-item title="数据库更新时间" prepend-icon="mdi-database">
<template #append> <template #append>
<v-list-item-subtitle>{{ dbInfo.find(item => item.key === "dataUpdated")?.value }}</v-list-item-subtitle> <v-list-item-subtitle>{{
dbInfo.find((item) => item.key === "dataUpdated")?.value
}}</v-list-item-subtitle>
</template> </template>
<v-list-item-subtitle>更新于 {{ dbInfo.find(item => item.key === "dataUpdated")?.updated }}</v-list-item-subtitle> <v-list-item-subtitle
>更新于
{{ dbInfo.find((item) => item.key === "dataUpdated")?.updated }}</v-list-item-subtitle
>
</v-list-item> </v-list-item>
<v-list-item title="数据库版本" prepend-icon="mdi-database"> <v-list-item title="数据库版本" prepend-icon="mdi-database">
<template #append> <template #append>
<v-list-item-subtitle>{{ dbInfo.find(item => item.key === "appVersion")?.value }}</v-list-item-subtitle> <v-list-item-subtitle>{{
dbInfo.find((item) => item.key === "appVersion")?.value
}}</v-list-item-subtitle>
</template> </template>
<v-list-item-subtitle>更新于 {{ dbInfo.find(item => item.key === "appVersion")?.updated }}</v-list-item-subtitle> <v-list-item-subtitle
>更新于
{{ dbInfo.find((item) => item.key === "appVersion")?.updated }}</v-list-item-subtitle
>
</v-list-item> </v-list-item>
<v-list-subheader inset class="config-header"> <v-list-subheader inset class="config-header"> 设置 </v-list-subheader>
设置
</v-list-subheader>
<v-divider inset class="border-opacity-75" /> <v-divider inset class="border-opacity-75" />
<v-list-item> <v-list-item>
<template #prepend> <template #prepend>
<v-icon>mdi-view-dashboard</v-icon> <v-icon>mdi-view-dashboard</v-icon>
</template> </template>
<v-select v-model="showHome" :items="homeStore.getShowItems()" label="首页显示组件" multiple chips /> <v-select
v-model="showHome"
:items="homeStore.getShowItems()"
label="首页显示组件"
multiple
chips
/>
<template #append> <template #append>
<v-btn class="card-btn" @click="submitHome"> <v-btn class="card-btn" @click="submitHome">
<template #prepend> <template #prepend>
<img src="../assets/icons/circle-check.svg" alt="check"> <img src="../assets/icons/circle-check.svg" alt="check" />
确定 确定
</template> </template>
</v-btn> </v-btn>
@@ -112,9 +123,7 @@
<v-list-item prepend-icon="mdi-delete" title="清除用户缓存" @click="tryConfirm('delUser')" /> <v-list-item prepend-icon="mdi-delete" title="清除用户缓存" @click="tryConfirm('delUser')" />
<v-list-item prepend-icon="mdi-delete" title="清除临时数据" @click="tryConfirm('delTemp')" /> <v-list-item prepend-icon="mdi-delete" title="清除临时数据" @click="tryConfirm('delTemp')" />
<v-list-item prepend-icon="mdi-cog" title="恢复默认设置" @click="tryConfirm('delApp')" /> <v-list-item prepend-icon="mdi-cog" title="恢复默认设置" @click="tryConfirm('delApp')" />
<v-list-subheader inset class="config-header"> <v-list-subheader inset class="config-header"> 调试 </v-list-subheader>
调试
</v-list-subheader>
<v-divider inset class="border-opacity-75" /> <v-divider inset class="border-opacity-75" />
<v-list-item v-if="appStore.devEnv" title="调试模式" subtitle="开启后将显示调试信息"> <v-list-item v-if="appStore.devEnv" title="调试模式" subtitle="开启后将显示调试信息">
<template #prepend> <template #prepend>
@@ -122,7 +131,10 @@
</template> </template>
<template #append> <template #append>
<v-switch <v-switch
v-model="appStore.devMode" :label="appStore.devMode ? '开启' : '关闭'" inset color="#FAC51E" v-model="appStore.devMode"
:label="appStore.devMode ? '开启' : '关闭'"
inset
color="#FAC51E"
@click="submitDevMode" @click="submitDevMode"
/> />
</template> </template>
@@ -135,16 +147,21 @@
<span style="cursor: pointer" @click="tryConfirm('inputCookie')">手动输入 Cookie</span> <span style="cursor: pointer" @click="tryConfirm('inputCookie')">手动输入 Cookie</span>
</template> </template>
<template #append> <template #append>
<v-icon style="cursor: pointer" @click="toOuter('https://github.com/BTMuli/Tauri.Genshin/issues/18')"> <v-icon
style="cursor: pointer"
@click="toOuter('https://github.com/BTMuli/Tauri.Genshin/issues/18')"
>
mdi-help-circle-outline mdi-help-circle-outline
</v-icon> </v-icon>
</template> </template>
</v-list-item> </v-list-item>
<v-list-item title="重置数据库" prepend-icon="mdi-delete" @click="tryConfirm('resetDB')" /> <v-list-item title="重置数据库" prepend-icon="mdi-delete" @click="tryConfirm('resetDB')" />
<v-list-item title="检测 SQLite 数据库完整性" prepend-icon="mdi-database-check" @click="tryConfirm('checkDB')" /> <v-list-item
<v-list-subheader inset class="config-header"> title="检测 SQLite 数据库完整性"
路径 prepend-icon="mdi-database-check"
</v-list-subheader> @click="tryConfirm('checkDB')"
/>
<v-list-subheader inset class="config-header"> 路径 </v-list-subheader>
<v-divider inset class="border-opacity-75" /> <v-divider inset class="border-opacity-75" />
<v-list-item prepend-icon="mdi-database"> <v-list-item prepend-icon="mdi-database">
<v-list-item-title>本地数据库路径</v-list-item-title> <v-list-item-title>本地数据库路径</v-list-item-title>
@@ -165,8 +182,12 @@
</v-snackbar> </v-snackbar>
<!-- 确认弹窗 --> <!-- 确认弹窗 -->
<TOConfirm <TOConfirm
v-model="confirmShow" :model-input="confirmInput" :title="confirmText" v-model="confirmShow"
:subtitle="confirmSub" :is-input="isConfirmInput" @confirm="doConfirm(confirmOper)" :model-input="confirmInput"
:title="confirmText"
:subtitle="confirmSub"
:is-input="isConfirmInput"
@confirm="doConfirm(confirmOper)"
/> />
</template> </template>
@@ -203,7 +224,7 @@ const buildTime = computed(() => appStore.buildTime);
// About OS // About OS
const osPlatform = ref("" as string); const osPlatform = ref("" as string);
const osVersion = ref("" as string); const osVersion = ref("" as string);
const dbInfo = ref([] as { key: string, value: string, updated: string }[]); const dbInfo = ref([] as { key: string; value: string; updated: string }[]);
// loading // loading
const loading = ref(true as boolean); const loading = ref(true as boolean);
@@ -251,12 +272,12 @@ onMounted(async () => {
}); });
// 打开外部链接 // 打开外部链接
function toOuter (url: string) { function toOuter(url: string) {
window.open(url); window.open(url);
} }
// open confirm // open confirm
function tryConfirm (oper: string) { function tryConfirm(oper: string) {
confirmSub.value = ""; confirmSub.value = "";
isConfirmInput.value = false; isConfirmInput.value = false;
switch (oper) { switch (oper) {
@@ -317,7 +338,7 @@ function tryConfirm (oper: string) {
} }
// transfer confirm oper // transfer confirm oper
async function doConfirm (oper: string) { async function doConfirm(oper: string) {
await new Promise((resolve) => setTimeout(resolve, 500)); await new Promise((resolve) => setTimeout(resolve, 500));
switch (oper) { switch (oper) {
case "backup": case "backup":
@@ -356,7 +377,7 @@ async function doConfirm (oper: string) {
} }
// confirmOper // confirmOper
async function backupData () { async function backupData() {
loadingTitle.value = "正在备份数据..."; loadingTitle.value = "正在备份数据...";
loading.value = true; loading.value = true;
const achievements = await TGSqlite.getUIAF(); const achievements = await TGSqlite.getUIAF();
@@ -371,7 +392,7 @@ async function backupData () {
snackbar.value = true; snackbar.value = true;
} }
async function restoreData () { async function restoreData() {
loadingTitle.value = "正在恢复数据..."; loadingTitle.value = "正在恢复数据...";
loading.value = true; loading.value = true;
const fail = []; const fail = [];
@@ -399,7 +420,7 @@ async function restoreData () {
loading.value = false; loading.value = false;
} }
async function delTempData () { async function delTempData() {
await fs.removeDir("tempData", { await fs.removeDir("tempData", {
dir: fs.BaseDirectory.AppLocalData, dir: fs.BaseDirectory.AppLocalData,
recursive: true, recursive: true,
@@ -409,7 +430,7 @@ async function delTempData () {
snackbar.value = true; snackbar.value = true;
} }
async function delUserData () { async function delUserData() {
await fs.removeDir("userData", { await fs.removeDir("userData", {
dir: fs.BaseDirectory.AppLocalData, dir: fs.BaseDirectory.AppLocalData,
recursive: true, recursive: true,
@@ -421,7 +442,7 @@ async function delUserData () {
} }
// 恢复默认配置 // 恢复默认配置
function initAppData () { function initAppData() {
appStore.init(); appStore.init();
homeStore.init(); homeStore.init();
achievementsStore.init(); achievementsStore.init();
@@ -433,14 +454,16 @@ function initAppData () {
} }
// 开启 dev 模式 // 开启 dev 模式
function submitDevMode () { function submitDevMode() {
appStore.devMode ? (snackbarText.value = "已关闭 dev 模式!") : (snackbarText.value = "已开启 dev 模式!"); appStore.devMode
? (snackbarText.value = "已关闭 dev 模式!")
: (snackbarText.value = "已开启 dev 模式!");
snackbarColor.value = "success"; snackbarColor.value = "success";
snackbar.value = true; snackbar.value = true;
} }
// 修改首页显示 // 修改首页显示
function submitHome () { function submitHome() {
// 获取已选 // 获取已选
const show = showHome.value; const show = showHome.value;
if (show.length < 1) { if (show.length < 1) {
@@ -457,7 +480,7 @@ function submitHome () {
} }
// 刷新用户数据 // 刷新用户数据
async function refreshUser () { async function refreshUser() {
const ck = userStore.cookie; const ck = userStore.cookie;
let failCount = 0; let failCount = 0;
loadingTitle.value = "正在验证 ltoken..."; loadingTitle.value = "正在验证 ltoken...";
@@ -524,7 +547,7 @@ async function refreshUser () {
} }
// 输入 Cookie // 输入 Cookie
async function inputCookie () { async function inputCookie() {
const cookie = confirmInput.value; const cookie = confirmInput.value;
if (cookie === "") { if (cookie === "") {
snackbarText.value = "Cookie 为空!"; snackbarText.value = "Cookie 为空!";
@@ -533,7 +556,10 @@ async function inputCookie () {
return; return;
} }
loadingTitle.value = "正在获取 tokens..."; loadingTitle.value = "正在获取 tokens...";
const cookieObj = cookie.trim().split(";").map((item) => item.trim().split("=")); const cookieObj = cookie
.trim()
.split(";")
.map((item) => item.trim().split("="));
const ticket = cookieObj.find((item) => item[0] === "login_ticket")?.[1]; const ticket = cookieObj.find((item) => item[0] === "login_ticket")?.[1];
const uid = cookieObj.find((item) => item[0] === "login_uid")?.[1]; const uid = cookieObj.find((item) => item[0] === "login_uid")?.[1];
// 如果两者不存在 // 如果两者不存在
@@ -573,7 +599,7 @@ async function inputCookie () {
} }
// 检查 SQLite 数据库 // 检查 SQLite 数据库
async function checkDB () { async function checkDB() {
loadingTitle.value = "正在检查数据库表单完整性..."; loadingTitle.value = "正在检查数据库表单完整性...";
loading.value = true; loading.value = true;
const res = await TGSqlite.check(); const res = await TGSqlite.check();
@@ -610,7 +636,7 @@ async function checkDB () {
} }
// 重置 SQLite 数据库 // 重置 SQLite 数据库
async function resetDB () { async function resetDB() {
loadingTitle.value = "正在重置数据库..."; loadingTitle.value = "正在重置数据库...";
loading.value = true; loading.value = true;
await TGSqlite.reset(); await TGSqlite.reset();
@@ -623,7 +649,7 @@ async function resetDB () {
} }
// 更新 SQLite 数据库 // 更新 SQLite 数据库
async function updateDB () { async function updateDB() {
await new Promise((resolve) => setTimeout(resolve, 500)); await new Promise((resolve) => setTimeout(resolve, 500));
loadingTitle.value = "正在更新数据库..."; loadingTitle.value = "正在更新数据库...";
loading.value = true; loading.value = true;

View File

@@ -34,7 +34,7 @@ const itemRefs = ref([] as any[]);
// 定时器 // 定时器
const timer = ref(null as any); const timer = ref(null as any);
function readLoading (): void { function readLoading(): void {
if (!loading.value) return; if (!loading.value) return;
const loadingMap = itemRefs.value.map((item) => { const loadingMap = itemRefs.value.map((item) => {
return item.loading ? item.name : null; return item.loading ? item.name : null;
@@ -82,7 +82,7 @@ onMounted(async () => {
timer.value = setInterval(readLoading, 100); timer.value = setInterval(readLoading, 100);
}); });
function setItemRef (item: any) { function setItemRef(item: any) {
if (itemRefs.value.includes(item)) return; if (itemRefs.value.includes(item)) return;
itemRefs.value.push(item); itemRefs.value.push(item);
} }

View File

@@ -1,7 +1,5 @@
<template> <template>
<h1>测试页</h1> <h1>测试页</h1>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup></script>
</script> <style lang="css" scoped></style>
<style lang="css" scoped>
</style>

View File

@@ -17,7 +17,12 @@
</div> </div>
</v-tabs> </v-tabs>
<v-window v-model="userTab" class="ua-window"> <v-window v-model="userTab" class="ua-window">
<v-window-item v-for="item in localAbyss" :key="item.id" :value="item.id" class="ua-window-item"> <v-window-item
v-for="item in localAbyss"
:key="item.id"
:value="item.id"
class="ua-window-item"
>
<div :ref="getAbyssRef"> <div :ref="getAbyssRef">
<div class="uaw-title"> <div class="uaw-title">
<span></span> <span></span>
@@ -41,13 +46,16 @@
</div> </div>
<TSubLine>详情</TSubLine> <TSubLine>详情</TSubLine>
<div class="uaw-d-box"> <div class="uaw-d-box">
<TuaDetail v-for="floor in JSON.parse(item.floors) as TGApp.Sqlite.Abyss.Floor[]" :model-value="floor" /> <TuaDetail
v-for="floor in JSON.parse(item.floors) as TGApp.Sqlite.Abyss.Floor[]"
:model-value="floor"
/>
</div> </div>
</div> </div>
</v-window-item> </v-window-item>
</v-window> </v-window>
<div v-show="localAbyssID.length === 0" class="user-empty"> <div v-show="localAbyssID.length === 0" class="user-empty">
<img src="/source/UI/empty.webp" alt="empty"> <img src="/source/UI/empty.webp" alt="empty" />
<span>暂无数据请尝试刷新</span> <span>暂无数据请尝试刷新</span>
</div> </div>
</div> </div>
@@ -74,8 +82,7 @@ const loadingTitle = ref("");
// data // data
const userTab = ref(0); const userTab = ref(0);
const abyssCookie = ref(computed( const abyssCookie = ref(computed(() => userStore.getCookieGroup4() as Record<string, string>));
() => userStore.getCookieGroup4() as Record<string, string>));
const user = computed(() => userStore.getCurAccount()); const user = computed(() => userStore.getCurAccount());
const localAbyss = ref([] as TGApp.Sqlite.Abyss.SingleTable[]); const localAbyss = ref([] as TGApp.Sqlite.Abyss.SingleTable[]);
@@ -89,7 +96,7 @@ onMounted(async () => {
loading.value = false; loading.value = false;
}); });
async function initAbyssData () { async function initAbyssData() {
localAbyss.value = await TGSqlite.getAbyss(user.value.gameUid); localAbyss.value = await TGSqlite.getAbyss(user.value.gameUid);
localAbyss.value.forEach((item) => { localAbyss.value.forEach((item) => {
localAbyssID.value.push(item.id); localAbyssID.value.push(item.id);
@@ -98,7 +105,7 @@ async function initAbyssData () {
userTab.value = localAbyssID.value[0]; userTab.value = localAbyssID.value[0];
} }
async function getAbyssData (): Promise<void> { async function getAbyssData(): Promise<void> {
loadingTitle.value = "正在获取深渊数据"; loadingTitle.value = "正在获取深渊数据";
loading.value = true; loading.value = true;
if (localAbyssID.value.length < 2) { if (localAbyssID.value.length < 2) {
@@ -120,15 +127,15 @@ async function getAbyssData (): Promise<void> {
loading.value = false; loading.value = false;
} }
function toAbyss (id: number): void { function toAbyss(id: number): void {
curAbyss.value = localAbyss.value.find((item) => item.id === id)!; curAbyss.value = localAbyss.value.find((item) => item.id === id)!;
} }
function getAbyssRef (el: HTMLElement): void { function getAbyssRef(el: HTMLElement): void {
abyssRef.value = el; abyssRef.value = el;
} }
async function shareAbyss (): Promise<void> { async function shareAbyss(): Promise<void> {
const fileName = `【深渊数据】${curAbyss.value.id}-${user.value.gameUid}`; const fileName = `【深渊数据】${curAbyss.value.id}-${user.value.gameUid}`;
await generateShareImg(fileName, abyssRef.value); await generateShareImg(fileName, abyssRef.value);
} }

View File

@@ -70,13 +70,13 @@ onMounted(async () => {
loading.value = false; loading.value = false;
}); });
function getGridGap () { function getGridGap() {
const width = document.querySelector(".uc-grid")?.clientWidth - 20; const width = document.querySelector(".uc-grid")?.clientWidth - 20;
const count = Math.floor(width / 180); const count = Math.floor(width / 180);
gridGap.value = `${(width - count * 180) / (count - 1)}px`; gridGap.value = `${(width - count * 180) / (count - 1)}px`;
} }
async function loadRole () { async function loadRole() {
const roleData = await TGSqlite.getUserCharacter(user.value.gameUid); const roleData = await TGSqlite.getUserCharacter(user.value.gameUid);
if (roleData !== false) { if (roleData !== false) {
roleList.value = roleData; roleList.value = roleData;
@@ -84,7 +84,7 @@ async function loadRole () {
} }
} }
async function refresh () { async function refresh() {
loadingTitle.value = "正在获取角色数据"; loadingTitle.value = "正在获取角色数据";
loading.value = true; loading.value = true;
const res = await TGRequest.User.byLToken.getRoleList(roleCookie.value, user.value); const res = await TGRequest.User.byLToken.getRoleList(roleCookie.value, user.value);
@@ -97,13 +97,13 @@ async function refresh () {
loading.value = false; loading.value = false;
} }
async function shareRoles () { async function shareRoles() {
const rolesBox = document.querySelector(".uc-box") as HTMLElement; const rolesBox = document.querySelector(".uc-box") as HTMLElement;
const fileName = `【角色列表】-${user.value.gameUid}`; const fileName = `【角色列表】-${user.value.gameUid}`;
await generateShareImg(fileName, rolesBox); await generateShareImg(fileName, rolesBox);
} }
function getUpdateTime () { function getUpdateTime() {
let lastUpdateTime = 0; let lastUpdateTime = 0;
roleList.value.forEach((role) => { roleList.value.forEach((role) => {
const updateTime = new Date(role.updated).getTime(); const updateTime = new Date(role.updated).getTime();
@@ -114,7 +114,7 @@ function getUpdateTime () {
return new Date(lastUpdateTime).toLocaleString().replace(/\//g, "-"); return new Date(lastUpdateTime).toLocaleString().replace(/\//g, "-");
} }
function selectRole (role: TGApp.Sqlite.Character.UserRole) { function selectRole(role: TGApp.Sqlite.Character.UserRole) {
dataVal.value = role; dataVal.value = role;
visible.value = true; visible.value = true;
} }

View File

@@ -1,7 +1,5 @@
<template> <template>
<h1>祈愿数据获取展示统计</h1> <h1>祈愿数据获取展示统计</h1>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup></script>
</script> <style lang="css" scoped></style>
<style lang="css" scoped>
</style>

View File

@@ -68,7 +68,7 @@ onMounted(async () => {
}, 3000); }, 3000);
}); });
async function initUserRecordData () { async function initUserRecordData() {
const recordGet = await TGSqlite.getUserRecord(user.value.gameUid); const recordGet = await TGSqlite.getUserRecord(user.value.gameUid);
if (recordGet !== false) { if (recordGet !== false) {
recordData.value = recordGet; recordData.value = recordGet;
@@ -78,7 +78,7 @@ async function initUserRecordData () {
} }
} }
async function refresh () { async function refresh() {
loadingTitle.value = "正在获取战绩数据"; loadingTitle.value = "正在获取战绩数据";
loading.value = true; loading.value = true;
const res = await TGRequest.User.getRecord(recordCookie.value, user.value); const res = await TGRequest.User.getRecord(recordCookie.value, user.value);
@@ -93,18 +93,18 @@ async function refresh () {
loading.value = false; loading.value = false;
} }
function getTitle () { function getTitle() {
const role = JSON.parse(recordData.value.role) as TGApp.Sqlite.Record.Role; const role = JSON.parse(recordData.value.role) as TGApp.Sqlite.Record.Role;
return `${role.nickname} Lv.${role.level}${recordData.value.uid}`; return `${role.nickname} Lv.${role.level}${recordData.value.uid}`;
} }
async function shareRecord () { async function shareRecord() {
const recordBox = document.querySelector(".ur-box") as HTMLElement; const recordBox = document.querySelector(".ur-box") as HTMLElement;
const fileName = `【原神战绩】-${user.value.gameUid}`; const fileName = `【原神战绩】-${user.value.gameUid}`;
await generateShareImg(fileName, recordBox); await generateShareImg(fileName, recordBox);
} }
function getTheme () { function getTheme() {
let theme = localStorage.getItem("theme"); let theme = localStorage.getItem("theme");
if (theme) { if (theme) {
theme = JSON.parse(theme).theme; theme = JSON.parse(theme).theme;

View File

@@ -21,7 +21,7 @@ onMounted(async () => {
overview.value = await HutaoRequest.Abyss.getOverview(); overview.value = await HutaoRequest.Abyss.getOverview();
}); });
function getUpdated () { function getUpdated() {
return new Date(overview.value.timestamp) return new Date(overview.value.timestamp)
.toLocaleString("zh-CN", { hour12: false }) .toLocaleString("zh-CN", { hour12: false })
.replace(/\//g, "-"); .replace(/\//g, "-");

View File

@@ -3,9 +3,7 @@
<div v-for="item in cardsInfo" :key="item.id" class="card-box" @click="toOuter(item)"> <div v-for="item in cardsInfo" :key="item.id" class="card-box" @click="toOuter(item)">
<TibWikiAvatar size="128px" :model-value="item" /> <TibWikiAvatar size="128px" :model-value="item" />
</div> </div>
<v-snackbar v-model="snackbar" timeout="1500" color="error"> <v-snackbar v-model="snackbar" timeout="1500" color="error"> 该角色暂无详情 </v-snackbar>
该角色暂无详情
</v-snackbar>
</div> </div>
</template> </template>
@@ -23,7 +21,7 @@ const snackbar = ref(false);
// data // data
const cardsInfo = computed(() => AppCharacterData); const cardsInfo = computed(() => AppCharacterData);
function toOuter (item: TGApp.App.Character.WikiBriefInfo) { function toOuter(item: TGApp.App.Character.WikiBriefInfo) {
if (item.contentId === 0) { if (item.contentId === 0) {
snackbar.value = true; snackbar.value = true;
return; return;
@@ -31,7 +29,6 @@ function toOuter (item: TGApp.App.Character.WikiBriefInfo) {
const url = OBC_CONTENT_API.replace("{content_id}", item.contentId.toString()); const url = OBC_CONTENT_API.replace("{content_id}", item.contentId.toString());
createTGWindow(url, "角色详情", item.name, 1200, 800, true); createTGWindow(url, "角色详情", item.name, 1200, 800, true);
} }
</script> </script>
<style scoped> <style scoped>
.cards-grid { .cards-grid {

View File

@@ -2,15 +2,9 @@
<TOLoading v-model="loading" title="正在加载卡牌列表" /> <TOLoading v-model="loading" title="正在加载卡牌列表" />
<v-tabs v-model="tab" align-tabs="start" class="cards-tab"> <v-tabs v-model="tab" align-tabs="start" class="cards-tab">
<div v-show="!doSearch"> <div v-show="!doSearch">
<v-tab value="character"> <v-tab value="character"> 角色牌 </v-tab>
角色牌 <v-tab value="action"> 行动牌 </v-tab>
</v-tab> <v-tab value="monster"> 魔物牌 </v-tab>
<v-tab value="action">
行动牌
</v-tab>
<v-tab value="monster">
魔物牌
</v-tab>
</div> </div>
<v-spacer /> <v-spacer />
<v-text-field <v-text-field
@@ -28,14 +22,16 @@
<v-window-item value="character"> <v-window-item value="character">
<div class="cards-grid"> <div class="cards-grid">
<v-card <v-card
v-for="item in CardsInfoC" :key="item.contentId" class="card-cls" v-for="item in CardsInfoC"
:key="item.contentId"
class="card-cls"
@click="toOuter(item.name, item.contentId)" @click="toOuter(item.name, item.contentId)"
> >
<div class="card-border"> <div class="card-border">
<img src="/WIKI/GCG/bg/normal.webp" alt="border"> <img src="/WIKI/GCG/bg/normal.webp" alt="border" />
</div> </div>
<div class="card-cover"> <div class="card-cover">
<img :src="item.icon" alt="cover"> <img :src="item.icon" alt="cover" />
</div> </div>
<div class="card-content"> <div class="card-content">
<span>{{ item.name }}</span> <span>{{ item.name }}</span>
@@ -46,14 +42,16 @@
<v-window-item value="action"> <v-window-item value="action">
<div class="cards-grid"> <div class="cards-grid">
<v-card <v-card
v-for="item in CardsInfoA" :key="item.contentId" class="card-cls" v-for="item in CardsInfoA"
:key="item.contentId"
class="card-cls"
@click="toOuter(item.name, item.contentId)" @click="toOuter(item.name, item.contentId)"
> >
<div class="card-border"> <div class="card-border">
<img src="/WIKI/GCG/bg/normal.webp" alt="border"> <img src="/WIKI/GCG/bg/normal.webp" alt="border" />
</div> </div>
<div class="card-cover"> <div class="card-cover">
<img :src="item.icon" alt="cover"> <img :src="item.icon" alt="cover" />
</div> </div>
<div class="card-content"> <div class="card-content">
<span>{{ item.name }}</span> <span>{{ item.name }}</span>
@@ -64,14 +62,16 @@
<v-window-item value="monster"> <v-window-item value="monster">
<div class="cards-grid"> <div class="cards-grid">
<v-card <v-card
v-for="item in CardsInfoM" :key="item.contentId" class="card-cls" v-for="item in CardsInfoM"
:key="item.contentId"
class="card-cls"
@click="toOuter(item.name, item.contentId)" @click="toOuter(item.name, item.contentId)"
> >
<div class="card-border"> <div class="card-border">
<img src="/WIKI/GCG/bg/normal.webp" alt="border"> <img src="/WIKI/GCG/bg/normal.webp" alt="border" />
</div> </div>
<div class="card-cover"> <div class="card-cover">
<img :src="item.icon" alt="cover"> <img :src="item.icon" alt="cover" />
</div> </div>
<div class="card-content"> <div class="card-content">
<span>{{ item.name }}</span> <span>{{ item.name }}</span>
@@ -84,14 +84,16 @@
<div v-show="doSearch"> <div v-show="doSearch">
<div class="cards-grid"> <div class="cards-grid">
<v-card <v-card
v-for="item in CardsInfoS" :key="item.contentId" class="card-cls" v-for="item in CardsInfoS"
:key="item.contentId"
class="card-cls"
@click="toOuter(item.name, item.contentId)" @click="toOuter(item.name, item.contentId)"
> >
<div class="card-border"> <div class="card-border">
<img src="/WIKI/GCG/bg/special.webp" alt="border"> <img src="/WIKI/GCG/bg/special.webp" alt="border" />
</div> </div>
<div class="card-cover"> <div class="card-cover">
<img :src="item.icon" alt="cover"> <img :src="item.icon" alt="cover" />
</div> </div>
<div class="card-content"> <div class="card-content">
<span>{{ item.name }}</span> <span>{{ item.name }}</span>
@@ -99,9 +101,7 @@
</v-card> </v-card>
</div> </div>
</div> </div>
<v-snackbar v-model="snackbar" timeout="1500" color="error"> <v-snackbar v-model="snackbar" timeout="1500" color="error"> 未找到相关卡牌 </v-snackbar>
未找到相关卡牌
</v-snackbar>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
// vue // vue
@@ -132,7 +132,7 @@ onMounted(async () => {
await loadData(); await loadData();
}); });
async function loadData () { async function loadData() {
await Promise.allSettled( await Promise.allSettled(
allCards.value.map(async (item) => { allCards.value.map(async (item) => {
if (item.type === "角色牌") CardsInfoC.value.push(item); if (item.type === "角色牌") CardsInfoC.value.push(item);
@@ -143,12 +143,12 @@ async function loadData () {
loading.value = false; loading.value = false;
} }
function toOuter (cardName: string, cardId: number) { function toOuter(cardName: string, cardId: number) {
const url = OBC_CONTENT_API.replace("{content_id}", cardId.toString()); const url = OBC_CONTENT_API.replace("{content_id}", cardId.toString());
createTGWindow(url, "GCG", cardName, 1200, 800, true); createTGWindow(url, "GCG", cardName, 1200, 800, true);
} }
async function searchCard () { async function searchCard() {
loading.value = true; loading.value = true;
if (search.value === "") { if (search.value === "") {
setTimeout(() => { setTimeout(() => {
@@ -159,7 +159,9 @@ async function searchCard () {
} }
doSearch.value = true; doSearch.value = true;
const res: TGApp.App.GCG.WikiBriefInfo[] = []; const res: TGApp.App.GCG.WikiBriefInfo[] = [];
await Promise.allSettled(allCards.value.map((item) => (item.name.includes(search.value) ? res.push(item) : null))); await Promise.allSettled(
allCards.value.map((item) => (item.name.includes(search.value) ? res.push(item) : null)),
);
res.sort((a, b) => a.name.localeCompare(b.name)); res.sort((a, b) => a.name.localeCompare(b.name));
console.log(res); console.log(res);
loading.value = false; loading.value = false;

View File

@@ -3,9 +3,7 @@
<div v-for="item in cardsInfo" :key="item.id" class="card-box" @click="toOuter(item)"> <div v-for="item in cardsInfo" :key="item.id" class="card-box" @click="toOuter(item)">
<TibWikiWeapon size="128px" :model-value="item" /> <TibWikiWeapon size="128px" :model-value="item" />
</div> </div>
<v-snackbar v-model="snackbar" timeout="1500" color="error"> <v-snackbar v-model="snackbar" timeout="1500" color="error"> 该武器暂无详情 </v-snackbar>
该武器暂无详情
</v-snackbar>
</div> </div>
</template> </template>
@@ -23,7 +21,7 @@ const snackbar = ref(false);
// data // data
const cardsInfo = computed(() => AppWeaponData); const cardsInfo = computed(() => AppWeaponData);
function toOuter (item: TGApp.App.Weapon.WikiBriefInfo) { function toOuter(item: TGApp.App.Weapon.WikiBriefInfo) {
if (item.contentId === 0) { if (item.contentId === 0) {
snackbar.value = true; snackbar.value = true;
return; return;
@@ -31,7 +29,6 @@ function toOuter (item: TGApp.App.Weapon.WikiBriefInfo) {
const url = OBC_CONTENT_API.replace("{content_id}", item.contentId.toString()); const url = OBC_CONTENT_API.replace("{content_id}", item.contentId.toString());
createTGWindow(url, "武器详情", item.name, 1200, 800, true); createTGWindow(url, "武器详情", item.name, 1200, 800, true);
} }
</script> </script>
<style scoped> <style scoped>
.cards-grid { .cards-grid {

View File

@@ -11,9 +11,11 @@ import {
AvatarUpRateApi, AvatarUpRateApi,
AvatarUseRateApi, AvatarUseRateApi,
DataUploadApi, DataUploadApi,
OverviewApi, TeamCombinationApi, OverviewApi,
TeamCombinationApi,
UidCheckApi, UidCheckApi,
UidRankApi, WeaponCollocationApi, UidRankApi,
WeaponCollocationApi,
} from "./abyss"; } from "./abyss";
const HutaoApi = { const HutaoApi = {

View File

@@ -15,13 +15,15 @@ import HutaoApi from "../api";
* @since Alpha v0.2.0 * @since Alpha v0.2.0
* @return {Promise<TGApp.Plugins.Hutao.AbyssAvatarCollocation[]>} * @return {Promise<TGApp.Plugins.Hutao.AbyssAvatarCollocation[]>}
*/ */
async function getAvatarCollect (): Promise<TGApp.Plugins.Hutao.AbyssAvatarCollocation[]> { async function getAvatarCollect(): Promise<TGApp.Plugins.Hutao.AbyssAvatarCollocation[]> {
const url = HutaoApi.Abyss.avatar.collect; const url = HutaoApi.Abyss.avatar.collect;
return await http.fetch<TGApp.Plugins.Hutao.AbyssAvatarCollocationResponse>(url, { return await http
method: "GET", .fetch<TGApp.Plugins.Hutao.AbyssAvatarCollocationResponse>(url, {
}).then((res) => { method: "GET",
return res.data.data; })
}); .then((res) => {
return res.data.data;
});
} }
export default getAvatarCollect; export default getAvatarCollect;

View File

@@ -15,13 +15,15 @@ import HutaoApi from "../api";
* @since Alpha v0.2.0 * @since Alpha v0.2.0
* @returns {Promise<TGApp.Plugins.Hutao.AbyssAvatarHoldRate[]>} * @returns {Promise<TGApp.Plugins.Hutao.AbyssAvatarHoldRate[]>}
*/ */
async function getAvatarHoldRate (): Promise<TGApp.Plugins.Hutao.AbyssAvatarHoldRate[]> { async function getAvatarHoldRate(): Promise<TGApp.Plugins.Hutao.AbyssAvatarHoldRate[]> {
const url = HutaoApi.Abyss.avatar.holdRate; const url = HutaoApi.Abyss.avatar.holdRate;
return await http.fetch<TGApp.Plugins.Hutao.AbyssAvatarHoldRateResponse>(url, { return await http
method: "GET", .fetch<TGApp.Plugins.Hutao.AbyssAvatarHoldRateResponse>(url, {
}).then((res) => { method: "GET",
return res.data.data; })
}); .then((res) => {
return res.data.data;
});
} }
export default getAvatarHoldRate; export default getAvatarHoldRate;

View File

@@ -15,13 +15,15 @@ import HutaoApi from "../api";
* @since Alpha v0.2.0 * @since Alpha v0.2.0
* @return {Promise<TGApp.Plugins.Hutao.AbyssAvatarUpRate[]>} * @return {Promise<TGApp.Plugins.Hutao.AbyssAvatarUpRate[]>}
*/ */
async function getAvatarUpRate (): Promise<TGApp.Plugins.Hutao.AbyssAvatarUpRate[]> { async function getAvatarUpRate(): Promise<TGApp.Plugins.Hutao.AbyssAvatarUpRate[]> {
const url = HutaoApi.Abyss.avatar.upRate; const url = HutaoApi.Abyss.avatar.upRate;
return await http.fetch<TGApp.Plugins.Hutao.AbyssAvatarUpRateResponse>(url, { return await http
method: "GET", .fetch<TGApp.Plugins.Hutao.AbyssAvatarUpRateResponse>(url, {
}).then((res) => { method: "GET",
return res.data.data; })
}); .then((res) => {
return res.data.data;
});
} }
export default getAvatarUpRate; export default getAvatarUpRate;

View File

@@ -15,13 +15,15 @@ import HutaoApi from "../api";
* @since Alpha v0.2.0 * @since Alpha v0.2.0
* @return {Promise<TGApp.Plugins.Hutao.AbyssAvatarUseRate[]>} * @return {Promise<TGApp.Plugins.Hutao.AbyssAvatarUseRate[]>}
*/ */
async function getAvatarUseRate (): Promise<TGApp.Plugins.Hutao.AbyssAvatarUseRate[]> { async function getAvatarUseRate(): Promise<TGApp.Plugins.Hutao.AbyssAvatarUseRate[]> {
const url = HutaoApi.Abyss.avatar.useRate; const url = HutaoApi.Abyss.avatar.useRate;
return await http.fetch<TGApp.Plugins.Hutao.AbyssAvatarUseRateResponse>(url, { return await http
method: "GET", .fetch<TGApp.Plugins.Hutao.AbyssAvatarUseRateResponse>(url, {
}).then((res) => { method: "GET",
return res.data.data; })
}); .then((res) => {
return res.data.data;
});
} }
export default getAvatarUseRate; export default getAvatarUseRate;

View File

@@ -15,13 +15,15 @@ import HutaoApi from "../api";
* @since Alpha v0.2.0 * @since Alpha v0.2.0
* @return {Promise<TGApp.Plugins.Hutao.AbyssOverview>} * @return {Promise<TGApp.Plugins.Hutao.AbyssOverview>}
*/ */
async function getOverview (): Promise<TGApp.Plugins.Hutao.AbyssOverview> { async function getOverview(): Promise<TGApp.Plugins.Hutao.AbyssOverview> {
const url = HutaoApi.Abyss.overview; const url = HutaoApi.Abyss.overview;
return await http.fetch<TGApp.Plugins.Hutao.AbyssOverviewResponse>(url, { return await http
method: "GET", .fetch<TGApp.Plugins.Hutao.AbyssOverviewResponse>(url, {
}).then((res) => { method: "GET",
return res.data.data; })
}); .then((res) => {
return res.data.data;
});
} }
export default getOverview; export default getOverview;

View File

@@ -15,13 +15,15 @@ import HutaoApi from "../api";
* @since Alpha v0.2.0 * @since Alpha v0.2.0
* @return {Promise<TGApp.Plugins.Hutao.AbyssTeamCombination[]>} * @return {Promise<TGApp.Plugins.Hutao.AbyssTeamCombination[]>}
*/ */
async function getTeamCollect (): Promise<TGApp.Plugins.Hutao.AbyssTeamCombination[]> { async function getTeamCollect(): Promise<TGApp.Plugins.Hutao.AbyssTeamCombination[]> {
const url = HutaoApi.Abyss.team; const url = HutaoApi.Abyss.team;
return await http.fetch<TGApp.Plugins.Hutao.AbyssTeamCombinationResponse>(url, { return await http
method: "GET", .fetch<TGApp.Plugins.Hutao.AbyssTeamCombinationResponse>(url, {
}).then((res) => { method: "GET",
return res.data.data; })
}); .then((res) => {
return res.data.data;
});
} }
export default getTeamCollect; export default getTeamCollect;

View File

@@ -17,13 +17,15 @@ import HutaoApi from "../api";
* @param {string} uid * @param {string} uid
* @return {Promise<boolean>} * @return {Promise<boolean>}
*/ */
export async function checkUid (uid: string): Promise<boolean> { export async function checkUid(uid: string): Promise<boolean> {
const url = HutaoApi.Abyss.user.check.replace("{uid}", uid); const url = HutaoApi.Abyss.user.check.replace("{uid}", uid);
return await http.fetch<TGApp.Plugins.Hutao.AbyssRecordExistResponse>(url, { return await http
method: "GET", .fetch<TGApp.Plugins.Hutao.AbyssRecordExistResponse>(url, {
}).then((res) => { method: "GET",
return res.data.data; })
}); .then((res) => {
return res.data.data;
});
} }
/** /**
@@ -33,11 +35,13 @@ export async function checkUid (uid: string): Promise<boolean> {
* @param {string} uid * @param {string} uid
* @return {Promise<TGApp.Plugins.Hutao.AbyssRecordRank>} * @return {Promise<TGApp.Plugins.Hutao.AbyssRecordRank>}
*/ */
export async function getUserData (uid: string): Promise<TGApp.Plugins.Hutao.AbyssRecordRank> { export async function getUserData(uid: string): Promise<TGApp.Plugins.Hutao.AbyssRecordRank> {
const url = HutaoApi.Abyss.user.rank.replace("{uid}", uid); const url = HutaoApi.Abyss.user.rank.replace("{uid}", uid);
return await http.fetch<TGApp.Plugins.Hutao.AbyssRecordRankResponse>(url, { return await http
method: "GET", .fetch<TGApp.Plugins.Hutao.AbyssRecordRankResponse>(url, {
}).then((res) => { method: "GET",
return res.data.data; })
}); .then((res) => {
return res.data.data;
});
} }

View File

@@ -15,13 +15,15 @@ import HutaoApi from "../api";
* @since Alpha v0.2.0 * @since Alpha v0.2.0
* @return {Promise<TGApp.Plugins.Hutao.AbyssWeaponCollocation[]>} * @return {Promise<TGApp.Plugins.Hutao.AbyssWeaponCollocation[]>}
*/ */
async function getWeaponCollect (): Promise<TGApp.Plugins.Hutao.AbyssWeaponCollocation[]> { async function getWeaponCollect(): Promise<TGApp.Plugins.Hutao.AbyssWeaponCollocation[]> {
const url = HutaoApi.Abyss.weapon; const url = HutaoApi.Abyss.weapon;
return await http.fetch<TGApp.Plugins.Hutao.AbyssWeaponCollocationResponse>(url, { return await http
method: "GET", .fetch<TGApp.Plugins.Hutao.AbyssWeaponCollocationResponse>(url, {
}).then((res) => { method: "GET",
return res.data.data; })
}); .then((res) => {
return res.data.data;
});
} }
export default getWeaponCollect; export default getWeaponCollect;

View File

@@ -17,12 +17,14 @@ import HutaoApi from "../api";
* @param {TGApp.Plugins.Hutao.AbyssRecordUpload} data 用户数据 * @param {TGApp.Plugins.Hutao.AbyssRecordUpload} data 用户数据
* @returns {Promise<unknown>} 上传结果 * @returns {Promise<unknown>} 上传结果
*/ */
async function uploadData (data: TGApp.Plugins.Hutao.AbyssRecordUpload): Promise<unknown> { async function uploadData(data: TGApp.Plugins.Hutao.AbyssRecordUpload): Promise<unknown> {
const url = HutaoApi.Abyss.upload; const url = HutaoApi.Abyss.upload;
return await http.fetch(url, { return await http
method: "POST", .fetch(url, {
body: http.Body.json(data), method: "POST",
}).then(res => res.data); body: http.Body.json(data),
})
.then((res) => res.data);
} }
export default uploadData; export default uploadData;

View File

@@ -15,9 +15,9 @@
* @returns {MysResponse} * @returns {MysResponse}
*/ */
export interface MysResponse { export interface MysResponse {
retcode: number retcode: number;
message: string message: string;
data: any data: any;
} }
/** /**
@@ -30,8 +30,8 @@ export interface MysResponse {
*/ */
export interface MysObcResponse extends MysResponse { export interface MysObcResponse extends MysResponse {
data: { data: {
list: MysObc[] list: MysObc[];
} };
} }
/** /**
@@ -48,13 +48,13 @@ export interface MysObcResponse extends MysResponse {
* @returns {MysObc} * @returns {MysObc}
*/ */
export interface MysObc { export interface MysObc {
id: number id: number;
name: string name: string;
parent_id: number parent_id: number;
depth: number depth: number;
ch_ext: string ch_ext: string;
children: MysObc[] children: MysObc[];
list: unknown[] list: unknown[];
} }
/** /**

View File

@@ -17,8 +17,8 @@ import { type MysResponse } from "./base";
*/ */
export interface GachaResponse extends MysResponse { export interface GachaResponse extends MysResponse {
data: { data: {
list: GachaData[] list: GachaData[];
} };
} }
/** /**
@@ -39,16 +39,16 @@ export interface GachaResponse extends MysResponse {
* @returns {GachaData} * @returns {GachaData}
*/ */
export interface GachaData { export interface GachaData {
id: string id: string;
title: string title: string;
activity_url: string activity_url: string;
content_before_act: string content_before_act: string;
pool: GachaPool[] pool: GachaPool[];
voice_icon: string voice_icon: string;
voice_url: string voice_url: string;
voice_status: string voice_status: string;
start_time: string start_time: string;
end_time: string end_time: string;
} }
/** /**
@@ -60,8 +60,8 @@ export interface GachaData {
* @returns {GachaPool} * @returns {GachaPool}
*/ */
export interface GachaPool { export interface GachaPool {
icon: string icon: string;
url: string url: string;
} }
/** /**
@@ -82,16 +82,16 @@ export interface GachaPool {
* @returns {GachaCard} * @returns {GachaCard}
*/ */
export interface GachaCard { export interface GachaCard {
title: string title: string;
subtitle: string subtitle: string;
cover: string cover: string;
post_id: number post_id: number;
characters: GachaPool[] characters: GachaPool[];
voice: GachaPool voice: GachaPool;
time: { time: {
start: string start: string;
start_stamp: number start_stamp: number;
end: string end: string;
end_stamp: number end_stamp: number;
} };
} }

View File

@@ -18,8 +18,8 @@ import { type UserInfoPost } from "./user";
*/ */
export interface LotteryResponse extends MysResponse { export interface LotteryResponse extends MysResponse {
data: { data: {
show_lottery: LotteryData show_lottery: LotteryData;
} };
} }
/** /**
@@ -44,21 +44,21 @@ export interface LotteryResponse extends MysResponse {
* @returns {LotteryData} * @returns {LotteryData}
*/ */
export interface LotteryData { export interface LotteryData {
id: string id: string;
creator: UserInfoPost creator: UserInfoPost;
draw_time: string draw_time: string;
participant_way: string participant_way: string;
is_expect_unfocus_user: boolean is_expect_unfocus_user: boolean;
is_expect_non_real_name_user: boolean is_expect_non_real_name_user: boolean;
user_rewards: LotteryReward[] user_rewards: LotteryReward[];
status: string status: string;
is_blocked: boolean is_blocked: boolean;
user_status: string user_status: string;
is_upload_address: boolean is_upload_address: boolean;
lottery_entity_summary: string lottery_entity_summary: string;
entity_id: string entity_id: string;
entity_type: string entity_type: string;
now_time: string now_time: string;
} }
/** /**
@@ -74,12 +74,12 @@ export interface LotteryData {
* @returns {LotteryReward} * @returns {LotteryReward}
*/ */
export interface LotteryReward { export interface LotteryReward {
reward_name: string reward_name: string;
winner_number: number winner_number: number;
scheduled_winner_number: number scheduled_winner_number: number;
is_send_by_post: boolean is_send_by_post: boolean;
users: UserInfoPost[] users: UserInfoPost[];
id: string id: string;
} }
/** /**
@@ -95,12 +95,12 @@ export interface LotteryReward {
* @returns {LotteryCard} * @returns {LotteryCard}
*/ */
export interface LotteryCard { export interface LotteryCard {
id: string id: string;
participantWay: string participantWay: string;
status: string status: string;
creator: UserInfoPost creator: UserInfoPost;
drawTime: string drawTime: string;
rewards: LotteryRewardCard[] rewards: LotteryRewardCard[];
} }
/** /**
@@ -114,8 +114,8 @@ export interface LotteryCard {
* @returns {LotteryRewardCard} * @returns {LotteryRewardCard}
*/ */
export interface LotteryRewardCard { export interface LotteryRewardCard {
rewardName: string rewardName: string;
winnerNumber: number winnerNumber: number;
scheduledWinnerNumber: number scheduledWinnerNumber: number;
users: UserInfoPost[] users: UserInfoPost[];
} }

View File

@@ -19,7 +19,7 @@ import { type ImageData, type HelpSys } from "./utils";
* @returns {NewsResponse} * @returns {NewsResponse}
*/ */
export interface NewsResponse extends MysResponse { export interface NewsResponse extends MysResponse {
data: NewsData data: NewsData;
} }
/** /**
@@ -32,9 +32,9 @@ export interface NewsResponse extends MysResponse {
* @returns {NewsData} * @returns {NewsData}
*/ */
export interface NewsData { export interface NewsData {
last_id: number last_id: number;
is_last: boolean is_last: boolean;
list: NewsItem[] list: NewsItem[];
} }
/** /**
@@ -65,27 +65,27 @@ export interface NewsData {
* @returns {NewsItem} * @returns {NewsItem}
*/ */
export interface NewsItem { export interface NewsItem {
post: Post post: Post;
forum: Forum forum: Forum;
topics: Topic[] topics: Topic[];
user: UserInfoPost user: UserInfoPost;
self_operation: SelfOperation self_operation: SelfOperation;
stat: PostStat stat: PostStat;
help_sys: HelpSys help_sys: HelpSys;
cover: ImageData cover: ImageData;
image_list: ImageData[] image_list: ImageData[];
is_official_master: boolean is_official_master: boolean;
is_user_master: boolean is_user_master: boolean;
hot_reply_exist: boolean hot_reply_exist: boolean;
vote_count: number vote_count: number;
last_modify_time: number last_modify_time: number;
recommend_type: string recommend_type: string;
collection: unknown collection: unknown;
vod_list: unknown[] vod_list: unknown[];
is_block_on: boolean is_block_on: boolean;
forum_rank_info: unknown forum_rank_info: unknown;
link_card_list: unknown[] link_card_list: unknown[];
news_meta: NewsMeta news_meta: NewsMeta;
} }
/** /**
@@ -98,9 +98,9 @@ export interface NewsItem {
* @returns {NewsMeta} * @returns {NewsMeta}
*/ */
export interface NewsMeta { export interface NewsMeta {
activity_status: number activity_status: number;
start_at_sec: string start_at_sec: string;
end_at_sec: string end_at_sec: string;
} }
/** /**
@@ -115,11 +115,11 @@ export interface NewsMeta {
* @returns {NewsCard} * @returns {NewsCard}
*/ */
export interface NewsCard { export interface NewsCard {
title: string title: string;
cover: string cover: string;
post_id: number post_id: number;
subtitle: string subtitle: string;
status?: ActivityStatus status?: ActivityStatus;
} }
/** /**
@@ -130,6 +130,6 @@ export interface NewsCard {
* @returns {ActivityStatus} * @returns {ActivityStatus}
*/ */
export interface ActivityStatus { export interface ActivityStatus {
status: string status: string;
colorCss: string colorCss: string;
} }

View File

@@ -17,8 +17,8 @@ import { type MysObcResponse, type MysObc } from "./base";
*/ */
export interface PositionResponse extends MysObcResponse { export interface PositionResponse extends MysObcResponse {
data: { data: {
list: PositionObc[] list: PositionObc[];
} };
} }
/** /**
@@ -30,7 +30,7 @@ export interface PositionResponse extends MysObcResponse {
* @returns {PositionObc} * @returns {PositionObc}
*/ */
export interface PositionObc extends MysObc { export interface PositionObc extends MysObc {
list: PositionData[] list: PositionData[];
} }
/** /**
@@ -53,19 +53,19 @@ export interface PositionObc extends MysObc {
* @returns {PositionData} * @returns {PositionData}
*/ */
export interface PositionData { export interface PositionData {
recommend_id: number recommend_id: number;
content_id: number content_id: number;
title: string title: string;
ext: string ext: string;
type: number type: number;
url: string url: string;
icon: string icon: string;
abstract: string abstract: string;
article_user_name: string article_user_name: string;
avatar_url: string avatar_url: string;
article_time: string article_time: string;
create_time: string create_time: string;
end_time: string end_time: string;
} }
/** /**
@@ -84,14 +84,14 @@ export interface PositionData {
* @returns {PositionCard} * @returns {PositionCard}
*/ */
export interface PositionCard { export interface PositionCard {
title: string title: string;
post_id: number post_id: number;
icon: string icon: string;
abstract: string abstract: string;
time: { time: {
start: string start: string;
start_stamp: number start_stamp: number;
end: string end: string;
end_stamp: number end_stamp: number;
} };
} }

View File

@@ -20,8 +20,8 @@ import { type ImageData, type HelpSys } from "./utils";
*/ */
export interface PostResponse extends MysResponse { export interface PostResponse extends MysResponse {
data: { data: {
post: PostData post: PostData;
} };
} }
/** /**
@@ -52,27 +52,27 @@ export interface PostResponse extends MysResponse {
* @returns {PostData} * @returns {PostData}
*/ */
export interface PostData { export interface PostData {
post: Post post: Post;
forum: Forum forum: Forum;
topics: Topic[] topics: Topic[];
user: UserInfoPost user: UserInfoPost;
self_operation: SelfOperation self_operation: SelfOperation;
stat: PostStat stat: PostStat;
help_sys: HelpSys | null help_sys: HelpSys | null;
cover: ImageData | null cover: ImageData | null;
image_list: ImageData[] image_list: ImageData[];
is_official_master: boolean is_official_master: boolean;
is_user_master: boolean is_user_master: boolean;
hot_reply_exist: boolean hot_reply_exist: boolean;
vot_count: number vot_count: number;
last_modify_time: number last_modify_time: number;
recommend_type: string recommend_type: string;
collection: unknown | null collection: unknown | null;
vod_list: unknown[] vod_list: unknown[];
is_block_on: boolean is_block_on: boolean;
forum_rank_info: unknown | null forum_rank_info: unknown | null;
link_card_list: unknown[] link_card_list: unknown[];
news_meta: NewsMeta | null news_meta: NewsMeta | null;
} }
/** /**
@@ -121,46 +121,46 @@ export interface PostData {
* @returns {Post} * @returns {Post}
*/ */
export interface Post { export interface Post {
game_id: number game_id: number;
post_id: string post_id: string;
f_forum_id: number f_forum_id: number;
uid: string uid: string;
subject: string subject: string;
content: string content: string;
cover: string cover: string;
view_type: number view_type: number;
created_at: number created_at: number;
images: string[] images: string[];
post_status: { post_status: {
is_top: boolean is_top: boolean;
is_good: boolean is_good: boolean;
is_official: boolean is_official: boolean;
} };
topic_ids: number[] topic_ids: number[];
view_status: number view_status: number;
max_floor: number max_floor: number;
is_original: number is_original: number;
republish_authorization: number republish_authorization: number;
reply_time: string reply_time: string;
is_deleted: number is_deleted: number;
is_interactive: boolean is_interactive: boolean;
structured_content: string structured_content: string;
structured_content_rows: string[] structured_content_rows: string[];
review_id: number review_id: number;
is_profit: boolean is_profit: boolean;
is_in_profit: boolean is_in_profit: boolean;
updated_at: number updated_at: number;
deleted_at: number deleted_at: number;
pre_pub_status: number pre_pub_status: number;
cate_id: number cate_id: number;
profit_post_status: number profit_post_status: number;
audit_status: number audit_status: number;
meta_content: string meta_content: string;
is_missing: boolean is_missing: boolean;
block_reply_img: number block_reply_img: number;
is_showing_missing: boolean is_showing_missing: boolean;
block_latest_reply_time: number block_latest_reply_time: number;
selected_comment: number selected_comment: number;
} }
/** /**
@@ -175,11 +175,11 @@ export interface Post {
* @returns {Forum} * @returns {Forum}
*/ */
export interface Forum { export interface Forum {
id: number id: number;
name: string name: string;
icon: string icon: string;
game_id: number game_id: number;
forum_cate: unknown | null forum_cate: unknown | null;
} }
/** /**
@@ -197,14 +197,14 @@ export interface Forum {
* @returns {Topic} * @returns {Topic}
*/ */
export interface Topic { export interface Topic {
id: number id: number;
name: string name: string;
cover: string cover: string;
is_top: boolean is_top: boolean;
is_good: boolean is_good: boolean;
is_interactive: boolean is_interactive: boolean;
game_id: number game_id: number;
content_type: number content_type: number;
} }
/** /**
@@ -219,11 +219,11 @@ export interface Topic {
* @returns {PostStat} * @returns {PostStat}
*/ */
export interface PostStat { export interface PostStat {
view_num: number view_num: number;
reply_num: number reply_num: number;
like_num: number like_num: number;
bookmark_num: number bookmark_num: number;
forward_num: number forward_num: number;
} }
/** /**
@@ -236,8 +236,8 @@ export interface PostStat {
* @returns {PostContent} * @returns {PostContent}
*/ */
export interface PostContent { export interface PostContent {
describe: string describe: string;
imgs?: string[] imgs?: string[];
} }
/** /**
@@ -271,38 +271,37 @@ export interface PostContent {
* @returns {PostStructuredContent} * @returns {PostStructuredContent}
*/ */
export interface PostStructuredContent { export interface PostStructuredContent {
insert: insert:
| { | {
image?: string image?: string;
video?: string video?: string;
vod?: PostStructuredContentVod vod?: PostStructuredContentVod;
backup_text?: string backup_text?: string;
lottery?: { lottery?: {
id: string id: string;
toast: string toast: string;
} };
fold?: { fold?: {
title: string title: string;
content: string content: string;
} };
link_card?: PostStructuredContentLinkCard link_card?: PostStructuredContentLinkCard;
divider?: string divider?: string;
mention?: { mention?: {
uid: string uid: string;
nickname: string nickname: string;
} };
} }
| string | string;
attributes?: { attributes?: {
height?: number height?: number;
width?: number width?: number;
size?: number size?: number;
ext?: string ext?: string;
bold?: boolean bold?: boolean;
color?: string color?: string;
link?: string link?: string;
} };
} }
/** /**
@@ -327,22 +326,22 @@ export interface PostStructuredContent {
* @returns {PostStructuredContentVod} * @returns {PostStructuredContentVod}
*/ */
export interface PostStructuredContentVod { export interface PostStructuredContentVod {
id: number id: number;
duration: number duration: number;
cover: string cover: string;
resolutions: Array<{ resolutions: Array<{
url: string url: string;
definition: string definition: string;
height: number height: number;
width: number width: number;
bitrate: number bitrate: number;
size: number size: number;
format: string format: string;
label: string label: string;
}> }>;
view_num: number view_num: number;
transcoding_status: number transcoding_status: number;
review_status: number review_status: number;
} }
/** /**
@@ -363,15 +362,15 @@ export interface PostStructuredContentVod {
* @returns {PostStructuredContentLinkCard} * @returns {PostStructuredContentLinkCard}
*/ */
export interface PostStructuredContentLinkCard { export interface PostStructuredContentLinkCard {
link_type: number link_type: number;
origin_url: string origin_url: string;
landing_url: string landing_url: string;
cover: string cover: string;
title: string title: string;
card_id: string card_id: string;
card_status: number card_status: number;
market_price: string market_price: string;
price: string price: string;
button_text: string button_text: string;
landing_url_type: number landing_url_type: number;
} }

View File

@@ -16,7 +16,7 @@ import { type MysResponse } from "./base";
* @returns {UserResponse} * @returns {UserResponse}
*/ */
export interface UserResponse extends MysResponse { export interface UserResponse extends MysResponse {
data: UserInfoFull data: UserInfoFull;
} }
/** /**
@@ -41,23 +41,23 @@ export interface UserResponse extends MysResponse {
* @returns {UserInfoFull} * @returns {UserInfoFull}
*/ */
export interface UserInfoFull { export interface UserInfoFull {
user_info: UserInfo user_info: UserInfo;
follow_relation: unknown follow_relation: unknown;
auth_relations: unknown[] auth_relations: unknown[];
is_in_blacklist: boolean is_in_blacklist: boolean;
is_has_collection: boolean is_has_collection: boolean;
is_creator: boolean is_creator: boolean;
custom_service: { custom_service: {
is_customer_service_staff: boolean is_customer_service_staff: boolean;
game_id: number game_id: number;
} };
audit_info: { audit_info: {
is_nickname_in_audit: boolean is_nickname_in_audit: boolean;
nickname: string nickname: string;
is_introduce_in_audit: boolean is_introduce_in_audit: boolean;
introduce: string introduce: string;
nickname_status: number nickname_status: number;
} };
} }
/** /**
@@ -82,21 +82,21 @@ export interface UserInfoFull {
* @returns {UserInfo} * @returns {UserInfo}
*/ */
export interface UserInfo { export interface UserInfo {
uid: string uid: string;
nickname: string nickname: string;
introduce: string introduce: string;
avatar: string avatar: string;
gender: number gender: number;
certification: UserCertification certification: UserCertification;
level_exps: UserLevelExp[] level_exps: UserLevelExp[];
archive: UserArchive archive: UserArchive;
community_info: UserCommunityInfo community_info: UserCommunityInfo;
avatar_url: string avatar_url: string;
certifications: UserCertification[] certifications: UserCertification[];
level_exp: UserLevelExp level_exp: UserLevelExp;
pendant: string pendant: string;
is_logoff: boolean is_logoff: boolean;
ip_region: string ip_region: string;
} }
/** /**
@@ -108,8 +108,8 @@ export interface UserInfo {
* @returns {UserCertification} * @returns {UserCertification}
*/ */
export interface UserCertification { export interface UserCertification {
type: number type: number;
label: string label: string;
} }
/** /**
@@ -123,9 +123,9 @@ export interface UserCertification {
* @returns {UserLevelExp} * @returns {UserLevelExp}
*/ */
export interface UserLevelExp { export interface UserLevelExp {
level: number level: number;
exp: number exp: number;
game_id: number game_id: number;
} }
/** /**
@@ -144,15 +144,15 @@ export interface UserLevelExp {
* @returns {UserArchive} * @returns {UserArchive}
*/ */
export interface UserArchive { export interface UserArchive {
like_num: string like_num: string;
post_num: string post_num: string;
replypost_num: string replypost_num: string;
follow_cnt: string follow_cnt: string;
followed_cnt: string followed_cnt: string;
topic_cnt: string topic_cnt: string;
new_follower_num: string new_follower_num: string;
good_post_num: string good_post_num: string;
follow_collection_cnt: string follow_collection_cnt: string;
} }
/** /**
@@ -189,36 +189,36 @@ export interface UserArchive {
* @returns {UserCommunityInfo} * @returns {UserCommunityInfo}
*/ */
export interface UserCommunityInfo { export interface UserCommunityInfo {
is_realname: boolean is_realname: boolean;
agree_status: boolean agree_status: boolean;
silent_end_time: number silent_end_time: number;
forbid_end_time: number forbid_end_time: number;
info_upd_time: number info_upd_time: number;
privacy_invisible: { privacy_invisible: {
post: boolean post: boolean;
collect: boolean collect: boolean;
watermark: boolean watermark: boolean;
reply: boolean reply: boolean;
post_and_instant: boolean post_and_instant: boolean;
} };
notify_disable: { notify_disable: {
reply: boolean reply: boolean;
upvote: boolean upvote: boolean;
follow: boolean follow: boolean;
system: boolean system: boolean;
chat: boolean chat: boolean;
} };
has_initialized: boolean has_initialized: boolean;
user_func_status: { user_func_status: {
enable_history_view: boolean enable_history_view: boolean;
enable_recommend: boolean enable_recommend: boolean;
enable_mention: boolean enable_mention: boolean;
user_center_view: number user_center_view: number;
} };
forum_silent_info: unknown[] forum_silent_info: unknown[];
last_login_ip: string last_login_ip: string;
last_login_time: number last_login_time: number;
created_at: number created_at: number;
} }
/** /**
@@ -241,20 +241,20 @@ export interface UserCommunityInfo {
* @returns {UserInfoPost} * @returns {UserInfoPost}
*/ */
export interface UserInfoPost { export interface UserInfoPost {
uid: string uid: string;
nickname: string nickname: string;
introduce: string introduce: string;
avatar: string avatar: string;
gender: number gender: number;
certification: UserCertification certification: UserCertification;
level_exp: { level_exp: {
level: number level: number;
exp: number exp: number;
} };
is_following: boolean is_following: boolean;
is_follower: boolean is_follower: boolean;
avatar_url: string avatar_url: string;
pendant: string pendant: string;
} }
/** /**
@@ -266,6 +266,6 @@ export interface UserInfoPost {
* @returns {SelfOperation} * @returns {SelfOperation}
*/ */
export interface SelfOperation { export interface SelfOperation {
attitude: number attitude: number;
is_collected: boolean is_collected: boolean;
} }

View File

@@ -41,23 +41,23 @@ export const OBC_CONTENT_API =
* @returns {ImageData} * @returns {ImageData}
*/ */
export interface ImageData { export interface ImageData {
url: string url: string;
height: number height: number;
width: number width: number;
format: string format: string;
size: string size: string;
crop: { crop: {
x: number x: number;
y: number y: number;
w: number w: number;
h: number h: number;
url: string url: string;
} | null } | null;
is_user_set_cover: boolean is_user_set_cover: boolean;
image_id: string image_id: string;
entity_type: string entity_type: string;
entity_id: string entity_id: string;
is_deleted: boolean is_deleted: boolean;
} }
/** /**
@@ -71,7 +71,7 @@ export interface ImageData {
* @returns {HelpSys} * @returns {HelpSys}
*/ */
export interface HelpSys { export interface HelpSys {
top_up: unknown | null top_up: unknown | null;
top_n: unknown[] top_n: unknown[];
answer_num: number answer_num: number;
} }

View File

@@ -9,21 +9,22 @@ import { http } from "@tauri-apps/api";
import { type GachaResponse, type GachaData } from "../interface/gacha"; import { type GachaResponse, type GachaData } from "../interface/gacha";
// 卡池 API // 卡池 API
const GACHA_POOL_API = "https://api-takumi.mihoyo.com/common/blackboard/ys_obc/v1/gacha_pool?app_sn=ys_obc"; const GACHA_POOL_API =
"https://api-takumi.mihoyo.com/common/blackboard/ys_obc/v1/gacha_pool?app_sn=ys_obc";
/** /**
* @description 获取卡池信息 * @description 获取卡池信息
* @since Alpha * @since Alpha
* @return {Promise<GachaData[]>} * @return {Promise<GachaData[]>}
*/ */
export async function getGachaData (): Promise<GachaData[]> { export async function getGachaData(): Promise<GachaData[]> {
return await http return await http
.fetch<GachaResponse>(GACHA_POOL_API, { .fetch<GachaResponse>(GACHA_POOL_API, {
method: "GET", method: "GET",
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
}, },
}) })
.then((res) => { .then((res) => {
return res.data.data.list; return res.data.data.list;
}); });

View File

@@ -9,7 +9,8 @@ import { http } from "@tauri-apps/api";
import { type LotteryResponse, type LotteryData } from "../interface/lottery"; import { type LotteryResponse, type LotteryData } from "../interface/lottery";
// 抽奖 API // 抽奖 API
const LOTTERY_API = "https://bbs-api.miyoushe.com/painter/wapi/lottery/user/show?gids=2&id={lottery_id}"; const LOTTERY_API =
"https://bbs-api.miyoushe.com/painter/wapi/lottery/user/show?gids=2&id={lottery_id}";
/** /**
* @description 获取抽奖信息 * @description 获取抽奖信息
@@ -17,14 +18,14 @@ const LOTTERY_API = "https://bbs-api.miyoushe.com/painter/wapi/lottery/user/show
* @param {string} lotteryId 抽奖 ID * @param {string} lotteryId 抽奖 ID
* @return {Promise<LotteryData>} * @return {Promise<LotteryData>}
*/ */
export async function getLotteryData (lotteryId: string): Promise<LotteryData> { export async function getLotteryData(lotteryId: string): Promise<LotteryData> {
return await http return await http
.fetch<LotteryResponse>(LOTTERY_API.replace("{lottery_id}", lotteryId), { .fetch<LotteryResponse>(LOTTERY_API.replace("{lottery_id}", lotteryId), {
method: "GET", method: "GET",
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
}, },
}) })
.then((res) => { .then((res) => {
return res.data.data.show_lottery; return res.data.data.show_lottery;
}); });

View File

@@ -37,7 +37,11 @@ enum NewsType {
* @param {number} lastId 上一次请求的最后一条数据的 id * @param {number} lastId 上一次请求的最后一条数据的 id
* @return {Promise<NewsData>} * @return {Promise<NewsData>}
*/ */
export async function getNoticeList (gid: string = "2", pageSize: number = 20, lastId: number = 0): Promise<NewsData> { export async function getNoticeList(
gid: string = "2",
pageSize: number = 20,
lastId: number = 0,
): Promise<NewsData> {
const url = NEWS_LIST_API.replace("{page_size}", pageSize.toString()) const url = NEWS_LIST_API.replace("{page_size}", pageSize.toString())
.replace("{gid}", gid) .replace("{gid}", gid)
.replace("{news_type}", NewsType.NOTICE) .replace("{news_type}", NewsType.NOTICE)
@@ -53,7 +57,11 @@ export async function getNoticeList (gid: string = "2", pageSize: number = 20, l
* @param {number} lastId 上一次请求的最后一条数据的 id * @param {number} lastId 上一次请求的最后一条数据的 id
* @return {Promise<NewsData>} * @return {Promise<NewsData>}
*/ */
export async function getActivityList (gid: string = "2", pageSize: number = 20, lastId: number = 0): Promise<NewsData> { export async function getActivityList(
gid: string = "2",
pageSize: number = 20,
lastId: number = 0,
): Promise<NewsData> {
const url = NEWS_LIST_API.replace("{page_size}", pageSize.toString()) const url = NEWS_LIST_API.replace("{page_size}", pageSize.toString())
.replace("{gid}", gid) .replace("{gid}", gid)
.replace("{news_type}", NewsType.ACTIVITY) .replace("{news_type}", NewsType.ACTIVITY)
@@ -69,7 +77,11 @@ export async function getActivityList (gid: string = "2", pageSize: number = 20,
* @param {number} lastId 上一次请求的最后一条数据的 id * @param {number} lastId 上一次请求的最后一条数据的 id
* @return {Promise<NewsData>} * @return {Promise<NewsData>}
*/ */
export async function getNewsList (gid: string = "2", pageSize: number = 20, lastId: number = 0): Promise<NewsData> { export async function getNewsList(
gid: string = "2",
pageSize: number = 20,
lastId: number = 0,
): Promise<NewsData> {
const url = NEWS_LIST_API.replace("{page_size}", pageSize.toString()) const url = NEWS_LIST_API.replace("{page_size}", pageSize.toString())
.replace("{gid}", gid) .replace("{gid}", gid)
.replace("{news_type}", NewsType.NEWS) .replace("{news_type}", NewsType.NEWS)

View File

@@ -10,21 +10,22 @@ import { type PositionResponse, type PositionData } from "../interface/position"
import { dfs } from "../utils/position"; import { dfs } from "../utils/position";
// 热点追踪 API // 热点追踪 API
const POSITION_API = "https://api-static.mihoyo.com/common/blackboard/ys_obc/v1/home/position?app_sn=ys_obc"; const POSITION_API =
"https://api-static.mihoyo.com/common/blackboard/ys_obc/v1/home/position?app_sn=ys_obc";
/** /**
* @description 获取热点追踪信息 * @description 获取热点追踪信息
* @since Alpha v0.1.1 * @since Alpha v0.1.1
* @return {Promise<PositionData[]>} * @return {Promise<PositionData[]>}
*/ */
export async function getPositionData (): Promise<PositionData[]> { export async function getPositionData(): Promise<PositionData[]> {
const res = await http const res = await http
.fetch<PositionResponse>(POSITION_API, { .fetch<PositionResponse>(POSITION_API, {
method: "GET", method: "GET",
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
}, },
}) })
.then((res) => { .then((res) => {
return res.data.data.list; return res.data.data.list;
}); });

View File

@@ -18,15 +18,15 @@ const POST_REFERER = "https://bbs.mihoyo.com/";
* @param {number} postId 帖子 ID * @param {number} postId 帖子 ID
* @return {Promise<PostData>} * @return {Promise<PostData>}
*/ */
export async function getPostData (postId: number): Promise<PostData> { export async function getPostData(postId: number): Promise<PostData> {
return await http return await http
.fetch<PostResponse>(POST_API.replace("{post_id}", postId.toString()), { .fetch<PostResponse>(POST_API.replace("{post_id}", postId.toString()), {
method: "GET", method: "GET",
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
Referer: POST_REFERER, Referer: POST_REFERER,
}, },
}) })
.then((res) => { .then((res) => {
return res.data.data.post; return res.data.data.post;
}); });

View File

@@ -15,7 +15,7 @@ import { type GachaCard, type GachaData } from "../interface/gacha";
* @param {Map<string>} poolCover 卡池封面 * @param {Map<string>} poolCover 卡池封面
* @returns {Promise<GachaCard[]>} * @returns {Promise<GachaCard[]>}
*/ */
export async function getGachaCard ( export async function getGachaCard(
gachaData: GachaData[], gachaData: GachaData[],
poolCover: Record<number, string> | undefined = undefined, poolCover: Record<number, string> | undefined = undefined,
): Promise<GachaCard[]> { ): Promise<GachaCard[]> {

View File

@@ -5,7 +5,12 @@
* @since Alpha v0.1.1 * @since Alpha v0.1.1
*/ */
import { type LotteryData, type LotteryCard, type LotteryRewardCard, type LotteryReward } from "../interface/lottery"; import {
type LotteryData,
type LotteryCard,
type LotteryRewardCard,
type LotteryReward,
} from "../interface/lottery";
/** /**
* @description 根据抽奖信息转为渲染用的抽奖信息 * @description 根据抽奖信息转为渲染用的抽奖信息
@@ -13,7 +18,7 @@ import { type LotteryData, type LotteryCard, type LotteryRewardCard, type Lotter
* @param {LotteryData} lotteryData 抽奖信息 * @param {LotteryData} lotteryData 抽奖信息
* @returns {LotteryCard} * @returns {LotteryCard}
*/ */
export function getLotteryCard (lotteryData: LotteryData): LotteryCard { export function getLotteryCard(lotteryData: LotteryData): LotteryCard {
return { return {
id: lotteryData.id, id: lotteryData.id,
participantWay: lotteryData.participant_way, participantWay: lotteryData.participant_way,
@@ -32,7 +37,7 @@ export function getLotteryCard (lotteryData: LotteryData): LotteryCard {
* @param {LotteryReward} lotteryReward 抽奖奖励信息 * @param {LotteryReward} lotteryReward 抽奖奖励信息
* @returns {LotteryRewardCard} * @returns {LotteryRewardCard}
*/ */
export function getLotteryRewardCard (lotteryReward: LotteryReward): LotteryRewardCard { export function getLotteryRewardCard(lotteryReward: LotteryReward): LotteryRewardCard {
return { return {
rewardName: lotteryReward.reward_name, rewardName: lotteryReward.reward_name,
winnerNumber: lotteryReward.winner_number, winnerNumber: lotteryReward.winner_number,

View File

@@ -5,7 +5,12 @@
* @since Alpha v0.1.2 * @since Alpha v0.1.2
*/ */
import { type NewsData, type NewsItem, type NewsCard, type ActivityStatus } from "../interface/news"; import {
type NewsData,
type NewsItem,
type NewsCard,
type ActivityStatus,
} from "../interface/news";
// 默认封面图 // 默认封面图
const defaultCover = "/source/UI/defaultCover.webp"; const defaultCover = "/source/UI/defaultCover.webp";
@@ -44,7 +49,7 @@ const EnumStatus = {
* @param {number} status 活动状态码 * @param {number} status 活动状态码
* @returns {string} * @returns {string}
*/ */
export function getActivityStatus (status: number): ActivityStatus { export function getActivityStatus(status: number): ActivityStatus {
switch (status) { switch (status) {
case 1: case 1:
return EnumStatus.STARTED; return EnumStatus.STARTED;
@@ -63,7 +68,7 @@ export function getActivityStatus (status: number): ActivityStatus {
* @param {NewsData} noticeData 公告数据 * @param {NewsData} noticeData 公告数据
* @returns {NewsCard[]} * @returns {NewsCard[]}
*/ */
export function getNoticeCard (noticeData: NewsData): NewsCard[] { export function getNoticeCard(noticeData: NewsData): NewsCard[] {
const noticeCard: NewsCard[] = []; const noticeCard: NewsCard[] = [];
noticeData.list.map((item: NewsItem) => { noticeData.list.map((item: NewsItem) => {
return noticeCard.push({ return noticeCard.push({
@@ -82,7 +87,7 @@ export function getNoticeCard (noticeData: NewsData): NewsCard[] {
* @param {NewsData} activityData 活动数据 * @param {NewsData} activityData 活动数据
* @returns {NewsCard[]} * @returns {NewsCard[]}
*/ */
export function getActivityCard (activityData: NewsData): NewsCard[] { export function getActivityCard(activityData: NewsData): NewsCard[] {
const activityCard: NewsCard[] = []; const activityCard: NewsCard[] = [];
activityData.list.map((item: NewsItem) => { activityData.list.map((item: NewsItem) => {
const startTime = new Date(Number(item.news_meta.start_at_sec) * 1000).toLocaleDateString(); const startTime = new Date(Number(item.news_meta.start_at_sec) * 1000).toLocaleDateString();
@@ -105,7 +110,7 @@ export function getActivityCard (activityData: NewsData): NewsCard[] {
* @param {NewsData} newsData 新闻数据 * @param {NewsData} newsData 新闻数据
* @returns {NewsCard[]} * @returns {NewsCard[]}
*/ */
export function getNewsCard (newsData: NewsData): NewsCard[] { export function getNewsCard(newsData: NewsData): NewsCard[] {
const newsCard: NewsCard[] = []; const newsCard: NewsCard[] = [];
newsData.list.map((item: NewsItem) => { newsData.list.map((item: NewsItem) => {
return newsCard.push({ return newsCard.push({

Some files were not shown because too many files have changed in this diff Show More