mirror of
https://github.com/BTMuli/TeyvatGuide.git
synced 2025-12-13 09:28:14 +08:00
✨ UIGFv4支持
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
/**
|
/**
|
||||||
* @file src/data/index.ts
|
* @file src/data/index.ts
|
||||||
* @description 数据文件入口
|
* @description 数据文件入口
|
||||||
* @since Beta v0.4.7
|
* @since Beta v0.5.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type { Schema } from "ajv";
|
import type { Schema } from "ajv";
|
||||||
@@ -19,6 +19,7 @@ import arcBirDraw from "./archive/birth_draw.json";
|
|||||||
import arcBirRole from "./archive/birth_role.json";
|
import arcBirRole from "./archive/birth_role.json";
|
||||||
import schemaUiaf from "./schema/uiaf-schema.json";
|
import schemaUiaf from "./schema/uiaf-schema.json";
|
||||||
import schemaUigf from "./schema/uigf-schema.json";
|
import schemaUigf from "./schema/uigf-schema.json";
|
||||||
|
import scheamUigf4 from "./schema/uigf4-schema.json";
|
||||||
import wikiCharacter from "./WIKI/character.json";
|
import wikiCharacter from "./WIKI/character.json";
|
||||||
import wikiMaterial from "./WIKI/material.json";
|
import wikiMaterial from "./WIKI/material.json";
|
||||||
import wikiWeapon from "./WIKI/weapon.json";
|
import wikiWeapon from "./WIKI/weapon.json";
|
||||||
@@ -35,6 +36,7 @@ export const AppWeaponData: TGApp.App.Weapon.WikiBriefInfo[] = weapon;
|
|||||||
// Schema
|
// Schema
|
||||||
export const UiafSchema: Schema = schemaUiaf;
|
export const UiafSchema: Schema = schemaUiaf;
|
||||||
export const UigfSchema: Schema = schemaUigf;
|
export const UigfSchema: Schema = schemaUigf;
|
||||||
|
export const Uigf4Schema: Schema = scheamUigf4;
|
||||||
// Archive
|
// Archive
|
||||||
export const ArcBirCalendar: TGApp.Archive.Birth.CalendarData = arcBirCalendar;
|
export const ArcBirCalendar: TGApp.Archive.Birth.CalendarData = arcBirCalendar;
|
||||||
export const ArcBirDraw: TGApp.Archive.Birth.DrawItem[] = arcBirDraw;
|
export const ArcBirDraw: TGApp.Archive.Birth.DrawItem[] = arcBirDraw;
|
||||||
|
|||||||
310
src/data/schema/uigf4-schema.json
Normal file
310
src/data/schema/uigf4-schema.json
Normal file
@@ -0,0 +1,310 @@
|
|||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"info": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"export_timestamp": {
|
||||||
|
"oneOf": [
|
||||||
|
{
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "导出档案的时间戳,秒级"
|
||||||
|
},
|
||||||
|
"export_app": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "导出档案的 App 名称"
|
||||||
|
},
|
||||||
|
"export_app_version": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "导出档案的 App 版本"
|
||||||
|
},
|
||||||
|
"version": {
|
||||||
|
"type": "string",
|
||||||
|
"pattern": "^v\\d+\\.\\d+$",
|
||||||
|
"description": "导出档案的 UIGF 版本号,格式为 'v{major}.{minor}',如 v4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": ["export_timestamp", "export_app", "export_app_version", "version"]
|
||||||
|
},
|
||||||
|
"hk4e": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"uid": {
|
||||||
|
"oneOf": [
|
||||||
|
{
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "UID"
|
||||||
|
},
|
||||||
|
"timezone": {
|
||||||
|
"type": "integer",
|
||||||
|
"description": "时区偏移,由米哈游 API 返回,若与服务器时区不同请注意 list 中 time 的转换"
|
||||||
|
},
|
||||||
|
"lang": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "语言代码",
|
||||||
|
"enum": [
|
||||||
|
"de-de",
|
||||||
|
"en-us",
|
||||||
|
"es-es",
|
||||||
|
"fr-fr",
|
||||||
|
"id-id",
|
||||||
|
"it-it",
|
||||||
|
"ja-jp",
|
||||||
|
"ko-kr",
|
||||||
|
"pt-pt",
|
||||||
|
"ru-ru",
|
||||||
|
"th-th",
|
||||||
|
"tr-tr",
|
||||||
|
"vi-vn",
|
||||||
|
"zh-cn",
|
||||||
|
"zh-tw"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"list": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"uigf_gacha_type": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "UIGF 卡池类型,用于区分卡池类型不同,但卡池保底计算相同的物品",
|
||||||
|
"enum": ["100", "200", "301", "302", "500"]
|
||||||
|
},
|
||||||
|
"gacha_type": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "卡池类型,米哈游 API 返回",
|
||||||
|
"enum": ["100", "200", "301", "302", "400", "500"]
|
||||||
|
},
|
||||||
|
"item_id": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "物品的内部 ID"
|
||||||
|
},
|
||||||
|
"count": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "物品个数,一般为1,米哈游 API 返回"
|
||||||
|
},
|
||||||
|
"time": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "抽取物品时对应时区(timezone)下的当地时间"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "物品名称,米哈游 API 返回"
|
||||||
|
},
|
||||||
|
"item_type": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "物品类型,米哈游 API 返回"
|
||||||
|
},
|
||||||
|
"rank_type": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "物品等级,米哈游 API 返回"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "记录内部 ID,米哈游 API 返回"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": ["uigf_gacha_type", "gacha_type", "item_id", "time", "id"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": ["uid", "timezone", "list"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"hkrpg": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"uid": {
|
||||||
|
"oneOf": [
|
||||||
|
{
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "UID"
|
||||||
|
},
|
||||||
|
"timezone": {
|
||||||
|
"type": "integer",
|
||||||
|
"description": "时区偏移,由米哈游 API 返回,若与服务器时区不同请注意 list 中 time 的转换"
|
||||||
|
},
|
||||||
|
"lang": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "语言代码",
|
||||||
|
"enum": [
|
||||||
|
"de-de",
|
||||||
|
"en-us",
|
||||||
|
"es-es",
|
||||||
|
"fr-fr",
|
||||||
|
"id-id",
|
||||||
|
"it-it",
|
||||||
|
"ja-jp",
|
||||||
|
"ko-kr",
|
||||||
|
"pt-pt",
|
||||||
|
"ru-ru",
|
||||||
|
"th-th",
|
||||||
|
"tr-tr",
|
||||||
|
"vi-vn",
|
||||||
|
"zh-cn",
|
||||||
|
"zh-tw"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"list": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"gacha_id": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "卡池 Id"
|
||||||
|
},
|
||||||
|
"gacha_type": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "卡池类型",
|
||||||
|
"enum": ["1", "2", "11", "12"]
|
||||||
|
},
|
||||||
|
"item_id": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "物品的内部 ID"
|
||||||
|
},
|
||||||
|
"count": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "物品个数,一般为1,米哈游 API 返回"
|
||||||
|
},
|
||||||
|
"time": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "抽取物品时对应时区(timezone)下的当地时间"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "物品名称,米哈游 API 返回"
|
||||||
|
},
|
||||||
|
"item_type": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "物品类型,米哈游 API 返回"
|
||||||
|
},
|
||||||
|
"rank_type": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "物品等级,米哈游 API 返回"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "内部 Id"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": ["gacha_type", "time", "item_id", "id"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": ["uid", "timezone", "list"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nap": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"uid": {
|
||||||
|
"oneOf": [
|
||||||
|
{
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "UID"
|
||||||
|
},
|
||||||
|
"timezone": {
|
||||||
|
"type": "integer",
|
||||||
|
"description": "时区偏移,由米哈游 API 返回,若与服务器时区不同请注意 list 中 time 的转换"
|
||||||
|
},
|
||||||
|
"lang": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "语言代码",
|
||||||
|
"enum": [
|
||||||
|
"de-de",
|
||||||
|
"en-us",
|
||||||
|
"es-es",
|
||||||
|
"fr-fr",
|
||||||
|
"id-id",
|
||||||
|
"it-it",
|
||||||
|
"ja-jp",
|
||||||
|
"ko-kr",
|
||||||
|
"pt-pt",
|
||||||
|
"ru-ru",
|
||||||
|
"th-th",
|
||||||
|
"tr-tr",
|
||||||
|
"vi-vn",
|
||||||
|
"zh-cn",
|
||||||
|
"zh-tw"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"list": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"gacha_id": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "卡池 Id"
|
||||||
|
},
|
||||||
|
"gacha_type": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "卡池类型",
|
||||||
|
"enum": ["1", "2", "3", "5"]
|
||||||
|
},
|
||||||
|
"item_id": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "物品的内部 ID"
|
||||||
|
},
|
||||||
|
"count": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "物品个数,一般为1,米哈游 API 返回"
|
||||||
|
},
|
||||||
|
"time": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "抽取物品时对应时区(timezone)下的当地时间"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "物品名称,米哈游 API 返回"
|
||||||
|
},
|
||||||
|
"item_type": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "物品类型,米哈游 API 返回"
|
||||||
|
},
|
||||||
|
"rank_type": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "物品等级,米哈游 API 返回"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "记录内部 ID,米哈游 API 返回"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": ["gacha_type", "item_id", "time", "id"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": ["uid", "timezone", "list"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": ["info", "hk4e"]
|
||||||
|
}
|
||||||
@@ -10,15 +10,17 @@
|
|||||||
<v-btn prepend-icon="mdi-refresh" class="gacha-top-btn" @click="confirmRefresh(true)"
|
<v-btn prepend-icon="mdi-refresh" class="gacha-top-btn" @click="confirmRefresh(true)"
|
||||||
>全量刷新
|
>全量刷新
|
||||||
</v-btn>
|
</v-btn>
|
||||||
<v-btn prepend-icon="mdi-import" class="gacha-top-btn" @click="handleImportBtn()">导入</v-btn>
|
<v-btn prepend-icon="mdi-import" class="gacha-top-btn" @click="handleImportBtn(false)"
|
||||||
<v-btn prepend-icon="mdi-export" class="gacha-top-btn" @click="handleExportBtn">导出</v-btn>
|
>导入
|
||||||
<v-btn prepend-icon="mdi-cloud-download" class="gacha-top-btn" @click="backupGacha">
|
|
||||||
备份
|
|
||||||
</v-btn>
|
</v-btn>
|
||||||
<v-btn prepend-icon="mdi-delete" class="gacha-top-btn" @click="deleteGacha">删除</v-btn>
|
<v-btn prepend-icon="mdi-import" class="gacha-top-btn" @click="handleImportBtn(true)"
|
||||||
<v-btn prepend-icon="mdi-cloud-upload" class="gacha-top-btn" @click="restoreGacha">
|
>导入(v4)
|
||||||
恢复
|
|
||||||
</v-btn>
|
</v-btn>
|
||||||
|
<v-btn prepend-icon="mdi-export" class="gacha-top-btn" @click="exportUigf()">导出 </v-btn>
|
||||||
|
<v-btn prepend-icon="mdi-export" class="gacha-top-btn" @click="exportUigf4()"
|
||||||
|
>导出(v4)
|
||||||
|
</v-btn>
|
||||||
|
<v-btn prepend-icon="mdi-delete" class="gacha-top-btn" @click="deleteGacha()">删除</v-btn>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="gacha-container">
|
<div class="gacha-container">
|
||||||
@@ -54,14 +56,18 @@ import GroOverview from "../../components/gachaRecord/gro-overview.vue";
|
|||||||
import ToLoading from "../../components/overlay/to-loading.vue";
|
import ToLoading from "../../components/overlay/to-loading.vue";
|
||||||
import { AppCharacterData, AppWeaponData } from "../../data/index.js";
|
import { AppCharacterData, AppWeaponData } from "../../data/index.js";
|
||||||
import TSUserGacha from "../../plugins/Sqlite/modules/userGacha.js";
|
import TSUserGacha from "../../plugins/Sqlite/modules/userGacha.js";
|
||||||
import { useAppStore } from "../../store/modules/app.js";
|
|
||||||
import { useUserStore } from "../../store/modules/user.js";
|
import { useUserStore } from "../../store/modules/user.js";
|
||||||
import TGLogger from "../../utils/TGLogger.js";
|
import TGLogger from "../../utils/TGLogger.js";
|
||||||
import { backupUigfData, exportUigfData, readUigfData, verifyUigfData } from "../../utils/UIGF.js";
|
import {
|
||||||
|
exportUigfData,
|
||||||
|
readUigf4Data,
|
||||||
|
readUigfData,
|
||||||
|
verifyUigfData,
|
||||||
|
exportUigf4Data,
|
||||||
|
} from "../../utils/UIGF.js";
|
||||||
import TGRequest from "../../web/request/TGRequest.js";
|
import TGRequest from "../../web/request/TGRequest.js";
|
||||||
|
|
||||||
// store
|
// store
|
||||||
const appStore = useAppStore();
|
|
||||||
const userStore = storeToRefs(useUserStore());
|
const userStore = storeToRefs(useUserStore());
|
||||||
const account = userStore.account.value;
|
const account = userStore.account.value;
|
||||||
const authkey = ref<string>("");
|
const authkey = ref<string>("");
|
||||||
@@ -267,36 +273,24 @@ async function getGachaLogs(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 导入按钮点击事件
|
// 导入按钮点击事件
|
||||||
async function handleImportBtn(savePath?: string): Promise<void> {
|
async function handleImportBtn(isV4: boolean): Promise<void> {
|
||||||
await TGLogger.Info("[UserGacha][handleImportBtn] 导入祈愿数据");
|
if (isV4) {
|
||||||
let selectedFile;
|
await TGLogger.Info("[UserGacha][handleImportBtn] 导入祈愿数据(v4)");
|
||||||
if (savePath) {
|
|
||||||
selectedFile = await open({
|
|
||||||
multiple: false,
|
|
||||||
title: "选择要导入的祈愿数据文件",
|
|
||||||
filters: [
|
|
||||||
{
|
|
||||||
name: "UIGF JSON",
|
|
||||||
extensions: ["json"],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
defaultPath: savePath,
|
|
||||||
directory: false,
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
selectedFile = await open({
|
await TGLogger.Info("[UserGacha][handleImportBtn] 导入祈愿数据");
|
||||||
multiple: false,
|
|
||||||
title: "选择要导入的祈愿数据文件",
|
|
||||||
filters: [
|
|
||||||
{
|
|
||||||
name: "UIGF JSON",
|
|
||||||
extensions: ["json"],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
defaultPath: `${await path.downloadDir()}`,
|
|
||||||
directory: false,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
const selectedFile = await open({
|
||||||
|
multiple: false,
|
||||||
|
title: "选择要导入的祈愿数据文件",
|
||||||
|
filters: [
|
||||||
|
{
|
||||||
|
name: "UIGF JSON",
|
||||||
|
extensions: ["json"],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
defaultPath: await path.downloadDir(),
|
||||||
|
directory: false,
|
||||||
|
});
|
||||||
if (!selectedFile) {
|
if (!selectedFile) {
|
||||||
showSnackbar({
|
showSnackbar({
|
||||||
color: "cancel",
|
color: "cancel",
|
||||||
@@ -304,14 +298,24 @@ async function handleImportBtn(savePath?: string): Promise<void> {
|
|||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const check = await verifyUigfData(selectedFile.path);
|
const check = await verifyUigfData(selectedFile.path, isV4);
|
||||||
if (!check) return;
|
if (!check) return;
|
||||||
const remoteData = await readUigfData(selectedFile.path);
|
if (isV4) {
|
||||||
|
await importUigf4(selectedFile.path);
|
||||||
|
} else {
|
||||||
|
await importUigf(selectedFile.path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 导入 v4 版本的祈愿数据
|
||||||
|
async function importUigf4(filePath: string): Promise<void> {
|
||||||
|
const remoteData = await readUigf4Data(filePath);
|
||||||
|
const uidCount = remoteData.hk4e.length;
|
||||||
|
const dataCount = remoteData.hk4e.reduce((acc, cur) => acc + cur.list.length, 0);
|
||||||
const res = await showConfirm({
|
const res = await showConfirm({
|
||||||
title: "是否导入祈愿数据?",
|
title: "是否导入祈愿数据?",
|
||||||
text: `UID:${remoteData.info.uid} 共 ${remoteData.list.length} 条数据`,
|
text: `共 ${uidCount} 个 UID,${dataCount} 条数据`,
|
||||||
});
|
});
|
||||||
await TGLogger.Info(`[UserGacha][${account.gameUid}][handleImportBtn] 确认导入祈愿数据`);
|
|
||||||
if (!res) {
|
if (!res) {
|
||||||
showSnackbar({
|
showSnackbar({
|
||||||
color: "cancel",
|
color: "cancel",
|
||||||
@@ -319,6 +323,37 @@ async function handleImportBtn(savePath?: string): Promise<void> {
|
|||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
loadingTitle.value = "正在导入祈愿数据(v4)";
|
||||||
|
loading.value = true;
|
||||||
|
for (const account of remoteData.hk4e) {
|
||||||
|
loadingSub.value = `正在导入 ${account.uid} 的祈愿数据`;
|
||||||
|
await TSUserGacha.mergeUIGF4(account);
|
||||||
|
}
|
||||||
|
loading.value = false;
|
||||||
|
showSnackbar({
|
||||||
|
text: `成功导入 ${uidCount} 个 UID 的 ${dataCount} 条祈愿数据`,
|
||||||
|
});
|
||||||
|
await TGLogger.Info(
|
||||||
|
`[UserGacha][importUigf4] 成功导入 ${uidCount} 个 UID,${dataCount} 条祈愿数据`,
|
||||||
|
);
|
||||||
|
setTimeout(() => {
|
||||||
|
window.location.reload();
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function importUigf(filePath: string): Promise<void> {
|
||||||
|
const remoteData = await readUigfData(filePath);
|
||||||
|
const confirm = await showConfirm({
|
||||||
|
title: "是否导入祈愿数据?",
|
||||||
|
text: `UID:${remoteData.info.uid},共 ${remoteData.list.length} 条数据`,
|
||||||
|
});
|
||||||
|
if (!confirm) {
|
||||||
|
showSnackbar({
|
||||||
|
color: "cancel",
|
||||||
|
text: "已取消祈愿数据导入",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
loadingTitle.value = "正在导入祈愿数据";
|
loadingTitle.value = "正在导入祈愿数据";
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
if (remoteData.list.length === 0) {
|
if (remoteData.list.length === 0) {
|
||||||
@@ -335,15 +370,16 @@ async function handleImportBtn(savePath?: string): Promise<void> {
|
|||||||
text: `成功导入 ${remoteData.list.length} 条祈愿数据`,
|
text: `成功导入 ${remoteData.list.length} 条祈愿数据`,
|
||||||
});
|
});
|
||||||
await TGLogger.Info(
|
await TGLogger.Info(
|
||||||
`[UserGacha][handleImportBtn] 成功导入 ${remoteData.info.uid} 的 ${remoteData.list.length} 条祈愿数据`,
|
`[UserGacha][importUigf] 成功导入 ${remoteData.info.uid} 的 ${remoteData.list.length} 条祈愿数据`,
|
||||||
);
|
);
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
}, 1000);
|
}, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 导出按钮点击事件
|
// 导出当前UID的祈愿数据
|
||||||
async function handleExportBtn(): Promise<void> {
|
async function exportUigf(): Promise<void> {
|
||||||
|
await TGLogger.Info(`[UserGacha][${uidCur.value}][exportUigf] 导出祈愿数据`);
|
||||||
const gachaList = await TSUserGacha.getGachaRecords(uidCur.value);
|
const gachaList = await TSUserGacha.getGachaRecords(uidCur.value);
|
||||||
if (gachaList.length === 0) {
|
if (gachaList.length === 0) {
|
||||||
showSnackbar({
|
showSnackbar({
|
||||||
@@ -352,15 +388,14 @@ async function handleExportBtn(): Promise<void> {
|
|||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const res = await showConfirm({
|
const res = showConfirm({
|
||||||
title: "是否导出祈愿数据?",
|
title: "是否导出祈愿数据?",
|
||||||
text: `UID:${uidCur.value},共 ${gachaList.length} 条数据`,
|
text: `UID:${uidCur.value},共 ${gachaList.length} 条数据`,
|
||||||
});
|
});
|
||||||
await TGLogger.Info(`[UserGacha][${account.gameUid}][handleExportBtn] 导出祈愿数据`);
|
|
||||||
if (!res) {
|
if (!res) {
|
||||||
showSnackbar({
|
showSnackbar({
|
||||||
color: "cancel",
|
color: "cancel",
|
||||||
text: "已取消祈愿数据导出",
|
text: `已取消 UID ${uidCur.value} 的祈愿数据导出`,
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -372,7 +407,7 @@ async function handleExportBtn(): Promise<void> {
|
|||||||
extensions: ["json"],
|
extensions: ["json"],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
defaultPath: `${await path.downloadDir()}${path.sep()}UIGF${uidCur.value}.json`,
|
defaultPath: `${await path.downloadDir()}${path.sep()}UIGF_${uidCur.value}.json`,
|
||||||
});
|
});
|
||||||
if (!file) {
|
if (!file) {
|
||||||
showSnackbar({
|
showSnackbar({
|
||||||
@@ -382,55 +417,69 @@ async function handleExportBtn(): Promise<void> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await TGLogger.Info(
|
await TGLogger.Info(
|
||||||
`[UserGacha][${account.gameUid}][handleExportBtn] 导出${gachaList.length} 条祈愿数据到 ${file}`,
|
`[UserGacha][${uidCur.value}][exportUigf] 导出${gachaList.length} 条祈愿数据到 ${file}`,
|
||||||
);
|
);
|
||||||
loadingTitle.value = "正在导出祈愿数据";
|
loadingTitle.value = `正在导出 ${uidCur.value} 的祈愿数据`;
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
await exportUigfData(uidCur.value, gachaList, file);
|
await exportUigfData(uidCur.value, gachaList, file);
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
|
showSnackbar({ text: `成功导出 ${uidCur.value} 的祈愿数据` });
|
||||||
|
await TGLogger.Info(`[UserGacha][${uidCur.value}][exportUigf] 导出祈愿数据完成`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 导出 UIGF v4 版本的祈愿数据
|
||||||
|
async function exportUigf4(): Promise<void> {
|
||||||
|
await TGLogger.Info(`[UserGacha][${uidCur.value}][exportUigf4] 导出祈愿数据(v4)`);
|
||||||
|
const allConfirm = await showConfirm({
|
||||||
|
title: "是否导出所有 UID 的祈愿数据?",
|
||||||
|
text: "取消则只导出当前 UID 的祈愿数据",
|
||||||
|
});
|
||||||
|
if (allConfirm === undefined) {
|
||||||
|
showSnackbar({
|
||||||
|
color: "cancel",
|
||||||
|
text: "已取消祈愿数据导出",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (allConfirm === false) {
|
||||||
|
const gachaList = await TSUserGacha.getGachaRecords(uidCur.value);
|
||||||
|
if (gachaList.length === 0) {
|
||||||
|
showSnackbar({
|
||||||
|
color: "error",
|
||||||
|
text: `UID ${uidCur.value} 暂无祈愿数据`,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const file = await save({
|
||||||
|
title: "选择导出祈愿数据的文件路径",
|
||||||
|
filters: [
|
||||||
|
{
|
||||||
|
name: "UIGF JSON",
|
||||||
|
extensions: ["json"],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
defaultPath: `${await path.downloadDir()}${path.sep()}UIGF4.json`,
|
||||||
|
});
|
||||||
|
if (!file) {
|
||||||
|
showSnackbar({
|
||||||
|
color: "cancel",
|
||||||
|
text: "已取消文件保存",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
loadingTitle.value = "正在导出祈愿数据";
|
||||||
|
loading.value = true;
|
||||||
|
if (allConfirm === false) {
|
||||||
|
await exportUigf4Data(file, uidCur.value);
|
||||||
|
} else {
|
||||||
|
await exportUigf4Data(file);
|
||||||
|
}
|
||||||
|
loading.value = false;
|
||||||
showSnackbar({
|
showSnackbar({
|
||||||
text: "祈愿数据已成功导出",
|
text: "祈愿数据已成功导出",
|
||||||
});
|
});
|
||||||
await TGLogger.Info(`[UserGacha][${account.gameUid}][handleExportBtn] 导出祈愿数据完成`);
|
await TGLogger.Info(`[UserGacha][${uidCur.value}][exportUigf4] 导出祈愿数据完成`);
|
||||||
}
|
|
||||||
|
|
||||||
// 恢复UID祈愿数据,相当于导入祈愿数据,不过目录固定
|
|
||||||
async function restoreGacha(): Promise<void> {
|
|
||||||
await handleImportBtn(appStore.userDir);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 备份当前 UID 的祈愿数据
|
|
||||||
async function backupGacha(): Promise<void> {
|
|
||||||
if (gachaListCur.value.length === 0) {
|
|
||||||
showSnackbar({
|
|
||||||
color: "error",
|
|
||||||
text: "暂无祈愿数据",
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
await TGLogger.Info(`[UserGacha][${uidCur.value}][backupGacha] 备份祈愿数据`);
|
|
||||||
const res = await showConfirm({
|
|
||||||
title: "是否备份祈愿数据?",
|
|
||||||
text: `UID:${uidCur.value},共 ${gachaListCur.value.length} 条数据`,
|
|
||||||
});
|
|
||||||
if (!res) {
|
|
||||||
showSnackbar({
|
|
||||||
color: "cancel",
|
|
||||||
text: "已取消祈愿数据备份",
|
|
||||||
});
|
|
||||||
await TGLogger.Warn(`[UserGacha][${uidCur.value}][backupGacha] 已取消祈愿数据备份`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
loadingTitle.value = "正在备份祈愿数据";
|
|
||||||
loading.value = true;
|
|
||||||
await backupUigfData(appStore.userDir, uidCur.value, gachaListCur.value);
|
|
||||||
loading.value = false;
|
|
||||||
showSnackbar({
|
|
||||||
text: `已成功备份 ${uidCur.value} 的祈愿数据`,
|
|
||||||
});
|
|
||||||
await TGLogger.Info(
|
|
||||||
`[UserGacha][${uidCur.value}][backupGacha] 成功备份 ${gachaListCur.value.length} 条祈愿数据`,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 删除当前 UID 的祈愿数据
|
// 删除当前 UID 的祈愿数据
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/**
|
/**
|
||||||
* @file plugins/Sqlite/modules/userGacha.ts
|
* @file plugins/Sqlite/modules/userGacha.ts
|
||||||
* @description 用户祈愿模块
|
* @description 用户祈愿模块
|
||||||
* @since Beta v0.4.7
|
* @since Beta v0.5.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { AppCharacterData, AppWeaponData } from "../../../data/index.js";
|
import { AppCharacterData, AppWeaponData } from "../../../data/index.js";
|
||||||
@@ -135,6 +135,21 @@ async function mergeUIGF(uid: string, data: TGApp.Plugins.UIGF.GachaItem[]): Pro
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 合并祈愿数据(v4.0)
|
||||||
|
* @since Beta v0.5.0
|
||||||
|
* @param {TGApp.Plugins.UIGF.GachaHk4e} data - UIGF数据
|
||||||
|
* @return {Promise<void>}
|
||||||
|
*/
|
||||||
|
async function mergeUIGF4(data: TGApp.Plugins.UIGF.GachaHk4e): Promise<void> {
|
||||||
|
const db = await TGSqlite.getDB();
|
||||||
|
for (const gacha of data.list) {
|
||||||
|
const trans = transGacha(gacha);
|
||||||
|
const sql = importUIGFData(data.uid.toString(), trans);
|
||||||
|
await db.execute(sql);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const TSUserGacha = {
|
const TSUserGacha = {
|
||||||
getUidList,
|
getUidList,
|
||||||
getGachaCheck,
|
getGachaCheck,
|
||||||
@@ -142,6 +157,7 @@ const TSUserGacha = {
|
|||||||
getGachaItemType,
|
getGachaItemType,
|
||||||
deleteGachaRecords,
|
deleteGachaRecords,
|
||||||
mergeUIGF,
|
mergeUIGF,
|
||||||
|
mergeUIGF4,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default TSUserGacha;
|
export default TSUserGacha;
|
||||||
|
|||||||
74
src/types/Plugins/UIGF.d.ts
vendored
74
src/types/Plugins/UIGF.d.ts
vendored
@@ -1,28 +1,41 @@
|
|||||||
/**
|
/**
|
||||||
* @file types/Plugins/UIGF.d.ts
|
* @file types/Plugins/UIGF.d.ts
|
||||||
* @description UIGF 插件类型定义文件
|
* @description UIGF 插件类型定义文件
|
||||||
* @since Beta v0.3.5
|
* @since Beta v0.5.0
|
||||||
* @version UIGF v2.4
|
* @version UIGF v3.0 | UIGF v4.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
declare namespace TGApp.Plugins.UIGF {
|
declare namespace TGApp.Plugins.UIGF {
|
||||||
/**
|
/**
|
||||||
* @description UIGF 数据
|
* @description UIGF 数据
|
||||||
* @since Alpha v0.2.3
|
* @since Beta v0.5.0
|
||||||
* @interface FullData
|
* @interface Schema
|
||||||
* @property {Export} info - UIGF 头部信息
|
* @property {Info} info - UIGF 头部信息
|
||||||
* @property {GachaItem[]} list - UIGF 祈愿列表
|
* @property {GachaItem[]} list - UIGF 祈愿列表
|
||||||
* @return FullData
|
* @return Schema
|
||||||
*/
|
*/
|
||||||
interface FullData {
|
interface Schema {
|
||||||
info: Export;
|
info: Info;
|
||||||
list: GachaItem[];
|
list: GachaItem[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description UIGF 数据, v4.0
|
||||||
|
* @since Beta v0.5.0
|
||||||
|
* @interface Schema4
|
||||||
|
* @property {Info4} info - UIGF 头部信息
|
||||||
|
* @property {GachaItem4[]} hk4e - UIGF 祈愿列表,原神数据
|
||||||
|
* @return Schema4
|
||||||
|
*/
|
||||||
|
interface Schema4 {
|
||||||
|
info: Info4;
|
||||||
|
hk4e: GachaHk4e[];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description UIGF 头部信息
|
* @description UIGF 头部信息
|
||||||
* @since Beta v0.3.5
|
* @since Beta v0.5.0
|
||||||
* @interface Export
|
* @interface Info
|
||||||
* @see docs\UIGF.md
|
* @see docs\UIGF.md
|
||||||
* @property {string} uid - UID
|
* @property {string} uid - UID
|
||||||
* @property {string} lang - 语言
|
* @property {string} lang - 语言
|
||||||
@@ -32,9 +45,9 @@ declare namespace TGApp.Plugins.UIGF {
|
|||||||
* @property {string} export_app - 导出应用
|
* @property {string} export_app - 导出应用
|
||||||
* @property {string} export_app_version - 导出应用版本
|
* @property {string} export_app_version - 导出应用版本
|
||||||
* @property {number} region_time_zone - 时区
|
* @property {number} region_time_zone - 时区
|
||||||
* @return Export
|
* @return Info
|
||||||
*/
|
*/
|
||||||
interface Export {
|
interface Info {
|
||||||
uid: string;
|
uid: string;
|
||||||
lang: string;
|
lang: string;
|
||||||
uigf_version: string;
|
uigf_version: string;
|
||||||
@@ -45,6 +58,24 @@ declare namespace TGApp.Plugins.UIGF {
|
|||||||
region_time_zone?: number;
|
region_time_zone?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description UIGF 头部信息, v4.0
|
||||||
|
* @since Beta v0.5.0
|
||||||
|
* @interface Info4
|
||||||
|
* @see docs\UIGF4.md
|
||||||
|
* @property {string} export_timestamp - 导出时间戳(秒)
|
||||||
|
* @property {string} export_app - 导出应用
|
||||||
|
* @property {string} export_app_version - 导出应用版本
|
||||||
|
* @property {string} version - UIGF 版本
|
||||||
|
* @return Info4
|
||||||
|
*/
|
||||||
|
interface Info4 {
|
||||||
|
export_timestamp: string;
|
||||||
|
export_app: string;
|
||||||
|
export_app_version: string;
|
||||||
|
version: string;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description 祈愿类型
|
* @description 祈愿类型
|
||||||
* @since Alpha v0.2.3
|
* @since Alpha v0.2.3
|
||||||
@@ -97,6 +128,7 @@ declare namespace TGApp.Plugins.UIGF {
|
|||||||
* @return GachaItem
|
* @return GachaItem
|
||||||
*/
|
*/
|
||||||
interface GachaItem {
|
interface GachaItem {
|
||||||
|
uigf_gacha_type: string;
|
||||||
gacha_type: string;
|
gacha_type: string;
|
||||||
item_id?: string;
|
item_id?: string;
|
||||||
count?: string;
|
count?: string;
|
||||||
@@ -105,6 +137,22 @@ declare namespace TGApp.Plugins.UIGF {
|
|||||||
item_type?: string;
|
item_type?: string;
|
||||||
rank_type?: string;
|
rank_type?: string;
|
||||||
id: string;
|
id: string;
|
||||||
uigf_gacha_type: string;
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description UIGF 祈愿列表, v4.0,原神数据
|
||||||
|
* @since Beta v0.5.0
|
||||||
|
* @interface GachaHk4e
|
||||||
|
* @property {string|number} uid - UID
|
||||||
|
* @property {number} timezone - 时区
|
||||||
|
* @property {string} lang - 语言
|
||||||
|
* @property {GachaItem[]} list - 祈愿列表
|
||||||
|
* @return GachaHk4e
|
||||||
|
*/
|
||||||
|
interface GachaHk4e {
|
||||||
|
uid: string | number;
|
||||||
|
timezone: number;
|
||||||
|
lang?: string;
|
||||||
|
list: GachaItem[];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,12 +5,13 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { app, path } from "@tauri-apps/api";
|
import { app, path } from "@tauri-apps/api";
|
||||||
import { mkdir, exists, readTextFile, writeTextFile } from "@tauri-apps/plugin-fs";
|
import { readTextFile, writeTextFile } from "@tauri-apps/plugin-fs";
|
||||||
import Ajv from "ajv";
|
import Ajv from "ajv";
|
||||||
import { ErrorObject } from "ajv/lib/types/index.js";
|
import { ErrorObject } from "ajv/lib/types/index.js";
|
||||||
|
|
||||||
import showSnackbar from "../components/func/snackbar.js";
|
import showSnackbar from "../components/func/snackbar.js";
|
||||||
import { UigfSchema } from "../data/index.js";
|
import { Uigf4Schema, UigfSchema } from "../data/index.js";
|
||||||
|
import TSUserGacha from "../plugins/Sqlite/modules/userGacha.js";
|
||||||
|
|
||||||
import TGLogger from "./TGLogger.js";
|
import TGLogger from "./TGLogger.js";
|
||||||
import { timestampToDate } from "./toolFunc.js";
|
import { timestampToDate } from "./toolFunc.js";
|
||||||
@@ -31,9 +32,9 @@ function getUigfTimeZone(uid: string): number {
|
|||||||
* @description 获取 UIGF 头部信息
|
* @description 获取 UIGF 头部信息
|
||||||
* @since Beta v0.4.4
|
* @since Beta v0.4.4
|
||||||
* @param {string} uid - UID
|
* @param {string} uid - UID
|
||||||
* @returns {Promise<TGApp.Plugins.UIGF.Export>}
|
* @returns {Promise<TGApp.Plugins.UIGF.Info>}
|
||||||
*/
|
*/
|
||||||
export async function getUigfHeader(uid: string): Promise<TGApp.Plugins.UIGF.Export> {
|
async function getUigfHeader(uid: string): Promise<TGApp.Plugins.UIGF.Info> {
|
||||||
const stamp = Date.now();
|
const stamp = Date.now();
|
||||||
return {
|
return {
|
||||||
uid,
|
uid,
|
||||||
@@ -47,13 +48,28 @@ export async function getUigfHeader(uid: string): Promise<TGApp.Plugins.UIGF.Exp
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 获取 UIGF v4.0 头部信息
|
||||||
|
* @since Beta v0.5.0
|
||||||
|
* @returns {TGApp.Plugins.UIGF.Info4} UIGF v4.0 头部信息
|
||||||
|
*/
|
||||||
|
async function getUigf4Header(): Promise<TGApp.Plugins.UIGF.Info4> {
|
||||||
|
const stamp = Date.now();
|
||||||
|
return {
|
||||||
|
export_timestamp: Math.floor(stamp / 1000).toString(),
|
||||||
|
export_app: "TeyvatGuide",
|
||||||
|
export_app_version: await app.getVersion(),
|
||||||
|
version: "v4.0",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description 数据转换-数据库到 UIGF
|
* @description 数据转换-数据库到 UIGF
|
||||||
* @since Alpha v0.2.3
|
* @since Alpha v0.2.3
|
||||||
* @param {TGApp.Sqlite.GachaRecords.SingleTable[]} data - 数据库数据
|
* @param {TGApp.Sqlite.GachaRecords.SingleTable[]} data - 数据库数据
|
||||||
* @returns {TGApp.Plugins.UIGF.GachaItem[]} UIGF 数据
|
* @returns {TGApp.Plugins.UIGF.GachaItem[]} UIGF 数据
|
||||||
*/
|
*/
|
||||||
export function convertDataToUigf(
|
function convertDataToUigf(
|
||||||
data: TGApp.Sqlite.GachaRecords.SingleTable[],
|
data: TGApp.Sqlite.GachaRecords.SingleTable[],
|
||||||
): TGApp.Plugins.UIGF.GachaItem[] {
|
): TGApp.Plugins.UIGF.GachaItem[] {
|
||||||
return data.map((gacha) => {
|
return data.map((gacha) => {
|
||||||
@@ -75,26 +91,15 @@ export function convertDataToUigf(
|
|||||||
* @description 检测是否存在 UIGF 数据,采用 ajv 验证 schema
|
* @description 检测是否存在 UIGF 数据,采用 ajv 验证 schema
|
||||||
* @since Beta v0.5.0
|
* @since Beta v0.5.0
|
||||||
* @param {string} path - UIGF 数据路径
|
* @param {string} path - UIGF 数据路径
|
||||||
|
* @param {boolean} isVersion4 - 是否为 UIGF v4.0
|
||||||
* @returns {Promise<boolean>} 是否存在 UIGF 数据
|
* @returns {Promise<boolean>} 是否存在 UIGF 数据
|
||||||
*/
|
*/
|
||||||
export async function verifyUigfData(path: string): Promise<boolean> {
|
export async function verifyUigfData(path: string, isVersion4: boolean = false): Promise<boolean> {
|
||||||
const fileData: string = await readTextFile(path);
|
const fileData: string = await readTextFile(path);
|
||||||
const ajv = new Ajv();
|
|
||||||
const validate = ajv.compile(UigfSchema);
|
|
||||||
try {
|
try {
|
||||||
const fileJson = JSON.parse(fileData);
|
const fileJson = JSON.parse(fileData);
|
||||||
if (!validate(fileJson)) {
|
if (isVersion4) return validateUigf4Data(fileJson);
|
||||||
if (!validate.errors || validate.errors.length === 0) return false;
|
return validateUigfData(fileJson);
|
||||||
const error: ErrorObject = validate.errors[0];
|
|
||||||
showSnackbar({
|
|
||||||
text: `${error.instancePath || error.schemaPath} ${error.message}`,
|
|
||||||
color: "error",
|
|
||||||
});
|
|
||||||
await TGLogger.Error(`UIGF 数据验证失败,文件路径:${path}`);
|
|
||||||
await TGLogger.Error(`错误信息 ${validate.errors}`);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
showSnackbar({ text: `UIGF 数据格式错误 ${e}`, color: "error" });
|
showSnackbar({ text: `UIGF 数据格式错误 ${e}`, color: "error" });
|
||||||
await TGLogger.Error(`UIGF 数据格式错误,文件路径:${path}`);
|
await TGLogger.Error(`UIGF 数据格式错误,文件路径:${path}`);
|
||||||
@@ -103,15 +108,68 @@ export async function verifyUigfData(path: string): Promise<boolean> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 验证 UIGF 数据
|
||||||
|
* @since Beta v0.5.0
|
||||||
|
* @param {object} data - UIGF 数据
|
||||||
|
* @returns {boolean} 是否验证通过
|
||||||
|
*/
|
||||||
|
function validateUigfData(data: object): boolean {
|
||||||
|
const ajv = new Ajv();
|
||||||
|
const validate = ajv.compile(UigfSchema);
|
||||||
|
if (!validate(data)) {
|
||||||
|
if (!validate.errors || validate.errors.length === 0) return false;
|
||||||
|
const error: ErrorObject = validate.errors[0];
|
||||||
|
showSnackbar({
|
||||||
|
text: `${error.instancePath || error.schemaPath} ${error.message}`,
|
||||||
|
color: "error",
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 验证 UIGF v4.0 数据
|
||||||
|
* @since Beta v0.5.0
|
||||||
|
* @param {object} data - UIGF 数据
|
||||||
|
* @returns {boolean} 是否验证通过
|
||||||
|
*/
|
||||||
|
function validateUigf4Data(data: object): boolean {
|
||||||
|
const ajv = new Ajv();
|
||||||
|
const validate4 = ajv.compile(Uigf4Schema);
|
||||||
|
if (!validate4(data)) {
|
||||||
|
if (!validate4.errors || validate4.errors.length === 0) return false;
|
||||||
|
const error: ErrorObject = validate4.errors[0];
|
||||||
|
showSnackbar({
|
||||||
|
text: `${error.instancePath || error.schemaPath} ${error.message}`,
|
||||||
|
color: "error",
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description 读取 UIGF 数据
|
* @description 读取 UIGF 数据
|
||||||
* @since Beta v0.5.0
|
* @since Beta v0.5.0
|
||||||
* @param {string} userPath - UIGF 数据路径
|
* @param {string} userPath - UIGF 数据路径
|
||||||
* @returns {Promise<TGApp.Plugins.UIGF.FullData>} UIGF 数据
|
* @returns {Promise<TGApp.Plugins.UIGF.Schema>} UIGF 数据
|
||||||
*/
|
*/
|
||||||
export async function readUigfData(userPath: string): Promise<TGApp.Plugins.UIGF.FullData> {
|
export async function readUigfData(userPath: string): Promise<TGApp.Plugins.UIGF.Schema> {
|
||||||
const fileData = await readTextFile(userPath);
|
const fileData: string = await readTextFile(userPath);
|
||||||
return <TGApp.Plugins.UIGF.FullData>JSON.parse(fileData);
|
return JSON.parse(fileData);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 读取 UIGF 4.0 数据
|
||||||
|
* @since Beta v0.5.0
|
||||||
|
* @param {string} userPath - UIGF 数据路径
|
||||||
|
* @returns {Promise<TGApp.Plugins.UIGF.Schema4>} UIGF 数据
|
||||||
|
*/
|
||||||
|
export async function readUigf4Data(userPath: string): Promise<TGApp.Plugins.UIGF.Schema4> {
|
||||||
|
const fileData: string = await readTextFile(userPath);
|
||||||
|
return JSON.parse(fileData);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -136,18 +194,31 @@ export async function exportUigfData(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description 备份 UIGF 数据
|
* @description 导出 UIGF v4.0 数据
|
||||||
* @since Beta v0.5.0
|
* @since Beta v0.5.0
|
||||||
* @param {string} dirPath - 备份路径
|
* @param {string} filePath - 保存路径
|
||||||
* @param {string} uid - UID
|
* @param {string} uid - UID,如果为空表示导出所有数据
|
||||||
* @param {TGApp.Sqlite.GachaRecords.SingleTable[]} gachaList - 祈愿列表
|
|
||||||
* @returns {Promise<void>}
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
export async function backupUigfData(
|
export async function exportUigf4Data(filePath: string, uid?: string): Promise<void> {
|
||||||
dirPath: string,
|
const UigfData: TGApp.Plugins.UIGF.Schema4 = {
|
||||||
uid: string,
|
info: await getUigf4Header(),
|
||||||
gachaList: TGApp.Sqlite.GachaRecords.SingleTable[],
|
hk4e: [],
|
||||||
): Promise<void> {
|
};
|
||||||
if (!(await exists(dirPath))) await mkdir(dirPath, { recursive: true });
|
let uidList: string[] = [];
|
||||||
await exportUigfData(uid, gachaList, `${dirPath}${path.sep()}UIGF_${uid}.json`);
|
if (uid) {
|
||||||
|
uidList.push(uid);
|
||||||
|
} else {
|
||||||
|
uidList = await TSUserGacha.getUidList();
|
||||||
|
}
|
||||||
|
for (const uid of uidList) {
|
||||||
|
const gachaList = await TSUserGacha.getGachaRecords(uid);
|
||||||
|
const data: TGApp.Plugins.UIGF.GachaHk4e = {
|
||||||
|
uid: uid,
|
||||||
|
timezone: getUigfTimeZone(uid),
|
||||||
|
list: convertDataToUigf(gachaList),
|
||||||
|
};
|
||||||
|
UigfData.hk4e.push(data);
|
||||||
|
}
|
||||||
|
await writeTextFile(filePath, JSON.stringify(UigfData));
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user