Compare commits

...

45 Commits

Author SHA1 Message Date
BTMuli
c0e781b6b9 🚀 feat(0.1.4): 版本更新 2023-05-02 18:25:42 +08:00
BTMuli
91fc39b579 📦 add(source): 完善遗漏数据#9 2023-05-02 18:11:53 +08:00
BTMuli
14fd56fd9c 🐛 fix(pool): 修复窗口不可见问题并进行一些优化 2023-05-02 17:38:31 +08:00
BTMuli
b225827ef3 🏷️ fix(achievement): 适应页面更改类型 2023-05-01 22:53:46 +08:00
BTMuli
f869028fd5 🎨 fix(sql): 优化触发器 2023-05-01 22:52:27 +08:00
BTMuli
317d05aad6 🐛 fix(weapon): 删除多余资源 2023-05-01 22:32:35 +08:00
BTMuli
fc0c607726 📖 docs(README): 更新文档 2023-05-01 21:52:33 +08:00
BTMuli
a26b7fb053 🎨 fix(search): 优化查询体验 2023-04-26 22:54:15 +08:00
BTMuli
ec55ff69d6 🤔 fix(list): 优化滚动体验 2023-04-26 22:52:37 +08:00
BTMuli
3c6587cb73 🐛 fix(search): 修复查询时成就名片未重置的问题 2023-04-26 21:27:46 +08:00
BTMuli
5963e9a153 👌 feat(list): 虚拟列表#13 2023-04-26 21:21:28 +08:00
BTMuli
b69ae3b0a3 🐛 fix(update): 执行后刷新以免一直检测版本过低 2023-04-25 23:12:48 +08:00
BTMuli
528d4f6e83 🐛 fix(db): name 作为主键防止重复性插入 2023-04-25 22:59:59 +08:00
BTMuli
8cb05dd188 🔧 add(dev): 添加 debug 打包命令 2023-04-25 22:37:34 +08:00
BTMuli
3d0a9d57b2 🎨 fix(sth): 一些小优化 2023-04-25 22:36:34 +08:00
BTMuli
501f6bfa0e 💄 fix(confirm): 添加副标题 2023-04-25 22:30:33 +08:00
BTMuli
c442a1c5eb feat(update): 数据库更新 #11 2023-04-25 21:29:03 +08:00
BTMuli
5ac43c95e5 🎨 fix(achievement): 减了一个变量 2023-04-25 21:13:52 +08:00
BTMuli
b89c3ac101 📦 add(db): 添加数据库信息 2023-04-25 20:57:38 +08:00
BTMuli
89d2e214bc 🎨 fix(db): 数据库更新优化 2023-04-25 20:23:30 +08:00
BTMuli
96018666c5 🎨 fix(db): 不知道有没有什么用但还是感觉有优化 2023-04-25 20:17:30 +08:00
BTMuli
c9bef8927b 🎨 fix(db): 调整结构,将名片数据也写到数据库里 2023-04-25 20:02:51 +08:00
BTMuli
f40d9e61d4 🏷️ fix(type): 精简类型 2023-04-25 19:03:16 +08:00
BTMuli
27828e3a40 🎨 del(bbs): 删除 bbsTable 2023-04-25 17:18:22 +08:00
BTMuli
35d9382643 🎨 fix(db): 改进代码结构 2023-04-25 16:08:35 +08:00
BTMuli
cc42d1fcb3 🤔 feat(SQLite): 尝试另一种实现 2023-04-25 14:37:07 +08:00
BTMuli
6b3b9748cd 🐛 fix(search): 怎么回事呢 2023-04-25 00:39:20 +08:00
BTMuli
d6e60ee264 👌 del(db): indexedDB 已经是过去式了 2023-04-25 00:29:38 +08:00
BTMuli
4c8cb39bf6 💄 fix(scroll): 调整滚动条样式 2023-04-24 23:57:53 +08:00
BTMuli
ffc354a319 💄 fix(sth): 样式美化 2023-04-24 22:16:54 +08:00
BTMuli
26048dc12e feat(db): 数据源更改 2023-04-24 21:50:58 +08:00
BTMuli
ff36275184 🤔 fix(db): 完成数据库数据初始化&更新,后者未经过测试 2023-04-24 20:19:52 +08:00
BTMuli
0c178f8958 💄 fix(ui): 优化confirm组件深色模式表现 2023-04-24 20:11:12 +08:00
BTMuli
42f6d7bdaa 🤔 feat(sql): 基础准备差不多了,可以开测了 2023-04-24 19:16:45 +08:00
BTMuli
eeba1f9978 📦 add(db): 添加数据库路径 2023-04-24 17:32:44 +08:00
BTMuli
805b358e6d 🤔 feat(sqlite): 数据成功输入,接下来就是读取、校验了,先干饭吧 2023-04-24 15:04:49 +08:00
BTMuli
f9199efd03 🤔 feat(sqlite): 引入 sqlite 2023-04-24 13:20:56 +08:00
BTMuli
8da4ebdcf5 👌 update(pkg): 更新依赖 2023-04-24 13:14:06 +08:00
BTMuli
214d1d1090 feat(backup): 成就数据备份 2023-04-23 21:25:52 +08:00
BTMuli
019306d08c 🐛 fix(check): 开发时检测优化 2023-04-23 20:27:25 +08:00
BTMuli
ceea064d73 🔧 fix(key): 坏了,本地 key 无了,重搞一个吧 2023-04-23 16:18:40 +08:00
BTMuli
bbfd608b02 feat(check): 更新完后自动更新资源 2023-04-23 15:44:49 +08:00
BTMuli
8f728808a8 📖 fix(changelog): 更正 url 2023-04-23 14:04:06 +08:00
BTMuli
8c004a8af9 🐛 fix(achievement): 修复导入成就后索引未更新的问题 2023-04-23 14:03:46 +08:00
BTMuli
5d180857a3 🤔 build(v0.1.4): 开写 v0.1.4 2023-04-23 14:03:28 +08:00
45 changed files with 4235 additions and 6285 deletions

2
.gitignore vendored
View File

@@ -4,3 +4,5 @@
node_modules
# Tauri build
dist
# Secrets
.env.sh

View File

@@ -2,34 +2,52 @@
Author: 目棃
Date: 2023-03-30
Description: CHANGELOG
Update: 2023-04-23
Update: 2023-05-02
---
> 本文档 [`Front-matter`](https://github.com/BTMuli/Mucli#FrontMatter) 由 [MuCli](https://github.com/BTMuli/Mucli) 自动生成于`2023-03-30 15:39:49`
>
> 更新于 `2023-04-23 13:33:35`
> 更新于 `2023-05-02 18:24:21`
# CHANGELOG
## [0.1.4](https://github.com/BTMuli/Tauri.Genshin/releases/v0.1.4) (2023-05-02)
### Feat
- 应用:支持资源完整性检测&更新 [`bbfd608`](https://github.com/BTMuli/Tauri.Genshin/commit/bbfd608)
- 应用:支持数据备份&恢复 [`214d1d1`](https://github.com/BTMuli/Tauri.Genshin/commit/214d1d10)
- 应用:数据源更改为 Sqlite 而非之前的 IndexedDB [`26048dc`](https://github.com/BTMuli/Tauri.Genshin/commit/26048dc) [#11](https://github.com/BTMuli/Tauri.Genshin/issues/11)
### Fix
- 成就:使用虚拟列表优化内存占用及浏览体验 [`5963e9a`](https://github.com/BTMuli/Tauri.Genshin/commit/5963e9a) [#13](https://github.com/BTMuli/Tauri.Genshin/issues/13)
- 组件:优化 `TConfirm` 组件表现
- 应用:优化侧边滚动条表现
- 应用:检测更新 Key 更改,下版本更新将提示更新 [`ceea064`](https://github.com/BTMuli/Tauri.Genshin/commit/ceea064)
- 应用:添加 `3.6` 版本遗漏数据 [`91fc39b`](https://github.com/BTMuli/Tauri.Genshin/commit/91fc39b)
FullCommits: [`v0.1.3 ~ v0.1.4`](https://github.com/BTMuli/Tauri.Genshin/compare/v0.1.3...v0.1.4)
## [0.1.3](https://github.com/BTMuli/Tauri.Genshin/releases/v0.1.3) (2023-04-23)
### Feat
- 应用:支持浅色\深色主题切换
- 应用:支持检测更新
- 图鉴:角色图鉴草创 [`d154b5bd`](https://BTMuli/Tauri.Genshin/commit/d154b5bd)
- 图鉴:武器图鉴草创 [`1c309e38`](https://BTMuli/Tauri.Genshin/commit/1c309e38)
- 滚动条:样式美化 [`4022504`](https://BTMuli/Tauri.Genshin/commit/4022504)
- 图鉴:角色图鉴草创 [`d154b5bd`](https://github.com/BTMuli/Tauri.Genshin/commit/d154b5bd)
- 图鉴:武器图鉴草创 [`1c309e38`](https://github.com/BTMuli/Tauri.Genshin/commit/1c309e38)
- 滚动条:样式美化 [`4022504`](https://github.com/BTMuli/Tauri.Genshin/commit/4022504)
### Fix
- 应用:修复初始化未重新加载资源的问题 [`513be2e`](https://BTMuli/Tauri.Genshin/commit/513be2e)
- 应用:修复初始化未重新加载资源的问题 [`513be2e`](https://github.com/BTMuli/Tauri.Genshin/commit/513be2e)
- 应用:除成就数据外的 `readonly` 数据直接读取应用内 `json` 文件
- 应用:添加游戏新版本资源
- GCG相关资源归到 `WIKI`
- 首页:素材日历资源采用 WIKI 资源
FullCommits: [`v0.1.2 ~ v0.1.3`](https://BTMuli/Tauri.Genshin/compare/v0.1.2...v0.1.3)
FullCommits: [`v0.1.2 ~ v0.1.3`](https://github.com/BTMuli/Tauri.Genshin/compare/v0.1.2...v0.1.3)
## [0.1.2](https://github.com/BTMuli/Tauri.Genshin/releases/v0.1.2) (2023-04-12)

View File

@@ -2,12 +2,12 @@
Author: 目棃
Date: 2023-03-05
Description: 说明文档
Update: 2023-04-23
Update: 2023-05-01
---
> 本文档 [`Front-matter`](https://github.com/BTMuli/Mucli#FrontMatter) 由 [MuCli](https://github.com/BTMuli/Mucli) 自动生成于`2023-03-05 14:41:55`
>
> 更新于 `2023-04-23 12:55:01`
> 更新于 `2023-05-01 21:51:54`
![](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/v/release/BTMuli/Tauri.Genshin?include_prereleases&style=for-the-badge) ![](https://img.shields.io/github/license/BTMuli/Tauri.Genshin?style=for-the-badge)
@@ -22,13 +22,13 @@ Tauri 练手项目
## 技术栈
- [Tauri](https://tauri.studio/zh-CN/)
- [Vue3](https://v3.cn.vuejs.org/)
- [Vite](https://cn.vitejs.dev/)
- [TypeScript](https://www.typescriptlang.org/)
- [Vuetify](https://vuetifyjs.com/en/)
- [Tauri](https://github.com/tauri-apps/tauri)
- [Vue3](https://github.com/vuejs/core)
- [Vite](https://github.com/vitejs/vite)
- [TypeScript](https://github.com/microsoft/TypeScript)
- [Vuetify](https://github.com/vuetifyjs/vuetify)
## 当前进度(v0.1.3 Alpha)
## 当前进度
> 以下进度仅为开发进度,不代表最终版本
@@ -45,9 +45,17 @@ Tauri 练手项目
### 计划中
- [ ] UIGF 祈愿数据导入导出&展示
- [ ] Wiki 详情页
- [ ] 游戏数据获取
### 长期计划
- [ ] Wiki 详情页
- [ ] 游戏资源更新
## 仓库概况
![Status](https://repobeats.axiom.co/api/embed/0edac184a5892f2520e83e3fe6519c4168db2e1b.svg "Repobeats analytics image")
## UI 参考
- [Snap.Hutao](https://github.com/DGP-Studio/Snap.Hutao)
@@ -73,14 +81,14 @@ npm run dev
npm run build
```
# License
项目基于 [MIT](LICENSE) 协议开源。
应用版本号遵循 [Semantic Versioning 2.0.0](https://semver.org/lang/zh-CN/) 规范。
# Contributors
- [BTMuli](https://github.com/BTMuli)
- [舰队的偶像岛风酱!](https://github.com/frg2089)
- [jerry765](https://github.com/jerry765)
# License
项目基于 [MIT](LICENSE) 协议开源。
应用版本号遵循 [Semantic Versioning 2.0.0](https://semver.org/lang/zh-CN/) 规范。

View File

@@ -13,6 +13,8 @@ Update: 2023-04-23
本文档用于说明项目原始资源来源。
相关仓库:[TGAssistant](https://github.com/BTMuli/TGAssistant)。
> 如下 JSON 均经过处理,并未直接作为项目 JSON 数据使用。
>
> 如下图像均经过 Sharp 处理转换为 webp 格式,并未直接作为项目图像资源使用。

258
package-lock.json generated
View File

@@ -1,19 +1,20 @@
{
"name": "tauri-genshin",
"version": "0.1.3",
"version": "0.1.4",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "tauri-genshin",
"version": "0.1.3",
"version": "0.1.4",
"license": "MIT",
"dependencies": {
"@mdi/font": "7.2.96",
"@tauri-apps/api": "^1.2.0",
"clipboard": "^2.0.11",
"pinia": "^2.0.33",
"pinia": "^2.0.35",
"pinia-plugin-persistedstate": "^3.1.0",
"tauri-plugin-sql-api": "github:tauri-apps/tauri-plugin-sql",
"vue": "^3.2.47",
"vue-json-viewer": "^3.0.4",
"vue-router": "^4.1.6",
@@ -21,26 +22,26 @@
},
"devDependencies": {
"@tauri-apps/cli": "^1.2.3",
"@types/node": "^18.15.11",
"@typescript-eslint/eslint-plugin": "^5.57.1",
"@typescript-eslint/parser": "^5.57.1",
"@types/node": "^18.16.0",
"@typescript-eslint/eslint-plugin": "^5.59.0",
"@typescript-eslint/parser": "^5.59.0",
"@vitejs/plugin-vue": "^4.1.0",
"@vue/devtools": "^6.5.0",
"concurrently": "^8.0.1",
"eslint": "^8.37.0",
"eslint": "^8.39.0",
"eslint-config-standard-with-typescript": "^34.0.1",
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-n": "^15.7.0",
"eslint-plugin-promise": "^6.1.1",
"eslint-plugin-vue": "^9.10.0",
"prettier": "2.8.7",
"stylelint": "^15.4.0",
"eslint-plugin-vue": "^9.11.0",
"prettier": "2.8.8",
"stylelint": "^15.6.0",
"stylelint-config-standard-vue": "^1.0.0",
"stylelint-declaration-block-no-ignored-properties": "^2.7.0",
"stylelint-high-performance-animation": "^1.8.0",
"stylelint-order": "^6.0.3",
"typescript": "^5.0.3",
"vite": "^4.2.1",
"typescript": "^5.0.4",
"vite": "^4.3.1",
"vite-plugin-vuetify": "^1.0.2"
}
},
@@ -162,37 +163,37 @@
}
},
"node_modules/@csstools/css-parser-algorithms": {
"version": "2.1.0",
"resolved": "https://registry.npmmirror.com/@csstools/css-parser-algorithms/-/css-parser-algorithms-2.1.0.tgz",
"integrity": "sha512-KP8TicdXpUyeB1NMlbHud/1l39xvLGvqNFWMpG4qC6H1zs9SadGUHe5SO92n/659sDW9aGDvm9AMru0DZkN1Bw==",
"version": "2.1.1",
"resolved": "https://registry.npmmirror.com/@csstools/css-parser-algorithms/-/css-parser-algorithms-2.1.1.tgz",
"integrity": "sha512-viRnRh02AgO4mwIQb2xQNJju0i+Fh9roNgmbR5xEuG7J3TGgxjnE95HnBLgsFJOJOksvcfxOUCgODcft6Y07cA==",
"dev": true,
"engines": {
"node": "^14 || ^16 || >=18"
},
"peerDependencies": {
"@csstools/css-tokenizer": "^2.0.0"
"@csstools/css-tokenizer": "^2.1.1"
}
},
"node_modules/@csstools/css-tokenizer": {
"version": "2.1.0",
"resolved": "https://registry.npmmirror.com/@csstools/css-tokenizer/-/css-tokenizer-2.1.0.tgz",
"integrity": "sha512-dtqFyoJBHUxGi9zPZdpCKP1xk8tq6KPHJ/NY4qWXiYo6IcSGwzk3L8x2XzZbbyOyBs9xQARoGveU2AsgLj6D2A==",
"version": "2.1.1",
"resolved": "https://registry.npmmirror.com/@csstools/css-tokenizer/-/css-tokenizer-2.1.1.tgz",
"integrity": "sha512-GbrTj2Z8MCTUv+52GE0RbFGM527xuXZ0Xa5g0Z+YN573uveS4G0qi6WNOMyz3yrFM/jaILTTwJ0+umx81EzqfA==",
"dev": true,
"engines": {
"node": "^14 || ^16 || >=18"
}
},
"node_modules/@csstools/media-query-list-parser": {
"version": "2.0.2",
"resolved": "https://registry.npmmirror.com/@csstools/media-query-list-parser/-/media-query-list-parser-2.0.2.tgz",
"integrity": "sha512-8V6JD8Av1HttuClYr1ZBu0LRVe5Nnz4qrv8RppO8mobsX/USBHZy5JQOXYIlpOVhl46nzkx3X5cfH6CqUghjrQ==",
"version": "2.0.4",
"resolved": "https://registry.npmmirror.com/@csstools/media-query-list-parser/-/media-query-list-parser-2.0.4.tgz",
"integrity": "sha512-GyYot6jHgcSDZZ+tLSnrzkR7aJhF2ZW6d+CXH66mjy5WpAQhZD4HDke2OQ36SivGRWlZJpAz7TzbW6OKlEpxAA==",
"dev": true,
"engines": {
"node": "^14 || ^16 || >=18"
},
"peerDependencies": {
"@csstools/css-parser-algorithms": "^2.0.0",
"@csstools/css-tokenizer": "^2.0.0"
"@csstools/css-parser-algorithms": "^2.1.1",
"@csstools/css-tokenizer": "^2.1.1"
}
},
"node_modules/@csstools/selector-specificity": {
@@ -604,9 +605,9 @@
}
},
"node_modules/@eslint/js": {
"version": "8.37.0",
"resolved": "https://registry.npmmirror.com/@eslint/js/-/js-8.37.0.tgz",
"integrity": "sha512-x5vzdtOOGgFVDCUs81QRB2+liax8rFg3+7hqM+QhBG0/G3F1ZsoYl97UrqgHgQ9KKT7G6c4V+aTUCgu/n22v1A==",
"version": "8.39.0",
"resolved": "https://registry.npmmirror.com/@eslint/js/-/js-8.39.0.tgz",
"integrity": "sha512-kf9RB0Fg7NZfap83B3QOqOGg9QmD9yBudqQXzzOtn3i4y7ZUXe5ONeW34Gwi+TxhH4mvj72R1Zc300KUMa9Bng==",
"dev": true,
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
@@ -919,9 +920,9 @@
"dev": true
},
"node_modules/@types/node": {
"version": "18.15.11",
"resolved": "https://registry.npmmirror.com/@types/node/-/node-18.15.11.tgz",
"integrity": "sha512-E5Kwq2n4SbMzQOn6wnmBjuK9ouqlURrcZDVfbo9ftDDTFt3nk7ZKK4GMOzoYgnpQJKcxwQw+lGaBvvlMo0qN/Q==",
"version": "18.16.0",
"resolved": "https://registry.npmmirror.com/@types/node/-/node-18.16.0.tgz",
"integrity": "sha512-BsAaKhB+7X+H4GnSjGhJG9Qi8Tw+inU9nJDwmD5CgOmBLEI6ArdhikpLX7DjbjDRDTbqZzU2LSQNZg8WGPiSZQ==",
"devOptional": true
},
"node_modules/@types/normalize-package-data": {
@@ -947,15 +948,15 @@
}
},
"node_modules/@typescript-eslint/eslint-plugin": {
"version": "5.57.1",
"resolved": "https://registry.npmmirror.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.57.1.tgz",
"integrity": "sha512-1MeobQkQ9tztuleT3v72XmY0XuKXVXusAhryoLuU5YZ+mXoYKZP9SQ7Flulh1NX4DTjpGTc2b/eMu4u7M7dhnQ==",
"version": "5.59.0",
"resolved": "https://registry.npmmirror.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.0.tgz",
"integrity": "sha512-p0QgrEyrxAWBecR56gyn3wkG15TJdI//eetInP3zYRewDh0XS+DhB3VUAd3QqvziFsfaQIoIuZMxZRB7vXYaYw==",
"dev": true,
"dependencies": {
"@eslint-community/regexpp": "^4.4.0",
"@typescript-eslint/scope-manager": "5.57.1",
"@typescript-eslint/type-utils": "5.57.1",
"@typescript-eslint/utils": "5.57.1",
"@typescript-eslint/scope-manager": "5.59.0",
"@typescript-eslint/type-utils": "5.59.0",
"@typescript-eslint/utils": "5.59.0",
"debug": "^4.3.4",
"grapheme-splitter": "^1.0.4",
"ignore": "^5.2.0",
@@ -992,14 +993,14 @@
}
},
"node_modules/@typescript-eslint/parser": {
"version": "5.57.1",
"resolved": "https://registry.npmmirror.com/@typescript-eslint/parser/-/parser-5.57.1.tgz",
"integrity": "sha512-hlA0BLeVSA/wBPKdPGxoVr9Pp6GutGoY380FEhbVi0Ph4WNe8kLvqIRx76RSQt1lynZKfrXKs0/XeEk4zZycuA==",
"version": "5.59.0",
"resolved": "https://registry.npmmirror.com/@typescript-eslint/parser/-/parser-5.59.0.tgz",
"integrity": "sha512-qK9TZ70eJtjojSUMrrEwA9ZDQ4N0e/AuoOIgXuNBorXYcBDk397D2r5MIe1B3cok/oCtdNC5j+lUUpVB+Dpb+w==",
"dev": true,
"dependencies": {
"@typescript-eslint/scope-manager": "5.57.1",
"@typescript-eslint/types": "5.57.1",
"@typescript-eslint/typescript-estree": "5.57.1",
"@typescript-eslint/scope-manager": "5.59.0",
"@typescript-eslint/types": "5.59.0",
"@typescript-eslint/typescript-estree": "5.59.0",
"debug": "^4.3.4"
},
"engines": {
@@ -1015,26 +1016,26 @@
}
},
"node_modules/@typescript-eslint/scope-manager": {
"version": "5.57.1",
"resolved": "https://registry.npmmirror.com/@typescript-eslint/scope-manager/-/scope-manager-5.57.1.tgz",
"integrity": "sha512-N/RrBwEUKMIYxSKl0oDK5sFVHd6VI7p9K5MyUlVYAY6dyNb/wHUqndkTd3XhpGlXgnQsBkRZuu4f9kAHghvgPw==",
"version": "5.59.0",
"resolved": "https://registry.npmmirror.com/@typescript-eslint/scope-manager/-/scope-manager-5.59.0.tgz",
"integrity": "sha512-tsoldKaMh7izN6BvkK6zRMINj4Z2d6gGhO2UsI8zGZY3XhLq1DndP3Ycjhi1JwdwPRwtLMW4EFPgpuKhbCGOvQ==",
"dev": true,
"dependencies": {
"@typescript-eslint/types": "5.57.1",
"@typescript-eslint/visitor-keys": "5.57.1"
"@typescript-eslint/types": "5.59.0",
"@typescript-eslint/visitor-keys": "5.59.0"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
}
},
"node_modules/@typescript-eslint/type-utils": {
"version": "5.57.1",
"resolved": "https://registry.npmmirror.com/@typescript-eslint/type-utils/-/type-utils-5.57.1.tgz",
"integrity": "sha512-/RIPQyx60Pt6ga86hKXesXkJ2WOS4UemFrmmq/7eOyiYjYv/MUSHPlkhU6k9T9W1ytnTJueqASW+wOmW4KrViw==",
"version": "5.59.0",
"resolved": "https://registry.npmmirror.com/@typescript-eslint/type-utils/-/type-utils-5.59.0.tgz",
"integrity": "sha512-d/B6VSWnZwu70kcKQSCqjcXpVH+7ABKH8P1KNn4K7j5PXXuycZTPXF44Nui0TEm6rbWGi8kc78xRgOC4n7xFgA==",
"dev": true,
"dependencies": {
"@typescript-eslint/typescript-estree": "5.57.1",
"@typescript-eslint/utils": "5.57.1",
"@typescript-eslint/typescript-estree": "5.59.0",
"@typescript-eslint/utils": "5.59.0",
"debug": "^4.3.4",
"tsutils": "^3.21.0"
},
@@ -1051,22 +1052,22 @@
}
},
"node_modules/@typescript-eslint/types": {
"version": "5.57.1",
"resolved": "https://registry.npmmirror.com/@typescript-eslint/types/-/types-5.57.1.tgz",
"integrity": "sha512-bSs4LOgyV3bJ08F5RDqO2KXqg3WAdwHCu06zOqcQ6vqbTJizyBhuh1o1ImC69X4bV2g1OJxbH71PJqiO7Y1RuA==",
"version": "5.59.0",
"resolved": "https://registry.npmmirror.com/@typescript-eslint/types/-/types-5.59.0.tgz",
"integrity": "sha512-yR2h1NotF23xFFYKHZs17QJnB51J/s+ud4PYU4MqdZbzeNxpgUr05+dNeCN/bb6raslHvGdd6BFCkVhpPk/ZeA==",
"dev": true,
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
}
},
"node_modules/@typescript-eslint/typescript-estree": {
"version": "5.57.1",
"resolved": "https://registry.npmmirror.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.57.1.tgz",
"integrity": "sha512-A2MZqD8gNT0qHKbk2wRspg7cHbCDCk2tcqt6ScCFLr5Ru8cn+TCfM786DjPhqwseiS+PrYwcXht5ztpEQ6TFTw==",
"version": "5.59.0",
"resolved": "https://registry.npmmirror.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.0.tgz",
"integrity": "sha512-sUNnktjmI8DyGzPdZ8dRwW741zopGxltGs/SAPgGL/AAgDpiLsCFLcMNSpbfXfmnNeHmK9h3wGmCkGRGAoUZAg==",
"dev": true,
"dependencies": {
"@typescript-eslint/types": "5.57.1",
"@typescript-eslint/visitor-keys": "5.57.1",
"@typescript-eslint/types": "5.59.0",
"@typescript-eslint/visitor-keys": "5.59.0",
"debug": "^4.3.4",
"globby": "^11.1.0",
"is-glob": "^4.0.3",
@@ -1083,9 +1084,9 @@
}
},
"node_modules/@typescript-eslint/typescript-estree/node_modules/semver": {
"version": "7.3.8",
"resolved": "https://registry.npmmirror.com/semver/-/semver-7.3.8.tgz",
"integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
"version": "7.5.0",
"resolved": "https://registry.npmmirror.com/semver/-/semver-7.5.0.tgz",
"integrity": "sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA==",
"dev": true,
"dependencies": {
"lru-cache": "^6.0.0"
@@ -1098,17 +1099,17 @@
}
},
"node_modules/@typescript-eslint/utils": {
"version": "5.57.1",
"resolved": "https://registry.npmmirror.com/@typescript-eslint/utils/-/utils-5.57.1.tgz",
"integrity": "sha512-kN6vzzf9NkEtawECqze6v99LtmDiUJCVpvieTFA1uL7/jDghiJGubGZ5csicYHU1Xoqb3oH/R5cN5df6W41Nfg==",
"version": "5.59.0",
"resolved": "https://registry.npmmirror.com/@typescript-eslint/utils/-/utils-5.59.0.tgz",
"integrity": "sha512-GGLFd+86drlHSvPgN/el6dRQNYYGOvRSDVydsUaQluwIW3HvbXuxyuD5JETvBt/9qGYe+lOrDk6gRrWOHb/FvA==",
"dev": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@types/json-schema": "^7.0.9",
"@types/semver": "^7.3.12",
"@typescript-eslint/scope-manager": "5.57.1",
"@typescript-eslint/types": "5.57.1",
"@typescript-eslint/typescript-estree": "5.57.1",
"@typescript-eslint/scope-manager": "5.59.0",
"@typescript-eslint/types": "5.59.0",
"@typescript-eslint/typescript-estree": "5.59.0",
"eslint-scope": "^5.1.1",
"semver": "^7.3.7"
},
@@ -1142,9 +1143,9 @@
}
},
"node_modules/@typescript-eslint/utils/node_modules/semver": {
"version": "7.3.8",
"resolved": "https://registry.npmmirror.com/semver/-/semver-7.3.8.tgz",
"integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
"version": "7.5.0",
"resolved": "https://registry.npmmirror.com/semver/-/semver-7.5.0.tgz",
"integrity": "sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA==",
"dev": true,
"dependencies": {
"lru-cache": "^6.0.0"
@@ -1157,12 +1158,12 @@
}
},
"node_modules/@typescript-eslint/visitor-keys": {
"version": "5.57.1",
"resolved": "https://registry.npmmirror.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.57.1.tgz",
"integrity": "sha512-RjQrAniDU0CEk5r7iphkm731zKlFiUjvcBS2yHAg8WWqFMCaCrD0rKEVOMUyMMcbGPZ0bPp56srkGWrgfZqLRA==",
"version": "5.59.0",
"resolved": "https://registry.npmmirror.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.0.tgz",
"integrity": "sha512-qZ3iXxQhanchCeaExlKPV3gDQFxMUmU35xfd5eCXB6+kUw1TUAbIy2n7QIrwz9s98DQLzNWyHp61fY0da4ZcbA==",
"dev": true,
"dependencies": {
"@typescript-eslint/types": "5.57.1",
"@typescript-eslint/types": "5.59.0",
"eslint-visitor-keys": "^3.3.0"
},
"engines": {
@@ -2464,15 +2465,15 @@
}
},
"node_modules/eslint": {
"version": "8.37.0",
"resolved": "https://registry.npmmirror.com/eslint/-/eslint-8.37.0.tgz",
"integrity": "sha512-NU3Ps9nI05GUoVMxcZx1J8CNR6xOvUT4jAUMH5+z8lpp3aEdPVCImKw6PWG4PY+Vfkpr+jvMpxs/qoE7wq0sPw==",
"version": "8.39.0",
"resolved": "https://registry.npmmirror.com/eslint/-/eslint-8.39.0.tgz",
"integrity": "sha512-mwiok6cy7KTW7rBpo05k6+p4YVZByLNjAZ/ACB9DRCu4YDRwjXI01tWHp6KAUWelsBetTxKK/2sHB0vdS8Z2Og==",
"dev": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.4.0",
"@eslint/eslintrc": "^2.0.2",
"@eslint/js": "8.37.0",
"@eslint/js": "8.39.0",
"@humanwhocodes/config-array": "^0.11.8",
"@humanwhocodes/module-importer": "^1.0.1",
"@nodelib/fs.walk": "^1.2.8",
@@ -2482,7 +2483,7 @@
"debug": "^4.3.2",
"doctrine": "^3.0.0",
"escape-string-regexp": "^4.0.0",
"eslint-scope": "^7.1.1",
"eslint-scope": "^7.2.0",
"eslint-visitor-keys": "^3.4.0",
"espree": "^9.5.1",
"esquery": "^1.4.2",
@@ -2730,9 +2731,9 @@
}
},
"node_modules/eslint-plugin-vue": {
"version": "9.10.0",
"resolved": "https://registry.npmmirror.com/eslint-plugin-vue/-/eslint-plugin-vue-9.10.0.tgz",
"integrity": "sha512-2MgP31OBf8YilUvtakdVMc8xVbcMp7z7/iQj8LHVpXrSXHPXSJRUIGSPFI6b6pyCx/buKaFJ45ycqfHvQRiW2g==",
"version": "9.11.0",
"resolved": "https://registry.npmmirror.com/eslint-plugin-vue/-/eslint-plugin-vue-9.11.0.tgz",
"integrity": "sha512-bBCJAZnkBV7ATH4Z1E7CvN3nmtS4H7QUU3UBxPdo8WohRU+yHjnQRALpTbxMVcz0e4Mx3IyxIdP5HYODMxK9cQ==",
"dev": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.3.0",
@@ -2766,9 +2767,9 @@
}
},
"node_modules/eslint-scope": {
"version": "7.1.1",
"resolved": "https://registry.npmmirror.com/eslint-scope/-/eslint-scope-7.1.1.tgz",
"integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==",
"version": "7.2.0",
"resolved": "https://registry.npmmirror.com/eslint-scope/-/eslint-scope-7.2.0.tgz",
"integrity": "sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==",
"dev": true,
"dependencies": {
"esrecurse": "^4.3.0",
@@ -3247,7 +3248,7 @@
"version": "1.1.1",
"resolved": "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.1.tgz",
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
"devOptional": true
"dev": true
},
"node_modules/function.prototype.name": {
"version": "1.1.5",
@@ -3555,7 +3556,7 @@
"version": "1.0.3",
"resolved": "https://registry.npmmirror.com/has/-/has-1.0.3.tgz",
"integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
"devOptional": true,
"dev": true,
"dependencies": {
"function-bind": "^1.1.1"
},
@@ -3837,7 +3838,7 @@
"version": "2.11.0",
"resolved": "https://registry.npmmirror.com/is-core-module/-/is-core-module-2.11.0.tgz",
"integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==",
"devOptional": true,
"dev": true,
"dependencies": {
"has": "^1.0.3"
}
@@ -4410,9 +4411,9 @@
"devOptional": true
},
"node_modules/nanoid": {
"version": "3.3.4",
"resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.4.tgz",
"integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==",
"version": "3.3.6",
"resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.6.tgz",
"integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==",
"bin": {
"nanoid": "bin/nanoid.cjs"
},
@@ -4723,7 +4724,7 @@
"version": "1.0.7",
"resolved": "https://registry.npmmirror.com/path-parse/-/path-parse-1.0.7.tgz",
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
"devOptional": true
"dev": true
},
"node_modules/path-to-regexp": {
"version": "0.1.7",
@@ -4771,9 +4772,9 @@
}
},
"node_modules/pinia": {
"version": "2.0.33",
"resolved": "https://registry.npmmirror.com/pinia/-/pinia-2.0.33.tgz",
"integrity": "sha512-HOj1yVV2itw6rNIrR2f7+MirGNxhORjrULL8GWgRwXsGSvEqIQ+SE0MYt6cwtpegzCda3i+rVTZM+AM7CG+kRg==",
"version": "2.0.35",
"resolved": "https://registry.npmmirror.com/pinia/-/pinia-2.0.35.tgz",
"integrity": "sha512-P1IKKQWhxGXiiZ3atOaNI75bYlFUbRxtJdhPLX059Z7+b9Z04rnTZdSY8Aph1LA+/4QEMAYHsTQ638Wfe+6K5g==",
"dependencies": {
"@vue/devtools-api": "^6.5.0",
"vue-demi": "*"
@@ -4835,11 +4836,11 @@
}
},
"node_modules/postcss": {
"version": "8.4.21",
"resolved": "https://registry.npmmirror.com/postcss/-/postcss-8.4.21.tgz",
"integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==",
"version": "8.4.23",
"resolved": "https://registry.npmmirror.com/postcss/-/postcss-8.4.23.tgz",
"integrity": "sha512-bQ3qMcpF6A/YjR55xtoTr0jGOlnPOKAIMdOWiv0EIT6HVPEaJiJB4NLljSbiHoC2RX7DN5Uvjtpbg1NPdwv1oA==",
"dependencies": {
"nanoid": "^3.3.4",
"nanoid": "^3.3.6",
"picocolors": "^1.0.0",
"source-map-js": "^1.0.2"
},
@@ -4941,9 +4942,9 @@
}
},
"node_modules/prettier": {
"version": "2.8.7",
"resolved": "https://registry.npmmirror.com/prettier/-/prettier-2.8.7.tgz",
"integrity": "sha512-yPngTo3aXUUmyuTjeTUT75txrf+aMh9FiD7q9ZE/i6r0bPb22g4FsE6Y338PQX1bmfy08i9QQCB7/rcUAVntfw==",
"version": "2.8.8",
"resolved": "https://registry.npmmirror.com/prettier/-/prettier-2.8.8.tgz",
"integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==",
"dev": true,
"bin": {
"prettier": "bin-prettier.js"
@@ -5183,7 +5184,7 @@
"version": "1.22.1",
"resolved": "https://registry.npmmirror.com/resolve/-/resolve-1.22.1.tgz",
"integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==",
"devOptional": true,
"dev": true,
"dependencies": {
"is-core-module": "^2.9.0",
"path-parse": "^1.0.7",
@@ -5252,9 +5253,9 @@
}
},
"node_modules/rollup": {
"version": "3.18.0",
"resolved": "https://registry.npmmirror.com/rollup/-/rollup-3.18.0.tgz",
"integrity": "sha512-J8C6VfEBjkvYPESMQYxKHxNOh4A5a3FlP+0BETGo34HEcE4eTlgCrO2+eWzlu2a/sHs2QUkZco+wscH7jhhgWg==",
"version": "3.21.0",
"resolved": "https://registry.npmmirror.com/rollup/-/rollup-3.21.0.tgz",
"integrity": "sha512-ANPhVcyeHvYdQMUyCbczy33nbLzI7RzrBje4uvNiTDJGIMtlKoOStmympwr9OtS1LZxiDmE2wvxHyVhoLtf1KQ==",
"devOptional": true,
"bin": {
"rollup": "dist/bin/rollup"
@@ -5741,14 +5742,14 @@
"dev": true
},
"node_modules/stylelint": {
"version": "15.4.0",
"resolved": "https://registry.npmmirror.com/stylelint/-/stylelint-15.4.0.tgz",
"integrity": "sha512-TlOvpG3MbcFwHmK0q2ykhmpKo7Dq892beJit0NPdpyY9b1tFah/hGhqnAz/bRm2PDhDbJLKvjzkEYYBEz7Dxcg==",
"version": "15.6.0",
"resolved": "https://registry.npmmirror.com/stylelint/-/stylelint-15.6.0.tgz",
"integrity": "sha512-Cqzpc8tvJm77KaM8qUbhpJ/UYK55Ia0whQXj4b9IId9dlPICO7J8Lyo15SZWiHxKjlvy3p5FQor/3n6i8ignXg==",
"dev": true,
"dependencies": {
"@csstools/css-parser-algorithms": "^2.1.0",
"@csstools/css-tokenizer": "^2.1.0",
"@csstools/media-query-list-parser": "^2.0.1",
"@csstools/css-parser-algorithms": "^2.1.1",
"@csstools/css-tokenizer": "^2.1.1",
"@csstools/media-query-list-parser": "^2.0.4",
"@csstools/selector-specificity": "^2.2.0",
"balanced-match": "^2.0.0",
"colord": "^2.9.3",
@@ -5762,7 +5763,7 @@
"global-modules": "^2.0.0",
"globby": "^11.1.0",
"globjoin": "^0.1.4",
"html-tags": "^3.2.0",
"html-tags": "^3.3.1",
"ignore": "^5.2.4",
"import-lazy": "^4.0.0",
"imurmurhash": "^0.1.4",
@@ -5773,7 +5774,7 @@
"micromatch": "^4.0.5",
"normalize-path": "^3.0.0",
"picocolors": "^1.0.0",
"postcss": "^8.4.21",
"postcss": "^8.4.22",
"postcss-media-query-parser": "^0.2.3",
"postcss-resolve-nested-selector": "^0.1.1",
"postcss-safe-parser": "^6.0.0",
@@ -5974,7 +5975,7 @@
"version": "1.0.0",
"resolved": "https://registry.npmmirror.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
"devOptional": true,
"dev": true,
"engines": {
"node": ">= 0.4"
}
@@ -6019,6 +6020,14 @@
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
"dev": true
},
"node_modules/tauri-plugin-sql-api": {
"version": "0.0.0",
"resolved": "git+ssh://git@github.com/tauri-apps/tauri-plugin-sql.git#62b21ef24303d80e9905f57b2b6d27efc8677c23",
"license": "MIT or APACHE-2.0",
"dependencies": {
"@tauri-apps/api": "^1.2.0"
}
},
"node_modules/text-table": {
"version": "0.2.0",
"resolved": "https://registry.npmmirror.com/text-table/-/text-table-0.2.0.tgz",
@@ -6167,9 +6176,9 @@
}
},
"node_modules/typescript": {
"version": "5.0.3",
"resolved": "https://registry.npmmirror.com/typescript/-/typescript-5.0.3.tgz",
"integrity": "sha512-xv8mOEDnigb/tN9PSMTwSEqAnUvkoXMQlicOb0IUVDBSQCgBSaAAROUZYy2IcUy5qU6XajK5jjjO7TMWqBTKZA==",
"version": "5.0.4",
"resolved": "https://registry.npmmirror.com/typescript/-/typescript-5.0.4.tgz",
"integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==",
"devOptional": true,
"bin": {
"tsc": "bin/tsc",
@@ -6294,15 +6303,14 @@
}
},
"node_modules/vite": {
"version": "4.2.1",
"resolved": "https://registry.npmmirror.com/vite/-/vite-4.2.1.tgz",
"integrity": "sha512-7MKhqdy0ISo4wnvwtqZkjke6XN4taqQ2TBaTccLIpOKv7Vp2h4Y+NpmWCnGDeSvvn45KxvWgGyb0MkHvY1vgbg==",
"version": "4.3.1",
"resolved": "https://registry.npmmirror.com/vite/-/vite-4.3.1.tgz",
"integrity": "sha512-EPmfPLAI79Z/RofuMvkIS0Yr091T2ReUoXQqc5ppBX/sjFRhHKiPPF/R46cTdoci/XgeQpB23diiJxq5w30vdg==",
"devOptional": true,
"dependencies": {
"esbuild": "^0.17.5",
"postcss": "^8.4.21",
"resolve": "^1.22.1",
"rollup": "^3.18.0"
"rollup": "^3.20.2"
},
"bin": {
"vite": "bin/vite.js"

View File

@@ -2,7 +2,7 @@
"name": "tauri-genshin",
"description": "A Tauri App Demo",
"private": true,
"version": "0.1.3",
"version": "0.1.4",
"author": "BTMuli <bt-muli@outlook.com>",
"scripts": {
"lint": "concurrently \"npm:lint:*(!fix)\"",
@@ -16,6 +16,7 @@
"vite:dev": "vite dev",
"vite:build": "vite build",
"build": "tauri build",
"debug": "tauri build --debug",
"preview": "vite preview",
"tauri": "tauri"
},
@@ -43,8 +44,9 @@
"@mdi/font": "7.2.96",
"@tauri-apps/api": "^1.2.0",
"clipboard": "^2.0.11",
"pinia": "^2.0.33",
"pinia": "^2.0.35",
"pinia-plugin-persistedstate": "^3.1.0",
"tauri-plugin-sql-api": "github:tauri-apps/tauri-plugin-sql",
"vue": "^3.2.47",
"vue-json-viewer": "^3.0.4",
"vue-router": "^4.1.6",
@@ -52,26 +54,26 @@
},
"devDependencies": {
"@tauri-apps/cli": "^1.2.3",
"@types/node": "^18.15.11",
"@typescript-eslint/eslint-plugin": "^5.57.1",
"@typescript-eslint/parser": "^5.57.1",
"@types/node": "^18.16.0",
"@typescript-eslint/eslint-plugin": "^5.59.0",
"@typescript-eslint/parser": "^5.59.0",
"@vitejs/plugin-vue": "^4.1.0",
"@vue/devtools": "^6.5.0",
"concurrently": "^8.0.1",
"eslint": "^8.37.0",
"eslint": "^8.39.0",
"eslint-config-standard-with-typescript": "^34.0.1",
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-n": "^15.7.0",
"eslint-plugin-promise": "^6.1.1",
"eslint-plugin-vue": "^9.10.0",
"prettier": "2.8.7",
"stylelint": "^15.4.0",
"eslint-plugin-vue": "^9.11.0",
"prettier": "2.8.8",
"stylelint": "^15.6.0",
"stylelint-config-standard-vue": "^1.0.0",
"stylelint-declaration-block-no-ignored-properties": "^2.7.0",
"stylelint-high-performance-animation": "^1.8.0",
"stylelint-order": "^6.0.3",
"typescript": "^5.0.3",
"vite": "^4.2.1",
"typescript": "^5.0.4",
"vite": "^4.3.1",
"vite-plugin-vuetify": "^1.0.2"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

440
src-tauri/Cargo.lock generated
View File

@@ -8,6 +8,17 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "ahash"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47"
dependencies = [
"getrandom 0.2.8",
"once_cell",
"version_check",
]
[[package]]
name = "aho-corasick"
version = "0.7.20"
@@ -95,6 +106,15 @@ dependencies = [
"system-deps 6.0.3",
]
[[package]]
name = "atoi"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7c57d12312ff59c811c0643f4d80830505833c9ffaebd193d819392b265be8e"
dependencies = [
"num-traits",
]
[[package]]
name = "atomic"
version = "0.5.1"
@@ -420,6 +440,21 @@ dependencies = [
"libc",
]
[[package]]
name = "crc"
version = "3.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86ec7a15cbe22e59248fc7eadb1907dab5ba09372595da4d73dd805ed4417dfe"
dependencies = [
"crc-catalog",
]
[[package]]
name = "crc-catalog"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9cace84e55f07e7301bae1c519df89cdad8cc3cd868413d3fdbdeca9ff3db484"
[[package]]
name = "crc32fast"
version = "1.3.2"
@@ -439,6 +474,16 @@ dependencies = [
"crossbeam-utils",
]
[[package]]
name = "crossbeam-queue"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d1cfb3ea8a53f37c40dea2c7bedcbd88bdfae54f5e2175d6ecaff1c988353add"
dependencies = [
"cfg-if",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.15"
@@ -630,6 +675,12 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b"
[[package]]
name = "dotenvy"
version = "0.15.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b"
[[package]]
name = "dtoa"
version = "0.4.8"
@@ -704,6 +755,12 @@ dependencies = [
"libc",
]
[[package]]
name = "event-listener"
version = "2.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
[[package]]
name = "fastrand"
version = "1.9.0"
@@ -759,6 +816,18 @@ dependencies = [
"miniz_oxide",
]
[[package]]
name = "flume"
version = "0.10.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1657b4441c3403d9f7b3409e47575237dac27b1b5726df654a6ecbf92f0f7577"
dependencies = [
"futures-core",
"futures-sink",
"pin-project",
"spin 0.9.8",
]
[[package]]
name = "fnv"
version = "1.0.7"
@@ -840,6 +909,17 @@ dependencies = [
"futures-util",
]
[[package]]
name = "futures-intrusive"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a604f7a68fbf8103337523b1fadc8ade7361ee3f112f7c680ad179651616aed5"
dependencies = [
"futures-core",
"lock_api",
"parking_lot 0.11.2",
]
[[package]]
name = "futures-io"
version = "0.3.28"
@@ -1197,6 +1277,18 @@ name = "hashbrown"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
dependencies = [
"ahash",
]
[[package]]
name = "hashlink"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69fe1fcf8b4278d860ad0548329f892a3631fb63f82574df68275f34cdbe0ffa"
dependencies = [
"hashbrown",
]
[[package]]
name = "heck"
@@ -1212,6 +1304,9 @@ name = "heck"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
dependencies = [
"unicode-segmentation",
]
[[package]]
name = "hermit-abi"
@@ -1228,6 +1323,12 @@ version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286"
[[package]]
name = "hex"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]]
name = "html5ever"
version = "0.25.2"
@@ -1420,6 +1521,15 @@ dependencies = [
"windows-sys 0.48.0",
]
[[package]]
name = "itertools"
version = "0.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
dependencies = [
"either",
]
[[package]]
name = "itoa"
version = "0.4.8"
@@ -1528,6 +1638,17 @@ dependencies = [
"pkg-config",
]
[[package]]
name = "libsqlite3-sys"
version = "0.24.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "898745e570c7d0453cc1fbc4a701eb6c662ed54e8fec8b7d14be137ebeeb9d14"
dependencies = [
"cc",
"pkg-config",
"vcpkg",
]
[[package]]
name = "line-wrap"
version = "0.1.1"
@@ -1661,6 +1782,18 @@ version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
[[package]]
name = "minimal-lexical"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]]
name = "minisign-verify"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "933dca44d65cdd53b355d0b73d380a2ff5da71f87f036053188bf1eab6a19881"
[[package]]
name = "miniz_oxide"
version = "0.6.2"
@@ -1696,7 +1829,7 @@ dependencies = [
"log",
"memchr",
"mime",
"spin",
"spin 0.9.8",
"tokio",
"tokio-util",
"version_check",
@@ -1760,6 +1893,16 @@ version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb"
[[package]]
name = "nom"
version = "7.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
dependencies = [
"memchr",
"minimal-lexical",
]
[[package]]
name = "notify-rust"
version = "4.8.0"
@@ -1995,6 +2138,17 @@ dependencies = [
"system-deps 6.0.3",
]
[[package]]
name = "parking_lot"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
dependencies = [
"instant",
"lock_api",
"parking_lot_core 0.8.6",
]
[[package]]
name = "parking_lot"
version = "0.12.1"
@@ -2002,7 +2156,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
dependencies = [
"lock_api",
"parking_lot_core",
"parking_lot_core 0.9.7",
]
[[package]]
name = "parking_lot_core"
version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc"
dependencies = [
"cfg-if",
"instant",
"libc",
"redox_syscall",
"smallvec",
"winapi",
]
[[package]]
@@ -2157,6 +2325,26 @@ dependencies = [
"siphasher",
]
[[package]]
name = "pin-project"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc"
dependencies = [
"pin-project-internal",
]
[[package]]
name = "pin-project-internal"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "pin-project-lite"
version = "0.2.9"
@@ -2482,6 +2670,21 @@ dependencies = [
"windows 0.37.0",
]
[[package]]
name = "ring"
version = "0.16.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc"
dependencies = [
"cc",
"libc",
"once_cell",
"spin 0.5.2",
"untrusted",
"web-sys",
"winapi",
]
[[package]]
name = "rocket"
version = "0.5.0-rc.3"
@@ -2502,7 +2705,7 @@ dependencies = [
"memchr",
"multer",
"num_cpus",
"parking_lot",
"parking_lot 0.12.1",
"pin-project-lite",
"rand 0.8.5",
"ref-cast",
@@ -2600,6 +2803,27 @@ dependencies = [
"windows-sys 0.45.0",
]
[[package]]
name = "rustls"
version = "0.20.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f"
dependencies = [
"log",
"ring",
"sct",
"webpki",
]
[[package]]
name = "rustls-pemfile"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b"
dependencies = [
"base64 0.21.0",
]
[[package]]
name = "rustversion"
version = "1.0.11"
@@ -2648,6 +2872,16 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "sct"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4"
dependencies = [
"ring",
"untrusted",
]
[[package]]
name = "security-framework"
version = "2.8.2"
@@ -2906,11 +3140,121 @@ dependencies = [
"system-deps 5.0.0",
]
[[package]]
name = "spin"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
[[package]]
name = "spin"
version = "0.9.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
dependencies = [
"lock_api",
]
[[package]]
name = "sqlformat"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c12bc9199d1db8234678b7051747c07f517cdcf019262d1847b94ec8b1aee3e"
dependencies = [
"itertools",
"nom",
"unicode_categories",
]
[[package]]
name = "sqlx"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8de3b03a925878ed54a954f621e64bf55a3c1bd29652d0d1a17830405350188"
dependencies = [
"sqlx-core",
"sqlx-macros",
]
[[package]]
name = "sqlx-core"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa8241483a83a3f33aa5fff7e7d9def398ff9990b2752b6c6112b83c6d246029"
dependencies = [
"ahash",
"atoi",
"bitflags 1.3.2",
"byteorder",
"bytes",
"crc",
"crossbeam-queue",
"dotenvy",
"either",
"event-listener",
"flume",
"futures-channel",
"futures-core",
"futures-executor",
"futures-intrusive",
"futures-util",
"hashlink",
"hex",
"indexmap",
"itoa 1.0.6",
"libc",
"libsqlite3-sys",
"log",
"memchr",
"once_cell",
"paste",
"percent-encoding",
"rustls",
"rustls-pemfile",
"serde",
"serde_json",
"sha2",
"smallvec",
"sqlformat",
"sqlx-rt",
"stringprep",
"thiserror",
"time",
"tokio-stream",
"url",
"webpki-roots",
]
[[package]]
name = "sqlx-macros"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9966e64ae989e7e575b19d7265cb79d7fc3cbbdf179835cb0d716f294c2049c9"
dependencies = [
"dotenvy",
"either",
"heck 0.4.1",
"once_cell",
"proc-macro2",
"quote",
"serde_json",
"sha2",
"sqlx-core",
"sqlx-rt",
"syn 1.0.109",
"url",
]
[[package]]
name = "sqlx-rt"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "804d3f245f894e61b1e6263c84b23ca675d96753b5abfd5cc8597d86806e8024"
dependencies = [
"once_cell",
"tokio",
"tokio-rustls",
]
[[package]]
name = "stable-pattern"
@@ -2944,7 +3288,7 @@ checksum = "7d69e88b23f23030bf4d0e9ca7b07434f70e1c1f4d3ca7e93ce958b373654d9f"
dependencies = [
"new_debug_unreachable",
"once_cell",
"parking_lot",
"parking_lot 0.12.1",
"phf_shared 0.10.0",
"precomputed-hash",
"serde",
@@ -2962,6 +3306,16 @@ dependencies = [
"quote",
]
[[package]]
name = "stringprep"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ee348cb74b87454fff4b551cbf727025810a004f88aeacae7f85b87f4e9a1c1"
dependencies = [
"unicode-bidi",
"unicode-normalization",
]
[[package]]
name = "strsim"
version = "0.10.0"
@@ -3070,7 +3424,7 @@ dependencies = [
"ndk-sys",
"objc",
"once_cell",
"parking_lot",
"parking_lot 0.12.1",
"paste",
"png",
"raw-window-handle",
@@ -3102,6 +3456,7 @@ checksum = "fe7e0f1d535e7cbbbab43c82be4fc992b84f9156c16c160955617e0260ebc449"
dependencies = [
"anyhow",
"attohttpc",
"base64 0.13.1",
"cocoa",
"dirs-next",
"embed_plist",
@@ -3114,6 +3469,7 @@ dependencies = [
"heck 0.4.1",
"http",
"ignore",
"minisign-verify",
"notify-rust",
"objc",
"once_cell",
@@ -3139,12 +3495,14 @@ dependencies = [
"tauri-utils",
"tempfile",
"thiserror",
"time",
"tokio",
"url",
"uuid 1.3.0",
"webkit2gtk",
"webview2-com",
"windows 0.39.0",
"zip",
]
[[package]]
@@ -3191,13 +3549,14 @@ dependencies = [
[[package]]
name = "tauri-genshin"
version = "0.1.3"
version = "0.1.4"
dependencies = [
"rocket",
"serde",
"serde_json",
"tauri",
"tauri-build",
"tauri-plugin-sql",
]
[[package]]
@@ -3214,6 +3573,22 @@ dependencies = [
"tauri-utils",
]
[[package]]
name = "tauri-plugin-sql"
version = "0.1.0"
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=dev#7acf865ffbb82c6d00334926a4527dd5ff3163a4"
dependencies = [
"futures-core",
"log",
"serde",
"serde_json",
"sqlx",
"tauri",
"thiserror",
"time",
"tokio",
]
[[package]]
name = "tauri-runtime"
version = "0.12.1"
@@ -3425,6 +3800,17 @@ dependencies = [
"syn 1.0.109",
]
[[package]]
name = "tokio-rustls"
version = "0.23.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59"
dependencies = [
"rustls",
"tokio",
"webpki",
]
[[package]]
name = "tokio-stream"
version = "0.1.12"
@@ -3617,6 +4003,18 @@ version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
[[package]]
name = "unicode_categories"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e"
[[package]]
name = "untrusted"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
[[package]]
name = "url"
version = "2.3.1"
@@ -3836,6 +4234,25 @@ dependencies = [
"system-deps 6.0.3",
]
[[package]]
name = "webpki"
version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd"
dependencies = [
"ring",
"untrusted",
]
[[package]]
name = "webpki-roots"
version = "0.22.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6c71e40d7d2c34a5106301fb632274ca37242cd0c9d3e64dbece371a40a2d87"
dependencies = [
"webpki",
]
[[package]]
name = "webview2-com"
version = "0.19.1"
@@ -4271,3 +4688,14 @@ name = "yansi"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec"
[[package]]
name = "zip"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0445d0fbc924bb93539b4316c11afb121ea39296f99a3c4c9edad09e3658cdef"
dependencies = [
"byteorder",
"crc32fast",
"crossbeam-utils",
]

View File

@@ -1,6 +1,6 @@
[package]
name = "tauri-genshin"
version = "0.1.3"
version = "0.1.4"
description = "A Tauri App"
authors = ["BTMuli<bt-muli@outlook.com>"]
license = "MIT"
@@ -14,10 +14,15 @@ tauri-build = { version = "1.2", features = [] }
[dependencies]
rocket = "0.5.0-rc.1"
tauri = { version = "1.2", features = ["api-all"] }
tauri = { version = "1.2", features = ["api-all", "updater"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
[dependencies.tauri-plugin-sql]
git = "https://github.com/tauri-apps/plugins-workspace"
branch = "dev"
features = ["sqlite"]
[features]
# this feature is used for production builds or when `devPath` points to the filesystem
# DO NOT REMOVE!!

View File

@@ -74,6 +74,7 @@ fn read_cookie() -> String {
fn main() {
tauri::Builder::default()
.plugin(tauri_plugin_sql::Builder::default().build())
.invoke_handler(tauri::generate_handler![mys_login, read_cookie])
.setup(|_app| {
tauri::async_runtime::spawn(

View File

@@ -8,7 +8,7 @@
},
"package": {
"productName": "tauri-genshin",
"version": "0.1.3"
"version": "0.1.4"
},
"tauri": {
"allowlist": {
@@ -52,7 +52,7 @@
"active": true,
"dialog": true,
"endpoints": ["https://github.com/BTMuli/Tauri.Genshin/releases/latest/latest.json"],
"pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IEU5OEE2RkU0QUZCMTMzMUEKUldRYU03R3Y1RytLNlI4bytTRDhpYTNTL2lTOUVZeWQwOTAxNHBock8zY3FrdVliR2kvdHhoN2IK"
"pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDg2MkVGRjMxQzJDQzFBNTkKUldSWkdzekNNZjh1aHJGRXBEOGtwbUxLaU1wdWNVeUJaeGhoV2ZlZ3VlYmQ0b2tYZWQwODdnTHkK"
},
"windows": [
{

View File

@@ -33,10 +33,6 @@ import TBackTop from "./components/t-backTop.vue";
import { fs, window, app, event } from "@tauri-apps/api";
// store
import { useAppStore } from "./store/modules/app";
// utils
import { InitTGData, DeleteTGData, WriteTGData } from "./utils/TGIndex";
// data
import { TGAppDataList, TGGetDataList } from "./data";
const appStore = useAppStore();
const isMain = ref(true as boolean);
@@ -72,38 +68,18 @@ async function checkLoad () {
console.info("数据已加载!");
return;
}
DeleteTGData();
await createDataDir();
await writeData();
await writeIndex();
appStore.loading = true;
console.info("数据加载完成!");
}
// 创建数据文件夹
async function createDataDir () {
console.info("开始创建数据文件夹...");
await fs.createDir("appData", { dir: fs.BaseDirectory.AppLocalData, recursive: true });
await fs.createDir("userData", { dir: fs.BaseDirectory.AppLocalData, recursive: true });
await fs.createDir("tempData", { dir: fs.BaseDirectory.AppLocalData, recursive: true });
// 如果不存在则创建
if (!await fs.exists("userData", { dir: fs.BaseDirectory.AppLocalData })) { await fs.createDir("userData", { dir: fs.BaseDirectory.AppLocalData, recursive: true }); }
if (!await fs.exists("tempData", { dir: fs.BaseDirectory.AppLocalData })) { await fs.createDir("tempData", { dir: fs.BaseDirectory.AppLocalData, recursive: true }); }
console.info("数据文件夹创建完成!");
}
// 将数据写入文件夹
async function writeData () {
console.info("开始写入数据...");
TGAppDataList.map(async (item) => {
await fs.writeFile(`${appStore.dataPath.appDataDir}\\${item.name}`, JSON.stringify(item.data));
});
console.info("数据写入完成!");
}
// 写入 IndexedDB
async function writeIndex () {
console.info("开始写入 IndexedDB...");
await InitTGData();
TGGetDataList.map(async (item) => {
await WriteTGData(item.name, item.data);
});
console.info("IndexedDB 写入完成!");
}
</script>
<style lang="css">
.app-main {

View File

@@ -2,24 +2,30 @@
@import url("themes/default.css");
@import url("themes/dark.css");
/*
* @description 让滚动条在内侧显示
* @since Alpha v0.1.0
*/
html {
overflow: overlay;
}
/*
* @description 侧边滚动条样式
* @since Alpha v0.1.3
*/
::-webkit-scrollbar {
width: 10px;
height: 10px;
border-radius: 10px;
width: 8px;
border-radius: 5px;
}
::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 10px;
background: var(--scroll-bg);
border-radius: 5px;
}
::-webkit-scrollbar-thumb {
background: #888;
border-radius: 10px;
background: #96979A;
border-radius: 5px;
}
::-webkit-scrollbar-thumb:hover {

View File

@@ -2,7 +2,7 @@
* @file assets themes light.css
* @description 主题样式文件
* @author BTMuli<bt-muli@outlook.com>
* @since Alpha v0.1.3
* @since Alpha v0.1.4
*/
/* 主题色 */
@@ -10,6 +10,8 @@ html.dark {
--sidebar-bg: #1e1e1e;
--sidebar-icon: #e1e1e1;
--page-bg:#2a2a2a;
--scroll-bg: #ECE5D8;
--calendar-btn-bg: #1e1e1e;
--back-top-shadow: #000000;
--theme-switch-icon: #e1e1e1;
--post-default-text: #faf7e8;
@@ -22,7 +24,7 @@ html.dark {
--content-text-3: #e1e1e1;
--btn-bg-1: #3b3d3b;
--btn-bg-2: #000000;
--btn-bg-2: #e1e1e1;
--btn-bg-3: #1e1e1e;
--btn-text-1: #393b40;

View File

@@ -2,7 +2,7 @@
* @file assets themes dark.css
* @description 主题样式文件
* @author BTMuli<bt-muli@outlook.com>
* @since Alpha v0.1.3
* @since Alpha v0.1.4
*/
/* 主题色 */
@@ -10,6 +10,8 @@ html.default {
--sidebar-bg: #485466;
--sidebar-icon: #ece5d8;
--page-bg:#ece5d8;
--scroll-bg: #2A2A2A;
--calendar-btn-bg: #393b40;
--back-top-shadow: #546d8b;
--theme-switch-icon: #393b40;
--post-default-text: #1e1e1e;

View File

@@ -51,8 +51,8 @@ onMounted(() => {
<style scoped>
.back-top {
position: fixed;
right: 0.4rem;
bottom: 1rem;
right: 20px;
bottom: 20px;
width: 60px;
height: 60px;
border-radius: 50%;

View File

@@ -12,8 +12,9 @@
class="calendar-btn"
:style="{
border: text.week === weekNow ? '2px solid var(--btn-bg-1)' : '0',
background: text.week === btnNow ? 'var(--btn-bg-1)' : 'var(--btn-bg-2)',
color: '#faf7e8'
background: text.week === btnNow ? 'var(--btn-bg-1)' : 'var(--calendar-btn-bg)',
color: '#faf7e8',
marginBottom: '1px'
}"
@click="getContents(text.week)"
>
@@ -102,7 +103,6 @@
<div
v-for="item of weapon.contents"
:key="item.id"
alt="content.content_id"
class="card-box"
@click="showContent(item)"
>
@@ -138,7 +138,7 @@
// vue
import { ref, onMounted } from "vue";
// data
import { TGAppData } from "../data/index";
import { TGAppData } from "../data";
// interface
import { OBC_CONTENT_API } from "../plugins/Mys/interface/utils";
import { createTGWindow } from "../utils/TGWindow";

View File

@@ -5,6 +5,9 @@
<div class="confirm-title">
{{ title }}
</div>
<div v-show="subtitle!==''" class="confirm-subtitle">
{{ subtitle }}
</div>
<div class="confirm-btn-box">
<button class="confirm-btn" @click="onCancel">
<img class="btn-icon" src="../assets/icons/circle-cancel.svg" alt="cancel">
@@ -30,6 +33,7 @@ import { computed } from "vue";
interface TConfirmProps {
title: string;
subtitle?: string;
cancel?: string;
confirm?: string;
/** 此值为 true 时显示对话框 */
@@ -46,6 +50,7 @@ interface TConfirmEmits {
const emits = defineEmits<TConfirmEmits>();
const props = withDefaults(defineProps<TConfirmProps>(), {
title: "确认",
subtitle: "",
cancel: "取消",
confirm: "确定",
});
@@ -93,12 +98,24 @@ const onConfirm = () => {
height: 20%;
width: 100%;
color: var(--content-text-2);
margin: 20px;
margin: 10px;
font-size: 30px;
}
.confirm-subtitle {
border-top: 1px solid var(--btn-bg-2);
font-family: Genshin-Light, serif;
text-align: center;
height: 20%;
width: 100%;
color: var(--content-text-2);
font-size: 20px;
}
.confirm-btn-box {
height: 60%;
position: absolute;
bottom: 0;
height: 40%;
width: 100%;
display: flex;
justify-content: space-around;

View File

@@ -14,9 +14,9 @@
<v-list style="background: var(--content-bg-2); color: #546d8b">
<v-list-item :title="pool.title" :subtitle="pool.subtitle">
<template #prepend>
<v-img :src="pool.voice.icon" style="transform: translate(0, -10px); width: 60px; height: 60px" />
<v-img :src="pool.voice.icon" class="pool-sideIcon" />
</template>
<template #append>
<template v-if="pool.voice.url" #append>
<audio :src="pool.voice.url" controls />
</template>
</v-list-item>
@@ -29,7 +29,7 @@
<img :src="character.icon" class="pool-icon" alt="character">
</div>
<div class="pool-clock">
<v-progress-circular :model-value="poolTimePass[pool.post_id]" size="100" width="10" :color="poolColor">
<v-progress-circular :model-value="poolTimePass[pool.post_id]" size="100" width="10" :color="poolColor[pool.post_id]">
{{ poolTimeGet[pool.post_id] }}
</v-progress-circular>
</div>
@@ -47,8 +47,10 @@
</template>
<script lang="ts" setup>
// vue
import { ref, onMounted, onUpdated } from "vue";
import { ref, onMounted, onUnmounted } from "vue";
import { useRouter } from "vue-router";
// tauri
import { dialog } from "@tauri-apps/api";
// store
import { useHomeStore } from "../store/modules/home";
// utils
@@ -71,37 +73,38 @@ const loading = ref(true as boolean);
const poolCards = ref([] as GachaCard[]);
const poolTimeGet = ref({} as Record<number, string>);
const poolTimePass = ref({} as Record<number, number>);
const poolColor = ref("#90caf9" as string);
const timer = ref(null as any);
const poolColor = ref({} as Record<number, string>);
const timer = ref({} as Record<number, any>);
// expose
defineExpose({
name: "限时祈愿",
loading,
});
function poolLastInterval () {
poolCards.value.map((pool) => {
poolTimeGet.value[pool.post_id] = getLastPoolTime(pool.time.end_stamp - Date.now());
poolTimePass.value[pool.post_id] =
function poolLastInterval (postId: number) {
const pool = poolCards.value.find((pool) => pool.post_id === postId);
if (!pool) return;
if (poolTimeGet.value[postId] === "未开始") {
const isStart = pool.time.start_stamp - Date.now();
if (isStart > 0) return;
poolTimeGet.value[postId] = getLastPoolTime(pool.time.end_stamp - Date.now());
poolTimePass.value[postId] = pool.time.end_stamp - Date.now();
poolColor.value[postId] = "#90caf9";
} else {
const isEnd = pool.time.end_stamp - Date.now();
poolTimeGet.value[postId] = getLastPoolTime(isEnd);
poolTimePass.value[postId] =
((pool.time.end_stamp - Date.now()) / (pool.time.end_stamp - pool.time.start_stamp)) * 100;
return pool;
});
if (isEnd >= 0) return;
clearInterval(timer.value[postId]);
timer.value[postId] = null;
poolTimePass.value[postId] = 100;
poolTimeGet.value[postId] = "已结束";
poolColor.value[postId] = "#f44336";
}
return pool;
}
// 监听 poolTimePass
onUpdated(() => {
poolCards.value.map((pool) => {
if (poolTimePass.value[pool.post_id] <= 0) {
clearInterval(timer.value);
timer.value = null;
poolTimeGet.value[pool.post_id] = "已结束";
poolTimePass.value[pool.post_id] = 100;
poolColor.value = "#f44336";
}
return pool;
});
});
onMounted(async () => {
const gachaData = await MysOper.Gacha.get();
if (!gachaData) {
@@ -122,11 +125,22 @@ onMounted(async () => {
poolCards.value.map((pool) => {
poolTimeGet.value[pool.post_id] = getLastPoolTime(pool.time.end_stamp - Date.now());
poolTimePass.value[pool.post_id] = pool.time.end_stamp - Date.now();
if (poolTimePass.value[pool.post_id] <= 0) {
poolTimeGet.value[pool.post_id] = "已结束";
poolTimePass.value[pool.post_id] = 100;
poolColor.value[pool.post_id] = "#f44336";
} else if (pool.time.start_stamp - Date.now() > 0) {
poolTimeGet.value[pool.post_id] = "未开始";
poolTimePass.value[pool.post_id] = 100;
poolColor.value[pool.post_id] = "#32A9CA";
} else {
poolColor.value[pool.post_id] = "#90caf9";
}
timer.value[pool.post_id] = setInterval(() => {
poolLastInterval(pool.post_id);
}, 1000);
return pool;
});
timer.value = setInterval(() => {
poolLastInterval();
}, 1000);
loading.value = false;
});
@@ -155,8 +169,15 @@ function checkCover (data: GachaData[]) {
});
}
function toOuter (url: string, title: string) {
createTGWindow(url, "祈愿", title, 1200, 800, true, false);
async function toOuter (url: string, title: string) {
if (!url) {
await dialog.message("该角色池暂无详情", {
title,
type: "error",
});
return;
}
createTGWindow(url, "祈愿", title, 1200, 800, true, true);
}
function getLastPoolTime (time: number) {
@@ -176,6 +197,12 @@ function toPost (pool: GachaCard) {
}).href;
createTGWindow(path, "限时祈愿", pool.title, 960, 720, false, false);
}
onUnmounted(() => {
Object.keys(timer.value).forEach((key) => {
clearInterval(timer.value[Number(key)]);
});
});
</script>
<style lang="css" scoped>
@@ -200,6 +227,20 @@ function toPost (pool: GachaCard) {
margin-top: 10px;
}
.pool-sideIcon {
margin-top: 10px;
transform: translate(0, -10px);
width: 40px;
height: 40px;
border-radius: 50%;
}
.pool-sideIcon img {
width: 100%;
height: 100%;
border-radius: 50%;
}
.pool-cover {
margin: 0 20px 10px;
width: calc(100% - 40px);

View File

@@ -83,7 +83,7 @@ onMounted(async () => {
positionTimeGet.value[card.post_id] = getLastPositionTime(card.time.end_stamp - Date.now());
positionTimeEnd.value[card.post_id] = card.time.end_stamp;
});
await setInterval(() => {
setInterval(() => {
positionCards.value.forEach((card) => {
const time = card.time.end_stamp - Date.now();
if (time <= 0) {

View File

@@ -2,7 +2,7 @@
<v-navigation-drawer permanent :rail="rail" style="background: var(--sidebar-bg); color: #faf7e8">
<v-list v-model:opened="open" class="side-list" density="compact" nav>
<!-- 负责收缩侧边栏 -->
<v-list-item @click="collapse">
<v-list-item @click="collapse()">
<template v-if="rail" #prepend>
<v-list-item-action>
<v-icon style="color:var(--sidebar-icon)">
@@ -120,7 +120,7 @@
<img :src="userInfo.avatar" alt="userIcon" class="side-icon">
</template>
</v-list-item> -->
<v-list-item :title="themeTitle" value="theme" @click="switchTheme">
<v-list-item :title="themeTitle" value="theme" @click="switchTheme()">
<template #prepend>
<v-icon style="color:var(--sidebar-icon)">
{{ themeGet === 'default' ? 'mdi-weather-night' : 'mdi-weather-sunny' }}

View File

@@ -1,507 +1,330 @@
{
"0": {
[
{
"id": 0,
"order": 1,
"name": "天地万象",
"version": "3.6",
"achievements": [
80091, 80127, 80128, 80129, 80142, 80143, 80144, 81000, 81001, 81002, 81003, 81004, 81005, 81010, 81014, 81015,
81016, 81017, 81018, 81019, 81020, 81021, 81022, 81023, 81024, 81025, 80092, 81026, 81027, 81028, 81029, 81030,
81031, 81032, 81033, 81034, 81035, 81036, 81037, 81038, 81039, 81040, 81041, 81042, 81043, 81044, 81045, 81046,
81047, 81048, 81074, 81075, 81076, 81077, 81078, 81096, 81097, 81098, 81099, 81100, 81104, 81105, 81106, 81108,
81109, 81111, 81112, 81113, 81114, 81115, 81116, 81117, 81118, 81119, 81120, 81121, 81122, 81123, 81124, 81125,
81130, 81141, 81142, 81150, 81151, 81152, 81153, 81154, 81155, 81156, 81157, 81158, 81159, 81160, 81161, 81162,
81163, 81164, 81165, 81167, 81168, 81170, 81171, 81172, 81173, 81174, 81175, 81176, 81177, 81179, 81180, 81181,
81182, 81183, 81184, 81185, 81186, 81187, 81188, 81189, 81191, 81192, 81193, 81194, 81195, 81196, 81197, 81198,
81199, 81200, 81201, 81202, 81203, 81204, 81205, 81206, 81207, 81208, 81209, 81210, 81211, 81212, 81213, 81214,
81215, 81216, 81217, 81218, 81220, 81221, 81222, 81223, 81224, 81225, 81226, 81227, 81228, 81229, 81230, 81231,
81232, 81233, 81234, 81235, 81236, 81237, 81238, 81239, 81240, 81241, 81242, 81243, 81244, 81245, 81246, 81247,
81248, 81249, 81250, 81251, 81252, 81253, 81254, 81255, 81256, 81257, 81258, 81259, 81260, 81261, 81262, 81263,
81264, 81265, 81266, 81267, 81268, 81269, 81270, 81271, 81272, 81273, 81274, 81275, 81276, 81277, 81278, 81280,
81281, 81282, 81283, 81284, 81285, 81286, 81288, 81289, 81290, 81291, 81292, 81293, 81295, 81296, 81297, 81298,
81299, 81300, 81301, 81302, 81303, 81304, 81306, 81307, 81308, 81309, 81310, 81311, 81312, 81313, 82008, 82009,
82010, 82012, 82013, 82014, 82015, 82017, 82040, 82041, 82042, 82043, 82052, 82063, 82064, 82065, 82074, 82075,
82076, 82077, 82078, 82079, 82080, 82081, 82082, 82083, 82084, 82085, 82086, 82087, 82088, 82089, 82090, 82099,
82100, 82101, 82102, 82103, 82104, 82105, 82106, 82107, 82108, 82110, 82111, 82112, 82113, 82114, 82121, 82122,
82123, 82124, 82125, 82127, 82129, 82130, 82131, 82132, 82133, 82142, 82143, 82144, 82145, 82155, 82156, 82157,
82158, 82160, 84000, 84001, 84002, 84003, 84004, 84005, 84006, 84007, 84008, 84009, 84010, 84011, 84012, 84013,
84014, 84015, 84016, 84017, 84018, 84019, 84020, 84021, 84022, 84023, 84024, 84025, 84029, 84030, 84031, 84032,
84033, 84034, 84035, 84036, 84037, 84038, 84039, 84040, 84041, 84042, 84043, 84044, 84045, 84046, 84047, 84048,
84049, 84050, 84051, 84052, 84053, 84056, 84057, 84058, 84059, 84060, 84061, 84062, 84063, 84064, 84065, 84066,
84067, 84068, 84069, 84070, 84071, 84072, 84073, 84074, 84075, 84076, 84077, 84078, 84079, 84080, 84081, 84082,
84083, 84084, 84085, 84086, 84087, 84088, 84089, 84090, 84091, 84092, 84093, 84094, 84095, 84508, 84509, 84510,
84512, 84513, 84514, 84515, 84516, 84518, 84519, 84520, 84522, 84523, 84524, 84525, 84526, 84527, 84528, 84529,
84530, 84531, 84532, 84533, 84534, 84535, 84536, 84537, 84538, 84539, 84540, 84541, 84542, 84054, 84055, 84543,
84544, 84545, 84546, 84547, 84548, 84549, 84550, 84551, 84552, 84553, 84554, 84555, 84556, 84557, 84558, 84559,
84560, 84561, 84562, 84563, 84564, 84565, 85000, 85001, 85002, 85003, 85004, 85005, 85006, 81314, 81315, 81316,
81317, 81318, 81319, 81320, 81321, 81322, 81323, 81324, 81325, 81326, 81327, 81328, 81329, 81339, 81331, 81332,
81333, 81334, 81335, 81336, 81337, 81338, 82168
],
"total_count": 487,
"completed_count": 0,
"version": 3.6,
"card": "",
"icon": "/source/achievementSeries/0.webp"
},
"1": {
{
"id": 1,
"order": 3,
"name": "尘世巡游·第一辑",
"version": "1.0",
"achievements": [80001, 80002, 80003, 80004, 80005, 80006],
"total_count": 6,
"completed_count": 0,
"card": "成就·游遍",
"icon": "/source/achievementSeries/1.webp"
},
"2": {
{
"id": 2,
"order": 6,
"name": "冒险手艺",
"version": "1.0",
"achievements": [80007, 80008, 80009, 80010, 80011, 80012, 80013],
"total_count": 7,
"completed_count": 0,
"card": "成就·殊技",
"icon": "/source/achievementSeries/2.webp"
},
"3": {
{
"id": 3,
"order": 7,
"name": "英雄之旅",
"version": "1.0",
"achievements": [
80014, 80015, 80016, 80017, 80018, 80019, 80020, 80021, 80022, 80023, 80024, 80025, 80026, 80027, 80028, 80029
],
"total_count": 16,
"completed_count": 0,
"card": "成就·侠行",
"icon": "/source/achievementSeries/3.webp"
},
"4": {
{
"id": 4,
"order": 8,
"name": "蒙德·风与牧歌的城邦",
"version": "1.0",
"achievements": [80030, 80031, 80032, 80033, 80034, 80035, 80036, 80037, 80038, 80039, 80040, 80041, 80042],
"total_count": 13,
"completed_count": 0,
"card": "蒙德·风吟",
"icon": "/source/achievementSeries/4.webp"
},
"5": {
{
"id": 5,
"order": 9,
"name": "璃月·岩与契约的海港",
"version": "1.0",
"achievements": [80043, 80044, 80045, 80046, 80047, 80048, 80049, 80050, 80051, 80052, 80053, 80054, 80055],
"total_count": 13,
"completed_count": 0,
"card": "璃月·岩寂",
"icon": "/source/achievementSeries/5.webp"
},
"6": {
{
"id": 6,
"order": 10,
"name": "元素专家·第一辑",
"version": "1.0",
"achievements": [
82019, 82020, 82021, 82022, 82023, 82024, 82025, 82026, 82027, 82028, 82029, 82030, 82031, 82032, 82033, 82034,
82035, 82036, 82037, 82038, 82039
],
"total_count": 21,
"completed_count": 0,
"card": "成就·虹色",
"icon": "/source/achievementSeries/6.webp"
},
"7": {
{
"id": 7,
"order": 12,
"name": "神射手",
"version": "1.0",
"achievements": [82001, 82002, 82003],
"total_count": 3,
"completed_count": 0,
"card": "成就·强弓",
"icon": "/source/achievementSeries/7.webp"
},
"8": {
{
"id": 8,
"order": 13,
"name": "挑战者·第一辑",
"version": "1.0",
"achievements": [82004, 82005, 82006, 82007],
"total_count": 4,
"completed_count": 0,
"card": "成就·挑战",
"icon": "/source/achievementSeries/8.webp"
},
"9": {
{
"id": 9,
"order": 20,
"name": "秘境与深境螺旋·第一辑",
"version": "1.0",
"achievements": [82044, 82045, 82046, 82047, 82048, 82049, 82050, 82051],
"total_count": 8,
"completed_count": 0,
"card": "成就·深秘",
"icon": "/source/achievementSeries/9.webp"
},
"10": {
{
"id": 10,
"order": 21,
"name": "Olah第一辑",
"version": "1.0",
"achievements": [84501, 84502],
"total_count": 2,
"completed_count": 0,
"card": "成就·山民",
"icon": "/source/achievementSeries/10.webp"
},
"11": {
{
"id": 11,
"order": 22,
"name": "至冬国不相信眼泪·第一辑",
"version": "1.0",
"achievements": [84503, 84504],
"total_count": 2,
"completed_count": 0,
"card": "成就·雪乡",
"icon": "/source/achievementSeries/11.webp"
},
"12": {
{
"id": 12,
"order": 23,
"name": "岩港往事·第一辑",
"version": "1.0",
"achievements": [84505, 84506, 84507],
"total_count": 3,
"completed_count": 0,
"card": "成就·合扇",
"icon": "/source/achievementSeries/12.webp"
},
"13": {
{
"id": 13,
"order": 24,
"name": "异世相逢·第一辑",
"version": "1.0",
"achievements": [86001, 86002, 86003, 86004, 86005, 86006, 86007, 86008, 86009, 86010, 86011, 86012, 86013],
"total_count": 13,
"completed_count": 0,
"card": "成就·相逢",
"icon": "/source/achievementSeries/13.webp"
},
"14": {
{
"id": 14,
"order": 14,
"name": "挑战者·第二辑",
"version": "1.1",
"achievements": [82053, 82054, 82055, 82056, 82057, 82058, 82059, 82060, 82061, 82062],
"total_count": 10,
"completed_count": 0,
"version": 1.1,
"card": "成就·挑战·其二",
"icon": "/source/achievementSeries/14.webp"
},
"15": {
{
"id": 15,
"order": 15,
"name": "挑战者·第三辑",
"version": "1.2",
"achievements": [82066, 82067, 82068, 82069, 82070, 82071, 82072, 82073],
"total_count": 8,
"completed_count": 0,
"version": 1.2,
"card": "成就·挑战·其三",
"icon": "/source/achievementSeries/15.webp"
},
"16": {
{
"id": 16,
"order": 27,
"name": "雪山上的来客",
"version": "1.2",
"achievements": [80056, 80057, 80058, 80059, 80060, 80061, 80062, 80063, 80064, 80065, 80066, 80067, 80068],
"total_count": 13,
"completed_count": 0,
"version": 1.2,
"card": "成就·雪峰",
"icon": "/source/achievementSeries/16.webp"
},
"17": {
{
"id": 17,
"order": 2,
"name": "心跳的记忆",
"version": "3.6",
"achievements": [
84026, 84100, 84101, 84104, 84028, 84107, 84102, 84108, 84105, 84103, 84106, 84109, 84110, 84111, 84112, 84113,
84114, 84115, 84116, 84117, 84118, 84119, 84120, 84121, 84122, 84123, 84124, 84125, 84126, 84127, 84128, 84129,
84130, 84131, 84132, 84133, 84134, 84135, 84136, 84137, 84138, 84139, 84140, 84141, 84142, 84143, 84144, 84145
],
"total_count": 48,
"completed_count": 0,
"version": 3.6,
"card": "",
"icon": "/source/achievementSeries/17.webp"
},
"18": {
{
"id": 18,
"order": 28,
"name": "世外洞天·第一辑",
"version": "1.5",
"achievements": [
81049, 81050, 81051, 81052, 81053, 81054, 81055, 81056, 81057, 81058, 81059, 81060, 81061, 81062, 81063, 81064,
81065, 81066, 81067, 81068, 81069, 81070, 81071, 81072, 81073
],
"total_count": 25,
"completed_count": 0,
"version": 1.5,
"card": "成就·壶歌",
"icon": "/source/achievementSeries/18.webp"
},
"19": {
{
"id": 19,
"order": 29,
"name": "世外洞天·第二辑",
"version": "1.6",
"achievements": [81079, 81080, 81081, 81082, 81083, 81084, 81085],
"total_count": 7,
"completed_count": 0,
"version": 1.6,
"card": "成就·旅居",
"icon": "/source/achievementSeries/19.webp"
},
"20": {
{
"id": 20,
"order": 16,
"name": "挑战者·第四辑",
"version": "2.0",
"achievements": [82091, 82092, 82093, 82094, 82095, 82096, 82097, 82098, 82109],
"total_count": 9,
"completed_count": 0,
"card": "成就·石龙",
"icon": "/source/achievementSeries/20.webp"
},
"21": {
{
"id": 21,
"order": 25,
"name": "异世相逢·第二辑",
"version": "2.1",
"achievements": [86021, 86015, 86016, 86017, 86018, 86019, 86020],
"total_count": 7,
"completed_count": 0,
"version": 2.1,
"card": "成就·门扉",
"icon": "/source/achievementSeries/21.webp"
},
"22": {
{
"id": 22,
"order": 4,
"name": "尘世巡游·第二辑",
"version": "2.0",
"achievements": [80069, 80070, 80071, 80072, 80073],
"total_count": 5,
"completed_count": 0,
"card": "成就·遍历",
"icon": "/source/achievementSeries/22.webp"
},
"23": {
{
"id": 23,
"order": 30,
"name": "世外洞天·第三辑",
"version": "2.0",
"achievements": [81086, 81087, 81088, 81089, 81090, 81091, 81092, 81093, 81094, 81095],
"total_count": 10,
"completed_count": 0,
"card": "成就·繁花",
"icon": "/source/achievementSeries/23.webp"
},
"24": {
{
"id": 24,
"order": 31,
"name": "稻妻·雷与永恒的群岛·其之一",
"version": "2.0",
"achievements": [
80074, 80075, 80076, 80077, 80078, 80079, 80080, 80081, 80082, 80083, 80084, 80085, 80086, 80087, 80088, 80089,
80090, 80093, 80094, 80095
],
"total_count": 20,
"completed_count": 0,
"card": "稻妻·九条之纹",
"icon": "/source/achievementSeries/24.webp"
},
"25": {
{
"id": 25,
"order": 34,
"name": "提瓦特钓鱼指南·第一辑",
"version": "2.1",
"achievements": [81131, 81132, 81133, 81134, 81135, 81136, 81137, 81138, 81139, 81140, 81143, 81144],
"total_count": 12,
"completed_count": 0,
"version": 2.1,
"card": "成就·敲针",
"icon": "/source/achievementSeries/25.webp"
},
"26": {
{
"id": 26,
"order": 32,
"name": "稻妻·雷与永恒的群岛·其之二",
"version": "2.1",
"achievements": [
80096, 80097, 80098, 80099, 80100, 80101, 80102, 80105, 80106, 80107, 80110, 80111, 80112, 80108, 80109
],
"total_count": 15,
"completed_count": 0,
"version": 2.1,
"card": "稻妻·珊瑚宫之纹",
"icon": "/source/achievementSeries/26.webp"
},
"27": {
{
"id": 27,
"order": 33,
"name": "雾海纪行",
"version": "2.2",
"achievements": [80113, 80114, 80115, 80116, 80119, 80120, 80121, 80122, 80123, 80124, 80125, 80126],
"total_count": 12,
"completed_count": 0,
"version": 2.2,
"card": "稻妻·鹫羽",
"icon": "/source/achievementSeries/27.webp"
},
"28": {
{
"id": 28,
"order": 35,
"name": "白昼之光",
"version": "2.4",
"achievements": [80130, 80131, 80132, 80133, 80134, 80135, 80136, 80137, 80138, 80139, 80140, 80141],
"total_count": 12,
"completed_count": 0,
"version": 2.4,
"card": "稻妻·常世",
"icon": "/source/achievementSeries/28.webp"
},
"29": {
{
"id": 29,
"order": 17,
"name": "挑战者·第五辑",
"version": "2.6",
"achievements": [82115, 82116, 82117, 82118, 82119, 82120, 82126, 82128],
"total_count": 8,
"completed_count": 0,
"version": 2.6,
"card": "成就·雷音",
"icon": "/source/achievementSeries/29.webp"
},
"30": {
{
"id": 30,
"order": 36,
"name": "岩窟流明",
"version": "2.6",
"achievements": [
80145, 80146, 80147, 80148, 80149, 80150, 80151, 80152, 80153, 80154, 80155, 80156, 80157, 80158, 80159
],
"total_count": 15,
"completed_count": 0,
"version": 2.6,
"card": "成就·层岩",
"icon": "/source/achievementSeries/30.webp"
},
"31": {
{
"id": 31,
"order": 37,
"name": "须弥·玄识深藏的雨林",
"version": "3.0",
"achievements": [
80160, 80161, 80162, 80163, 80164, 80165, 80166, 80167, 80168, 80169, 80170, 80171, 80172, 80173, 80174
],
"total_count": 15,
"completed_count": 0,
"card": "须弥·瑶林",
"icon": "/source/achievementSeries/31.webp"
},
"32": {
{
"id": 32,
"order": 5,
"name": "尘世巡游·第三辑",
"version": "3.0",
"achievements": [80175, 80176, 80177, 80178],
"total_count": 4,
"completed_count": 0,
"card": "成就·漫行",
"icon": "/source/achievementSeries/32.webp"
},
"33": {
{
"id": 33,
"order": 26,
"name": "异世相逢·第三辑",
"version": "3.0",
"achievements": [86022, 86023, 86024, 86025, 86026, 86027, 86028, 86029],
"total_count": 8,
"completed_count": 0,
"card": "成就·逢缘",
"icon": "/source/achievementSeries/33.webp"
},
"34": {
{
"id": 34,
"order": 18,
"name": "挑战者·第六辑",
"version": "3.1",
"achievements": [82134, 82135, 82136, 82137, 82138, 82139, 82140, 82141],
"total_count": 8,
"completed_count": 0,
"version": 3.1,
"card": "成就·镜梦",
"icon": "/source/achievementSeries/34.webp"
},
"35": {
{
"id": 35,
"order": 38,
"name": "须弥·饰金砂原·其之一",
"version": "3.1",
"achievements": [80179, 80180, 80181, 80182, 80183, 80184, 80185, 80186, 80187, 80188, 80189, 80190, 80191],
"total_count": 13,
"completed_count": 0,
"version": 3.1,
"card": "须弥·踏沙",
"icon": "/source/achievementSeries/35.webp"
},
"36": {
{
"id": 36,
"order": 11,
"name": "元素专家·第二辑",
"version": "3.1",
"achievements": [82146, 82147, 82148, 82149, 82150, 82151, 82159],
"total_count": 7,
"completed_count": 0,
"version": 3.1,
"card": "成就·七芒",
"icon": "/source/achievementSeries/36.webp"
},
"37": {
{
"id": 37,
"order": 40,
"name": "七圣召唤",
"version": "3.3",
"achievements": [
80192, 80193, 80197, 80198, 80199, 80203, 80204, 80205, 80206, 80207, 80208, 80209, 80210, 80211, 80212, 80213,
80214, 80215, 80216, 80217, 80218, 80219, 80220, 80221, 80222, 80223
],
"total_count": 26,
"completed_count": 0,
"version": 3.3,
"card": "成就·七圣",
"icon": "/source/achievementSeries/37.webp"
},
"38": {
{
"id": 38,
"order": 39,
"name": "须弥·饰金砂原·其之二",
"version": "3.4",
"achievements": [80224, 80225, 80226, 80228, 80229, 80230, 80231, 80232, 80233, 80234, 80235, 80236, 80227],
"total_count": 13,
"completed_count": 0,
"version": 3.4,
"card": "须弥·砂岚",
"icon": "/source/achievementSeries/38.webp"
},
"39": {
{
"id": 39,
"order": 19,
"name": "挑战者·第七辑",
"version": "3.6",
"achievements": [82161, 82162, 82163, 82164, 82165, 82166, 82167, 82169],
"total_count": 8,
"completed_count": 0,
"version": 3.6,
"card": "成就·槿暮",
"icon": "/source/achievementSeries/39.webp"
},
"41": {
{
"id": 41,
"order": 41,
"name": "佑灵砾漠",
"version": "3.6",
"achievements": [80237, 80238, 80239, 80240, 80241, 80242, 80243, 80244, 80245, 80246, 80247, 80248, 80250, 80249],
"total_count": 14,
"completed_count": 0,
"version": 3.6,
"card": "成就·万种",
"icon": "/source/achievementSeries/41.webp"
}
}
]

File diff suppressed because it is too large Load Diff

View File

@@ -413,7 +413,7 @@
},
{
"id": 10000082,
"content_id": null,
"content_id": 6489,
"name": "白术",
"star": 5,
"bg": "/icon/bg/5-Star.webp",
@@ -885,7 +885,7 @@
},
{
"id": 10000081,
"content_id": null,
"content_id": 6490,
"name": "卡维",
"star": 4,
"bg": "/icon/bg/4-Star.webp",
@@ -3367,7 +3367,7 @@
},
{
"id": 10000081,
"content_id": null,
"content_id": 6490,
"name": "卡维",
"star": 4,
"bg": "/icon/bg/4-Star.webp",
@@ -3988,7 +3988,7 @@
},
{
"id": 10000082,
"content_id": null,
"content_id": 6489,
"name": "白术",
"star": 5,
"bg": "/icon/bg/5-Star.webp",

View File

@@ -1,7 +1,7 @@
[
{
"id": 10000082,
"content_id": null,
"content_id": 6489,
"name": "白术",
"star": 5,
"bg": "/icon/bg/5-Star.webp",
@@ -331,7 +331,7 @@
},
{
"id": 10000081,
"content_id": null,
"content_id": 6490,
"name": "卡维",
"star": 4,
"bg": "/icon/bg/4-Star.webp",

View File

@@ -2,7 +2,7 @@
* @file data app index
* @description data app index
* @author BTMuli<bt-muli@outlook.com>
* @since Alpha v0.1.3
* @since Alpha v0.1.4
*/
// Data
@@ -17,11 +17,11 @@ import weapon from "./weapon.json";
export const AppDataList = [
{
name: "achievements.json",
data: achievements as Record<number, BTMuli.Genshin.Achievement>,
data: achievements as BTMuli.Genshin.Achievement[],
},
{
name: "achievementSeries.json",
data: achievementSeries as Record<number, BTMuli.Genshin.AchievementSeries>,
data: achievementSeries as BTMuli.Genshin.AchievementSeries[],
},
{
name: "calendar.json",
@@ -37,7 +37,7 @@ export const AppDataList = [
},
{
name: "nameCards.json",
data: nameCards as Record<number, BTMuli.Genshin.NameCard[]>,
data: nameCards as BTMuli.Genshin.NameCard[],
},
{
name: "weapon.json",
@@ -46,11 +46,11 @@ export const AppDataList = [
];
export const AppData = {
achievements: achievements as Record<number, BTMuli.Genshin.Achievement>,
achievementSeries: achievementSeries as Record<number, BTMuli.Genshin.AchievementSeries>,
achievements: achievements as BTMuli.Genshin.Achievement[],
achievementSeries: achievementSeries as BTMuli.Genshin.AchievementSeries[],
calendar: calendar as Record<number, BTMuli.Genshin.Calendar.Data>,
character: character as BTMuli.Genshin.Wiki.Character.BriefInfo[],
GCG: GCG as BTMuli.Genshin.Wiki.GCG.BriefInfo[],
nameCards: nameCards as Record<number, BTMuli.Genshin.NameCard[]>,
nameCards: nameCards as BTMuli.Genshin.NameCard[],
weapon: weapon as BTMuli.Genshin.Wiki.Weapon.BriefInfo[],
};

File diff suppressed because it is too large Load Diff

View File

@@ -332,15 +332,6 @@
"type": "/icon/weapon/单手剑.webp",
"icon": "/WIKI/weapon/icon/11501.webp"
},
{
"id": 15419,
"content_id": null,
"name": "鹮穿之喙",
"star": 4,
"bg": "/icon/bg/4-Star.webp",
"type": "/icon/weapon/弓.webp",
"icon": "/WIKI/weapon/icon/15419.webp"
},
{
"id": 15418,
"content_id": 4437,

View File

@@ -2,13 +2,9 @@
* @file data index
* @description data index
* @author BTMuli<bt-muli@outlook.com>
* @since Alpha
* @since Alpha v0.1.4
*/
import { AppData, AppDataList } from "./app";
import { ConfigList, getDataList } from "./init";
import { AppData } from "./app";
export const TGAppData = AppData;
export const TGAppDataList = AppDataList;
export const TGConfigList = ConfigList;
export const TGGetDataList = getDataList;

View File

@@ -1,30 +0,0 @@
/**
* @file data init achievementSeries
* @description data init achievementSeries
* @author BTMuli<bt-muli@outlook.com>
* @since Alpha v0.1.2
*/
import { AppData } from "../app";
/**
* @description 成就系列表参数
* @since Alpha v0.1.2
* @returns {BTMuli.Genshin.Base.DBConfig}
*/
export const Config: BTMuli.Genshin.Base.DBConfig = {
storeName: "AchievementSeries",
keyPath: "id",
indexes: ["order", "name", "card"],
};
/**
* @description 成就系列数据
* @since Alpha v0.1.2
* @return {BTMuli.Genshin.AchievementSeries[]}
*/
export function getData (): BTMuli.Genshin.AchievementSeries[] {
const data: Record<number, BTMuli.Genshin.AchievementSeries> = AppData.achievementSeries;
return Object.keys(data).map((key) => {
return data[Number(key)];
});
}

View File

@@ -1,30 +0,0 @@
/**
* @file data init achievement
* @description data init achievement
* @author BTMuli<bt-muli@outlook.com>
* @since Alpha v0.1.2
*/
import { AppData } from "../app";
/**
* @description 成就表参数
* @since Alpha v0.1.2
* @returns {BTMuli.Genshin.Base.DBConfig}
*/
export const Config: BTMuli.Genshin.Base.DBConfig = {
storeName: "Achievements",
keyPath: "id",
indexes: ["name", "description", "series", "order", "reward", "version"],
};
/**
* @description 成就数据
* @since Alpha v0.1.2
* @return {BTMuli.Genshin.Achievement[]}
*/
export function getData (): BTMuli.Genshin.Achievement[] {
const data: Record<number, BTMuli.Genshin.Achievement> = AppData.achievements;
return Object.keys(data).map((key) => {
return data[Number(key)];
});
}

View File

@@ -1,21 +0,0 @@
/**
* @file data init index
* @description data init index
* @author BTMuli<bt-muli@outlook.com>
* @since Alpha v0.1.3
*/
import { Config as AchievementsConfig, getData as getAchievementsData } from "./achievements";
import { Config as SeriesConfig, getData as getSeriesData } from "./achievementSeries";
export const ConfigList = [AchievementsConfig, SeriesConfig];
export const getDataList = [
{
name: "Achievements",
data: getAchievementsData(),
},
{
name: "AchievementSeries",
data: getSeriesData(),
},
];

View File

@@ -28,7 +28,7 @@
<div v-show="!loading" class="wrap">
<!-- 左侧菜单 -->
<div class="left-wrap">
<v-list v-for="(series, index) in seriesList" :key="series.id" class="card-left" @click="selectSeries(index)">
<v-list v-for="series in seriesList" :key="series.id" class="card-left" @click="selectSeries(series.id)">
<div class="version-icon-series">
v{{ series.version }}
</div>
@@ -39,14 +39,14 @@
<v-list-item-title>
{{ series.name }}
</v-list-item-title>
<v-list-item-subtitle> {{ series.completed_count }} / {{ series.total_count }} </v-list-item-subtitle>
<v-list-item-subtitle> {{ series.finCount }} / {{ series.totalCount }} </v-list-item-subtitle>
</v-list-item>
</v-list>
</div>
<!-- 右侧内容-->
<div class="right-wrap">
<div class="right-wrap" @scroll="handleScroll">
<v-list
v-if="selectedIndex !== -1 && selectedSeries !== 0 && selectedSeries !== 17"
v-if="selectedSeries !== 0 && selectedSeries !== 17 && selectedSeries !== -1"
:style="{
backgroundImage: 'url(' + getCardInfo.bg || null + ')',
backgroundPosition: 'right',
@@ -57,6 +57,7 @@
color: '#485466',
fontFamily: 'Genshin,serif',
cursor: 'pointer',
position: 'relative',
}"
@click="openImg()"
>
@@ -66,33 +67,38 @@
</template>
</v-list-item>
</v-list>
<v-list v-for="achievement in selectedAchievement" :key="achievement.id" class="card-right">
<div v-if="achievement.progress !== 0" class="achievement-progress">
{{ achievement.progress }}
</div>
<v-list-item>
<template #prepend>
<v-icon :color="achievement.completed ? '#fec90b' : '#485466'">
<!-- todo 图标替换 -->
{{ achievement.completed ? "mdi-check-circle" : "mdi-circle" }}
</v-icon>
</template>
<v-list-item-title>
{{ achievement.name }}
<span class="version-icon-single">v{{ achievement.version }}</span>
</v-list-item-title>
<v-list-item-subtitle>{{ achievement.description }}</v-list-item-subtitle>
<template #append>
<span v-show="achievement.completed" class="right-time">{{ achievement.completed_time }}</span>
<v-card class="reward-card" @click="showMaterial('/source/material/原石.webp')">
<v-img src="/source/material/原石.webp" sizes="32" />
<div class="reward-num">
<span>{{ achievement.reward }}</span>
</div>
</v-card>
</template>
</v-list-item>
</v-list>
<div
class="list-empty"
:style="{height: `${emptyHeight}px`}"
>
<v-list v-for="achievement in renderAchievement" :key="achievement.id" class="card-right" :style="{Transform:`translateY(${translateY})`}">
<div v-if="achievement.progress !== 0" class="achievement-progress">
{{ achievement.progress }}
</div>
<v-list-item>
<template #prepend>
<v-icon :color="achievement.isCompleted ? '#fec90b' : '#485466'">
<!-- todo 图标替换 -->
{{ achievement.isCompleted ? "mdi-check-circle" : "mdi-circle" }}
</v-icon>
</template>
<v-list-item-title>
{{ achievement.name }}
<span class="version-icon-single">v{{ achievement.version }}</span>
</v-list-item-title>
<v-list-item-subtitle>{{ achievement.description }}</v-list-item-subtitle>
<template #append>
<span v-show="achievement.isCompleted" class="right-time">{{ achievement.completedTime }}</span>
<v-card class="reward-card">
<v-img src="/source/material/原石.webp" sizes="32" />
<div class="reward-num">
<span>{{ achievement.reward }}</span>
</div>
</v-card>
</template>
</v-list-item>
</v-list>
</div>
</div>
<!-- 弹窗提示 -->
<v-snackbar v-model="snackbar" timeout="1500" :color="snackbarColor" top>
@@ -103,17 +109,16 @@
<script lang="ts" setup>
// vue
import { onMounted, ref } from "vue";
import { onMounted, ref, onBeforeMount, computed } from "vue";
import TLoading from "../components/t-loading.vue";
// tauri
import { dialog, fs } from "@tauri-apps/api";
// Store
import { useAchievementsStore } from "../store/modules/achievements";
// Utils
import { TGAppData } from "../data";
import { createTGWindow } from "../utils/TGWindow";
import { ReadAllTGData, ReadTGDataByIndex, ReadTGDataByKey, UpdateTGDataByKey } from "../utils/TGIndex";
import { getUiafHeader, readUiafData, verifyUiafData } from "../utils/UIAF";
import TGSqlite from "../utils/TGSqlite";
// Store
const achievementsStore = useAchievementsStore();
@@ -124,81 +129,105 @@ const loadingTitle = ref("正在加载数据" as string);
// data
const title = ref(achievementsStore.title as string);
const CardsInfo = ref([] as BTMuli.Genshin.NameCard[]);
const getCardInfo = ref({} as BTMuli.Genshin.NameCard);
const getCardInfo = ref({} as BTMuli.SQLite.NameCard);
// series
const seriesList = ref([] as BTMuli.Genshin.AchievementSeries[]);
const selectedIndex = ref(-1 as number);
const seriesList = ref([] as BTMuli.SQLite.AchievementSeries[]);
const selectedSeries = ref(-1 as number);
const selectedAchievement = ref([] as BTMuli.Genshin.Achievement[]);
const selectedAchievement = ref([] as BTMuli.SQLite.Achievements[]);
const renderAchievement = computed(() => {
return selectedAchievement.value.slice(start.value, start.value + itemCount.value + 1);
});
// virtual list
const start = ref(0 as number);
const itemCount = computed(() => {
return Math.ceil((window.innerHeight - 100) / 76);
});
const emptyHeight = computed(() => {
return selectedAchievement.value.length * 76;
});
const translateY = ref("0px" as string);
// render
const search = ref("" as string);
const snackbar = ref(false as boolean);
const snackbarText = ref("" as string);
const snackbarColor = ref("#F5810A" as string);
onMounted(async () => {
await loadData();
onBeforeMount(async () => {
const { total, fin } = await TGSqlite.getAchievementsOverview();
achievementsStore.flushData(total, fin);
title.value = achievementsStore.title;
});
// 加载数据,数据源:合并后的本地数据
async function loadData () {
onMounted(async () => {
loading.value = true;
loadingTitle.value = "正在获取成就系列数据";
const seriesDB: BTMuli.Genshin.AchievementSeries[] = await ReadAllTGData("AchievementSeries");
CardsInfo.value = TGAppData.nameCards[1];
seriesList.value = seriesDB.sort((a, b) => a.order - b.order);
seriesList.value = await TGSqlite.getAchievementSeries();
loadingTitle.value = "正在获取成就数据";
const getAchievements = await ReadAllTGData("Achievements");
getAchievements.sort((a, b) => {
if (a.completed === b.completed) {
return a.id - b.id;
} else {
return a.completed ? 1 : -1;
}
});
selectedAchievement.value = getAchievements;
title.value = achievementsStore.title;
selectedAchievement.value = await TGSqlite.getAchievements();
loading.value = false;
});
function handleScroll (e: Event) {
// 如果 scrollTop 到底部了
if ((e.target as HTMLElement).scrollTop + (e.target as HTMLElement).offsetHeight >= (e.target as HTMLElement).scrollHeight) {
// 如果 selectedAchievement 的长度小于 itemCount不进行偏移
if (selectedAchievement.value.length <= itemCount.value) {
window.requestAnimationFrame(() => {
start.value = 0;
translateY.value = "0px";
});
return;
}
window.requestAnimationFrame(() => {
start.value = selectedAchievement.value.length - itemCount.value;
translateY.value = `${(selectedAchievement.value.length - itemCount.value) * 76}px`;
});
return;
}
if (selectedSeries.value !== 0 && selectedSeries.value !== 17 && selectedSeries.value !== -1) {
window.requestAnimationFrame(() => {
const { scrollTop } = e.target as HTMLElement;
if (scrollTop < 86.8) {
start.value = 0;
translateY.value = "0px";
} else {
start.value = Math.floor((scrollTop - 86.8) / 76);
translateY.value = `${scrollTop - 86.8}px`;
}
});
} else {
window.requestAnimationFrame(() => {
const { scrollTop } = e.target as HTMLElement;
start.value = Math.floor(scrollTop / 76);
translateY.value = `${scrollTop}px`;
});
}
}
// 渲染选中的成就系列
async function selectSeries (index: number) {
// 如果选中的是已经选中的系列,则不进行操作
if (selectedIndex.value === index) {
if (selectedSeries.value === index) {
snackbarText.value = "已经选中该系列";
snackbar.value = true;
return;
}
loading.value = true;
loadingTitle.value = "正在获取对应的成就数据";
const getAchievements = await ReadTGDataByIndex("Achievements", "series", seriesList.value[index].id);
selectedIndex.value = index;
selectedSeries.value = seriesList.value[index].id;
selectedSeries.value = index;
selectedAchievement.value = await TGSqlite.getAchievements(index);
loadingTitle.value = "正在查找对应的成就名片";
let getCard: BTMuli.Genshin.NameCard;
if (selectedSeries.value !== 0 && selectedSeries.value !== 17) {
getCard = CardsInfo.value.find((card) => card.name === seriesList.value[index].card)!;
} else {
getCard = {} as BTMuli.Genshin.NameCard;
getCardInfo.value = await TGSqlite.getNameCard(index);
}
getAchievements.sort((a, b) => {
if (a.completed === b.completed) {
return a.id - b.id;
} else {
return a.completed ? 1 : -1;
}
});
selectedAchievement.value = getAchievements;
getCardInfo.value = getCard;
loading.value = false;
}
// 打开图片
function openImg () {
createTGWindow(getCardInfo.value.profile, "nameCard", getCardInfo.value.name, 840, 400, false);
}
function showMaterial (path: string) {
createTGWindow(path, "material", "原石", 256, 256, false);
}
async function searchCard () {
if (search.value === "") {
snackbarColor.value = "#F5810A";
@@ -206,35 +235,16 @@ async function searchCard () {
snackbar.value = true;
return;
}
selectedSeries.value = -1;
loadingTitle.value = "正在搜索";
loading.value = true;
const res: BTMuli.Genshin.Achievement[] = [];
const allAchievements = await ReadAllTGData("Achievements");
allAchievements.map((achievement) => {
if (achievement.name.includes(search.value) || achievement.description.includes(search.value)) {
return res.push(achievement);
}
return null;
});
selectedIndex.value = -1;
setTimeout(() => {
loading.value = false;
}, 500);
if (res.length === 0) {
selectedAchievement.value = await TGSqlite.searchAchievements(search.value);
if (selectedAchievement.value.length === 0) {
snackbarColor.value = "#F5810A";
snackbarText.value = "没有找到对应的成就";
snackbar.value = true;
selectedAchievement.value = allAchievements;
} else {
res.sort((a, b) => {
if (a.completed === b.completed) {
return a.id - b.id;
} else {
return a.completed ? 1 : -1;
}
});
selectedAchievement.value = res;
}
loading.value = false;
}
// 导入 UIAF 数据,进行数据合并、刷新
async function importJson () {
@@ -256,70 +266,15 @@ async function importJson () {
}
loadingTitle.value = "正在解析数据";
loading.value = true;
const remoteData: TGPlugin.UIAF.BaseData = JSON.parse(remoteRaw);
loadingTitle.value = "正在合并成就数据";
await Promise.allSettled(
remoteData.list.map(async (data) => {
const id = data.id;
const localData: BTMuli.Genshin.Achievement = (await ReadTGDataByKey("Achievements", [id]))[0];
// 获取 timeStamp 2023-03-15 00:00:00
const localTime = localData.completed_time;
// 如果本地数据不存在,或者本地数据的 timeStamp 小于远程数据的 timeStamp更新数据
if (data.timestamp !== 0) {
const finishTime = new Date(data.timestamp * 1000).toLocaleString("zh", {
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
second: "2-digit",
});
if (finishTime !== localTime || localData.progress !== data.current) {
// eslint-disable-next-line camelcase
localData.completed_time = finishTime;
localData.progress = data.current;
localData.completed = true;
// 更新数据
await UpdateTGDataByKey("Achievements", localData);
}
} else {
if (localData.progress !== data.current) {
// eslint-disable-next-line camelcase
localData.completed_time = "";
localData.progress = data.current;
localData.completed = false;
// 更新数据
await UpdateTGDataByKey("Achievements", localData);
}
}
}),
);
loadingTitle.value = "正在更新成就系列数据";
let seriesDB = await ReadAllTGData("AchievementSeries");
await Promise.allSettled(
seriesDB.map(async (data) => {
const seriesId = data.id;
const achievementsDB = await ReadTGDataByIndex("Achievements", "series", seriesId);
// eslint-disable-next-line camelcase
data.completed_count = achievementsDB.filter((data) => {
return data.completed === true;
}).length;
await UpdateTGDataByKey("AchievementSeries", data);
}),
);
loadingTitle.value = "正在刷新数据";
seriesDB = await ReadAllTGData("AchievementSeries");
const finishAchievments = seriesDB.reduce((a, b) => {
return a + b.completed_count;
}, 0);
const totalAchievements = seriesDB.reduce((a, b) => {
return a + b.total_count;
}, 0);
achievementsStore.flushData(totalAchievements, finishAchievments);
// 刷新数据
await loadData();
await TGSqlite.mergeUIAF(JSON.parse(remoteRaw).list);
loadingTitle.value = "即将刷新页面";
setTimeout(() => {
window.location.reload();
}, 1000);
}
}
// 导出
async function exportJson () {
// 判断是否有数据
@@ -330,35 +285,10 @@ async function exportJson () {
return;
}
// 获取本地数据
const achievements = (await ReadAllTGData("Achievements")).filter((data) => {
return data.progress !== 0 || data.completed === true;
});
const UiafData = {
info: await getUiafHeader(),
list: [] as TGPlugin.UIAF.Achievement[],
list: await TGSqlite.getUIAF(),
};
// 转换数据
UiafData.list = achievements.map((data) => {
let status;
// 计算点数但是没有完成
if (data.progress !== 0 && data.completed === false) {
status = 1;
// 已完成且未计算点数
} else if (data.progress === 0 && data.completed === true) {
status = 2;
// 已完成且已计算点数
} else if (data.progress !== 0 && data.completed === true) {
status = 3;
} else {
status = 0;
}
return {
id: data.id,
timestamp: data.completed ? Math.round(new Date(data.completed_time).getTime() / 1000) : 0,
current: data.progress,
status,
};
});
const isSave = await dialog.save({
// TODO: 设置保存文件名
filters: [
@@ -370,10 +300,14 @@ async function exportJson () {
});
if (isSave) {
await fs.writeTextFile(isSave, JSON.stringify(UiafData));
snackbarColor.value = "#00BFA5";
snackbarText.value = "导出成功";
snackbar.value = true;
} else {
snackbarColor.value = "#F5810A";
snackbarText.value = "导出已取消";
snackbar.value = true;
}
snackbarColor.value = "#00BFA5";
snackbarText.value = "导出成功";
snackbar.value = true;
}
</script>
@@ -403,12 +337,25 @@ async function exportJson () {
/* 右侧成就 */
.right-wrap {
position: relative;
float: right;
width: 75%;
max-height: calc(100vh - 100px);
overflow: auto;
}
.list-empty {
position: relative;
width: 100%;
}
.list-container {
position: relative;
width: 100%;
height: 100%;
max-height: calc(100vh - 100px);
}
/* 版本信息 */
.version-icon-series {
font-family: Genshin, serif;

View File

@@ -1,6 +1,6 @@
<template>
<div v-if="loading">
<TLoading />
<TLoading :title="loadingTitle" />
</div>
<div v-else>
<v-list class="config-list">
@@ -61,11 +61,24 @@
<v-list-item-subtitle>{{ osVersion }}</v-list-item-subtitle>
</template>
</v-list-item>
<v-list-item title="数据库更新时间" prepend-icon="mdi-database">
<template #append>
<v-list-item-subtitle>{{ dbInfo.find(item => item.key === "dataUpdated")?.value }}</v-list-item-subtitle>
</template>
<v-list-item-subtitle>更新于 {{ dbInfo.find(item => item.key === "dataUpdated")?.updated }}</v-list-item-subtitle>
</v-list-item>
<v-list-item title="数据库版本" prepend-icon="mdi-database">
<template #append>
<v-list-item-subtitle>{{ dbInfo.find(item => item.key === "appVersion")?.value }}</v-list-item-subtitle>
</template>
<v-list-item-subtitle>更新于 {{ dbInfo.find(item => item.key === "appVersion")?.updated }}</v-list-item-subtitle>
</v-list-item>
<v-list-subheader inset class="config-header">
设置
</v-list-subheader>
<v-divider inset class="border-opacity-75" />
<v-list-item prepend-icon="mdi-folder" title="打开用户数据目录" @click="openMergeData" />
<v-list-item prepend-icon="mdi-content-save" title="数据备份" @click="tryConfirm('backup')" />
<v-list-item prepend-icon="mdi-content-save" title="数据恢复" @click="tryConfirm('restore')" />
<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-cog" title="恢复默认设置" @click="tryConfirm('delApp')" />
@@ -115,13 +128,19 @@
</template>
</v-list-item>
<v-list-item title="删除 IndexedDB" prepend-icon="mdi-delete" @click="tryConfirm('delDB')" />
<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-subheader inset class="config-header">
路径
</v-list-subheader>
<v-divider inset class="border-opacity-75" />
<v-list-item prepend-icon="mdi-database">
<v-list-item-title>本地数据库路径</v-list-item-title>
<v-list-item-subtitle>{{ appStore.dataPath.dbDataPath }}</v-list-item-subtitle>
</v-list-item>
<v-list-item prepend-icon="mdi-folder">
<v-list-item-title>本地应用数据路径</v-list-item-title>
<v-list-item-subtitle>{{ appStore.dataPath.appDataDir }}</v-list-item-subtitle>
<v-list-item-title>本地临时数据路径</v-list-item-title>
<v-list-item-subtitle>{{ appStore.dataPath.tempDataDir }}</v-list-item-subtitle>
</v-list-item>
<v-list-item prepend-icon="mdi-folder">
<v-list-item-title>本地用户数据路径</v-list-item-title>
@@ -133,7 +152,7 @@
{{ snackbarText }}
</v-snackbar>
<!-- 确认弹窗 -->
<TConfirm v-model="confirmShow" :title="confirmText" @confirm="doConfirm(confirmOper)" />
<TConfirm v-model="confirmShow" :title="confirmText" :subtitle="confirmSub" @confirm="doConfirm(confirmOper)" />
</div>
</template>
@@ -141,20 +160,18 @@
// vue
import { onMounted, ref } from "vue";
import { getBuildTime } from "../utils/TGBuild";
import TLoading from "../components/t-loading.vue";
import TConfirm from "../components/t-confirm.vue";
// tauri
import { dialog, fs, app, os, tauri } from "@tauri-apps/api";
import { fs, app, os, tauri } from "@tauri-apps/api";
// store
import { useAppStore } from "../store/modules/app";
import { useHomeStore } from "../store/modules/home";
import { useHk4eStore } from "../store/modules/hk4e";
import { useAchievementsStore } from "../store/modules/achievements";
// utils
import { WriteTGData, DeleteTGData } from "../utils/TGIndex";
// data
import { getDataList } from "../data/init";
import { backupUiafData, restoreUiafData } from "../utils/UIAF";
import TGSqlite from "../utils/TGSqlite";
// Store
const appStore = useAppStore();
@@ -169,9 +186,11 @@ const buildTime = ref(getBuildTime());
// About OS
const osPlatform = ref("" as string);
const osVersion = ref("" as string);
const dbInfo = ref([] as { key: string, value: string, updated: string }[]);
// loading
const loading = ref(true as boolean);
const loadingTitle = ref("正在加载..." as string);
// data
const showHome = ref(homeStore.getShowValue() as string[]);
@@ -184,6 +203,7 @@ const snackbarColor = ref("success" as string);
// confirm
const confirmText = ref("" as string);
const confirmSub = ref("" as string);
const confirmOper = ref("" as string);
const confirmShow = ref(false as boolean);
@@ -193,9 +213,8 @@ onMounted(async () => {
versionTauri.value = await app.getTauriVersion();
osPlatform.value = `${await os.platform()}`;
osVersion.value = await os.version();
setTimeout(() => {
loading.value = false;
}, 1000);
dbInfo.value = await TGSqlite.getAppData();
loading.value = false;
});
// 打开外部链接
@@ -203,17 +222,22 @@ function toOuter (url: string) {
window.open(url);
}
// 打开用户数据目录
async function openMergeData () {
await dialog.open({
defaultPath: appStore.dataPath.userDataDir,
filters: [],
});
}
// open confirm
function tryConfirm (oper: string) {
confirmSub.value = "";
switch (oper) {
case "backup":
confirmText.value = "确认备份数据吗?";
confirmSub.value = "若已备份将会被覆盖";
confirmOper.value = "backup";
confirmShow.value = true;
break;
case "restore":
confirmText.value = "确认恢复数据吗?";
confirmSub.value = "请确保存在备份数据";
confirmOper.value = "restore";
confirmShow.value = true;
break;
case "delTemp":
confirmText.value = "确认清除临时数据吗?";
confirmOper.value = "delTemp";
@@ -221,6 +245,7 @@ function tryConfirm (oper: string) {
break;
case "delUser":
confirmText.value = "确认清除用户缓存吗?";
confirmSub.value = "备份数据也将被清除";
confirmOper.value = "delUser";
confirmShow.value = true;
break;
@@ -241,15 +266,34 @@ function tryConfirm (oper: string) {
break;
case "delDB":
confirmText.value = "确认清除 IndexedDB 吗?";
confirmSub.value = "Alpha v0.1.4 后不再支持 IndexedDB";
confirmOper.value = "delDB";
confirmShow.value = true;
break;
case "checkDB":
confirmText.value = "将检测数据库表单完整性";
confirmSub.value = "数据库版本与更新时间也会进行检测";
confirmOper.value = "checkDB";
confirmShow.value = true;
break;
case "resetDB":
confirmText.value = "确认重置数据库吗?";
confirmSub.value = "请确认已经备份关键数据";
confirmOper.value = "resetDB";
confirmShow.value = true;
break;
}
}
// transfer confirm oper
async function doConfirm (oper: string) {
switch (oper) {
case "backup":
await backupData();
break;
case "restore":
await restoreData();
break;
case "delTemp":
await delTempData();
break;
@@ -269,12 +313,48 @@ async function doConfirm (oper: string) {
case "delDB":
delDB();
break;
case "checkDB":
await checkDB();
break;
case "resetDB":
await resetDB();
break;
case "updateDB":
await updateDB();
break;
default:
break;
}
}
// confirmOper
async function backupData () {
loadingTitle.value = "正在备份数据...";
loading.value = true;
const achievements = await TGSqlite.getUIAF();
await backupUiafData(achievements);
loading.value = false;
snackbarText.value = "数据已备份!";
snackbarColor.value = "success";
snackbar.value = true;
}
async function restoreData () {
loadingTitle.value = "正在恢复数据...";
loading.value = true;
const res = await restoreUiafData();
loading.value = false;
if (res !== false) {
snackbarText.value = "数据已恢复!";
snackbarColor.value = "success";
snackbar.value = true;
} else {
snackbarText.value = "未检测到备份数据!";
snackbarColor.value = "error";
snackbar.value = true;
}
}
async function delTempData () {
await fs.removeDir("tempData", {
dir: fs.BaseDirectory.AppLocalData,
@@ -290,18 +370,10 @@ async function delUserData () {
dir: fs.BaseDirectory.AppLocalData,
recursive: true,
});
await fs.removeDir("tempData", {
dir: fs.BaseDirectory.AppLocalData,
recursive: true,
});
getDataList.map(async (item) => {
await WriteTGData(item.name, item.data);
});
snackbarText.value = "用户数据已删除!";
snackbar.value = true;
achievementsStore.init();
await fs.createDir("userData", { dir: fs.BaseDirectory.AppLocalData });
await fs.createDir("tempData", { dir: fs.BaseDirectory.AppLocalData });
}
// 恢复默认配置
@@ -309,7 +381,7 @@ function initAppData () {
appStore.init();
homeStore.init();
achievementsStore.init();
snackbarText.value = "已恢复默认配置!";
snackbarText.value = "已恢复默认配置!即将刷新页面...";
snackbar.value = true;
setTimeout(() => {
window.location.reload();
@@ -364,11 +436,73 @@ async function readCookie () {
// 删除 IndexedDB
function delDB () {
DeleteTGData();
window.indexedDB.deleteDatabase("TGData");
snackbarText.value = "IndexedDB 已清除!若无法正常使用,请初始化配置。";
snackbarColor.value = "success";
snackbar.value = true;
}
// 检查 SQLite 数据库
async function checkDB () {
loadingTitle.value = "正在检查数据库表单完整性...";
loading.value = true;
const res = await TGSqlite.check();
if (!res) {
confirmOper.value = "resetDB";
confirmText.value = "数据库表单不完整,是否重置数据库?";
loading.value = false;
confirmShow.value = true;
} else {
const appVersion = await app.getVersion();
const dbVersion = dbInfo.value.find((item) => item.key === "appVersion")?.value;
const dbUpdatedTime = dbInfo.value.find((item) => item.key === "dataUpdated")?.value;
if (!dbVersion || dbVersion < appVersion) {
confirmOper.value = "updateDB";
confirmText.value = "数据库版本过低,是否更新数据库?";
loading.value = false;
confirmShow.value = true;
return;
} else if (!buildTime.value.startsWith("dev")) {
if (!dbUpdatedTime || dbUpdatedTime < buildTime.value) {
confirmOper.value = "updateDB";
confirmText.value = "数据库可能过时,是否更新数据库?";
loading.value = false;
confirmShow.value = true;
return;
}
}
loading.value = false;
snackbarText.value = "数据库已是最新!";
snackbarColor.value = "success";
snackbar.value = true;
}
}
// 重置 SQLite 数据库
async function resetDB () {
loadingTitle.value = "正在重置数据库...";
loading.value = true;
await TGSqlite.reset();
loading.value = false;
snackbarText.value = "数据库已重置!请进行再次检查。";
snackbarColor.value = "success";
snackbar.value = true;
// 刷新
window.location.reload();
}
// 更新 SQLite 数据库
async function updateDB () {
loadingTitle.value = "正在更新数据库...";
loading.value = true;
await TGSqlite.update();
loading.value = false;
snackbarText.value = "数据库已是最新!";
snackbarColor.value = "success";
snackbar.value = true;
// 刷新
window.location.reload();
}
</script>
<style lang="css" scoped>

View File

@@ -12,6 +12,8 @@ import TPosition from "../components/t-position.vue";
import TCalendar from "../components/t-calendar.vue";
// store
import { useHomeStore } from "../store/modules/home";
// utils
import TGSqlite from "../utils/TGSqlite";
// store
const homeStore = useHomeStore();
@@ -40,6 +42,12 @@ function readLoading (): void {
}
onMounted(async () => {
loadingTitle.value = "正在检测数据完整性";
const isOK = await TGSqlite.check();
if (!isOK) {
loadingTitle.value = "正在修复数据";
await TGSqlite.reset();
}
loadingTitle.value = "正在加载首页";
const showItems = homeStore.getShowValue();
await Promise.allSettled(

View File

@@ -2,7 +2,7 @@
* @file plugins Mys utils gacha.ts
* @description Mys 插件抽卡工具
* @author BTMuli<bt-muli@outlook.com>
* @since Alpha v0.1.2
* @since Alpha v0.1.4
*/
import { getPostData } from "../request/post";
@@ -10,7 +10,7 @@ import { type GachaCard, type GachaData } from "../interface/gacha";
/**
* @description 根据卡池信息转为渲染用的卡池信息
* @since Alpha v0.1.2
* @since Alpha v0.1.4
* @param {GachaData[]} gachaData 卡池信息
* @param {Map<string>} poolCover 卡池封面
* @returns {Promise<GachaCard[]>}
@@ -42,19 +42,22 @@ export async function getGachaCard (
title: data.title,
subtitle: data.content_before_act,
cover,
// eslint-disable-next-line camelcase
post_id: postId,
characters: data.pool.map((character) => ({
icon: character.icon,
url: character.url,
})),
voice: {
icon: data.voice_icon,
icon: data.voice_icon || "/source/UI/defaultUser.webp",
url: data.voice_url,
},
time: {
start: data.start_time,
// eslint-disable-next-line camelcase
start_stamp: new Date(data.start_time).getTime(),
end: data.end_time,
// eslint-disable-next-line camelcase
end_stamp: new Date(data.end_time).getTime(),
},
});

View File

@@ -2,7 +2,7 @@
* @file store modules app.ts
* @description App store module
* @author BTMuli<bt-muli@outlook.com>
* @since Alpha v0.1.3
* @since Alpha v0.1.4
*/
// vue
@@ -12,18 +12,20 @@ import { defineStore } from "pinia";
// tauri
import { path } from "@tauri-apps/api";
// 用于存储原生数据的路径
const appDataDir = `${await path.appLocalDataDir()}appData`;
// 用于存储用户数据的路径
const userDataDir = `${await path.appLocalDataDir()}userData`;
// 用于各种临时数据的路径
const tempDataDir = `${await path.appLocalDataDir()}tempData`;
// 用于存放数据库的路径
const dbDataPath = `${await path.appConfigDir()}tauri-genshin.db`;
export const useAppStore = defineStore(
"app",
() => {
// 应用加载状态
const loading = ref(false);
// 应用打包时间
const buildTime = ref("");
// 侧边栏设置
const sidebar = reactive({
// 是否折叠
@@ -42,20 +44,13 @@ export const useAppStore = defineStore(
const theme = ref("default");
const dataPath = reactive({
appDataDir,
userDataDir,
tempDataDir,
dbDataPath,
});
// 应用数据路径
const appPath = ref({
achievements: `${dataPath.appDataDir}/achievements.json`,
achievementSeries: `${dataPath.appDataDir}/achievementSeries.json`,
nameCards: `${dataPath.appDataDir}/nameCards.json`,
});
// 用户数据路径
// 用户数据路径
const userPath = ref({
achievements: `${dataPath.userDataDir}/achievements.json`,
UIAF: `${dataPath.userDataDir}/UIAF.json`,
});
// 初始化
@@ -82,10 +77,10 @@ export const useAppStore = defineStore(
return {
theme,
loading,
buildTime,
sidebar,
devMode,
dataPath,
appPath,
userPath,
init,
getSubmenu,
@@ -97,12 +92,12 @@ export const useAppStore = defineStore(
{
key: "appPath",
storage: window.localStorage,
paths: ["dataPath", "appPath", "userPath"],
paths: ["dataPath", "userPath"],
},
{
key: "app",
storage: window.localStorage,
paths: ["devMode", "loading"],
paths: ["devMode", "loading", "buildTime"],
},
{
key: "sidebar",

View File

@@ -2,13 +2,13 @@
* @file types Achievement.d.ts
* @author BTMuli<bt-muli@outlook.com>
* @description 成就相关类型定义
* @since Alpha v0.1.2
* @since Alpha v0.1.4
*/
declare namespace BTMuli.Genshin {
/**
* @description 本应用的成就类型
* @since Alpha v0.1.2
* @since Alpha v0.1.4
* @interface Achievement
* @property {number} id - 成就 ID
* @property {number} series - 成就系列 ID
@@ -16,9 +16,6 @@ declare namespace BTMuli.Genshin {
* @property {string} name - 成就名称
* @property {string} description - 成就描述
* @property {number} reward - 成就奖励
* @property {boolean} completed - 成就是否完成
* @property {string} completed_time - 成就完成时间
* @property {number} progress - 成就进度
* @property {string} version - 成就版本
* @return Achievement
*/
@@ -29,22 +26,16 @@ declare namespace BTMuli.Genshin {
name: string
description: string
reward: number
completed: boolean
completed_time: string | null
progress: number
version: string
}
/**
* @description 本应用的成就系列类型
* @since Alpha v0.1.2
* @since Alpha v0.1.4
* @interface AchievementSeries
* @property {number} id - 成就系列 ID
* @property {number} order - 成就系列排列顺序,用于展示全部成就系列
* @property {string} name - 成就系列名称
* @property {string} version - 成就系列版本
* @property {number[]} achievements - 成就系列包含的成就
* @property {number} total_count - 成就系列包含的成就数
* @property {number} completed_count - 成就系列已完成的成就数
* @property {string} card - 成就系列对应名片
* @property {string} icon - 成就系列图标
* @return AchievementSeries
@@ -54,10 +45,7 @@ declare namespace BTMuli.Genshin {
order: number
name: string
version: string
achievements: number[]
total_count: number
completed_count: number
card?: string
card: string
icon: string
}
}
@@ -109,3 +97,63 @@ declare namespace TGPlugin.UIAF {
status: number
}
}
declare namespace BTMuli.SQLite {
/**
* @description 数据库-成就表
* @since Alpha v0.1.4
* @interface Achievements
* @property {number} id - 成就 ID
* @property {number} series - 成就系列 ID
* @property {number} order - 成就排列顺序,用于展示全部成就
* @property {string} name - 成就名称
* @property {string} description - 成就描述
* @property {number} reward - 成就奖励
* @property {number} isCompleted - 成就是否完成
* @property {string} completedTime - 成就完成时间
* @property {number} progress - 成就进度
* @property {string} version - 成就版本
* @property {string} updated - 数据库更新时间
* @return Achievements
*/
export interface Achievements {
id: number
series: number
order: number
name: string
description: string
reward: number
isCompleted: 0 | 1
completedTime: string
progress: number
version: string
updated: string
}
/**
* @description 数据库-成就系列表
* @since Alpha v0.1.4
* @interface AchievementSeries
* @property {number} id - 成就系列 ID
* @property {number} order - 成就系列排列顺序,用于展示全部成就系列
* @property {string} name - 成就系列名称
* @property {string} version - 成就系列版本
* @property {number} totalConut - 成就系列包含的成就数
* @property {number} finCount - 成就系列已完成的成就数
* @property {string} icon - 成就系列图标
* @property {string} nameCard - 成就系列对应名片
* @property {string} updated - 数据库更新时间
* @returns AchievementSeries
*/
export interface AchievementSeries {
id: number
order: number
name: string | null
version: string | null
totalCount: number
finCount: number
icon: string
nameCard: string | null
updated: string | null
}
}

View File

@@ -2,7 +2,7 @@
* @file core types TGNameCard.d.ts
* @description 本应用的名片类型定义
* @author BTMuli<bt-muli@outlook.com>
* @since Alpha v0.1.2
* @since Alpha v0.1.4
*/
declare namespace BTMuli.Genshin {
@@ -29,3 +29,32 @@ declare namespace BTMuli.Genshin {
source: string
}
}
declare namespace BTMuli.SQLite {
/**
* @description 数据库内的名片类型
* @since Alpha v0.1.4
* @interface NameCard
* @property {number} id - 名片 ID
* @property {string} name - 名片名称
* @property {string} description - 名片描述
* @property {string} icon - 名片图标路径
* @property {string} bg - 名片背景图路径
* @property {string} profile - 名片 Profile 图路径
* @property {number} type - 名片类型 (0: 其他1: 成就2角色3纪行4活动)
* @property {string} source - 名片来源
* @property {string} updated - 名片更新时间
* @returns {NameCard}
*/
export interface NameCard {
id: number
name: string
description: string
icon: string
bg: string
profile: string
type: number
source: string
updated: string
}
}

View File

@@ -3,7 +3,7 @@
* @description 用于获取 vite 打包时间
* @see https://gitee.com/lihanspace/vite-plugin-build-time
* @author BTMuli<bt-muli@outlook.com>
* @since Alpha v0.1.2
* @since Alpha v0.1.4
*/
import { type Plugin } from "vite";
@@ -21,7 +21,7 @@ const buildTimePlugin = (modes: string[] = []): Plugin => {
if (_mode !== "production" && !modes.includes(_mode)) return;
return [{
tag: "script",
children: `window.${buildTimeKey} = ${Math.floor(Date.now() / 1000)}`,
children: `window.${buildTimeKey} = '${Math.floor(Date.now() / 1000)}'`,
}];
},
};

View File

@@ -1,197 +0,0 @@
/**
* @file utils TGIndex.ts
* @description IndexedDB utils
* @author BTMuli<bt-muli@outlook.com>
* @since Alpha v0.1.2
*/
import { TGConfigList } from "../data";
// 数据库参数
export const DB_NAME = "TGData";
export const DB_VERSION = 1;
/**
* @description 初始化数据库
* @description 只会在第一次打开游戏时执行
* @since Alpha v0.1.2
* @returns {Promise<void>}
*/
export async function InitTGData (): Promise<void> {
const request = window.indexedDB.open(DB_NAME, DB_VERSION);
request.onupgradeneeded = () => {
const db = request.result;
// 创建表
TGConfigList.forEach((config) => {
const store = db.createObjectStore(config.storeName, {
keyPath: config.keyPath,
});
config.indexes.forEach((index) => {
store.createIndex(index, index, { unique: false });
});
});
};
}
/**
* @description 删除数据库
* @since Alpha
* @returns {void}
*/
export function DeleteTGData (): void {
window.indexedDB.deleteDatabase(DB_NAME);
}
/**
* @description 向数据库中写入数据
* @since Alpha
* @param {string} storeName 表名
* @param {any[]} data 数据
* @returns {Promise<void>}
*/
export async function WriteTGData (storeName: string, data: any[]): Promise<void> {
const request = window.indexedDB.open(DB_NAME, DB_VERSION);
request.onsuccess = () => {
const db = request.result;
const transaction = db.transaction(storeName, "readwrite");
const store = transaction.objectStore(storeName);
data.forEach((item) => {
store.put(item);
});
};
}
/**
* @description 更新数据库中的单条数据-根据主键
* @since Alpha
* @param {string} storeName 表名
* @param {any} data 数据
* @returns {Promise<void>}
*/
export async function UpdateTGDataByKey (storeName: string, data: any): Promise<void> {
const request = window.indexedDB.open(DB_NAME, DB_VERSION);
request.onsuccess = () => {
const db = request.result;
const transaction = db.transaction(storeName, "readwrite");
const store = transaction.objectStore(storeName);
store.put(data);
};
}
/**
* @description 更新数据库中的单条数据-根据索引
* @since Alpha
* @param {string} storeName 表名
* @param {string} indexName 索引名
* @param {any} key 索引值
* @param {any} data 数据
* @returns {Promise<void>}
*/
export async function UpdateTGDataByIndex (storeName: string, indexName: string, key: any, data: any): Promise<void> {
const request = window.indexedDB.open(DB_NAME, DB_VERSION);
request.onsuccess = () => {
const db = request.result;
const transaction = db.transaction(storeName, "readwrite");
const store = transaction.objectStore(storeName);
const index = store.index(indexName);
const requestData = index.getAll(key);
requestData.onsuccess = () => {
const result = requestData.result;
result.forEach((item) => {
Object.keys(data).forEach((key) => {
item[key] = data[key];
});
store.put(item);
});
};
};
}
/**
* @description 从数据库中读取某些数据-按照主键
* @since Alpha
* @param {string} storeName 表名
* @param {any[]} keys 主键值
* @returns {Promise<any[]>}
*/
export async function ReadTGDataByKey (storeName: string, keys: any[]): Promise<any[]> {
const request = window.indexedDB.open(DB_NAME, DB_VERSION);
return await new Promise((resolve, reject) => {
request.onsuccess = () => {
const db = request.result;
const transaction = db.transaction(storeName, "readonly");
const store = transaction.objectStore(storeName);
const requestData = store.getAll();
requestData.onsuccess = () => {
const result = requestData.result;
const data = result.filter((item) => {
return keys.includes(item.id);
});
resolve(data);
};
requestData.onerror = () => {
reject(requestData.error);
};
};
request.onerror = () => {
reject(request.error);
};
});
}
/**
* @description 从数据库中读取某些数据-按照索引
* @since Alpha
* @param {string} storeName 表名
* @param {string} indexName 索引名
* @param {any} key 索引值
* @returns {Promise<any[]>}
*/
export async function ReadTGDataByIndex (storeName: string, indexName: string, key: any): Promise<any[]> {
const request = window.indexedDB.open(DB_NAME, DB_VERSION);
return await new Promise((resolve, reject) => {
request.onsuccess = () => {
const db = request.result;
const transaction = db.transaction(storeName, "readonly");
const store = transaction.objectStore(storeName);
const index = store.index(indexName);
const requestData = index.getAll(key);
requestData.onsuccess = () => {
resolve(requestData.result);
};
requestData.onerror = () => {
reject(requestData.error);
};
};
request.onerror = () => {
reject(request.error);
};
});
}
/**
* @description 从数据库中读取所有数据
* @since Alpha
* @param {string} storeName 表名
* @returns {Promise<any[]>}
*/
export async function ReadAllTGData (storeName: string): Promise<any[]> {
const request = window.indexedDB.open(DB_NAME, DB_VERSION);
return await new Promise((resolve, reject) => {
request.onsuccess = () => {
const db = request.result;
const transaction = db.transaction(storeName, "readonly");
const store = transaction.objectStore(storeName);
const requestData = store.getAll();
requestData.onsuccess = () => {
resolve(requestData.result);
};
requestData.onerror = () => {
reject(requestData.error);
};
};
request.onerror = () => {
reject(request.error);
};
});
}

265
src/utils/TGSql.ts Normal file
View File

@@ -0,0 +1,265 @@
/**
* @file utils TGSql.ts
* @description 数据库sql语句
* @author BTMuli<bt-muli@outlook.com>
* @since Alpha v0.1.4
*/
import { app } from "@tauri-apps/api";
import { getBuildTime } from "./TGBuild";
import { TGAppData } from "../data";
/**
* @description 初始化应用数据表
* @since Alpha v0.1.4
* @returns {string[]} sql
*/
function initAppTable (): string[] {
const sqlRes = [];
// 创建应用数据表
sqlRes.push(`
CREATE TABLE IF NOT EXISTS AppData
(
key TEXT PRIMARY KEY,
value TEXT DEFAULT NULL,
updated TEXT DEFAULT NULL
);
`);
return sqlRes;
}
/**
* @description 初始化成就系列数据表
* @since Alpha v0.1.4
* @returns {string[]} sql
*/
function initAchievementSeriesTable (): string[] {
const sqlRes = [];
// 创建成就系列数据表
sqlRes.push(`
CREATE TABLE IF NOT EXISTS AchievementSeries
(
id INTEGER PRIMARY KEY,
"order" INTEGER,
name TEXT DEFAULT NULL,
version TEXT DEFAULT NULL,
totalCount INTEGER DEFAULT 0,
finCount INTEGER DEFAULT 0,
icon TEXT NOT NULL,
nameCard TEXT NOT NULL,
updated TEXT DEFAULT NULL
);
`);
return sqlRes;
}
/**
* @description 初始化成就数据表
* @since Alpha v0.1.4
* @returns {string[]} sql
*/
function initAchievementTable (): string[] {
const sqlRes = [];
// 创建成就数据表
sqlRes.push(`
CREATE TABLE IF NOT EXISTS Achievements
(
id INTEGER PRIMARY KEY,
series INTEGER,
"order" INTEGER,
name TEXT DEFAULT NULL,
description TEXT DEFAULT NULL,
reward INTEGER DEFAULT 0,
isCompleted BOOLEAN DEFAULT 0,
completedTime TEXT DEFAULT NULL,
progress INTEGER DEFAULT 0,
version TEXT DEFAULT NULL,
updated TEXT DEFAULT NULL
);
`);
// 创建触发器
sqlRes.push(`
CREATE TRIGGER IF NOT EXISTS updateAchievement
AFTER UPDATE ON Achievements
FOR EACH ROW
BEGIN
UPDATE AchievementSeries SET finCount = finCount + 1, updated = datetime('now', 'localtime')
WHERE id = NEW.series AND NEW.isCompleted = 1 AND OLD.isCompleted = 0;
UPDATE AchievementSeries SET finCount = finCount - 1, updated = datetime('now', 'localtime')
WHERE id = NEW.series AND NEW.isCompleted = 0 AND OLD.isCompleted = 1;
END;
`);
sqlRes.push(`
CREATE TRIGGER IF NOT EXISTS insertAchievement
AFTER INSERT ON Achievements
FOR EACH ROW
BEGIN
UPDATE AchievementSeries SET totalCount = totalCount + 1, updated = datetime('now', 'localtime')
WHERE id = NEW.series;
UPDATE AchievementSeries SET version = NEW.version, updated = datetime('now', 'localtime')
WHERE id = NEW.series AND NEW.version > version;
END;
`);
return sqlRes;
}
/**
* @description 初始化名片数据表
* @since Alpha v0.1.4
* @returns {string[]} sql
*/
function initNameCardTable (): string[] {
const sqlRes = [];
// 创建名片数据表
sqlRes.push(`
CREATE TABLE IF NOT EXISTS NameCard
(
name TEXT PRIMARY KEY,
description TEXT DEFAULT NULL,
icon TEXT NOT NULL,
bg TEXT NOT NULL,
profile TEXT NOT NULL,
type INTEGER DEFAULT 0,
source TEXT DEFAULT NULL,
updated TEXT DEFAULT NULL
);
`);
return sqlRes;
}
/**
* @description 初始化数据库表
* @since Alpha v0.1.4
* @returns {string[]} sql
*/
export function initSQLiteTable (): string[] {
const sqlRes = [];
sqlRes.push(...initAppTable());
sqlRes.push(...initAchievementSeriesTable());
sqlRes.push(...initAchievementTable());
sqlRes.push(...initNameCardTable());
return sqlRes;
}
/**
* @description 初始化应用数据
* @since Alpha v0.1.4
* @returns {Promise<string[]>} sql
*/
async function initAppData (): Promise<string[]> {
const sqlRes = [];
const appVersion = await app.getVersion();
const buildTime = getBuildTime();
const dataUpdated = buildTime.startsWith("dev") ? buildTime.slice(4) : buildTime;
// 初始化应用版本
sqlRes.push(`
INSERT INTO AppData (key, value, updated)
VALUES ('appVersion', '${appVersion}', datetime('now', 'localtime'))
ON CONFLICT(key) DO UPDATE SET value = '${appVersion}', updated = datetime('now', 'localtime');
`);
// 初始化应用数据更新时间
sqlRes.push(`
INSERT INTO AppData (key, value, updated)
VALUES ('dataUpdated', '${dataUpdated}', datetime('now', 'localtime'))
ON CONFLICT(key) DO UPDATE SET value = '${dataUpdated}', updated = datetime('now', 'localtime');
`);
return sqlRes;
}
/**
* @description 初始化成就系列数据
* @since Alpha v0.1.4
* @returns {string[]} sql
*/
function initAchievementSeriesData (): string[] {
const sqlRes: string[] = [];
const oriData = TGAppData.achievementSeries;
oriData.map((data) => {
const sql = `
INSERT OR IGNORE INTO AchievementSeries (id, "order", name, version, icon, nameCard, updated)
VALUES (${data.id}, ${data.order}, '${data.name}', '${data.version}', '${data.icon}', '${data.card}', datetime('now', 'localtime'));
`;
return sqlRes.push(sql);
});
return sqlRes;
}
/**
* @description 初始化成就数据
* @since Alpha v0.1.4
* @returns {string[]} sql
*/
function initAchievementData (): string[] {
const sqlRes: string[] = [];
const oriData = TGAppData.achievements;
oriData.map((data) => {
const sql = `
INSERT OR IGNORE INTO Achievements (id, series, "order", name, description, reward, version, updated)
VALUES (${data.id}, ${data.series}, ${data.order}, '${data.name}', '${data.description}', ${data.reward}, '${data.version}', datetime('now', 'localtime'));
`;
return sqlRes.push(sql);
});
return sqlRes;
}
/**
* @description 初始化名片数据
* @since Alpha v0.1.4
* @returns {string[]} sql
*/
function initNameCardData (): string[] {
const sqlRes: string[] = [];
const oriData = TGAppData.nameCards;
oriData.map((data) => {
const sql = `
INSERT OR IGNORE INTO NameCard (name, description, icon, bg, profile, type, source, updated)
VALUES ('${data.name}', '${data.description}', '${data.icon}', '${data.bg}', '${data.profile}', ${data.type}, '${data.source}', datetime('now', 'localtime'));
`;
return sqlRes.push(sql);
});
return sqlRes;
}
/**
* @description 初始化数据库数据
* @since Alpha v0.1.4
* @returns {Promise<string[]>} sql
*/
export async function initSQLiteData (): Promise<string[]> {
const sqlRes = [];
sqlRes.push(...initAchievementSeriesData());
sqlRes.push(...initAchievementData());
sqlRes.push(...initNameCardData());
sqlRes.push(...await initAppData());
return sqlRes;
}
/**
* @description 导入UIAF数据
* @since Alpha v0.1.4
* @param {TGPlugin.UIAF.Achievement[]} data
* @returns {string[]} sql
*/
export function importUIAFData (data: TGPlugin.UIAF.Achievement[]): string[] {
const sqlRes: string[] = [];
data.map((achievement) => {
let sql;
// 获取完成状态
const isCompleted = achievement.status === 2 || achievement.status === 3;
if (isCompleted) {
const completedTime = new Date(achievement.timestamp * 1000).toISOString().replace("T", " ").slice(0, 19);
sql = `
UPDATE Achievements
SET isCompleted = 1, completedTime = '${completedTime}', progress = ${achievement.current}, updated = datetime('now', 'localtime')
WHERE id = ${achievement.id} AND (isCompleted = 0 OR completedTime != '${completedTime}' OR progress != ${achievement.current});
`;
} else {
sql = `
UPDATE Achievements
SET progress = ${achievement.current}, updated = datetime('now', 'localtime')
WHERE id = ${achievement.id} AND progress != ${achievement.current};
`;
}
return sqlRes.push(sql);
});
return sqlRes;
}

265
src/utils/TGSqlite.ts Normal file
View File

@@ -0,0 +1,265 @@
/**
* @description 数据库操作类
* @class TGSqlite
* @author BTMuli<bt-muli@outlook.com>
* @since Alpha v0.1.4
*/
// tauri
import Database from "tauri-plugin-sql-api";
// utils
import { importUIAFData, initSQLiteData, initSQLiteTable } from "./TGSql";
import { getUiafStatus } from "./UIAF";
class TGSqlite {
/**
* @description 数据库地址
* @private
* @type {string}
* @memberof TGSqlite
* @since Alpha v0.1.4
*/
private readonly dbPath: string = "sqlite:tauri-genshin.db";
/**
* @description 数据库包含的表
* @private
* @type {string[]}
* @memberof TGSqlite
* @since Alpha v0.1.4
*/
private readonly tables: string[] = [
"AppData",
"Achievements",
"AchievementSeries",
"NameCard",
];
/**
* @description 初始化数据库
* @memberof TGSqlite
* @since Alpha v0.1.4
* @returns {Promise<void>}
* @memberof TGSqlite
*/
public async init (): Promise<void> {
const db = await Database.load(this.dbPath);
const sqlT = initSQLiteTable();
for (const item of sqlT) {
await db.execute(item);
}
const sqlD = await initSQLiteData();
for (const item of sqlD) {
await db.execute(item);
}
await db.close();
}
/**
* @description 获取数据库信息
* @memberof TGSqlite
* @since Alpha v0.1.4
* @returns {Promise<{ key: string, value: string, updated: string }[]>}
*/
public async getAppData (): Promise<Array<{ key: string, value: string, updated: string }>> {
const db = await Database.load(this.dbPath);
const sql = "SELECT * FROM AppData;";
const res: Array<{ key: string, value: string, updated: string }> = await db.select(sql);
await db.close();
return res;
}
/**
* @description 已有数据表跟触发器不变的情况下,更新数据库数据
* @memberof TGSqlite
* @since Alpha v0.1.4
* @returns {Promise<void>}
*/
public async update (): Promise<void> {
const db = await Database.load(this.dbPath);
const sqlD = await initSQLiteData();
for (const item of sqlD) {
await db.execute(item);
}
await db.close();
}
/**
* @description 检测数据库完整性
* @memberof TGSqlite
* @since Alpha v0.1.4
* @returns {Promise<boolean>}
*/
public async check (): Promise<boolean> {
const db = await Database.load(this.dbPath);
let isVertified = false;
// 检测数据表是否都存在
const sqlT = "SELECT name FROM sqlite_master WHERE type='table' ORDER BY name;";
const res: Array<{ name: string }> = await db.select(sqlT);
// 考虑到 sqlite_sequence 表,所以需要 +1
if (res.length === this.tables.length + 1) {
if (this.tables.every((item) => res.map((i) => i.name).includes(item))) {
isVertified = true;
}
}
await db.close();
return isVertified;
}
/**
* @description 重置数据库
* @memberof TGSqlite
* @since Alpha v0.1.4
* @returns {Promise<void>}
*/
public async reset (): Promise<void> {
const db = await Database.load(this.dbPath);
this.tables.map(async (item) => {
const sql = `DROP TABLE IF EXISTS ${item};`;
await db.execute(sql);
});
await db.close();
await this.init();
}
/**
* @description 获取数据库版本及构建时间
* @memberof TGSqlite
* @since Alpha v0.1.4
* @returns {Promise<{ version: string, buildTime: string }>}
*/
public async getMetadata (): Promise<{ version: string, buildTime: string }> {
const db = await Database.load(this.dbPath);
const sql = "SELECT * FROM AppData WHERE key='appVersion' OR key='dataUpdated';";
const res: Array<{ key: string, value: string }> = await db.select(sql);
const version = res.find((item) => item.key === "appVersion")?.value ?? "0.0.0";
const buildTime = res.find((item) => item.key === "dataUpdated")?.value ?? "1970-01-01 00:00:00";
await db.close();
return { version, buildTime };
}
/**
* @description 获取成就系列列表
* @memberof TGSqlite
* @since Alpha v0.1.4
* @returns {Promise<BTMuli.SQLite.AchievementSeries[]>}
*/
public async getAchievementSeries (): Promise<BTMuli.SQLite.AchievementSeries[]> {
const db = await Database.load(this.dbPath);
const sql = "SELECT * FROM AchievementSeries ORDER BY `order` ASC;";
const res: BTMuli.SQLite.AchievementSeries[] = await db.select(sql);
await db.close();
return res;
}
/**
* @description 获取成就系列对应的名片
* @memberof TGSqlite
* @since Alpha v0.1.4
* @param {number} seriesId 系列 ID
* @returns {Promise<BTMuli.SQLite.NameCard>}
*/
public async getNameCard (seriesId: number): Promise<BTMuli.SQLite.NameCard> {
const db = await Database.load(this.dbPath);
const sql = `SELECT * FROM NameCard WHERE name=(SELECT nameCard FROM AchievementSeries WHERE id=${seriesId});`;
const res: BTMuli.SQLite.NameCard[] = await db.select(sql);
await db.close();
return res[0];
}
/**
* @description 获取成就列表
* @memberof TGSqlite
* @param {number} [seriesId] 系列 ID
* @since Alpha v0.1.4
* @returns {Promise<BTMuli.SQLite.Achievements[]>}
*/
public async getAchievements (seriesId?: number): Promise<BTMuli.SQLite.Achievements[]> {
const db = await Database.load(this.dbPath);
let sql;
if (seriesId) {
sql = `SELECT * FROM Achievements WHERE series=${seriesId} ORDER BY isCompleted ASC, \`order\` ASC;`;
} else {
sql = "SELECT * FROM Achievements ORDER BY isCompleted ASC, `order` ASC;";
}
const res: BTMuli.SQLite.Achievements[] = await db.select(sql);
await db.close();
return res;
}
/**
* @description 获取成就概况
* @since Alpha v0.1.4
* @memberof TGSqlite
* @returns {Promise<{total:number,fin:number}>}
*/
public async getAchievementsOverview (): Promise<{ total: number, fin: number }> {
const db = await Database.load(this.dbPath);
const sql = "SELECT SUM(totalCount) AS total, SUM(finCount) AS fin FROM AchievementSeries;";
const res: Array<{ total: number, fin: number }> = await db.select(sql);
await db.close();
return res[0];
}
/**
* @description 查询成就
* @memberof TGSqlite
* @param {string} keyword 关键词
* @since Alpha v0.1.4
* @returns {Promise<BTMuli.SQLite.Achievements[]>}
*/
public async searchAchievements (keyword: string): Promise<BTMuli.SQLite.Achievements[]> {
const db = await Database.load(this.dbPath);
let sql;
if (keyword.startsWith("v")) {
const version = keyword.replace("v", "");
sql = `SELECT * FROM Achievements WHERE version LIKE '%${version}%' ORDER BY isCompleted ASC, \`order\` ASC;`;
} else {
sql = `SELECT * FROM Achievements WHERE name LIKE '%${keyword}%' OR description LIKE '%${keyword}%' ORDER BY isCompleted ASC, \`order\` ASC;`;
}
const res: BTMuli.SQLite.Achievements[] = await db.select(sql);
await db.close();
return res;
}
/**
* @description 合并 UIAF 数据
* @memberof TGSqlite
* @param {BTMuli.UIAF.Achievement[]} achievements UIAF 数据
* @since Alpha v0.1.4
* @returns {Promise<void>}
*/
public async mergeUIAF (achievements: TGPlugin.UIAF.Achievement[]): Promise<void> {
const db = await Database.load(this.dbPath);
const sql = importUIAFData(achievements);
for (const item of sql) {
await db.execute(item);
}
await db.close();
}
/**
* @description 获取 UIAF 数据
* @memberof TGSqlite
* @since Alpha v0.1.4
* @returns {Promise<TGPlugin.UIAF.Achievement[]>}
*/
public async getUIAF (): Promise<TGPlugin.UIAF.Achievement[]> {
const db = await Database.load(this.dbPath);
const sql = "SELECT * FROM Achievements WHERE isCompleted = 1 OR progress > 0";
const res: BTMuli.SQLite.Achievements[] = await db.select(sql);
await db.close();
const achievements: TGPlugin.UIAF.Achievement[] = [];
for (const item of res) {
const completed = item.isCompleted === 1;
const status = getUiafStatus(completed, item.progress);
achievements.push({
id: item.id,
status,
timestamp: completed && item.completedTime ? new Date(item.completedTime).getTime() / 1000 : 0,
current: item.progress,
});
}
return achievements;
}
}
export default new TGSqlite();

View File

@@ -2,10 +2,49 @@
* @file utils UIAF.ts
* @description UIAF工具类
* @author BTMuli<bt-muli@outlook.com>
* @since Alpha v0.1.3
* @since Alpha v0.1.4
*/
import { app, fs } from "@tauri-apps/api";
// tauri
import { app, fs, path } from "@tauri-apps/api";
// utils
import TGSqlite from "./TGSqlite";
/**
* @description 时间戳转换为日期
* @since Alpha v0.1.4
* @param {number} timestamp - 时间戳
* @returns {string} 日期 2021-01-01 00:00:00
*/
export function timestampToDate (timestamp: number): string {
return new Date(timestamp * 1000).toLocaleString("zh", {
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
second: "2-digit",
});
}
/**
* @description 根据 completed 跟 progress 获取 status
* @since Alpha v0.1.4
* @param {boolean} completed - 是否完成
* @param {number} progress - 进度
* @returns {number} status
*/
export function getUiafStatus (completed: boolean, progress: number): number {
if (progress !== 0 && !completed) {
return 1;
} else if (progress === 0 && completed) {
return 2;
} else if (progress !== 0 && completed) {
return 3;
} else {
return 0;
}
}
/**
* @description 获取 UIAF 头部信息
@@ -56,3 +95,30 @@ export async function readUiafData (userPath: string): Promise<string | false> {
return false;
}
}
/**
* @description 根据成就数据导出 UIAF 数据
* @since Alpha v0.1.4
* @param {TGPlugin.UIAF.Achievement[]} achievementData - 成就数据
* @returns {Promise<void>}
*/
export async function backupUiafData (achievementData: TGPlugin.UIAF.Achievement[]): Promise<void> {
const savePath = `${await path.appLocalDataDir()}\\userData\\UIAF.json`;
await fs.writeTextFile(savePath, JSON.stringify(achievementData, null, 2));
}
/**
* @description 根据 UIAF 数据恢复成就数据
* @since Alpha v0.1.4
* @returns {Promise<boolean>} 恢复的成就数量
*/
export async function restoreUiafData (): Promise<boolean> {
const uiafPath = `${await path.appLocalDataDir()}\\userData\\UIAF.json`;
// 检测是否存在 UIAF 数据
if (!await fs.exists(uiafPath)) {
return false;
}
const uiafData = JSON.parse(await fs.readTextFile(uiafPath)) as TGPlugin.UIAF.Achievement[];
await TGSqlite.mergeUIAF(uiafData);
return true;
}

View File

@@ -266,7 +266,7 @@ onUpdated(() => {
.lottery-user-nickname {
display: inline-block;
font-size: 14px;
font-family: Genshin-Light, "仿宋";
font-family: Genshin-Light, "仿宋", serif;
color: var(--content-text-3);
overflow: hidden;
}