mirror of
https://github.com/BTMuli/TeyvatGuide.git
synced 2026-05-21 05:25:45 +08:00
🎨 fix(db): 改进代码结构
This commit is contained in:
44
src/App.vue
44
src/App.vue
@@ -33,12 +33,6 @@ import TBackTop from "./components/t-backTop.vue";
|
|||||||
import { fs, window, app, event } from "@tauri-apps/api";
|
import { fs, window, app, event } from "@tauri-apps/api";
|
||||||
// store
|
// store
|
||||||
import { useAppStore } from "./store/modules/app";
|
import { useAppStore } from "./store/modules/app";
|
||||||
import { useAchievementsStore } from "./store/modules/achievements";
|
|
||||||
// utils
|
|
||||||
import { getBuildTime } from "./utils/TGBuild";
|
|
||||||
// data
|
|
||||||
import { restoreUiafData } from "./utils/UIAF";
|
|
||||||
import TGSqlite from "./core/database/TGSqlite";
|
|
||||||
|
|
||||||
const appStore = useAppStore();
|
const appStore = useAppStore();
|
||||||
const isMain = ref(true as boolean);
|
const isMain = ref(true as boolean);
|
||||||
@@ -70,22 +64,11 @@ async function listenOnTheme () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function checkLoad () {
|
async function checkLoad () {
|
||||||
const localBuildTime = appStore.buildTime;
|
|
||||||
const buildTime = getBuildTime();
|
|
||||||
if (!buildTime.startsWith("dev")) {
|
|
||||||
if (localBuildTime.startsWith("dev") || localBuildTime < buildTime) {
|
|
||||||
appStore.buildTime = buildTime;
|
|
||||||
console.info("数据已过期,开始加载数据...");
|
|
||||||
appStore.loading = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (appStore.loading) {
|
if (appStore.loading) {
|
||||||
console.info("数据已加载!");
|
console.info("数据已加载!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await createDataDir();
|
await createDataDir();
|
||||||
await writeDB();
|
|
||||||
await writeData();
|
|
||||||
appStore.loading = true;
|
appStore.loading = true;
|
||||||
console.info("数据加载完成!");
|
console.info("数据加载完成!");
|
||||||
}
|
}
|
||||||
@@ -97,33 +80,6 @@ async function createDataDir () {
|
|||||||
if (!await fs.exists("tempData", { dir: fs.BaseDirectory.AppLocalData })) { await fs.createDir("tempData", { 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("数据文件夹创建完成!");
|
console.info("数据文件夹创建完成!");
|
||||||
}
|
}
|
||||||
// 写入 IndexedDB
|
|
||||||
async function writeDB () {
|
|
||||||
const res = await TGSqlite.checkDB();
|
|
||||||
if (!res) {
|
|
||||||
console.info("检测到数据库不完整,正在重置数据库...");
|
|
||||||
await TGSqlite.resetDB();
|
|
||||||
} else {
|
|
||||||
console.info("正在更新成就系列数据...");
|
|
||||||
await TGSqlite.update.achievementSeries();
|
|
||||||
console.info("正在更新成就数据...");
|
|
||||||
await TGSqlite.update.achievement();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 恢复数据
|
|
||||||
async function writeData () {
|
|
||||||
console.info("开始恢复数据...");
|
|
||||||
const res = await restoreUiafData();
|
|
||||||
if (res !== false) {
|
|
||||||
const { total, fin } = res;
|
|
||||||
console.info("开始恢复成就数据...");
|
|
||||||
const achievementsStore = useAchievementsStore();
|
|
||||||
achievementsStore.flushData(total, fin);
|
|
||||||
console.info("成就数据恢复完成!");
|
|
||||||
} else {
|
|
||||||
console.info("未找到成就数据!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
<style lang="css">
|
<style lang="css">
|
||||||
.app-main {
|
.app-main {
|
||||||
|
|||||||
@@ -1,36 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file core database TGSqlite.ts
|
|
||||||
* @description SQLite 数据库相关
|
|
||||||
* @author BTMuli<bt-muli@outlook.com>
|
|
||||||
* @since Alpha v0.1.4
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { initDatabase, resetDatabase, checkDatabase, sqlitePath } from "./init";
|
|
||||||
import { getAllSeries, getAchievementsBySeries, searchAchievement, getAchievementOverview } from "./select";
|
|
||||||
import { importUIAFData, exportUIAFData } from "./UIAF";
|
|
||||||
import { checkAchievement, checkAchievementSeries } from "./update";
|
|
||||||
|
|
||||||
const TGSqlite = {
|
|
||||||
initDB: initDatabase,
|
|
||||||
resetDB: resetDatabase,
|
|
||||||
checkDB: checkDatabase,
|
|
||||||
search: {
|
|
||||||
achievement: {
|
|
||||||
bySeries: getAchievementsBySeries,
|
|
||||||
bySearch: searchAchievement,
|
|
||||||
},
|
|
||||||
achievementSeries: getAllSeries,
|
|
||||||
overview: getAchievementOverview,
|
|
||||||
},
|
|
||||||
UIAF: {
|
|
||||||
import: importUIAFData,
|
|
||||||
export: exportUIAFData,
|
|
||||||
},
|
|
||||||
update: {
|
|
||||||
achievement: checkAchievement,
|
|
||||||
achievementSeries: checkAchievementSeries,
|
|
||||||
},
|
|
||||||
dbPath: sqlitePath,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default TGSqlite;
|
|
||||||
@@ -1,86 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file core database UIAF.ts
|
|
||||||
* @description UIAF 数据导入导出
|
|
||||||
* @author BTMuli<bt-muli@outlook.com>
|
|
||||||
* @since Alpha v0.1.4
|
|
||||||
*/
|
|
||||||
|
|
||||||
// tauri
|
|
||||||
import Database from "tauri-plugin-sql-api";
|
|
||||||
// local
|
|
||||||
import { sqlitePath } from "./init";
|
|
||||||
// utils
|
|
||||||
import { timestampToDate, getUiafStatus } from "../../utils/UIAF";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 根据本地数据跟导入数据获取更新 SQL
|
|
||||||
* @since Alpha v0.1.4
|
|
||||||
* @param {TGPlugin.UIAF.Achievement} importData - 导入数据
|
|
||||||
* @param {BTMuli.SQLite.Achievements} localData - 本地数据
|
|
||||||
* @returns {string} SQL
|
|
||||||
*/
|
|
||||||
function getUpdateSql (importData: TGPlugin.UIAF.Achievement, localData: BTMuli.SQLite.Achievements): string {
|
|
||||||
// 如果本地为未完成状态,直接更新
|
|
||||||
if (localData.isCompleted === 0) {
|
|
||||||
// 已完成
|
|
||||||
if (importData.status === 2 || importData.status === 3) {
|
|
||||||
const completedTime = timestampToDate(importData.timestamp);
|
|
||||||
return `UPDATE Achievements SET isCompleted = 1, progress = ${importData.current}, completedTime = '${completedTime}' WHERE id = ${importData.id}`;
|
|
||||||
} else if (importData.current > localData.progress) {
|
|
||||||
return `UPDATE Achievements SET progress = ${importData.current} WHERE id = ${importData.id}`;
|
|
||||||
} else {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 本地为已完成状态,判断进度
|
|
||||||
if (importData.current > localData.progress) {
|
|
||||||
// 进度大于本地进度,更新
|
|
||||||
return `UPDATE Achievements SET progress = ${importData.current} WHERE id = ${importData.id}`;
|
|
||||||
} else {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 导入 UIAF 数据,更新数据库
|
|
||||||
* @since Alpha v0.1.4
|
|
||||||
* @param {TGPlugin.UIAF.Achievement[]} achievements - 成就列表
|
|
||||||
* @returns {Promise<void>}
|
|
||||||
*/
|
|
||||||
export async function importUIAFData (achievements: TGPlugin.UIAF.Achievement[]): Promise<void> {
|
|
||||||
const db = await Database.load(sqlitePath);
|
|
||||||
for (const achievement of achievements) {
|
|
||||||
const id = achievement.id;
|
|
||||||
const selects: BTMuli.SQLite.Achievements[] = await db.select(`SELECT * FROM Achievements WHERE id = ${id}`);
|
|
||||||
if (selects.length === 1) {
|
|
||||||
const sql = getUpdateSql(achievement, selects[0]);
|
|
||||||
if (sql !== "") await db.execute(sql);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
await db.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 导出 UIAF 数据
|
|
||||||
* @since Alpha v0.1.4
|
|
||||||
* @returns {Promise<TGPlugin.UIAF.Achievement[]>}
|
|
||||||
*/
|
|
||||||
export async function exportUIAFData (): Promise<TGPlugin.UIAF.Achievement[]> {
|
|
||||||
const db = await Database.load(sqlitePath);
|
|
||||||
const sql = "SELECT * FROM Achievements WHERE isCompleted = 1 OR progress > 0";
|
|
||||||
const selects: BTMuli.SQLite.Achievements[] = await db.select(sql);
|
|
||||||
await db.close();
|
|
||||||
const achievements: TGPlugin.UIAF.Achievement[] = [];
|
|
||||||
for (const select of selects) {
|
|
||||||
const completed = select.isCompleted === 1;
|
|
||||||
const status = getUiafStatus(completed, select.progress);
|
|
||||||
achievements.push({
|
|
||||||
id: select.id,
|
|
||||||
status,
|
|
||||||
timestamp: completed && select.completedTime ? Math.round(new Date(select.completedTime).getTime() / 1000) : 0,
|
|
||||||
current: select.progress,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return achievements;
|
|
||||||
}
|
|
||||||
@@ -1,142 +0,0 @@
|
|||||||
/*
|
|
||||||
* @file core database init.sql
|
|
||||||
* @description SQLite 初始化
|
|
||||||
* @author BTMuli<bt-muli@outlook>
|
|
||||||
* @since Alpha v0.1.4
|
|
||||||
*/
|
|
||||||
|
|
||||||
-- /////////////////////////////
|
|
||||||
-- 创建各种表
|
|
||||||
-- /////////////////////////////
|
|
||||||
-- ----------------------------
|
|
||||||
-- 成就系列表
|
|
||||||
-- @table AchievementSeries
|
|
||||||
-- @field {number} id 成就系列ID,主键
|
|
||||||
-- @field {number} order 成就系列排列顺序
|
|
||||||
-- @field {string} name 成就系列名称
|
|
||||||
-- @field {string} version 成就系列版本
|
|
||||||
-- @field {number} totalCount 成就系列总成就数
|
|
||||||
-- @field {number} finCount 成就系列已完成成就数
|
|
||||||
-- @field {string} icon 成就系列图标
|
|
||||||
-- @field {string} nameCard 成就系列名片名称
|
|
||||||
-- @field {string} updated 数据更新时间
|
|
||||||
-- ----------------------------
|
|
||||||
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 DEFAULT NULL,
|
|
||||||
updated TEXT DEFAULT NULL
|
|
||||||
);
|
|
||||||
-- ----------------------------
|
|
||||||
-- 成就数据表
|
|
||||||
-- @table Achievements
|
|
||||||
-- @field {number} id 成就ID,主键
|
|
||||||
-- @field {number} series 成就系列ID,为成就系列表的主键
|
|
||||||
-- @field {number} order 成就排序
|
|
||||||
-- @field {string} name 成就名称
|
|
||||||
-- @field {string} description 成就描述
|
|
||||||
-- @field {number} reward 成就奖励
|
|
||||||
-- @field {boolean} isCompleted 成就是否已完成,默认为false
|
|
||||||
-- @field {string} completedTime 成就完成时间,默认为null
|
|
||||||
-- @field {number} progress 成就进度,默认为0
|
|
||||||
-- @field {string} version 成就版本
|
|
||||||
-- @field {string} updated 数据更新时间
|
|
||||||
-- ----------------------------
|
|
||||||
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
|
|
||||||
);
|
|
||||||
|
|
||||||
-- /////////////////////////////
|
|
||||||
-- 创建各种触发器
|
|
||||||
-- /////////////////////////////
|
|
||||||
-- ----------------------------
|
|
||||||
-- 成就系列数据插入触发器
|
|
||||||
-- @trigger SeriesInsert
|
|
||||||
-- @description 当成就系列数据插入时,更新更新时间
|
|
||||||
-- ----------------------------
|
|
||||||
CREATE TRIGGER IF NOT EXISTS SeriesInsert
|
|
||||||
AFTER INSERT
|
|
||||||
ON AchievementSeries
|
|
||||||
FOR EACH ROW
|
|
||||||
BEGIN
|
|
||||||
UPDATE AchievementSeries SET updated = datetime('now') WHERE id = NEW.id;
|
|
||||||
END;
|
|
||||||
-- ----------------------------
|
|
||||||
-- 成就系列数据更新触发器
|
|
||||||
-- @trigger SeriesUpdate
|
|
||||||
-- @description 当成就系列数据更新时,更新更新时间
|
|
||||||
-- ----------------------------
|
|
||||||
CREATE TRIGGER IF NOT EXISTS SeriesUpdate
|
|
||||||
AFTER UPDATE
|
|
||||||
OF totalCount, finCount, version
|
|
||||||
ON AchievementSeries
|
|
||||||
FOR EACH ROW
|
|
||||||
BEGIN
|
|
||||||
UPDATE AchievementSeries SET updated = datetime('now') WHERE id = NEW.id;
|
|
||||||
END;
|
|
||||||
-- ----------------------------
|
|
||||||
-- 成就数据插入触发器
|
|
||||||
-- @trigger AchievementInsert
|
|
||||||
-- @description 当成就数据插入时,更新成就系列表中的数据
|
|
||||||
-- ----------------------------
|
|
||||||
CREATE TRIGGER IF NOT EXISTS AchievementInsert
|
|
||||||
AFTER INSERT
|
|
||||||
ON Achievements
|
|
||||||
FOR EACH ROW
|
|
||||||
BEGIN
|
|
||||||
-- 更新更新时间
|
|
||||||
UPDATE Achievements SET updated = datetime('now') WHERE id = NEW.id;
|
|
||||||
-- 更新成就系列总数
|
|
||||||
UPDATE AchievementSeries SET totalCount = AchievementSeries.totalCount + 1 WHERE id = NEW.series;
|
|
||||||
-- 如果是已完成成就,则更新成就系列完成数
|
|
||||||
UPDATE AchievementSeries
|
|
||||||
SET finCount = AchievementSeries.finCount + 1
|
|
||||||
WHERE NEW.isCompleted = 1 AND id = NEW.series;
|
|
||||||
-- 如果成就系列版本低于成就版本,则更新成就系列版本
|
|
||||||
UPDATE AchievementSeries SET version = NEW.version WHERE version < NEW.version AND id = NEW.series;
|
|
||||||
END;
|
|
||||||
-- ----------------------------
|
|
||||||
-- 成就数据更新触发器
|
|
||||||
-- @trigger AchievementUpdate
|
|
||||||
-- @description 当成就数据更新时,更新成就系列表中的数据
|
|
||||||
-- ----------------------------
|
|
||||||
CREATE TRIGGER IF NOT EXISTS AchievementUpdate
|
|
||||||
AFTER UPDATE
|
|
||||||
OF isCompleted, completedTime, progress
|
|
||||||
ON Achievements
|
|
||||||
FOR EACH ROW
|
|
||||||
BEGIN
|
|
||||||
-- 更新更新时间
|
|
||||||
UPDATE Achievements
|
|
||||||
SET updated = datetime('now')
|
|
||||||
WHERE id = NEW.id;
|
|
||||||
-- 如果是已完成成就,则更新成就系列完成数
|
|
||||||
UPDATE AchievementSeries
|
|
||||||
SET finCount = AchievementSeries.finCount + 1
|
|
||||||
WHERE id = NEW.series
|
|
||||||
AND OLD.isCompleted = 0
|
|
||||||
AND NEW.isCompleted = 1;
|
|
||||||
-- 如果是未完成成就,则更新成就系列完成数
|
|
||||||
UPDATE AchievementSeries
|
|
||||||
SET finCount = AchievementSeries.finCount - 1
|
|
||||||
WHERE id = NEW.series
|
|
||||||
AND OLD.isCompleted = 1
|
|
||||||
AND NEW.isCompleted = 0;
|
|
||||||
END;
|
|
||||||
@@ -1,99 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file core database init.ts
|
|
||||||
* @description SQLite 数据库初始化
|
|
||||||
* @author BTMuli<bt-muli@outlook.com>
|
|
||||||
* @since Alpha v0.1.4
|
|
||||||
*/
|
|
||||||
|
|
||||||
// tauri
|
|
||||||
import Database from "tauri-plugin-sql-api";
|
|
||||||
// sql
|
|
||||||
import initSql from "./init.sql?raw";
|
|
||||||
// local
|
|
||||||
import { TGAppData } from "../../data";
|
|
||||||
|
|
||||||
export const sqlitePath = "sqlite:tauri-genshin.db";
|
|
||||||
export const sqliteTBList = ["Achievements", "AchievementSeries"];
|
|
||||||
export const sqliteTGList = ["SeriesInsert", "SeriesUpdate", "AchievementInsert", "AchievementUpdate"];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 初始化数据库
|
|
||||||
* @since Alpha v0.1.4
|
|
||||||
* @returns {Promise<void>}
|
|
||||||
*/
|
|
||||||
export async function initDatabase (): Promise<void> {
|
|
||||||
const db = await Database.load(sqlitePath);
|
|
||||||
// 初始化表格、触发器
|
|
||||||
await db.execute(initSql);
|
|
||||||
// 初始化数据
|
|
||||||
await insertData(db);
|
|
||||||
await db.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 初始化数据
|
|
||||||
* @since Alpha v0.1.4
|
|
||||||
* @param {Database} db
|
|
||||||
* @returns {Promise<void>}
|
|
||||||
*/
|
|
||||||
async function insertData (db: Database): Promise<void> {
|
|
||||||
// 插入成就系列数据
|
|
||||||
await Promise.all(Object.values(TGAppData.achievementSeries).map(async (item) => {
|
|
||||||
let sql;
|
|
||||||
if (item.card) {
|
|
||||||
sql = `INSERT INTO AchievementSeries (id, \`order\`, name, version, icon, nameCard) VALUES (${item.id}, ${item.order}, '${item.name}', '${item.version}', '${item.icon}', '${item.card}')`;
|
|
||||||
} else {
|
|
||||||
sql = `INSERT INTO AchievementSeries (id, \`order\`, name, version, icon, nameCard) VALUES (${item.id}, ${item.order}, '${item.name}', '${item.version}', '${item.icon}', NULL)`;
|
|
||||||
}
|
|
||||||
await db.execute(sql);
|
|
||||||
},
|
|
||||||
));
|
|
||||||
// 插入成就数据
|
|
||||||
await Promise.all(Object.values(TGAppData.achievements).map(async (item) => {
|
|
||||||
const sql = `INSERT INTO Achievements (id, series, \`order\`, name, description, reward, version) VALUES (${item.id}, ${item.series}, ${item.order}, '${item.name}', '${item.description}', ${item.reward}, '${item.version}')`;
|
|
||||||
await db.execute(sql);
|
|
||||||
},
|
|
||||||
));
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 删除所有数据,重新创建数据
|
|
||||||
* @since Alpha v0.1.4
|
|
||||||
* @returns {Promise<void>}
|
|
||||||
*/
|
|
||||||
export async function resetDatabase (): Promise<void> {
|
|
||||||
const db = await Database.load(sqlitePath);
|
|
||||||
// 删除所有触发器
|
|
||||||
await Promise.all(sqliteTGList.map(async (trigger) => {
|
|
||||||
await db.execute(`DROP TRIGGER IF EXISTS ${trigger}`);
|
|
||||||
}));
|
|
||||||
// 删除所有表格
|
|
||||||
await Promise.all(sqliteTBList.map(async (table) => {
|
|
||||||
await db.execute(`DROP TABLE IF EXISTS ${table}`);
|
|
||||||
}));
|
|
||||||
await db.close();
|
|
||||||
await initDatabase();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 检测表单是否完整
|
|
||||||
* @since Alpha v0.1.4
|
|
||||||
* @returns {Promise<boolean>}
|
|
||||||
*/
|
|
||||||
export async function checkDatabase (): Promise<boolean> {
|
|
||||||
const db = await Database.load(sqlitePath);
|
|
||||||
// 获取所有表格
|
|
||||||
const tables: Array<{ name: string }> = await db.select("SELECT name FROM sqlite_master WHERE type='table' ORDER BY name");
|
|
||||||
// 获取所有触发器
|
|
||||||
const triggers: Array<{ name: string }> = await db.select("SELECT name FROM sqlite_master WHERE type='trigger' ORDER BY name");
|
|
||||||
await db.close();
|
|
||||||
let res;
|
|
||||||
if (tables.length !== sqliteTBList.length || triggers.length !== sqliteTGList.length) {
|
|
||||||
res = false;
|
|
||||||
} else if (tables.every((item) => sqliteTBList.includes(item.name)) && triggers.every((item) => sqliteTGList.includes(item.name))) {
|
|
||||||
res = true;
|
|
||||||
} else {
|
|
||||||
res = false;
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file core database select.ts
|
|
||||||
* @description SQLite 数据库查询操作封装模块
|
|
||||||
* @author BTMuli<bt-muli@outlook.com>
|
|
||||||
* @since Alpha v0.1.4
|
|
||||||
*/
|
|
||||||
|
|
||||||
// tauri
|
|
||||||
import Database from "tauri-plugin-sql-api";
|
|
||||||
// local
|
|
||||||
import { sqlitePath } from "./init";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 返回所有成就系列数据
|
|
||||||
* @since Alpha v0.1.4
|
|
||||||
* @returns {Promise<BTMuli.SQLite.AchievementSeries[]>}
|
|
||||||
*/
|
|
||||||
export async function getAllSeries (): Promise<BTMuli.SQLite.AchievementSeries[]> {
|
|
||||||
const db = await Database.load(sqlitePath);
|
|
||||||
const sql = "SELECT * FROM AchievementSeries ORDER BY `order` ASC";
|
|
||||||
const result = await db.select(sql);
|
|
||||||
await db.close();
|
|
||||||
return result as BTMuli.SQLite.AchievementSeries[];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 查询成就数据,无参默认查询所有成就
|
|
||||||
* @since Alpha v0.1.4
|
|
||||||
* @param {number} series
|
|
||||||
* @returns {Promise<BTMuli.SQLite.Achievements[]>}
|
|
||||||
*/
|
|
||||||
export async function getAchievementsBySeries (series?: number): Promise<BTMuli.SQLite.Achievements[]> {
|
|
||||||
const db = await Database.load(sqlitePath);
|
|
||||||
let sql;
|
|
||||||
// 无参默认查询所有成就
|
|
||||||
if (!series) {
|
|
||||||
sql = "SELECT * FROM Achievements";
|
|
||||||
} else {
|
|
||||||
sql = `SELECT * FROM Achievements WHERE series = ${series}`;
|
|
||||||
}
|
|
||||||
const result = await db.select(sql);
|
|
||||||
await db.close();
|
|
||||||
return result as BTMuli.SQLite.Achievements[];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 条件查询
|
|
||||||
* @since Alpha v0.1.4
|
|
||||||
* @param {string} search
|
|
||||||
* @returns {Promise<BTMuli.SQLite.Achievements[]>}
|
|
||||||
*/
|
|
||||||
export async function searchAchievement (search: string): Promise<BTMuli.SQLite.Achievements[]> {
|
|
||||||
const db = await Database.load(sqlitePath);
|
|
||||||
const sql = `SELECT * FROM Achievements WHERE name LIKE '%${search}%' OR description LIKE '%${search}%'`;
|
|
||||||
const result = await db.select(sql);
|
|
||||||
await db.close();
|
|
||||||
return result as BTMuli.SQLite.Achievements[];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 返回成就概况
|
|
||||||
* @since Alpha v0.1.4
|
|
||||||
* @returns {Promise<{total: number, fin:number}>}
|
|
||||||
*/
|
|
||||||
export async function getAchievementOverview (): Promise<{ total: number, fin: number }> {
|
|
||||||
const db = await Database.load(sqlitePath);
|
|
||||||
const sql = "SELECT COUNT(*) AS total, SUM(isCompleted) AS fin FROM Achievements";
|
|
||||||
const res: Array<{ total: number, fin: number }> = await db.select(sql);
|
|
||||||
await db.close();
|
|
||||||
return res[0];
|
|
||||||
}
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file core database update.ts
|
|
||||||
* @description SQLite 数据库更新相关
|
|
||||||
* @since Alpha v0.1.4
|
|
||||||
*/
|
|
||||||
|
|
||||||
// tauri
|
|
||||||
import Database from "tauri-plugin-sql-api";
|
|
||||||
// local
|
|
||||||
import { TGAppData } from "../../data";
|
|
||||||
import { sqlitePath } from "./init";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 数据比对-成就系列数据
|
|
||||||
* @description 数据只有两种情况:新增、更新
|
|
||||||
* @since Alpha v0.1.4
|
|
||||||
* @returns {Promise<boolean>}
|
|
||||||
*/
|
|
||||||
export async function checkAchievement (): Promise<void> {
|
|
||||||
const db = await Database.load(sqlitePath);
|
|
||||||
await Promise.all(Object.values(TGAppData.achievements).map(async (item) => {
|
|
||||||
// 检测是否存在
|
|
||||||
const selectRes: BTMuli.SQLite.Achievements[] = await db.select(`SELECT * FROM Achievements WHERE id = ${item.id}`);
|
|
||||||
if (!selectRes || selectRes.length === 0) {
|
|
||||||
// 不存在则插入
|
|
||||||
const sql = `INSERT INTO Achievements (id, series, \`order\`, name, description, reward, version) VALUES (${item.id}, ${item.series}, ${item.order}, '${item.name}', '${item.description}', ${item.reward}, '${item.version}')`;
|
|
||||||
await db.execute(sql);
|
|
||||||
} else {
|
|
||||||
// 比对两者数据
|
|
||||||
const selectItem = selectRes[0];
|
|
||||||
if (selectItem.name !== item.name || selectItem.description !== item.description || selectItem.reward !== item.reward) {
|
|
||||||
// 更新
|
|
||||||
const sql = `UPDATE Achievements SET name = '${item.name}', description = '${item.description}', reward = ${item.reward}, version = '${item.version}' WHERE id = ${item.id}`;
|
|
||||||
await db.execute(sql);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
await db.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 数据比对-成就系列数据
|
|
||||||
* @description 只有新增,更新靠触发器解决
|
|
||||||
* @since Alpha v0.1.4
|
|
||||||
* @returns {Promise<void>}
|
|
||||||
*/
|
|
||||||
export async function checkAchievementSeries (): Promise<void> {
|
|
||||||
const db = await Database.load(sqlitePath);
|
|
||||||
await Promise.all(Object.values(TGAppData.achievementSeries).map(async (item) => {
|
|
||||||
// 检测是否存在
|
|
||||||
const selectRes: BTMuli.SQLite.AchievementSeries[] = await db.select(`SELECT * FROM AchievementSeries WHERE id = ${item.id}`);
|
|
||||||
if (!selectRes || selectRes.length === 0) {
|
|
||||||
// 不存在则插入
|
|
||||||
let sql;
|
|
||||||
if (item.card) {
|
|
||||||
sql = `INSERT INTO AchievementSeries (id, \`order\`, name, version, icon, nameCard) VALUES (${item.id}, ${item.order}, '${item.name}', '${item.version}', '${item.icon}', '${item.card}')`;
|
|
||||||
} else {
|
|
||||||
sql = `INSERT INTO AchievementSeries (id, \`order\`, name, version, icon, nameCard) VALUES (${item.id}, ${item.order}, '${item.name}', '${item.version}', '${item.icon}', NULL)`;
|
|
||||||
}
|
|
||||||
await db.execute(sql);
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
await db.close();
|
|
||||||
}
|
|
||||||
@@ -112,8 +112,8 @@ import { useAchievementsStore } from "../store/modules/achievements";
|
|||||||
// Utils
|
// Utils
|
||||||
import { TGAppData } from "../data";
|
import { TGAppData } from "../data";
|
||||||
import { createTGWindow } from "../utils/TGWindow";
|
import { createTGWindow } from "../utils/TGWindow";
|
||||||
import { getUiafHeader, readUiafData, verifyUiafData, backupUiafData } from "../utils/UIAF";
|
import { getUiafHeader, readUiafData, verifyUiafData } from "../utils/UIAF";
|
||||||
import TGSqlite from "../core/database/TGSqlite";
|
import TGSqlite from "../utils/TGSqlite";
|
||||||
|
|
||||||
// Store
|
// Store
|
||||||
const achievementsStore = useAchievementsStore();
|
const achievementsStore = useAchievementsStore();
|
||||||
@@ -144,13 +144,13 @@ onMounted(async () => {
|
|||||||
|
|
||||||
// 加载数据,数据源:合并后的本地数据
|
// 加载数据,数据源:合并后的本地数据
|
||||||
async function loadData () {
|
async function loadData () {
|
||||||
const { total, fin } = await TGSqlite.search.overview();
|
const { total, fin } = await TGSqlite.getAchievementsOverview();
|
||||||
achievementsStore.flushData(total, fin);
|
achievementsStore.flushData(total, fin);
|
||||||
loadingTitle.value = "正在获取成就系列数据";
|
loadingTitle.value = "正在获取成就系列数据";
|
||||||
CardsInfo.value = TGAppData.nameCards[1];
|
CardsInfo.value = TGAppData.nameCards[1];
|
||||||
seriesList.value = await TGSqlite.search.achievementSeries();
|
seriesList.value = await TGSqlite.getAchievementSeries();
|
||||||
loadingTitle.value = "正在获取成就数据";
|
loadingTitle.value = "正在获取成就数据";
|
||||||
const getAchievements = await TGSqlite.search.achievement.bySeries();
|
const getAchievements = await TGSqlite.getAchievements();
|
||||||
getAchievements.sort((a, b) => {
|
getAchievements.sort((a, b) => {
|
||||||
if (a.isCompleted === b.isCompleted) {
|
if (a.isCompleted === b.isCompleted) {
|
||||||
return a.id - b.id;
|
return a.id - b.id;
|
||||||
@@ -174,7 +174,7 @@ async function selectSeries (index: number) {
|
|||||||
loadingTitle.value = "正在获取对应的成就数据";
|
loadingTitle.value = "正在获取对应的成就数据";
|
||||||
selectedIndex.value = index;
|
selectedIndex.value = index;
|
||||||
selectedSeries.value = seriesList.value[index].id;
|
selectedSeries.value = seriesList.value[index].id;
|
||||||
const getAchievements = await TGSqlite.search.achievement.bySeries(selectedSeries.value);
|
const getAchievements = await TGSqlite.getAchievements(selectedSeries.value);
|
||||||
loadingTitle.value = "正在查找对应的成就名片";
|
loadingTitle.value = "正在查找对应的成就名片";
|
||||||
let getCard: BTMuli.Genshin.NameCard;
|
let getCard: BTMuli.Genshin.NameCard;
|
||||||
if (selectedSeries.value !== 0 && selectedSeries.value !== 17) {
|
if (selectedSeries.value !== 0 && selectedSeries.value !== 17) {
|
||||||
@@ -182,13 +182,6 @@ async function selectSeries (index: number) {
|
|||||||
} else {
|
} else {
|
||||||
getCard = {} as BTMuli.Genshin.NameCard;
|
getCard = {} as BTMuli.Genshin.NameCard;
|
||||||
}
|
}
|
||||||
getAchievements.sort((a, b) => {
|
|
||||||
if (a.isCompleted === b.isCompleted) {
|
|
||||||
return a.id - b.id;
|
|
||||||
} else {
|
|
||||||
return a.isCompleted ? 1 : -1;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
selectedAchievement.value = getAchievements;
|
selectedAchievement.value = getAchievements;
|
||||||
getCardInfo.value = getCard;
|
getCardInfo.value = getCard;
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
@@ -209,7 +202,7 @@ async function searchCard () {
|
|||||||
}
|
}
|
||||||
loadingTitle.value = "正在搜索";
|
loadingTitle.value = "正在搜索";
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
const res = await TGSqlite.search.achievement.bySearch(search.value);
|
const res = await TGSqlite.searchAchievements(search.value);
|
||||||
selectedIndex.value = -1;
|
selectedIndex.value = -1;
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
@@ -218,15 +211,8 @@ async function searchCard () {
|
|||||||
snackbarColor.value = "#F5810A";
|
snackbarColor.value = "#F5810A";
|
||||||
snackbarText.value = "没有找到对应的成就";
|
snackbarText.value = "没有找到对应的成就";
|
||||||
snackbar.value = true;
|
snackbar.value = true;
|
||||||
selectedAchievement.value = await TGSqlite.search.achievement.bySeries();
|
selectedAchievement.value = await TGSqlite.getAchievements();
|
||||||
} else {
|
} else {
|
||||||
res.sort((a, b) => {
|
|
||||||
if (a.isCompleted === b.isCompleted) {
|
|
||||||
return a.id - b.id;
|
|
||||||
} else {
|
|
||||||
return a.isCompleted ? 1 : -1;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
selectedAchievement.value = res;
|
selectedAchievement.value = res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -252,11 +238,9 @@ async function importJson () {
|
|||||||
loading.value = true;
|
loading.value = true;
|
||||||
const remoteData: TGPlugin.UIAF.BaseData = JSON.parse(remoteRaw);
|
const remoteData: TGPlugin.UIAF.BaseData = JSON.parse(remoteRaw);
|
||||||
loadingTitle.value = "正在合并成就数据";
|
loadingTitle.value = "正在合并成就数据";
|
||||||
await TGSqlite.UIAF.import(remoteData.list);
|
await TGSqlite.mergeUIAF(remoteData.list);
|
||||||
loadingTitle.value = "正在备份数据";
|
|
||||||
await backupAchievementData();
|
|
||||||
loadingTitle.value = "正在刷新数据";
|
loadingTitle.value = "正在刷新数据";
|
||||||
const overview = await TGSqlite.search.overview();
|
const overview = await TGSqlite.getAchievementsOverview();
|
||||||
achievementsStore.flushData(overview.total, overview.fin);
|
achievementsStore.flushData(overview.total, overview.fin);
|
||||||
// 刷新数据
|
// 刷新数据
|
||||||
await loadData();
|
await loadData();
|
||||||
@@ -264,12 +248,6 @@ async function importJson () {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 备份成就数据
|
|
||||||
async function backupAchievementData () {
|
|
||||||
const achievements = await TGSqlite.UIAF.export();
|
|
||||||
await backupUiafData(achievements);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 导出
|
// 导出
|
||||||
async function exportJson () {
|
async function exportJson () {
|
||||||
// 判断是否有数据
|
// 判断是否有数据
|
||||||
@@ -282,7 +260,7 @@ async function exportJson () {
|
|||||||
// 获取本地数据
|
// 获取本地数据
|
||||||
const UiafData = {
|
const UiafData = {
|
||||||
info: await getUiafHeader(),
|
info: await getUiafHeader(),
|
||||||
list: await TGSqlite.UIAF.export(),
|
list: await TGSqlite.getUIAF(),
|
||||||
};
|
};
|
||||||
const isSave = await dialog.save({
|
const isSave = await dialog.save({
|
||||||
// TODO: 设置保存文件名
|
// TODO: 设置保存文件名
|
||||||
@@ -295,10 +273,14 @@ async function exportJson () {
|
|||||||
});
|
});
|
||||||
if (isSave) {
|
if (isSave) {
|
||||||
await fs.writeTextFile(isSave, JSON.stringify(UiafData));
|
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>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -159,7 +159,7 @@ import { useHk4eStore } from "../store/modules/hk4e";
|
|||||||
import { useAchievementsStore } from "../store/modules/achievements";
|
import { useAchievementsStore } from "../store/modules/achievements";
|
||||||
// utils
|
// utils
|
||||||
import { backupUiafData, restoreUiafData } from "../utils/UIAF";
|
import { backupUiafData, restoreUiafData } from "../utils/UIAF";
|
||||||
import TGSqlite from "../core/database/TGSqlite";
|
import TGSqlite from "../utils/TGSqlite";
|
||||||
|
|
||||||
// Store
|
// Store
|
||||||
const appStore = useAppStore();
|
const appStore = useAppStore();
|
||||||
@@ -308,7 +308,7 @@ async function doConfirm (oper: string) {
|
|||||||
async function backupData () {
|
async function backupData () {
|
||||||
loadingTitle.value = "正在备份数据...";
|
loadingTitle.value = "正在备份数据...";
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
const achievements = await TGSqlite.UIAF.export();
|
const achievements = await TGSqlite.getUIAF();
|
||||||
await backupUiafData(achievements);
|
await backupUiafData(achievements);
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
snackbarText.value = "数据已备份!";
|
snackbarText.value = "数据已备份!";
|
||||||
@@ -319,7 +319,6 @@ async function backupData () {
|
|||||||
async function restoreData () {
|
async function restoreData () {
|
||||||
const res = await restoreUiafData();
|
const res = await restoreUiafData();
|
||||||
if (res !== false) {
|
if (res !== false) {
|
||||||
achievementsStore.flushData(res.total, res.fin);
|
|
||||||
snackbarText.value = "数据已恢复!";
|
snackbarText.value = "数据已恢复!";
|
||||||
snackbarColor.value = "success";
|
snackbarColor.value = "success";
|
||||||
snackbar.value = true;
|
snackbar.value = true;
|
||||||
@@ -420,18 +419,14 @@ function delDB () {
|
|||||||
// 检查 SQLite 数据库
|
// 检查 SQLite 数据库
|
||||||
async function checkDB () {
|
async function checkDB () {
|
||||||
loadingTitle.value = "正在检查数据库表单完整性...";
|
loadingTitle.value = "正在检查数据库表单完整性...";
|
||||||
const res = await TGSqlite.checkDB();
|
const res = await TGSqlite.check();
|
||||||
if (!res) {
|
if (!res) {
|
||||||
confirmOper.value = "resetDB";
|
confirmOper.value = "resetDB";
|
||||||
confirmText.value = "数据库表单不完整,是否重置数据库?";
|
confirmText.value = "数据库表单不完整,是否重置数据库?";
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
confirmShow.value = true;
|
confirmShow.value = true;
|
||||||
} else {
|
} else {
|
||||||
loadingTitle.value = "正在检查数据库数据完整性...";
|
snackbarText.value = "数据库表单完整!";
|
||||||
await TGSqlite.update.achievementSeries();
|
|
||||||
await TGSqlite.update.achievement();
|
|
||||||
loading.value = false;
|
|
||||||
snackbarText.value = "数据库检查完毕!";
|
|
||||||
snackbarColor.value = "success";
|
snackbarColor.value = "success";
|
||||||
snackbar.value = true;
|
snackbar.value = true;
|
||||||
}
|
}
|
||||||
@@ -439,7 +434,7 @@ async function checkDB () {
|
|||||||
|
|
||||||
// 重置 SQLite 数据库
|
// 重置 SQLite 数据库
|
||||||
async function resetDB () {
|
async function resetDB () {
|
||||||
await TGSqlite.resetDB();
|
await TGSqlite.reset();
|
||||||
snackbarText.value = "数据库已重置!请载入备份数据。";
|
snackbarText.value = "数据库已重置!请载入备份数据。";
|
||||||
snackbarColor.value = "success";
|
snackbarColor.value = "success";
|
||||||
snackbar.value = true;
|
snackbar.value = true;
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ import TPosition from "../components/t-position.vue";
|
|||||||
import TCalendar from "../components/t-calendar.vue";
|
import TCalendar from "../components/t-calendar.vue";
|
||||||
// store
|
// store
|
||||||
import { useHomeStore } from "../store/modules/home";
|
import { useHomeStore } from "../store/modules/home";
|
||||||
|
// utils
|
||||||
|
import TGSqlite from "../utils/TGSqlite";
|
||||||
|
|
||||||
// store
|
// store
|
||||||
const homeStore = useHomeStore();
|
const homeStore = useHomeStore();
|
||||||
@@ -40,6 +42,12 @@ function readLoading (): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
|
loadingTitle.value = "正在检测数据完整性";
|
||||||
|
const isOK = await TGSqlite.check();
|
||||||
|
if (!isOK) {
|
||||||
|
loadingTitle.value = "正在修复数据";
|
||||||
|
await TGSqlite.reset();
|
||||||
|
}
|
||||||
loadingTitle.value = "正在加载首页";
|
loadingTitle.value = "正在加载首页";
|
||||||
const showItems = homeStore.getShowValue();
|
const showItems = homeStore.getShowValue();
|
||||||
await Promise.allSettled(
|
await Promise.allSettled(
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ const TGSql = {
|
|||||||
achievement: insertAchievementData,
|
achievement: insertAchievementData,
|
||||||
achievementSeries: insertAchievementSeriesData,
|
achievementSeries: insertAchievementSeriesData,
|
||||||
bbsPost: insertBBSPostData,
|
bbsPost: insertBBSPostData,
|
||||||
|
UIAF: importUIAFData,
|
||||||
},
|
},
|
||||||
update: {
|
update: {
|
||||||
achievement: updateAchievementData,
|
achievement: updateAchievementData,
|
||||||
@@ -151,7 +152,7 @@ function initBbsPostTable (): string[] {
|
|||||||
created TEXT DEFAULT NULL,
|
created TEXT DEFAULT NULL,
|
||||||
modified TEXT DEFAULT NULL,
|
modified TEXT DEFAULT NULL,
|
||||||
isRead BOOLEAN DEFAULT 0,
|
isRead BOOLEAN DEFAULT 0,
|
||||||
updated TEXT DEFAULT NULL,
|
updated TEXT DEFAULT NULL
|
||||||
);
|
);
|
||||||
`);
|
`);
|
||||||
return sqlRes;
|
return sqlRes;
|
||||||
@@ -347,4 +348,35 @@ function updateBBSPostData (data: BTMuli.SQLite.BBSPost, isRead: boolean = false
|
|||||||
return sql;
|
return sql;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 导入UIAF数据
|
||||||
|
* @since Alpha v0.1.4
|
||||||
|
* @param {TGPlugin.UIAF.Achievement[]} data
|
||||||
|
* @returns {string[]} sql
|
||||||
|
*/
|
||||||
|
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", " ").replace("Z", "");
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
export default TGSql;
|
export default TGSql;
|
||||||
|
|||||||
@@ -7,6 +7,10 @@
|
|||||||
|
|
||||||
import Database from "tauri-plugin-sql-api";
|
import Database from "tauri-plugin-sql-api";
|
||||||
import TGSql from "./TGSql";
|
import TGSql from "./TGSql";
|
||||||
|
import { getUiafStatus } from "./UIAF";
|
||||||
|
import { TGAppData } from "../data";
|
||||||
|
|
||||||
|
const dbLink = await Database.load("sqlite:tauri-genshin.db");
|
||||||
|
|
||||||
class TGSqlite {
|
class TGSqlite {
|
||||||
/**
|
/**
|
||||||
@@ -46,7 +50,8 @@ class TGSqlite {
|
|||||||
* @since Alpha v0.1.4
|
* @since Alpha v0.1.4
|
||||||
*/
|
*/
|
||||||
constructor () {
|
constructor () {
|
||||||
this.db = new Database(this.dbPath);
|
// 异步
|
||||||
|
this.db = dbLink;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -91,8 +96,10 @@ class TGSqlite {
|
|||||||
* @returns {Promise<void>}
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
public async reset (): Promise<void> {
|
public async reset (): Promise<void> {
|
||||||
const sql = "DROP TABLE IF EXISTS AppData, Achievement, AchievementSeries, BbsPost;";
|
this.tables.map(async (item) => {
|
||||||
await this.db.execute(sql);
|
const sql = `DROP TABLE IF EXISTS ${item};`;
|
||||||
|
await this.db.execute(sql);
|
||||||
|
});
|
||||||
await this.init();
|
await this.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,17 +136,11 @@ class TGSqlite {
|
|||||||
/**
|
/**
|
||||||
* @description 获取成就系列列表
|
* @description 获取成就系列列表
|
||||||
* @memberof TGSqlite
|
* @memberof TGSqlite
|
||||||
* @param {number} [seriesId] 系列 ID
|
|
||||||
* @since Alpha v0.1.4
|
* @since Alpha v0.1.4
|
||||||
* @returns {Promise<BTMuli.SQLite.AchievementSeries[]>}
|
* @returns {Promise<BTMuli.SQLite.AchievementSeries[]>}
|
||||||
*/
|
*/
|
||||||
public async getAchievementSeries (seriesId?: number): Promise<BTMuli.SQLite.AchievementSeries[]> {
|
public async getAchievementSeries (): Promise<BTMuli.SQLite.AchievementSeries[]> {
|
||||||
let sql;
|
const sql = "SELECT * FROM AchievementSeries ORDER BY `order` ASC;";
|
||||||
if (seriesId) {
|
|
||||||
sql = `SELECT * FROM AchievementSeries WHERE id=${seriesId};`;
|
|
||||||
} else {
|
|
||||||
sql = "SELECT * FROM AchievementSeries;";
|
|
||||||
}
|
|
||||||
const res: BTMuli.SQLite.AchievementSeries[] = await this.db.select(sql);
|
const res: BTMuli.SQLite.AchievementSeries[] = await this.db.select(sql);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@@ -154,14 +155,26 @@ class TGSqlite {
|
|||||||
public async getAchievements (seriesId?: number): Promise<BTMuli.SQLite.Achievements[]> {
|
public async getAchievements (seriesId?: number): Promise<BTMuli.SQLite.Achievements[]> {
|
||||||
let sql;
|
let sql;
|
||||||
if (seriesId) {
|
if (seriesId) {
|
||||||
sql = `SELECT * FROM Achievement WHERE seriesId=${seriesId};`;
|
sql = `SELECT * FROM Achievements WHERE series=${seriesId} ORDER BY isCompleted DESC, \`order\` ASC;`;
|
||||||
} else {
|
} else {
|
||||||
sql = "SELECT * FROM Achievement;";
|
sql = "SELECT * FROM Achievements ORDER BY isCompleted DESC, `order` ASC;";
|
||||||
}
|
}
|
||||||
const res: BTMuli.SQLite.Achievements[] = await this.db.select(sql);
|
const res: BTMuli.SQLite.Achievements[] = await this.db.select(sql);
|
||||||
return res;
|
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 sql = "SELECT SUM(totalCount) AS total, SUM(finCount) AS fin FROM AchievementSeries;";
|
||||||
|
const res: Array<{ total: number, fin: number }> = await this.db.select(sql);
|
||||||
|
return res[0];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description 查询成就
|
* @description 查询成就
|
||||||
* @memberof TGSqlite
|
* @memberof TGSqlite
|
||||||
@@ -173,13 +186,50 @@ class TGSqlite {
|
|||||||
let sql;
|
let sql;
|
||||||
if (keyword.startsWith("v")) {
|
if (keyword.startsWith("v")) {
|
||||||
const version = keyword.replace("v", "");
|
const version = keyword.replace("v", "");
|
||||||
sql = `SELECT * FROM Achievement WHERE version='${version}';`;
|
sql = `SELECT * FROM Achievements WHERE version='${version}' ORDER BY isCompleted DESC, \`order\` ASC;`;
|
||||||
} else {
|
} else {
|
||||||
sql = `SELECT * FROM Achievement WHERE name LIKE '%${keyword}%' OR description LIKE '%${keyword}%';`;
|
sql = `SELECT * FROM Achievements WHERE name LIKE '%${keyword}%' OR description LIKE '%${keyword}%' ORDER BY isCompleted DESC, \`order\` ASC;`;
|
||||||
}
|
}
|
||||||
const res: BTMuli.SQLite.Achievements[] = await this.db.select(sql);
|
const res: BTMuli.SQLite.Achievements[] = await this.db.select(sql);
|
||||||
return res;
|
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 sql = TGSql.insert.UIAF(achievements);
|
||||||
|
for (const item of sql) {
|
||||||
|
await this.db.execute(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 获取 UIAF 数据
|
||||||
|
* @memberof TGSqlite
|
||||||
|
* @since Alpha v0.1.4
|
||||||
|
* @returns {Promise<TGPlugin.UIAF.Achievement[]>}
|
||||||
|
*/
|
||||||
|
public async getUIAF (): Promise<TGPlugin.UIAF.Achievement[]> {
|
||||||
|
const sql = "SELECT * FROM Achievements WHERE isCompleted = 1 OR progress > 0";
|
||||||
|
const res: BTMuli.SQLite.Achievements[] = await this.db.select(sql);
|
||||||
|
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() : 0,
|
||||||
|
current: item.progress,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return achievements;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default TGSqlite;
|
export default new TGSqlite();
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
// tauri
|
// tauri
|
||||||
import { app, fs, path } from "@tauri-apps/api";
|
import { app, fs, path } from "@tauri-apps/api";
|
||||||
// utils
|
// utils
|
||||||
import TGSqlite from "../core/database/TGSqlite";
|
import TGSqlite from "./TGSqlite";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description 时间戳转换为日期
|
* @description 时间戳转换为日期
|
||||||
@@ -110,16 +110,15 @@ export async function backupUiafData (achievementData: TGPlugin.UIAF.Achievement
|
|||||||
/**
|
/**
|
||||||
* @description 根据 UIAF 数据恢复成就数据
|
* @description 根据 UIAF 数据恢复成就数据
|
||||||
* @since Alpha v0.1.4
|
* @since Alpha v0.1.4
|
||||||
* @returns {Promise<{total: number, fin: number}> | false} 恢复的成就数量
|
* @returns {Promise<boolean>} 恢复的成就数量
|
||||||
*/
|
*/
|
||||||
export async function restoreUiafData (): Promise<{ total: number, fin: number } | false> {
|
export async function restoreUiafData (): Promise<boolean> {
|
||||||
const uiafPath = `${await path.appLocalDataDir()}\\userData\\UIAF.json`;
|
const uiafPath = `${await path.appLocalDataDir()}\\userData\\UIAF.json`;
|
||||||
// 检测是否存在 UIAF 数据
|
// 检测是否存在 UIAF 数据
|
||||||
if (!await fs.exists(uiafPath)) {
|
if (!await fs.exists(uiafPath)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const uiafData = JSON.parse(await fs.readTextFile(uiafPath)) as TGPlugin.UIAF.Achievement[];
|
const uiafData = JSON.parse(await fs.readTextFile(uiafPath)) as TGPlugin.UIAF.Achievement[];
|
||||||
await TGSqlite.UIAF.import(uiafData);
|
await TGSqlite.mergeUIAF(uiafData);
|
||||||
// 返回
|
return true;
|
||||||
return await TGSqlite.search.overview();
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user