mirror of
https://github.com/BTMuli/TeyvatGuide.git
synced 2025-12-10 08:58:15 +08:00
@@ -1,13 +1,14 @@
|
||||
<template>
|
||||
<div v-if="!props.modelValue">暂无数据</div>
|
||||
<div v-else class="tur-wg-box">
|
||||
<TurWorldSub v-for="(area, index) in getData()" :key="index" :data="area" :theme="theme" />
|
||||
<TurWorldSub v-for="area in getData()" :key="area.id" :data="area" :theme="theme" />
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { computed } from "vue";
|
||||
|
||||
import TurWorldSub from "./tur-world-sub.vue";
|
||||
import showSnackbar from "../func/snackbar";
|
||||
|
||||
interface TurWorldGridProps {
|
||||
modelValue?: string;
|
||||
@@ -24,7 +25,19 @@ const theme = computed(() => {
|
||||
});
|
||||
|
||||
function getData(): TGApp.Sqlite.Record.WorldExplore[] {
|
||||
return JSON.parse(<string>props.modelValue);
|
||||
let res: TGApp.Sqlite.Record.WorldExplore[] = JSON.parse(<string>props.modelValue);
|
||||
try {
|
||||
if (res[0].children) {
|
||||
console.log("检测到children字段");
|
||||
}
|
||||
} catch (e) {
|
||||
showSnackbar({
|
||||
text: "数据解析错误,建议刷新页面",
|
||||
color: "error",
|
||||
});
|
||||
res = [];
|
||||
}
|
||||
return res;
|
||||
}
|
||||
</script>
|
||||
<style lang="css" scoped>
|
||||
|
||||
@@ -1,34 +1,38 @@
|
||||
<template>
|
||||
<div
|
||||
class="tur-ws-box"
|
||||
:style="{
|
||||
backgroundImage: `url('${getUrl.bg}')`,
|
||||
backgroundPositionX: 'right',
|
||||
backgroundSize: 'cover',
|
||||
backgroundRepeat: 'no-repeat',
|
||||
}"
|
||||
>
|
||||
<div class="tur-ws-box">
|
||||
<div class="tur-ws-icon">
|
||||
<img :src="getUrl.icon" alt="icon" />
|
||||
<img :src="icon" alt="icon" />
|
||||
</div>
|
||||
<div class="tur-ws-content">
|
||||
<div class="tur-ws-title">
|
||||
{{ data.name }}
|
||||
<span>{{ data.name }}</span>
|
||||
<span v-if="data.offering" class="tur-ws-sub">
|
||||
<img :src="offer" alt="offer" />
|
||||
<span>{{ data.offering.name }}等级:</span>
|
||||
<span>{{ data.offering.level }}</span>
|
||||
<span>级</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="tur-ws-sub">
|
||||
<div class="tur-ws-sub" v-if="data.children.length === 0">
|
||||
<span>探索度:</span>
|
||||
<span>{{ data.exploration / 10 }}</span>
|
||||
<span>%</span>
|
||||
</div>
|
||||
<div v-if="data.type === 'Reputation'" class="tur-ws-sub">
|
||||
<span>声望等级:</span>
|
||||
<span>{{ data.level }}</span>
|
||||
<span>级</span>
|
||||
<div v-else>
|
||||
<div class="tur-ws-sub" v-if="data.exploration !== 0">
|
||||
<span>{{ data.name }}探索度:</span>
|
||||
<span>{{ data.exploration / 10 }}</span>
|
||||
<span>%</span>
|
||||
</div>
|
||||
<div class="tur-ws-sub" v-for="item in data.children" :key="item.id">
|
||||
<span>{{ item.name }}探索度:</span>
|
||||
<span>{{ item.exploration / 10 }}</span>
|
||||
<span>%</span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="data.offerings.length > 0" class="tur-ws-sub">
|
||||
<img :src="getUrl.offer" alt="offer" />
|
||||
<span>{{ data.offerings[0].name }}等级:</span>
|
||||
<span>{{ data.offerings[0].level }}</span>
|
||||
<div v-if="data.reputation" class="tur-ws-sub">
|
||||
<span>声望等级:</span>
|
||||
<span>{{ data.reputation }}</span>
|
||||
<span>级</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -36,7 +40,8 @@
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { event } from "@tauri-apps/api";
|
||||
import { onMounted, ref } from "vue";
|
||||
import { UnlistenFn } from "@tauri-apps/api/helpers/event";
|
||||
import { onMounted, onUnmounted, ref } from "vue";
|
||||
|
||||
import { saveImgLocal } from "../../utils/TGShare";
|
||||
|
||||
@@ -46,37 +51,48 @@ interface TurWorldSubProps {
|
||||
}
|
||||
|
||||
const props = defineProps<TurWorldSubProps>();
|
||||
const getUrl = ref({
|
||||
bg: "",
|
||||
icon: "",
|
||||
iconLight: "",
|
||||
iconDark: "",
|
||||
offer: "",
|
||||
});
|
||||
let themeListener: UnlistenFn;
|
||||
const bg = ref<string>();
|
||||
const icon = ref<string>();
|
||||
const iconLight = ref<string>();
|
||||
const iconDark = ref<string>();
|
||||
const offer = ref<string>();
|
||||
|
||||
onMounted(async () => {
|
||||
await listenOnTheme();
|
||||
getUrl.value.bg = await saveImgLocal(props.data.bg);
|
||||
getUrl.value.iconLight = await saveImgLocal(props.data.iconLight);
|
||||
getUrl.value.iconDark = await saveImgLocal(props.data.iconDark);
|
||||
if (props.data.offerings.length > 0) {
|
||||
getUrl.value.offer = await saveImgLocal(props.data.offerings[0].icon);
|
||||
}
|
||||
props.theme === "dark"
|
||||
? (getUrl.value.icon = getUrl.value.iconLight)
|
||||
: (getUrl.value.icon = getUrl.value.iconDark);
|
||||
});
|
||||
|
||||
async function listenOnTheme(): Promise<void> {
|
||||
await event.listen("readTheme", (e) => {
|
||||
themeListener = await event.listen("readTheme", (e) => {
|
||||
const theme = <string>e.payload;
|
||||
if (theme === "dark") {
|
||||
getUrl.value.icon = getUrl.value.iconLight;
|
||||
icon.value = iconLight.value;
|
||||
} else {
|
||||
getUrl.value.icon = getUrl.value.iconDark;
|
||||
icon.value = iconDark.value;
|
||||
}
|
||||
});
|
||||
}
|
||||
bg.value = `url('${await saveImgLocal(props.data.bg)}')`;
|
||||
iconLight.value = await saveImgLocal(props.data.iconLight);
|
||||
iconDark.value = await saveImgLocal(props.data.iconDark);
|
||||
if (props.data.offering) {
|
||||
offer.value = await saveImgLocal(props.data.offering.icon);
|
||||
}
|
||||
props.theme === "dark" ? (icon.value = iconLight.value) : (icon.value = iconDark.value);
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
if (themeListener) {
|
||||
themeListener();
|
||||
}
|
||||
const urlList = [iconLight.value, iconDark.value, offer.value];
|
||||
urlList.forEach((url) => {
|
||||
URL.revokeObjectURL(typeof url === "string" ? url : "");
|
||||
});
|
||||
const reg = /url\(['"]?([^'"]*)['"]?\)/;
|
||||
if (bg.value) {
|
||||
const bgOri = bg.value?.replace("url('", "").replace("')", "");
|
||||
const bgUrl = bgOri.match(reg);
|
||||
if (bgUrl) {
|
||||
URL.revokeObjectURL(bgUrl[1]);
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<style lang="css" scoped>
|
||||
.tur-ws-box {
|
||||
@@ -86,6 +102,10 @@ async function listenOnTheme(): Promise<void> {
|
||||
padding: 10px;
|
||||
border-radius: 5px;
|
||||
background: var(--box-bg-2);
|
||||
background-image: v-bind(bg);
|
||||
background-position-x: right;
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
.tur-ws-icon {
|
||||
@@ -106,6 +126,9 @@ async function listenOnTheme(): Promise<void> {
|
||||
}
|
||||
|
||||
.tur-ws-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
border-bottom: 1px inset var(--common-shadow-8);
|
||||
font-family: var(--font-title);
|
||||
font-size: 20px;
|
||||
|
||||
@@ -104,7 +104,6 @@ async function refresh(): Promise<void> {
|
||||
const res = await TGRequest.User.getRecord(cookie, user);
|
||||
if (!("retcode" in res)) {
|
||||
await TGLogger.Info(`[UserRecord][refresh][${user.gameUid}] 获取战绩数据成功`);
|
||||
await TGLogger.Info(`[UserRecord][refresh][${user.gameUid}] ${JSON.stringify(res)}`, false);
|
||||
loadingTitle.value = "正在保存战绩数据";
|
||||
await TGSqlite.saveUserRecord(res, user.gameUid);
|
||||
await initUserRecordData();
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
/**
|
||||
* @file plugins Sqlite utils transUserRecord.ts
|
||||
* @file plugins/Sqlite/utils/transUserRecord.ts
|
||||
* @description Sqlite 数据转换 用户战绩数据转换模块
|
||||
* @author BTMuli <bt-muli@outlook.com>
|
||||
* @since Alpha v0.2.2
|
||||
* @since Beta v0.4.3
|
||||
*/
|
||||
|
||||
/**
|
||||
* @description 将通过 api 获取到的用户战绩数据转换为数据库中的数据
|
||||
* @since Alpha v0.2.0
|
||||
* @since Beta v0.4.3
|
||||
* @param {TGApp.Game.Record.FullData} data 用户战绩数据
|
||||
* @returns {TGApp.Sqlite.Record.SingleTable} 转换后的用户战绩数据
|
||||
*/
|
||||
@@ -17,7 +16,7 @@ export function transUserRecord(data: TGApp.Game.Record.FullData): TGApp.Sqlite.
|
||||
role: transRole(data.role),
|
||||
avatars: transAvatar(data.avatars),
|
||||
stats: transStat(data.stats),
|
||||
worldExplore: transWorld(data.world_explorations),
|
||||
worldExplore: JSON.stringify(transWorld(data.world_explorations)),
|
||||
homes: transHome(data.homes),
|
||||
updated: "",
|
||||
};
|
||||
@@ -108,35 +107,47 @@ function transStat(data: TGApp.Game.Record.Stats): string {
|
||||
|
||||
/**
|
||||
* @description 将探索信息转换为数据库中的数据
|
||||
* @since Alpha v0.2.0
|
||||
* @since Beta v0.4.3
|
||||
* @param {TGApp.Game.Record.WorldExplore[]} data 城市探索信息
|
||||
* @returns {string} 转换后的城市探索信息
|
||||
* @returns {TGApp.Sqlite.Record.WorldExplore[]} 转换后的城市探索信息
|
||||
*/
|
||||
function transWorld(data: TGApp.Game.Record.WorldExplore[]): string {
|
||||
const worlds: TGApp.Sqlite.Record.WorldExplore[] = data.map((item) => {
|
||||
let offerings: TGApp.Sqlite.Record.WorldOffering[] = [];
|
||||
if (item.offerings !== undefined) {
|
||||
offerings = item.offerings.map((offering) => {
|
||||
return {
|
||||
name: offering.name,
|
||||
icon: offering.icon,
|
||||
level: offering.level,
|
||||
};
|
||||
});
|
||||
}
|
||||
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,
|
||||
function transWorld(data: TGApp.Game.Record.WorldExplore[]): TGApp.Sqlite.Record.WorldExplore[] {
|
||||
const areaParent = data.filter((i) => i.parent_id === 0);
|
||||
const areaChild = data.filter((i) => i.parent_id !== 0);
|
||||
const worlds: TGApp.Sqlite.Record.WorldExplore[] = [];
|
||||
// 先处理父级城市
|
||||
for (const area of areaParent) {
|
||||
const world: TGApp.Sqlite.Record.WorldExplore = {
|
||||
id: area.id,
|
||||
name: area.name,
|
||||
iconLight: area.icon,
|
||||
iconDark: area.inner_icon,
|
||||
bg: area.background_image,
|
||||
cover: area.cover,
|
||||
exploration: area.exploration_percentage,
|
||||
children: [],
|
||||
};
|
||||
});
|
||||
return JSON.stringify(worlds);
|
||||
if (area.type === "Reputation") {
|
||||
world.reputation = area.level;
|
||||
}
|
||||
if (area.offerings !== undefined && area.offerings.length > 0) {
|
||||
world.offering = {
|
||||
name: area.offerings[0].name,
|
||||
level: area.offerings[0].level,
|
||||
icon: area.offerings[0].icon,
|
||||
};
|
||||
}
|
||||
const children = areaChild.filter((i) => i.parent_id === area.id);
|
||||
children.map((child) => {
|
||||
return world.children.push({
|
||||
id: child.id,
|
||||
name: child.name,
|
||||
exploration: child.exploration_percentage,
|
||||
});
|
||||
});
|
||||
worlds.push(world);
|
||||
}
|
||||
return worlds;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
68
src/types/Sqlite/Record.d.ts
vendored
68
src/types/Sqlite/Record.d.ts
vendored
@@ -1,10 +1,15 @@
|
||||
/**
|
||||
* @file types Sqlite Record.d.ts
|
||||
* @file types/Sqlite/Record.d.ts
|
||||
* @description Sqlite 原神战绩相关类型定义文件
|
||||
* @author BTMuli <bt-muli@outlook.com>
|
||||
* @since Alpha v0.2.2
|
||||
* @since Beta v0.4.3
|
||||
*/
|
||||
|
||||
/**
|
||||
* @description Sqlite 原神战绩相关类型定义命名空间
|
||||
* @since Beta v0.4.3
|
||||
* @namespace Record
|
||||
* @memberof TGApp.Sqlite
|
||||
*/
|
||||
declare namespace TGApp.Sqlite.Record {
|
||||
/**
|
||||
* @description 原神战绩数据表
|
||||
@@ -20,7 +25,7 @@ declare namespace TGApp.Sqlite.Record {
|
||||
* @property {string} updated - 更新时间
|
||||
* @return SingleTable
|
||||
*/
|
||||
export interface SingleTable {
|
||||
interface SingleTable {
|
||||
uid: string;
|
||||
role: string; // Role
|
||||
avatars: string; // Avatar[]
|
||||
@@ -39,7 +44,7 @@ declare namespace TGApp.Sqlite.Record {
|
||||
* @property {number} level - 等级
|
||||
* @return Role
|
||||
*/
|
||||
export interface Role {
|
||||
interface Role {
|
||||
nickname: string;
|
||||
region: string;
|
||||
level: number;
|
||||
@@ -59,7 +64,7 @@ declare namespace TGApp.Sqlite.Record {
|
||||
* @property {boolean} isShow - 角色是否展示
|
||||
* @return Avatar
|
||||
*/
|
||||
export interface Avatar {
|
||||
interface Avatar {
|
||||
id: number;
|
||||
name: string;
|
||||
element: string;
|
||||
@@ -92,7 +97,7 @@ declare namespace TGApp.Sqlite.Record {
|
||||
* @property {number} magicChest - 奇馈宝箱数
|
||||
* @return Stats
|
||||
*/
|
||||
export interface Stats {
|
||||
interface Stats {
|
||||
activeDays: number;
|
||||
achievementNumber: number;
|
||||
avatarNumber: number;
|
||||
@@ -114,28 +119,30 @@ declare namespace TGApp.Sqlite.Record {
|
||||
/**
|
||||
* @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 - 祭祀物
|
||||
* @since Beta v0.4.3
|
||||
* @property {number} id - 地区 ID
|
||||
* @property {string} name - 地区名称
|
||||
* @property {string} iconLight - 地区图标(亮)
|
||||
* @property {string} iconDark - 地区图标(暗)
|
||||
* @property {string} bg - 背景
|
||||
* @property {string} cover - 封面
|
||||
* @property {number} reputation - 地区声望等级
|
||||
* @property {WorldOffering} offering - 地区供奉信息
|
||||
* @property {number} exploration - 地区探索进度
|
||||
* @property {WorldChild[]} children - 子地区
|
||||
* @return WorldExplore
|
||||
*/
|
||||
export interface WorldExplore {
|
||||
level: number;
|
||||
exploration: number;
|
||||
interface WorldExplore {
|
||||
id: number;
|
||||
name: string;
|
||||
iconLight: string;
|
||||
iconDark: string;
|
||||
name: string;
|
||||
type: string;
|
||||
offerings: WorldOffering[];
|
||||
bg: string;
|
||||
cover: string;
|
||||
reputation?: number;
|
||||
offering?: WorldOffering;
|
||||
exploration: number;
|
||||
children: WorldChild[];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -147,12 +154,27 @@ declare namespace TGApp.Sqlite.Record {
|
||||
* @property {string} icon - 图标
|
||||
* @return WorldOffering
|
||||
*/
|
||||
export interface WorldOffering {
|
||||
interface WorldOffering {
|
||||
name: string;
|
||||
level: number;
|
||||
icon: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 子地区类型
|
||||
* @interface WorldChild
|
||||
* @since Beta v0.4.3
|
||||
* @property {number} id - 子地区 ID
|
||||
* @property {string} name - 子地区名称
|
||||
* @property {number} exploration - 子地区探索进度
|
||||
* @return WorldChild
|
||||
*/
|
||||
interface WorldChild {
|
||||
id: number;
|
||||
name: string;
|
||||
exploration: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 尘歌壶信息类型
|
||||
* @interface Home
|
||||
@@ -167,7 +189,7 @@ declare namespace TGApp.Sqlite.Record {
|
||||
* @property {string} bg - 背景
|
||||
* @return Home
|
||||
*/
|
||||
export interface Home {
|
||||
interface Home {
|
||||
comfortIcon: string;
|
||||
comfortName: string;
|
||||
name: string;
|
||||
|
||||
@@ -33,7 +33,7 @@ export async function getGameRecord(
|
||||
})
|
||||
.then((res) => {
|
||||
if (res.data.retcode !== 0) {
|
||||
return res.data;
|
||||
return <TGApp.BBS.Response.Base>res.data;
|
||||
}
|
||||
return res.data.data;
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user