将战绩数据存到数据库中

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
</v-btn>
<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

@@ -35,15 +35,15 @@ create table if not exists AchievementSeries
-- @brief 创建角色数据表
create table if not exists AppCharacters
(
id integer primary key,
name text,
title text,
birthday text,
star integer,
element text,
weapon text,
nameCard text,
updated text
id integer primary key,
name text,
title text,
birthday text,
star integer,
element text,
weapon text,
nameCard text,
updated text
);
-- @brief 创建应用数据表
@@ -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);
return res.data;
if (res.data.retcode !== 0) {
return res.data;
}
return res.data.data;
});
}