将战绩数据存到数据库中

This commit is contained in:
BTMuli
2023-06-03 00:20:24 +08:00
parent 1c9989a030
commit 9f07918b27
7 changed files with 534 additions and 47 deletions

View File

@@ -1,45 +1,137 @@
<template>
<h1>实时便笺数据总览世界探索尘歌壶札记跳转</h1>
<!-- todo Invalid uid -->
<v-btn @click="getInfo1">
获取用户游戏数据1
</v-btn>
<v-btn @click="getInfo2">
获取用户游戏数据2
<ToLoading v-model="loading" :title="loadingTitle" />
<div class="ur-box">
<div class="ur-top">
<div class="ur-top-title">
原神战绩 更新于 {{ recordData.updated }}
</div>
<v-btn variant="outlined" class="ur-top-btn" @click="refresh">
更新数据
</v-btn>
</div>
<div class="ur-sub-title">
<img src="/src/assets/icons/arrow-right.svg" alt="overview">
<span>数据总览</span>
</div>
<div class="ur-overview-grid">
<!-- <TurOverview title="活跃天数" :text="recordData.stats.active_day_number" />-->
</div>
</div>
{{ recordData }}
</template>
<script lang="ts" setup>
// vue
import { onMounted, ref } from "vue";
import { computed, onMounted, ref } from "vue";
import ToLoading from "../../components/overlay/to-loading.vue";
import TurOverview from "../../components/userRecord/tur-overview.vue";
// tauri
import { fs } from "@tauri-apps/api";
// store
import { useAppStore } from "../../store/modules/app";
import { useUserStore } from "../../store/modules/user";
// utils
import TGRequest from "../../web/request/TGRequest";
import TGSqlite from "../../utils/TGSqlite";
import TGSqlite from "../../plugins/Sqlite";
// store
const appStore = useAppStore();
const userStore = useUserStore();
// loading
const loading = ref(false);
const loadingTitle = ref("");
// data
const user = ref({} as TGApp.Sqlite.Account.Game);
const recordData = ref({} as TGApp.Sqlite.Record.SingleTable);
const recordCookie = computed(() => userStore.getCookieGroup2() as Record<string, string>);
const user = computed(() => userStore.getCurAccount());
const filePath = computed(() => `${appStore.dataPath.userDataDir}/recordData.json`);
onMounted(async () => {
const curUser = await TGSqlite.getCurAccount();
if (curUser) {
user.value = curUser;
}
console.log(user.value);
loadingTitle.value = "正在加载战绩数据";
loading.value = true;
await initUserRecordData();
loading.value = false;
});
async function getInfo1 () {
const ck = userStore.getCookieGroup2() as Record<string, string>;
const res = await TGRequest.User.getRecord(ck, user.value);
async function initUserRecordData () {
const recordGet = await TGSqlite.getUserRecord(user.value.gameUid);
if (recordGet !== false) {
recordData.value = recordGet;
} else {
await refresh();
}
}
async function getInfo2 () {
const ck = userStore.getCookieGroup3() as Record<string, string>;
const res = await TGRequest.User.getRecord(ck, user.value);
async function refresh () {
loadingTitle.value = "正在获取战绩数据";
loading.value = true;
const res = await TGRequest.User.getRecord(recordCookie.value, user.value);
if (!res.hasOwnProperty("retcode")) {
const data = res as TGApp.Game.Record.FullData;
loadingTitle.value = "正在保存战绩数据";
await TGSqlite.saveUserRecord(data, user.value.gameUid);
await initUserRecordData();
}
loading.value = false;
}
</script>
<style lang="css" scoped>
.ur-box {
width: 100%;
border-radius: 5px;
padding: 10px;
box-shadow: 0 0 10px rgb(0 0 0 / 40%);
}
.ur-top {
width: 100%;
height: 50px;
border-radius: 5px;
padding: 10px;
display: flex;
align-items: center;
}
.ur-top-title {
font-family: Genshin, sans-serif;
font-size: 20px;
margin-right: 10px;
color: rgb(255 255 255 / 80%);
text-shadow: 0 0 10px rgb(0 0 0 / 80%);
}
.ur-top-btn {
font-family: Genshin-Light, serif;
border-radius: 5px;
background: #393b40;
color: #faf7e8;
margin-left: auto;
}
.ur-sub-title {
background: rgb(0 0 0 / 20%);
display: flex;
align-items: center;
height: 30px;
padding: 0 10px;
margin: 5px 0;
border-radius: 5px;
font-family: Genshin-Light, serif;
color: rgb(255 255 255 / 80%);
text-shadow: 0 0 10px rgb(0 0 0 / 80%);
}
.ur-sub-title img {
width: 20px;
height: 20px;
margin-right: 5px;
}
.ur-overview-grid {
display: grid;
grid-template-columns: repeat(5, 1fr);
grid-gap: 10px;
margin-bottom: 10px;
}
</style>

View File

@@ -12,7 +12,12 @@ import initDataSql from "./sql/initData";
import initTableSql from "./sql/initTable";
import { importUIAFData } from "./sql/updateData";
import { getUiafStatus } from "../../utils/UIAF";
import { insertAbyssData, insertAppData, insertGameAccountData } from "./sql/insertData";
import {
insertAbyssData,
insertAppData,
insertGameAccountData,
insertRecordData,
} from "./sql/insertData";
class Sqlite {
/**
@@ -34,6 +39,7 @@ class Sqlite {
"GameAccount",
"NameCard",
"SprialAbyss",
"UserRecord",
];
/**
@@ -336,6 +342,35 @@ class Sqlite {
return res;
}
/**
* @description 保存战绩数据
* @since Alpha v0.2.0
* @param {TGApp.Game.Record.FullData} data 战绩数据
* @param {string} uid 用户 uid
* @returns {Promise<void>}
*/
public async saveUserRecord (data: TGApp.Game.Record.FullData, uid: string): Promise<void> {
const db = await Database.load(this.dbPath);
const sql = insertRecordData(data, uid);
await db.execute(sql);
await db.close();
}
/**
* @description 获取战绩数据
* @since Alpha v0.2.0
* @param {string} uid 用户 uid
* @returns {Promise<TGApp.Sqlite.Record.SingleTable|false>}
*/
public async getUserRecord (uid: string): Promise<TGApp.Sqlite.Record.SingleTable | false> {
const db = await Database.load(this.dbPath);
const sql = `SELECT * FROM UserRecord WHERE uid = '${uid}'`;
const res: TGApp.Sqlite.Record.SingleTable[] = await db.select(sql);
await db.close();
if (res.length === 0) return false;
return res[0];
}
/**
* @description 获取角色数据
* @since Alpha v0.2.0

View File

@@ -100,3 +100,15 @@ create table if not exists SpiralAbyss
floors text,
updated text
);
-- @brief 创建战绩数据表
create table if not exists UserRecord
(
uid integer primary key,
role text,
avatars text,
stats text,
worldExplore text,
homes text,
updated text
)

View File

@@ -8,6 +8,7 @@
// utils
import { timeToSecond } from "../utils/transTime";
import { transCharacterData, transFloorData } from "../utils/transAbyssData";
import { transUserRecord } from "../utils/transUserRecord";
/**
* @description 插入成就数据
@@ -15,7 +16,7 @@ import { transCharacterData, transFloorData } from "../utils/transAbyssData";
* @param {TGApp.App.Achievement.Item} data 成就数据
* @returns {string} sql
*/
export function insertAchievementData(data: TGApp.App.Achievement.Item): string {
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}, '',
@@ -37,7 +38,7 @@ export function insertAchievementData(data: TGApp.App.Achievement.Item): string
* @param {TGApp.App.Achievement.Series} data 成就系列数据
* @returns {string} sql
*/
export function insertAchievementSeriesData(data: TGApp.App.Achievement.Series): string {
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}',
@@ -58,7 +59,7 @@ export function insertAchievementSeriesData(data: TGApp.App.Achievement.Series):
* @param {string} value 值
* @returns {string} sql
*/
export function insertAppData(key: string, value: string): string {
export function insertAppData (key: string, value: string): string {
return `
INSERT INTO AppData (key, value, updated)
VALUES ('${key}', '${value}', datetime('now', 'localtime'))
@@ -73,7 +74,7 @@ export function insertAppData(key: string, value: string): string {
* @param {TGApp.User.Account.Game} data 游戏账号数据
* @returns {string} sql
*/
export function insertGameAccountData(data: TGApp.User.Account.Game): string {
export function insertGameAccountData (data: TGApp.User.Account.Game): string {
const isChosen = data.is_chosen ? 1 : 0;
const isOfficial = data.is_official ? 1 : 0;
return `
@@ -97,7 +98,7 @@ export function insertGameAccountData(data: TGApp.User.Account.Game): string {
* @param {TGApp.App.NameCard.Item} data 名片数据
* @returns {string} sql
*/
export function insertNameCardData(data: TGApp.App.NameCard.Item): string {
export function insertNameCardData (data: TGApp.App.NameCard.Item): string {
return `
INSERT INTO NameCard (name, "desc", type, source, updated)
VALUES ('${data.name}', '${data.desc}', '${data.type}', '${data.source}', datetime('now', 'localtime'))
@@ -114,7 +115,7 @@ export function insertNameCardData(data: TGApp.App.NameCard.Item): string {
* @param {TGApp.User.Character.Item} data 角色数据
* @returns {string} sql
*/
export function insertCharacterData(data: TGApp.App.Character.WikiBriefInfo): string {
export function insertCharacterData (data: TGApp.App.Character.WikiBriefInfo): string {
return `
INSERT INTO AppCharacters (id, name, star, element, weapon, nameCard, birthday, updated)
VALUES (${data.id}, '${data.name}', ${data.star}, '${data.element}', '${data.weapon}',
@@ -135,7 +136,7 @@ export function insertCharacterData(data: TGApp.App.Character.WikiBriefInfo): st
* @param {TGApp.User.Abyss} data 深渊数据
* @returns {string} sql
*/
export function insertAbyssData(data: TGApp.Game.Abyss.FullData): string {
export function insertAbyssData (data: TGApp.Game.Abyss.FullData): string {
const startTime = timeToSecond(data.start_time);
const endTime = timeToSecond(data.end_time);
const isUnlock = data.is_unlock ? 1 : 0;
@@ -172,3 +173,27 @@ export function insertAbyssData(data: TGApp.Game.Abyss.FullData): string {
updated = datetime('now', 'localtime');
`;
}
/**
* @description 插入原神战绩数据
* @since Alpha v0.2.0
* @param {TGApp.Game.Record.FullData} data 原神战绩数据
* @param {string} uid 用户 UID
* @returns {string} sql
*/
export function insertRecordData (data: TGApp.Game.Record.FullData, uid: string): string {
const transData = transUserRecord(data);
transData.uid = uid;
return `
INSERT INTO UserRecord(uid, role, avatars, stats, worldExplore, homes, updated)
VALUES ('${transData.uid}', '${transData.role}', '${transData.avatars}', '${transData.stats}',
'${transData.worldExplore}', '${transData.homes}', datetime('now', 'localtime'))
ON CONFLICT(uid) DO UPDATE
SET role = '${transData.role}',
avatars = '${transData.avatars}',
stats = '${transData.stats}',
worldExplore = '${transData.worldExplore}',
homes = '${transData.homes}',
updated = datetime('now', 'localtime');
`;
}

View File

@@ -0,0 +1,144 @@
/**
* @file plugins Sqlite utils transUserRecord.ts
* @description Sqlite 数据转换 用户战绩数据转换模块
* @author BTMuli <bt-muli@outlook.com>
* @since Alpha v0.2.0
*/
/**
* @description 将通过 api 获取到的用户战绩数据转换为数据库中的数据
* @since Alpha v0.2.0
* @param {TGApp.Game.Record.FullData} data 用户战绩数据
* @returns {TGApp.Sqlite.Record.SingleTable} 转换后的用户战绩数据
*/
export function transUserRecord (data: TGApp.Game.Record.FullData): TGApp.Sqlite.Record.SingleTable {
return {
uid: "",
role: transRole(data.role),
avatars: transAvatar(data.avatars),
stats: transStat(data.stats),
worldExplore: transWorld(data.world_explorations),
homes: transHome(data.homes),
updated: "",
};
}
/**
* @description 将角色信息转换为数据库中的数据
* @since Alpha v0.2.0
* @param {TGApp.Game.Record.Role} data 角色信息
* @returns {string} 转换后的角色信息
*/
function transRole (data: TGApp.Game.Record.Role): string {
const role: TGApp.Sqlite.Record.Role = {
nickname: data.nickname,
region: data.region,
level: data.level,
};
return JSON.stringify(role);
}
/**
* @description 将角色列表转换为数据库中的数据
* @since Alpha v0.2.0
* @param {TGApp.Game.Record.Avatar[]} data 角色列表
* @returns {string} 转换后的角色列表
*/
function transAvatar (data: TGApp.Game.Record.Avatar[]): string {
const avatars: TGApp.Sqlite.Record.Avatar[] = data.map(item => {
return {
id: item.id,
name: item.name,
element: item.element,
fetter: item.fetter,
level: item.level,
star: item.rarity,
constellation: item.actived_constellation_num,
isShow: item.is_chosen ? 1 : 0,
} as TGApp.Sqlite.Record.Avatar;
});
return JSON.stringify(avatars);
}
/**
* @description 将统计信息转换为数据库中的数据
* @since Alpha v0.2.0
* @param {TGApp.Game.Record.Stats} data 统计信息
* @return {string} 转换后的统计信息
*/
function transStat (data: TGApp.Game.Record.Stats): string {
const stats: TGApp.Sqlite.Record.Stats = {
activeDays: data.active_day_number,
achievementNumber: data.achievement_number,
avatarNumber: data.avatar_number,
wayPoints: data.way_point_number,
domainNumber: data.domain_number,
anemoCulus: data.anemoculus_number,
geoCulus: data.geoculus_number,
electroCulus: data.electroculus_number,
dendroCulus: data.dendroculus_number,
sprialAbyss: data.spiral_abyss,
luxuriousChest: data.luxurious_chest_number,
preciousChest: data.precious_chest_number,
exquisiteChest: data.exquisite_chest_number,
commonChest: data.common_chest_number,
magicChest: data.magic_chest_number,
};
return JSON.stringify(stats);
}
/**
* @description 将探索信息转换为数据库中的数据
* @since Alpha v0.2.0
* @param {TGApp.Game.Record.WorldExplore[]} data 城市探索信息
* @returns {string} 转换后的城市探索信息
*/
function transWorld (data: TGApp.Game.Record.WorldExplore[]): string {
const worlds: TGApp.Sqlite.Record.WorldExplore[] = data.map(item => {
let offerings;
console.log(item.Offerings);
if (item.Offerings !== undefined) {
offerings = item.Offerings.map(offering => {
return {
name: offering.name,
icon: offering.icon,
level: offering.level,
} as TGApp.Sqlite.Record.WorldOffering;
});
}
return {
level: item.level,
exploration: item.exploration_percentage,
iconLight: item.icon,
iconDark: item.inner_icon,
name: item.name,
type: item.type,
offerings,
bg: item.background_image,
cover: item.cover,
} as TGApp.Sqlite.Record.WorldExplore;
});
return JSON.stringify(worlds);
}
/**
* @description 将住宅信息转换为数据库中的数据
* @since Alpha v0.2.0
* @param {TGApp.Game.Record.Home[]} data 住宅信息
* @returns {string} 转换后的住宅信息
*/
function transHome (data: TGApp.Game.Record.Home[]): string {
const homes: TGApp.Sqlite.Record.Home[] = data.map(item => {
return {
comfortIcon: item.comfort_level_icon,
comfortName: item.comfort_level_name,
name: item.name,
level: item.level,
comfort: item.comfort_num,
furniture: item.item_num,
visit: item.visit_num,
bg: item.icon,
} as TGApp.Sqlite.Record.Home;
});
return JSON.stringify(homes);
}

178
src/types/Sqlite/Record.d.ts vendored Normal file
View File

@@ -0,0 +1,178 @@
/**
* @file types Sqlite Record.d.ts
* @description Sqlite 原神战绩相关类型定义文件
* @author BTMuli <bt-muli@outlook.com>
* @since Alpha v0.2.0
*/
declare namespace TGApp.Sqlite.Record {
/**
* @description 原神战绩数据表
* @interface SingleTable
* @since Alpha v0.2.0
* @property {string} uid - UID
* @description 下面的数据在数据库中以 string 类型存储
* @property {Role} role - 角色信息
* @property {Avatar[]} avatars - 角色列表
* @property {Stats} stats - 统计信息
* @property {WorldExplore} worldExplore - 世界探索信息
* @property {Home[]} homes - 尘歌壶信息
* @property {string} updated - 更新时间
* @return SingleTable
*/
export interface SingleTable {
uid: string
role: string // Role
avatars: string // Avatar[]
stats: string // Stats
worldExplore: string // WorldExplore
homes: string // Home[]
updated: string
}
/**
* @description 角色信息类型
* @interface Role
* @since Alpha v0.2.0
* @property {string} nickname - 角色昵称
* @property {string} region - 区域
* @property {number} level - 等级
* @return Role
*/
export interface Role {
nickname: string
region: string
level: number
}
/**
* @description 角色列表类型
* @interface Avatar
* @since Alpha v0.2.0
* @property {number} id - 角色 ID
* @property {string} name - 角色名称
* @property {string} element - 角色元素
* @property {number} fetter - 角色羁绊等级
* @property {number} level - 角色等级
* @property {number} star - 角色星级
* @property {number} constellation - 角色命座
* @property {boolean} isShow - 角色是否展示
* @return Avatar
*/
export interface Avatar {
id: number
name: string
element: string
fetter: number
level: number
star: number
constellation: number
isShow: 0 | 1
}
/**
* @description 统计信息类型
* @interface Stats
* @since Alpha v0.2.0
* @property {number} activeDays - 活跃天数
* @property {number} achievementNumber - 成就达成数
* @property {number} avatarNumber - 获得角色数
* @property {number} wayPoints - 解锁传送点数
* @property {number} domainNumber - 解锁秘境数
* @property {number} anemoCulus - 风神瞳数
* @property {number} geoCulus - 岩神瞳数
* @property {number} electroCulus - 雷神瞳数
* @property {number} dendroCulus - 草神瞳数
* @property {string} sprialAbyss - 深境螺旋信息
* @property {number} luxuriousChest - 华丽宝箱数
* @property {number} preciousChest - 珍贵宝箱数
* @property {number} exquisiteChest - 精致宝箱数
* @property {number} commonChest - 普通宝箱数
* @property {number} magicChest - 奇馈宝箱数
* @return Stats
*/
export interface Stats {
activeDays: number
achievementNumber: number
avatarNumber: number
wayPoints: number
domainNumber: number
anemoCulus: number
geoCulus: number
electroCulus: number
dendroCulus: number
sprialAbyss: string
luxuriousChest: number
preciousChest: number
exquisiteChest: number
commonChest: number
magicChest: number
}
/**
* @description 世界探索信息类型
* @interface WorldExplore
* @since Alpha v0.2.0
* @property {number} level - 等级
* @property {number} exploration - 探索度 // 千分比
* @property {string} iconLight - 图标(浅色)
* @property {string} iconDark - 图标(深色)
* @property {string} name - 名称
* @property {string} type - 类型
* @property {WorldOffering[]} offerings - 祭祀物
* @property {string} bg - 背景
* @property {string} cover - 封面
* @return WorldExplore
*/
export interface WorldExplore {
level: number
exploration: number
iconLight: string
iconDark: string
name: string
type: string
offerings: WorldOffering[]
bg: string
cover: string
}
/**
* @description 祭祀物类型
* @interface WorldOffering
* @since Alpha v0.2.0
* @property {string} name - 名称
* @property {number} level - 等级
* @property {string} icon - 图标
* @return WorldOffering
*/
export interface WorldOffering {
name: string
level: number
icon: string
}
/**
* @description 尘歌壶信息类型
* @interface Home
* @since Alpha v0.2.0
* @property {string} comfortIcon - 洞天仙力图标
* @property {string} comfortName - 洞天仙力名称
* @property {string} name - 洞天名称
* @property {number} level - 信任等阶
* @property {number} comfort - 最高洞天仙力
* @property {number} furniture - 获得摆设数
* @property {number} visit - ;历史访客数
* @property {string} bg - 背景
* @return Home
*/
export interface Home {
comfortIcon: string
comfortName: string
name: string
level: number
comfort: number
furniture: number
visit: number
bg: string
}
}

View File

@@ -14,23 +14,24 @@ import TGUtils from "../utils/TGUtils";
/**
* @description 获取用户游戏数据
* @since Alpha v0.2.0
* @todo invalid uid
* @description 这边的 ck 可以是 cookie_token 和 account_id
* @description 也可以是 ltoken 和 ltuid
* @param {Record<string, string>} cookie cookie
* @param {TGApp.Sqlite.Account.Game} user 用户的基本信息
* @returns {Promise<unknown>} 用户基本信息
* @returns {Promise<TGApp.Game.Record.FullData|TGApp.BBS.Response.Base>} 用户基本信息
*/
export async function getGameRecord (cookie: Record<string, string>, user: TGApp.Sqlite.Account.Game): Promise<unknown> {
const url = TGApi.GameData.getUserCard;
export async function getGameRecord (cookie: Record<string, string>, user: TGApp.Sqlite.Account.Game): Promise<TGApp.Game.Record.FullData | TGApp.BBS.Response.Base> {
const url = TGApi.GameData.getUserBase;
const params = { role_id: user.gameUid, server: user.region };
const header = TGUtils.User.getHeader(cookie, "GET", params, "common");
return await http.fetch(url, {
return await http.fetch<TGApp.Game.Record.Response>(url, {
method: "GET",
headers: header,
query: params,
}).then((res) => {
console.log(res.data);
if (res.data.retcode !== 0) {
return res.data;
}
return res.data.data;
});
}