mirror of
https://github.com/BTMuli/TeyvatGuide.git
synced 2026-03-27 05:49:45 +08:00
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* @file plugins/Sqlite/index.ts
|
||||
* @description Sqlite 数据库操作类
|
||||
* @since Beta v0.5.3
|
||||
* @since Beta v0.6.0
|
||||
*/
|
||||
|
||||
import { app } from "@tauri-apps/api";
|
||||
@@ -165,22 +165,6 @@ class Sqlite {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 检测数据库完整性
|
||||
* @since Beta v0.4.4
|
||||
* @returns {Promise<boolean>}
|
||||
*/
|
||||
public async check(): Promise<boolean> {
|
||||
const db = await this.getDB();
|
||||
let isVerified = false;
|
||||
const sqlT = "SELECT name FROM sqlite_master WHERE type='table' ORDER BY name;";
|
||||
const res: Array<{ name: string }> = await db.select(sqlT);
|
||||
if (this.tables.every((item) => res.map((i) => i.name).includes(item))) {
|
||||
isVerified = true;
|
||||
}
|
||||
return isVerified;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 重置数据库
|
||||
* @since Beta v0.4.0
|
||||
|
||||
@@ -1,150 +1,240 @@
|
||||
/**
|
||||
* @file plugins/Sqlite/modules/userAchi.ts
|
||||
* @description 用户成就模块
|
||||
* @since Beta v0.5.5
|
||||
* @since Beta v0.6.0
|
||||
*/
|
||||
|
||||
import { getUiafStatus } from "../../../utils/UIAF.js";
|
||||
import { path } from "@tauri-apps/api";
|
||||
import { exists, mkdir, readDir, readTextFile, writeTextFile } from "@tauri-apps/plugin-fs";
|
||||
|
||||
import { AppAchievementsData, AppAchievementSeriesData } from "../../../data/index.js";
|
||||
import TGLogger from "../../../utils/TGLogger.js";
|
||||
import { timestampToDate } from "../../../utils/toolFunc.js";
|
||||
import TGSqlite from "../index.js";
|
||||
import { importUIAFData } from "../sql/updateData.js";
|
||||
|
||||
/**
|
||||
* @description 获取成就概况
|
||||
* @since Beta v0.4.7
|
||||
* @returns {Promise<TGApp.Sqlite.Achievement.Overview}> 成就概况
|
||||
* @description 根据 completed 跟 progress 获取 status
|
||||
* @since Beta v0.6.0
|
||||
* @param {boolean} completed - 是否完成
|
||||
* @param {number} progress - 进度
|
||||
* @returns {number} status
|
||||
*/
|
||||
async function getOverview(): Promise<TGApp.Sqlite.Achievement.Overview> {
|
||||
const db = await TGSqlite.getDB();
|
||||
const res = await db.select<TGApp.Sqlite.Achievement.Overview[]>(
|
||||
"SELECT SUM(totalCount) as total,SUM(finCount) AS fin From AchievementSeries",
|
||||
);
|
||||
return res[0];
|
||||
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 获取最新成就版本
|
||||
* @since Beta v0.4.7
|
||||
* @returns {Promise<string>} 最新成就版本
|
||||
* @since Beta v0.6.0
|
||||
* @returns {string} 最新成就版本
|
||||
*/
|
||||
async function getLatestAchiVersion(): Promise<string> {
|
||||
const db = await TGSqlite.getDB();
|
||||
type resType = { version: string };
|
||||
const res = await db.select<resType[]>(
|
||||
"SELECT version FROM Achievements ORDER BY version DESC LIMIT 1;",
|
||||
);
|
||||
return res[0].version;
|
||||
function getLatestAchiVersion(): string {
|
||||
let maxVersion = "0";
|
||||
for (const series of AppAchievementSeriesData) {
|
||||
if (series.version > maxVersion) maxVersion = series.version;
|
||||
}
|
||||
return maxVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 获取成就系列数据
|
||||
* @since Beta v0.4.7
|
||||
* @param {number|undefined} id 成就系列ID
|
||||
* @returns {Promise<TGApp.Sqlite.Achievement.SeriesTable[]>} 成就系列数据
|
||||
* @description 获取成就系列概况
|
||||
* @since Beta v0.6.0
|
||||
* @param {number} uid - 存档UID
|
||||
* @param {[number]} series - 系列ID
|
||||
* @returns {Promise<TGApp.Sqlite.Achievement.Overview>}
|
||||
*/
|
||||
async function getSeries(id?: number): Promise<TGApp.Sqlite.Achievement.SeriesTable[]> {
|
||||
async function getOverview(
|
||||
uid: number,
|
||||
series?: number,
|
||||
): Promise<TGApp.Sqlite.Achievement.Overview> {
|
||||
const db = await TGSqlite.getDB();
|
||||
let res: TGApp.Sqlite.Achievement.SeriesTable[];
|
||||
if (id === undefined) {
|
||||
res = await db.select<TGApp.Sqlite.Achievement.SeriesTable[]>(
|
||||
"SELECT * FROM AchievementSeries ORDER BY `order`;",
|
||||
);
|
||||
let totalAchi: number[] = [];
|
||||
if (series === undefined) {
|
||||
totalAchi = AppAchievementsData.map((i) => i.id);
|
||||
} else {
|
||||
res = await db.select<TGApp.Sqlite.Achievement.SeriesTable[]>(
|
||||
"SELECT * FROM AchievementSeries WHERE id = ?;",
|
||||
[id],
|
||||
);
|
||||
totalAchi = AppAchievementsData.filter((s) => s.series === series).map((i) => i.id);
|
||||
}
|
||||
return res;
|
||||
const finAchi = (
|
||||
await db.select<TGApp.Sqlite.Achievement.TableAchi[]>(
|
||||
"SELECT * FROM Achievements WHERE uid = ? AND isCompleted = 1;",
|
||||
[uid],
|
||||
)
|
||||
).filter((i) => totalAchi.includes(i.id));
|
||||
return { total: totalAchi.length, fin: finAchi.length };
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 合并成就数据
|
||||
* @since Beta v0.6.0
|
||||
* @param {TGApp.App.Achievement.Item} raw - 元数据
|
||||
* @param {[TGApp.Sqlite.Achievement.TableAchi]} data - 数据库数据
|
||||
* @param {[number]} uid - 存档 UID
|
||||
* @return {TGApp.Sqlite.Achievement.RenderAchi} - 渲染数据
|
||||
*/
|
||||
function getRenderAchi(
|
||||
raw: TGApp.App.Achievement.Item,
|
||||
uid?: number,
|
||||
data?: TGApp.Sqlite.Achievement.TableAchi,
|
||||
): TGApp.Sqlite.Achievement.RenderAchi {
|
||||
const emptyAchi: TGApp.Sqlite.Achievement.TableAchi = {
|
||||
id: 0,
|
||||
uid: uid ?? 0,
|
||||
isCompleted: 0,
|
||||
completedTime: "",
|
||||
progress: 0,
|
||||
updated: "",
|
||||
};
|
||||
const achiData = data ?? emptyAchi;
|
||||
return {
|
||||
id: raw.id,
|
||||
uid: achiData.uid,
|
||||
order: raw.order,
|
||||
series: raw.series,
|
||||
name: raw.name,
|
||||
description: raw.description,
|
||||
reward: raw.reward,
|
||||
version: raw.version,
|
||||
trigger: raw.trigger,
|
||||
isCompleted: achiData.isCompleted === 1,
|
||||
completedTime: achiData.completedTime,
|
||||
progress: achiData.progress,
|
||||
updated: achiData.updated,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 获取单个成就
|
||||
* @since Beta v0.6.0
|
||||
* @param {number} uid - 存档 UID
|
||||
* @param {number} id - 成就 ID
|
||||
* @returns {Promise<TGApp.Sqlite.Achievement.TableAchi|false>}
|
||||
*/
|
||||
async function getAchi(
|
||||
uid: number,
|
||||
id: number,
|
||||
): Promise<TGApp.Sqlite.Achievement.TableAchi | false> {
|
||||
const db = await TGSqlite.getDB();
|
||||
const res = await db.select<TGApp.Sqlite.Achievement.TableAchi[]>(
|
||||
"SELECT * FROM Achievements WHERE uid = ? AND id = ?;",
|
||||
[uid, id],
|
||||
);
|
||||
if (res.length === 0) return false;
|
||||
return res[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 获取成就数据
|
||||
* @since Beta v0.4.8
|
||||
* @param {number|undefined} id 成就系列ID
|
||||
* @returns {Promise<TGApp.Sqlite.Achievement.SingleTable[]>} 成就数据
|
||||
* @since Beta v0.6.0
|
||||
* @param {number} uid - 存档 UID
|
||||
* @param {[number]} series - 成就系列ID
|
||||
* @returns {Promise<TGApp.Sqlite.Achievement.RenderAchi[]>} 成就数据
|
||||
*/
|
||||
async function getAchievements(id?: string): Promise<TGApp.Sqlite.Achievement.SingleTable[]> {
|
||||
async function getAchievements(
|
||||
uid: number,
|
||||
series?: number,
|
||||
): Promise<TGApp.Sqlite.Achievement.RenderAchi[]> {
|
||||
const db = await TGSqlite.getDB();
|
||||
let res: TGApp.Sqlite.Achievement.SingleTable[];
|
||||
if (id === undefined) {
|
||||
res = await db.select<TGApp.Sqlite.Achievement.SingleTable[]>(
|
||||
"SELECT * FROM Achievements ORDER BY isCompleted,`order`;",
|
||||
);
|
||||
} else {
|
||||
res = await db.select<TGApp.Sqlite.Achievement.SingleTable[]>(
|
||||
"SELECT * FROM Achievements WHERE series = ? ORDER BY isCompleted,`order`;",
|
||||
[id],
|
||||
);
|
||||
const res: TGApp.Sqlite.Achievement.RenderAchi[] = [];
|
||||
const userData = await db.select<TGApp.Sqlite.Achievement.TableAchi[]>(
|
||||
"SELECT * FROM Achievements WHERE uid = ?;",
|
||||
[uid],
|
||||
);
|
||||
let rawData: TGApp.App.Achievement.Item[];
|
||||
if (series === undefined || series === -1) rawData = AppAchievementsData;
|
||||
else rawData = AppAchievementsData.filter((a) => a.series === series);
|
||||
for (const achi of rawData) {
|
||||
const achiFind = userData.find((u) => u.id === achi.id);
|
||||
const achievement = getRenderAchi(achi, uid, achiFind);
|
||||
res.push(achievement);
|
||||
}
|
||||
res.sort(
|
||||
(a, b) => a.isCompleted.toString().localeCompare(b.isCompleted.toString()) || a.order - b.order,
|
||||
);
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 获取成就名片
|
||||
* @since Beta v0.4.7
|
||||
* @param {string} id 成就系列ID
|
||||
* @returns {Promise<string>} 成就名片
|
||||
*/
|
||||
async function getSeriesNameCard(id: string): Promise<string> {
|
||||
const db = await TGSqlite.getDB();
|
||||
type resType = { nameCard: string };
|
||||
const res = await db.select<resType[]>("SELECT nameCard FROM AchievementSeries WHERE id = ?;", [
|
||||
id,
|
||||
]);
|
||||
return res[0].nameCard;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 查找成就数据
|
||||
* @since Beta v0.4.8
|
||||
* @param {string} keyword 关键词
|
||||
* @returns {Promise<TGApp.Sqlite.Achievement.SingleTable[]>} 成就数据
|
||||
* @since Beta v0.6.0
|
||||
* @param {number} uid - 存档 UID
|
||||
* @param {string} keyword - 关键词
|
||||
* @returns {Promise<TGApp.Sqlite.Achievement.RenderAchi[]>} 成就数据
|
||||
*/
|
||||
async function searchAchievements(
|
||||
async function searchAchi(
|
||||
uid: number,
|
||||
keyword: string,
|
||||
): Promise<TGApp.Sqlite.Achievement.SingleTable[]> {
|
||||
if (keyword === "") return await getAchievements();
|
||||
const db = await TGSqlite.getDB();
|
||||
): Promise<TGApp.Sqlite.Achievement.RenderAchi[]> {
|
||||
if (keyword === "") return await getAchievements(uid);
|
||||
const versionReg = /^v\d+(\.\d+)?$/;
|
||||
let rawData: TGApp.App.Achievement.Item[];
|
||||
const res: TGApp.Sqlite.Achievement.RenderAchi[] = [];
|
||||
if (versionReg.test(keyword)) {
|
||||
const version = keyword.replace("v", "");
|
||||
return await db.select<TGApp.Sqlite.Achievement.SingleTable[]>(
|
||||
"SELECT * FROM Achievements WHERE version LIKE ? ORDER BY isCompleted,`order`;",
|
||||
[`%${version}%`],
|
||||
);
|
||||
rawData = AppAchievementsData.filter((i) => i.version.includes(version));
|
||||
} else {
|
||||
rawData = AppAchievementsData.filter((a) => {
|
||||
if (a.name.includes(keyword)) return true;
|
||||
if (a.description.includes(keyword)) return true;
|
||||
});
|
||||
}
|
||||
return await db.select<TGApp.Sqlite.Achievement.SingleTable[]>(
|
||||
"SELECT * FROM Achievements WHERE name LIKE ? OR description LIKE ? ORDER BY isCompleted,`order`;",
|
||||
[`%${keyword}%`, `%${keyword}%`],
|
||||
for (const data of rawData) {
|
||||
const achiFind = await getAchi(uid, data.id);
|
||||
let achievement: TGApp.Sqlite.Achievement.RenderAchi;
|
||||
if (achiFind === false) achievement = getRenderAchi(data, uid);
|
||||
else achievement = getRenderAchi(data, uid, achiFind);
|
||||
res.push(achievement);
|
||||
}
|
||||
res.sort(
|
||||
(a, b) => a.isCompleted.toString().localeCompare(b.isCompleted.toString()) || a.order - b.order,
|
||||
);
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 更新成就数据
|
||||
* @since Beta v0.4.7
|
||||
* @param {TGApp.Sqlite.Achievement.SingleTable} data UIAF数据
|
||||
* @since Beta v0.6.0
|
||||
* @param {TGApp.Sqlite.Achievement.RenderAchi} data 成就数据
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async function updateAchievement(data: TGApp.Sqlite.Achievement.SingleTable): Promise<void> {
|
||||
async function updateAchi(data: TGApp.Sqlite.Achievement.RenderAchi): Promise<void> {
|
||||
const db = await TGSqlite.getDB();
|
||||
await db.execute("UPDATE Achievements SET isCompleted = ?, completedTime = ? WHERE id = ?;", [
|
||||
data.isCompleted,
|
||||
data.completedTime.toString(),
|
||||
data.id,
|
||||
]);
|
||||
await db.execute(
|
||||
"INSERT INTO Achievements(id, uid, isCompleted, completedTime, progress, updated) \
|
||||
VALUES (?, ?, ?, ?, ?, ?) ON CONFLICT(id,uid) DO UPDATE \
|
||||
SET isCompleted=?,completedTime=?,progress=?,updated=?;",
|
||||
[
|
||||
data.id,
|
||||
data.uid,
|
||||
data.isCompleted ? 1 : 0,
|
||||
data.completedTime,
|
||||
data.progress,
|
||||
timestampToDate(new Date().getTime()),
|
||||
data.isCompleted ? 1 : 0,
|
||||
data.completedTime,
|
||||
data.progress,
|
||||
timestampToDate(new Date().getTime()),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 将数据库数据转换为UIAF数据
|
||||
* @since Beta v0.5.5
|
||||
* @param {TGApp.Sqlite.Achievement.SingleTable} data 数据库数据
|
||||
* @since Beta v0.6.0
|
||||
* @param {TGApp.Sqlite.Achievement.TableAchi} data 数据库数据
|
||||
* @returns {TGApp.Plugins.UIAF.Achievement} UIAF数据
|
||||
*/
|
||||
function transDb2Uiaf(data: TGApp.Sqlite.Achievement.SingleTable): TGApp.Plugins.UIAF.Achievement {
|
||||
const isCompleted = data.isCompleted === 1;
|
||||
function transDb2Uiaf(data: TGApp.Sqlite.Achievement.TableAchi): TGApp.Plugins.UIAF.Achievement {
|
||||
let timestamp = 0;
|
||||
if (isCompleted) timestamp = Math.floor(new Date(data.completedTime).getTime() / 1000);
|
||||
const status = getUiafStatus(isCompleted, data.progress);
|
||||
if (data.isCompleted === 1) timestamp = Math.floor(new Date(data.completedTime).getTime() / 1000);
|
||||
const status = getUiafStatus(data.isCompleted === 1, data.progress);
|
||||
return {
|
||||
id: data.id,
|
||||
timestamp: timestamp,
|
||||
@@ -154,14 +244,16 @@ function transDb2Uiaf(data: TGApp.Sqlite.Achievement.SingleTable): TGApp.Plugins
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 获取UIAF数据
|
||||
* @since Beta v0.4.7
|
||||
* @description 获取指定Uid的UIAF数据
|
||||
* @since Beta v0.6.0
|
||||
* @param {number} uid - 存档UID
|
||||
* @returns {Promise<TGApp.Plugins.UIAF.Achievement[]>}
|
||||
*/
|
||||
async function getUIAF(): Promise<TGApp.Plugins.UIAF.Achievement[]> {
|
||||
async function getUiafData(uid: number): Promise<TGApp.Plugins.UIAF.Achievement[]> {
|
||||
const db = await TGSqlite.getDB();
|
||||
const data = await db.select<TGApp.Sqlite.Achievement.SingleTable[]>(
|
||||
"SELECT * FROM Achievements;",
|
||||
const data = await db.select<TGApp.Sqlite.Achievement.TableAchi[]>(
|
||||
"SELECT * FROM Achievements WHERE uid=?;",
|
||||
[uid],
|
||||
);
|
||||
const res: TGApp.Plugins.UIAF.Achievement[] = [];
|
||||
for (const item of data) {
|
||||
@@ -171,29 +263,111 @@ async function getUIAF(): Promise<TGApp.Plugins.UIAF.Achievement[]> {
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 合并UIAF数据
|
||||
* @since Beta v0.4.7
|
||||
* @param {TGApp.Plugins.UIAF.Achievement[]} data UIAF数据
|
||||
* @description 获取所有存档 uid
|
||||
* @since Beta v0.6.0
|
||||
* @return {Promise<Array<number>>}
|
||||
*/
|
||||
async function getAllUid(): Promise<Array<number>> {
|
||||
const db = await TGSqlite.getDB();
|
||||
type resType = Array<{ uid: number }>;
|
||||
const res = await db.select<resType>("SELECT DISTINCT uid FROM Achievements;");
|
||||
return res.map((i) => i.uid);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 备份成就数据
|
||||
* @since Beta v0.6.0
|
||||
* @param {string} dir - 存档数据
|
||||
* @param {number} uid - 存档UID,未指定则导出所有
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async function mergeUIAF(data: TGApp.Plugins.UIAF.Achievement[]): Promise<void> {
|
||||
const db = await TGSqlite.getDB();
|
||||
for (const item of data) {
|
||||
const sql = importUIAFData(item);
|
||||
await db.execute(sql);
|
||||
async function backupUiaf(dir: string, uid?: number): Promise<void> {
|
||||
let uidList = [];
|
||||
if (uid === undefined) uidList = await getAllUid();
|
||||
else uidList.push(uid);
|
||||
if (!(await exists(dir))) {
|
||||
await TGLogger.Warn("不存在指定的成就备份目录,即将创建");
|
||||
await mkdir(dir, { recursive: true });
|
||||
}
|
||||
for (const uidItem of uidList) {
|
||||
const data = await getUiafData(uidItem);
|
||||
const fileName = `UIAF_${uidItem}`;
|
||||
await writeTextFile(`${dir}${path.sep()}${fileName}.json`, JSON.stringify(data, null, 2));
|
||||
await TGLogger.Info(`成功备份${uidItem}的成就存档`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 恢复成就数据
|
||||
* @since Beta v0.6.0
|
||||
* @param {string} dir - 数据目录
|
||||
* @returns {Promise<boolean>}
|
||||
*/
|
||||
async function restoreUiaf(dir: string): Promise<boolean> {
|
||||
if (!(await exists(dir))) return false;
|
||||
const filesRead = await readDir(dir);
|
||||
const files = filesRead.filter((item) => item.name.includes("UIAF_") && item.isFile);
|
||||
// 正则匹配 UIAF_xx.json
|
||||
for (const file of files) {
|
||||
try {
|
||||
const reg = new RegExp(/(.*)UIAF_d{9}.json/);
|
||||
if (!file.name.match(reg)) return false;
|
||||
const uid: number = Number(file.name.match(reg)![0]);
|
||||
const data: TGApp.Plugins.UIAF.Achievement[] = JSON.parse(await readTextFile(file.name));
|
||||
await TSUserAchi.mergeUiaf(data, uid);
|
||||
} catch (e) {
|
||||
await TGLogger.Error(`[UIAF][RESTORE] 恢复成就数据${file.name} `);
|
||||
await TGLogger.Error(`${e}`);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 导入Uiaf数据
|
||||
* @since Beta v0.6.0
|
||||
* @param {TGApp.Plugins.UIAF.Achievement[]} data - 成就数据
|
||||
* @param {number} uid - 存档UID
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async function mergeUiaf(data: TGApp.Plugins.UIAF.Achievement[], uid: number): Promise<void> {
|
||||
const db = await TGSqlite.getDB();
|
||||
for (const achi of data) {
|
||||
const status = achi.status === 2 || achi.status === 3 ? 1 : 0;
|
||||
const timeC = status === 1 ? timestampToDate(achi.timestamp * 1000) : "";
|
||||
const timeN = timestampToDate(new Date().getTime());
|
||||
await db.execute(
|
||||
"INSERT INTO Achievements(id, uid, isCompleted, completedTime, progress, updated) \
|
||||
VALUES (?,?,?,?,?,?) ON CONFLICT(id,uid) DO UPDATE SET\
|
||||
isCompleted=?,completedTime=?,progress=?,updated=?;",
|
||||
[achi.id, uid, status, timeC, achi.current, timeN, status, timeC, achi.current, timeN],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 删除指定 UID 存档的数据
|
||||
* @since Beta v0.6.0
|
||||
* @param {number} uid - 存档UID
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async function delUid(uid: number): Promise<void> {
|
||||
const db = await TGSqlite.getDB();
|
||||
await db.execute("DELETE FROM Achievements WHERE uid=?;", [uid]);
|
||||
}
|
||||
|
||||
const TSUserAchi = {
|
||||
getOverview,
|
||||
getLatestAchiVersion,
|
||||
getSeries,
|
||||
getSeriesNameCard,
|
||||
getOverview,
|
||||
getAchievements,
|
||||
searchAchievements,
|
||||
updateAchievement,
|
||||
getUIAF,
|
||||
mergeUIAF,
|
||||
getAllUid,
|
||||
getUiafData,
|
||||
searchAchi,
|
||||
updateAchi,
|
||||
mergeUiaf,
|
||||
backupUiaf,
|
||||
restoreUiaf,
|
||||
delUid,
|
||||
};
|
||||
|
||||
export default TSUserAchi;
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
/**
|
||||
* @file plugins/Sqlite/modules/userGacha.ts
|
||||
* @description 用户祈愿模块
|
||||
* @since Beta v0.5.1
|
||||
* @since Beta v0.6.0
|
||||
*/
|
||||
|
||||
import { AppCharacterData, AppWeaponData } from "../../../data/index.js";
|
||||
import TGSqlite from "../index.js";
|
||||
import { importUIGFData } from "../sql/updateData.js";
|
||||
|
||||
type gachaItemTypeRes =
|
||||
| ["角色", TGApp.App.Character.WikiBriefInfo]
|
||||
@@ -27,6 +26,34 @@ function getGachaItemType(item_id: string): gachaItemTypeRes {
|
||||
return ["未知", "未知"];
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 获取导入 Sql
|
||||
* @since Beta v.6.0
|
||||
* @param {string} uid - UID
|
||||
* @param {TGApp.Plugins.UIGF.GachaItem} gacha - UIGF数据
|
||||
* @returns {string}
|
||||
*/
|
||||
function getInsertSql(uid: string, gacha: TGApp.Plugins.UIGF.GachaItem): string {
|
||||
return `
|
||||
INSERT INTO GachaRecords (uid, gachaType, itemId, count, time, name, type, rank, id, uigfType, updated)
|
||||
VALUES ('${uid}', '${gacha.gacha_type}', '${gacha.item_id ?? null}', '${gacha.count ?? null}', '${gacha.time}',
|
||||
'${gacha.name}', '${gacha.item_type ?? null}', '${gacha.rank_type ?? null}', '${gacha.id}',
|
||||
'${gacha.uigf_gacha_type}', datetime('now', 'localtime'))
|
||||
ON CONFLICT (id)
|
||||
DO UPDATE
|
||||
SET uid = '${uid}',
|
||||
gachaType = '${gacha.gacha_type}',
|
||||
uigfType = '${gacha.uigf_gacha_type}',
|
||||
time = '${gacha.time}',
|
||||
itemId = '${gacha.item_id ?? null}',
|
||||
count = '${gacha.count ?? null}',
|
||||
name = '${gacha.name}',
|
||||
type = '${gacha.item_type ?? null}',
|
||||
rank = '${gacha.rank_type ?? null}',
|
||||
updated = datetime('now', 'localtime');
|
||||
`;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 转换祈愿数据,防止多语言
|
||||
* @since Beta v0.5.1
|
||||
@@ -130,7 +157,7 @@ async function mergeUIGF(uid: string, data: TGApp.Plugins.UIGF.GachaItem[]): Pro
|
||||
const db = await TGSqlite.getDB();
|
||||
for (const gacha of data) {
|
||||
const trans = transGacha(gacha);
|
||||
const sql = importUIGFData(uid, trans);
|
||||
const sql = getInsertSql(uid, trans);
|
||||
await db.execute(sql);
|
||||
}
|
||||
}
|
||||
@@ -145,7 +172,7 @@ 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);
|
||||
const sql = getInsertSql(data.uid.toString(), trans);
|
||||
await db.execute(sql);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,35 +1,23 @@
|
||||
-- @file plugins/Sqlite/sql/createTable.sql
|
||||
-- @brief sqlite数据库创建表语句
|
||||
-- @since Beta v0.5.5
|
||||
-- @since Beta v0.6.0
|
||||
|
||||
-- @brief 重新创建成就数据表
|
||||
drop table if exists Achievements;
|
||||
-- @brief 创建成就数据表
|
||||
create table if not exists Achievements
|
||||
(
|
||||
id integer primary key,
|
||||
series integer,
|
||||
`order` integer,
|
||||
name text,
|
||||
description text,
|
||||
reward integer,
|
||||
id integer not null,
|
||||
uid integer not null,
|
||||
isCompleted boolean default false,
|
||||
completedTime text,
|
||||
progress integer default 0,
|
||||
version text,
|
||||
updated text
|
||||
updated text,
|
||||
primary key (id, uid)
|
||||
);
|
||||
|
||||
-- @brief 创建成就系列数据表
|
||||
create table if not exists AchievementSeries
|
||||
(
|
||||
id integer primary key,
|
||||
`order` integer,
|
||||
name text,
|
||||
version text,
|
||||
totalCount integer default 0,
|
||||
finCount integer default 0,
|
||||
nameCard text,
|
||||
updated text
|
||||
);
|
||||
-- @brief 重新创建成就系列数据表
|
||||
drop table if exists AchievementSeries;
|
||||
|
||||
-- @brief 创建角色数据表
|
||||
create table if not exists AppCharacters
|
||||
@@ -117,19 +105,19 @@ create table if not exists UserRecord
|
||||
-- @brief 创建角色数据表
|
||||
create table if not exists UserCharacters
|
||||
(
|
||||
uid integer,
|
||||
cid integer,
|
||||
avatar text,
|
||||
weapon text,
|
||||
relics text,
|
||||
constellations text,
|
||||
costumes text,
|
||||
skills text,
|
||||
propSelected text,
|
||||
propBase text,
|
||||
propExtra text,
|
||||
propRecommend text,
|
||||
updated text,
|
||||
uid integer,
|
||||
cid integer,
|
||||
avatar text,
|
||||
weapon text,
|
||||
relics text,
|
||||
constellations text,
|
||||
costumes text,
|
||||
skills text,
|
||||
propSelected text,
|
||||
propBase text,
|
||||
propExtra text,
|
||||
propRecommend text,
|
||||
updated text,
|
||||
primary key (uid, cid)
|
||||
);
|
||||
|
||||
|
||||
@@ -1,40 +1,9 @@
|
||||
-- @file plugins Sqlite sql createTrigger.sql
|
||||
-- @file plugins/Sqlite/sql/createTrigger.sql
|
||||
-- @brief 创建触发器
|
||||
-- @author BTMuli <bt-muli@outlook.com>
|
||||
-- @since Alpha v0.2.0
|
||||
-- @since Beta v0.6.0
|
||||
|
||||
-- @brief 成就表相关
|
||||
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;
|
||||
-- @brief 重新创建成就表插入触发器
|
||||
drop trigger if exists insertAchievement;
|
||||
|
||||
create trigger if not exists updateAchievement
|
||||
after update
|
||||
on Achievements
|
||||
for each row
|
||||
begin
|
||||
update AchievementSeries
|
||||
set updated = datetime('now', 'localtime'),
|
||||
finCount = finCount + 1
|
||||
where id = new.series
|
||||
and old.isCompleted = 0
|
||||
and new.isCompleted = 1;
|
||||
update AchievementSeries
|
||||
set updated = datetime('now', 'localtime'),
|
||||
finCount = finCount - 1
|
||||
where id = new.series
|
||||
and old.isCompleted = 1
|
||||
and new.isCompleted = 0;
|
||||
end;
|
||||
-- @brief 重新创建成就表更新触发器
|
||||
drop trigger if exists updateAchievement;
|
||||
|
||||
@@ -1,26 +1,16 @@
|
||||
/**
|
||||
* @file plugins/Sqlite/sql/initData.ts
|
||||
* @description Sqlite 初始化数据 sql 语句
|
||||
* @since Beta v0.4.5
|
||||
* @since Beta v0.6.0
|
||||
*/
|
||||
|
||||
import { app } from "@tauri-apps/api";
|
||||
|
||||
import {
|
||||
AppAchievementsData,
|
||||
AppAchievementSeriesData,
|
||||
AppNameCardsData,
|
||||
AppCharacterData,
|
||||
} from "../../../data/index.js";
|
||||
import { AppNameCardsData, AppCharacterData } from "../../../data/index.js";
|
||||
import { getBuildTime } from "../../../utils/TGBuild.js";
|
||||
|
||||
import initTableSql from "./initTable.js";
|
||||
import {
|
||||
insertAchievementData,
|
||||
insertAchievementSeriesData,
|
||||
insertNameCardData,
|
||||
insertCharacterData,
|
||||
} from "./insertData.js";
|
||||
import { insertNameCardData, insertCharacterData } from "./insertData.js";
|
||||
|
||||
/**
|
||||
* @description 初始化应用表数据
|
||||
@@ -51,24 +41,6 @@ async function initAppData(): Promise<string[]> {
|
||||
return sqlRes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 初始化成就系列数据
|
||||
* @since Alpha v0.2.0
|
||||
* @returns {string[]} sql
|
||||
*/
|
||||
function initAchievementSeriesData(): string[] {
|
||||
return AppAchievementSeriesData.map((item) => insertAchievementSeriesData(item));
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 初始化成就数据
|
||||
* @since Alpha v0.2.0
|
||||
* @returns {string[]} sql
|
||||
*/
|
||||
function initAchievementData(): string[] {
|
||||
return AppAchievementsData.map((item) => insertAchievementData(item));
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 初始化应用名片数据
|
||||
* @since Alpha v0.2.0
|
||||
@@ -96,8 +68,6 @@ async function initDataSql(): Promise<string[]> {
|
||||
const sqlRes: string[] = [];
|
||||
sqlRes.push(...initTableSql());
|
||||
sqlRes.push(...(await initAppData()));
|
||||
sqlRes.push(...initAchievementSeriesData());
|
||||
sqlRes.push(...initAchievementData());
|
||||
sqlRes.push(...initNameCardData());
|
||||
sqlRes.push(...initCharacterData());
|
||||
return sqlRes;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* @file plugins/Sqlite/sql/insertData.ts
|
||||
* @description Sqlite 插入数据 sql 语句
|
||||
* @since Beta v0.5.3
|
||||
* @since Beta v0.6.0
|
||||
*/
|
||||
|
||||
import { transCharacterData, transFloorData } from "../utils/transAbyssData.js";
|
||||
@@ -9,48 +9,6 @@ import { timeToSecond } from "../utils/transTime.js";
|
||||
import { transUserRecord } from "../utils/transUserRecord.js";
|
||||
import { transUserRoles } from "../utils/transUserRoles.js";
|
||||
|
||||
/**
|
||||
* @description 插入成就数据
|
||||
* @since Alpha v0.2.0
|
||||
* @param {TGApp.App.Achievement.Item} data 成就数据
|
||||
* @returns {string} sql
|
||||
*/
|
||||
export function insertAchievementData(data: TGApp.App.Achievement.Item): string {
|
||||
return `
|
||||
INSERT INTO Achievements (id, series, "order", name, description, reward, completedTime, version, updated)
|
||||
VALUES (${data.id}, ${data.series}, ${data.order}, '${data.name}', '${data.description}', ${data.reward}, '',
|
||||
'${data.version}', datetime('now', 'localtime'))
|
||||
ON CONFLICT(id) DO UPDATE
|
||||
SET series = ${data.series},
|
||||
"order" = ${data.order},
|
||||
name = '${data.name}',
|
||||
description = '${data.description}',
|
||||
reward = '${data.reward}',
|
||||
version = '${data.version}',
|
||||
updated = datetime('now', 'localtime');
|
||||
`;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 插入成就系列数据
|
||||
* @since Alpha v0.2.0
|
||||
* @param {TGApp.App.Achievement.Series} data 成就系列数据
|
||||
* @returns {string} sql
|
||||
*/
|
||||
export function insertAchievementSeriesData(data: TGApp.App.Achievement.Series): string {
|
||||
return `
|
||||
INSERT INTO AchievementSeries (id, "order", name, version, nameCard, updated)
|
||||
VALUES (${data.id}, ${data.order}, '${data.name}', '${data.version}', '${data.card}',
|
||||
datetime('now', 'localtime'))
|
||||
ON CONFLICT(id) DO UPDATE
|
||||
SET name = '${data.name}',
|
||||
"order" = ${data.order},
|
||||
version = '${data.version}',
|
||||
nameCard = '${data.card}',
|
||||
updated = datetime('now', 'localtime');
|
||||
`;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 插入应用数据
|
||||
* @since Alpha v0.2.0
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
/**
|
||||
* @file plugins/Sqlite/sql/updateData.ts
|
||||
* @description 更新数据
|
||||
* @since Beta v0.4.9
|
||||
*/
|
||||
|
||||
import minifySql from "../../../utils/minifySql.js";
|
||||
|
||||
/**
|
||||
* @description 导入UIAF数据-单项
|
||||
* @since Beta v0.4.9
|
||||
* @param {TGApp.Plugins.UIAF.Achievement} data
|
||||
* @returns {string} sql
|
||||
*/
|
||||
export function importUIAFData(data: TGApp.Plugins.UIAF.Achievement): string {
|
||||
let sql;
|
||||
const isCompleted = data.status === 2 || data.status === 3;
|
||||
if (isCompleted) {
|
||||
const completedTime = new Date(data.timestamp * 1000)
|
||||
.toISOString()
|
||||
.replace("T", " ")
|
||||
.slice(0, 19);
|
||||
sql = `
|
||||
UPDATE Achievements
|
||||
SET isCompleted = 1,
|
||||
completedTime = '${completedTime}',
|
||||
progress = ${data.current},
|
||||
updated = datetime('now', 'localtime')
|
||||
WHERE id = ${data.id}
|
||||
AND (isCompleted = 0 OR completedTime != '${completedTime}'
|
||||
OR progress != ${data.current});
|
||||
`;
|
||||
} else {
|
||||
sql = `
|
||||
UPDATE Achievements
|
||||
SET progress = ${data.current},
|
||||
updated = datetime('now', 'localtime')
|
||||
WHERE id = ${data.id}
|
||||
AND progress != ${data.current};
|
||||
`;
|
||||
}
|
||||
return minifySql(sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 导入UIGF数据-单项
|
||||
* @since Beta v0.4.7
|
||||
* @param {string} uid - UID
|
||||
* @param {TGApp.Plugins.UIGF.GachaItem} gacha - UIGF数据
|
||||
* @returns {string} sql
|
||||
*/
|
||||
export function importUIGFData(uid: string, gacha: TGApp.Plugins.UIGF.GachaItem): string {
|
||||
const sql = `
|
||||
INSERT INTO GachaRecords (uid, gachaType, itemId, count, time, name, type, rank, id, uigfType, updated)
|
||||
VALUES ('${uid}', '${gacha.gacha_type}', '${gacha.item_id ?? null}', '${gacha.count ?? null}', '${gacha.time}',
|
||||
'${gacha.name}', '${gacha.item_type ?? null}', '${gacha.rank_type ?? null}', '${gacha.id}',
|
||||
'${gacha.uigf_gacha_type}', datetime('now', 'localtime'))
|
||||
ON CONFLICT (id)
|
||||
DO UPDATE
|
||||
SET uid = '${uid}',
|
||||
gachaType = '${gacha.gacha_type}',
|
||||
uigfType = '${gacha.uigf_gacha_type}',
|
||||
time = '${gacha.time}',
|
||||
itemId = '${gacha.item_id ?? null}',
|
||||
count = '${gacha.count ?? null}',
|
||||
name = '${gacha.name}',
|
||||
type = '${gacha.item_type ?? null}',
|
||||
rank = '${gacha.rank_type ?? null}',
|
||||
updated = datetime('now', 'localtime');
|
||||
`;
|
||||
return minifySql(sql);
|
||||
}
|
||||
Reference in New Issue
Block a user