mirror of
https://github.com/BTMuli/TeyvatGuide.git
synced 2025-12-14 09:38:13 +08:00
fix(achievement): 导入导出逻辑完成
This commit is contained in:
@@ -10,37 +10,16 @@
|
|||||||
<v-btn @click="importJson" prepend-icon="mdi-import" class="bg-green-accent-2">
|
<v-btn @click="importJson" prepend-icon="mdi-import" class="bg-green-accent-2">
|
||||||
导入
|
导入
|
||||||
</v-btn>
|
</v-btn>
|
||||||
<!-- 数据合并按钮 -->
|
|
||||||
<v-btn @click="mergeJson" prepend-icon="mdi-merge" class="ms-2 bg-green-accent-2">
|
|
||||||
合并
|
|
||||||
</v-btn>
|
|
||||||
<!-- 导出按钮 -->
|
<!-- 导出按钮 -->
|
||||||
<v-btn @click="exportJson" prepend-icon="mdi-export" class="ms-2 bg-green-accent-2">
|
<v-btn @click="exportJson" prepend-icon="mdi-export" class="ms-2 bg-green-accent-2">
|
||||||
导出
|
导出
|
||||||
</v-btn>
|
</v-btn>
|
||||||
</template>
|
</template>
|
||||||
</v-app-bar>
|
</v-app-bar>
|
||||||
<!-- 主体内容 -->
|
<!-- 主体内容 考虑 tabs?-->
|
||||||
<!-- 侧边成就系列列表 -->
|
|
||||||
<v-layout>
|
<v-layout>
|
||||||
<!-- 成就列表 -->
|
<!-- 左侧菜单 todo -->
|
||||||
<!-- todo 样式 -->
|
<!-- 右侧内容 todo -->
|
||||||
<v-container fluid>
|
|
||||||
<!-- <v-card>-->
|
|
||||||
<!-- <v-card-title>成就列表</v-card-title>-->
|
|
||||||
<!-- <v-card-text>-->
|
|
||||||
<!-- <v-list>-->
|
|
||||||
<!-- <v-list-item v-for="item in achievementsTrans" :key="item.id">-->
|
|
||||||
<!-- <v-divider></v-divider>-->
|
|
||||||
<!-- <v-list-item-title>成就 ID:{{ item.id }}</v-list-item-title>-->
|
|
||||||
<!-- <v-list-item-subtitle-->
|
|
||||||
<!-- >成就完成时间: {{ item.time }}</v-list-item-subtitle-->
|
|
||||||
<!-- >-->
|
|
||||||
<!-- </v-list-item>-->
|
|
||||||
<!-- </v-list>-->
|
|
||||||
<!-- </v-card-text>-->
|
|
||||||
<!-- </v-card>-->
|
|
||||||
</v-container>
|
|
||||||
</v-layout>
|
</v-layout>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -52,11 +31,11 @@ import UIAF_Oper from "../plugins/UIAF";
|
|||||||
import { dialog, fs } from "@tauri-apps/api";
|
import { dialog, fs } from "@tauri-apps/api";
|
||||||
import { UIAF_Achievement, Achievements } from "../plugins/UIAF/interface/UIAF";
|
import { UIAF_Achievement, Achievements } from "../plugins/UIAF/interface/UIAF";
|
||||||
import {
|
import {
|
||||||
Achievement as TGAchievement,
|
AchievementMap as TGAchievementMap,
|
||||||
AchievementSeries as TGAchievementSeries,
|
SeriesMap as TGSeriesMap,
|
||||||
AchievementDisplay as TGAchievementDisplay,
|
|
||||||
AchievementSeriesDisplay as TGAchievementSeriesDisplay,
|
|
||||||
} from "../interface/Achievements";
|
} from "../interface/Achievements";
|
||||||
|
import TGMap from "../utils/TGMap";
|
||||||
|
import { Map } from "../interface/Base";
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: "Achievements",
|
name: "Achievements",
|
||||||
@@ -65,16 +44,45 @@ export default defineComponent({
|
|||||||
// 标题 成就完成数/成就总数 完成率
|
// 标题 成就完成数/成就总数 完成率
|
||||||
title: "" as string,
|
title: "" as string,
|
||||||
// 成就系列列表,用于侧边栏
|
// 成就系列列表,用于侧边栏
|
||||||
seriesList: [] as TGAchievementSeries[],
|
seriesList: {} as Map<TGSeriesMap>,
|
||||||
// 成就列表-所有
|
// 成就列表-所有成就的数据
|
||||||
achievementsAll: [] as TGAchievementDisplay[],
|
achievementsList: {} as Map<TGAchievementMap>,
|
||||||
|
// 选中的成就系列 id,用于决定右侧显示的成就列表
|
||||||
|
selectedSeries: -1 as number,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
async mounted() {
|
async mounted() {
|
||||||
await this.loadData();
|
await this.loadData();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
// 导入
|
// 加载数据,数据源:合并后的本地数据
|
||||||
|
async loadData() {
|
||||||
|
const appStore = useAppStore();
|
||||||
|
const achievementsStore = useAchievementsStore();
|
||||||
|
const localSeriesPath = appStore.mergePath.achievementSeries;
|
||||||
|
const localAchievementsPath = appStore.mergePath.achievements;
|
||||||
|
const seriesMap: TGMap<TGSeriesMap> = new TGMap<TGSeriesMap>(
|
||||||
|
JSON.parse(await fs.readTextFile(localSeriesPath))
|
||||||
|
);
|
||||||
|
const achievementsMap: TGMap<TGAchievementMap> = new TGMap<TGAchievementMap>(
|
||||||
|
JSON.parse(await fs.readTextFile(localAchievementsPath))
|
||||||
|
);
|
||||||
|
await achievementsStore.flushData(seriesMap);
|
||||||
|
this.title = this.getTitle();
|
||||||
|
this.achievementsList = achievementsMap.getMap();
|
||||||
|
this.seriesList = seriesMap.getMap();
|
||||||
|
},
|
||||||
|
// 获取标题
|
||||||
|
getTitle() {
|
||||||
|
const achievementsStore = useAchievementsStore();
|
||||||
|
const achievementsAll = achievementsStore.total_achievements;
|
||||||
|
const achievementsDone = achievementsStore.fin_achievements;
|
||||||
|
return `成就完成数:${achievementsDone}/${achievementsAll} 完成率:${(
|
||||||
|
(achievementsDone / achievementsAll) *
|
||||||
|
100
|
||||||
|
).toFixed(2)}%`;
|
||||||
|
},
|
||||||
|
// 导入 UIAF 数据,进行数据合并、刷新
|
||||||
async importJson() {
|
async importJson() {
|
||||||
const appStore = useAppStore();
|
const appStore = useAppStore();
|
||||||
const localPath = appStore.userPath.achievements;
|
const localPath = appStore.userPath.achievements;
|
||||||
@@ -87,55 +95,71 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
// 选中文件
|
if (selectedFile && (await UIAF_Oper.importOper.checkUIAFData(<string>selectedFile))) {
|
||||||
if (selectedFile) {
|
|
||||||
console.log("正在读取本地文件...");
|
|
||||||
// 读取应用内文件
|
|
||||||
const localRaw: string | false = await UIAF_Oper.importOper.readUIAFData(localPath);
|
const localRaw: string | false = await UIAF_Oper.importOper.readUIAFData(localPath);
|
||||||
console.log("读取本地文件成功");
|
|
||||||
// 检测文件是否符合 UIAF 格式
|
|
||||||
console.log("正在检测文件格式...");
|
|
||||||
if (await UIAF_Oper.importOper.checkUIAFData(<string>selectedFile)) {
|
|
||||||
await console.log("检测文件格式成功, 开始导入...");
|
|
||||||
// 读取选中文件
|
|
||||||
const remoteRaw: string | false = await UIAF_Oper.importOper.readUIAFData(
|
const remoteRaw: string | false = await UIAF_Oper.importOper.readUIAFData(
|
||||||
<string>selectedFile
|
<string>selectedFile
|
||||||
);
|
);
|
||||||
console.log("读取选中文件成功,开始解析数据...");
|
|
||||||
// 解析数据
|
|
||||||
let localData: UIAF_Achievement[] | false = false;
|
|
||||||
let remoteData: Achievements;
|
|
||||||
if (localRaw !== false) {
|
|
||||||
localData = JSON.parse(localRaw);
|
|
||||||
}
|
|
||||||
await console.log("解析数据成功,开始合并数据...");
|
|
||||||
if (localData === false) {
|
|
||||||
localData = [];
|
|
||||||
}
|
|
||||||
if (remoteRaw === false) {
|
if (remoteRaw === false) {
|
||||||
await dialog.message("文件格式不正确,导入失败");
|
await dialog.message("文件格式不正确,导入失败");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
remoteData = JSON.parse(remoteRaw);
|
let remoteData: Achievements = JSON.parse(remoteRaw);
|
||||||
// 数据合并
|
let localData: UIAF_Achievement[] = JSON.parse(localRaw || "[]");
|
||||||
const mergedData = await UIAF_Oper.importOper.mergeUIAFData(
|
// 因为
|
||||||
|
const mergeUIAF: UIAF_Achievement[] = await UIAF_Oper.importOper.mergeUIAFData(
|
||||||
localData,
|
localData,
|
||||||
remoteData
|
remoteData
|
||||||
);
|
);
|
||||||
if (mergedData === false) {
|
await fs.writeTextFile(localPath, JSON.stringify(mergeUIAF, null, 4));
|
||||||
await dialog.message("合并数据失败,请检查文件是否符合 UIAF 格式");
|
// 读取本地 mergeData
|
||||||
return;
|
const mergeAchievementMap: TGMap<TGAchievementMap> = new TGMap<TGAchievementMap>(
|
||||||
|
JSON.parse(await fs.readTextFile(appStore.mergePath.achievements))
|
||||||
|
);
|
||||||
|
const mergeSeriesMap: TGMap<TGSeriesMap> = new TGMap<TGSeriesMap>(
|
||||||
|
JSON.parse(await fs.readTextFile(appStore.mergePath.achievementSeries))
|
||||||
|
);
|
||||||
|
// 遍历 mergeUIAF,对 mergeData 进行更新
|
||||||
|
mergeUIAF.map(UIAF_Item => {
|
||||||
|
// 更新成就
|
||||||
|
if (mergeAchievementMap.has(UIAF_Item.id)) {
|
||||||
|
const achievement = mergeAchievementMap.get(UIAF_Item.id);
|
||||||
|
achievement.completed = true;
|
||||||
|
achievement.completed_time = new Date(
|
||||||
|
UIAF_Item.timestamp * 1000
|
||||||
|
).toLocaleString();
|
||||||
|
mergeAchievementMap.set(UIAF_Item.id, achievement);
|
||||||
|
// 如果成就系列中没有该成就,则添加
|
||||||
|
if (!mergeSeriesMap.has(achievement.series)) {
|
||||||
|
const series = mergeSeriesMap.get(achievement.series);
|
||||||
|
series.achievements.push(achievement.id);
|
||||||
|
mergeSeriesMap.set(achievement.series, series);
|
||||||
}
|
}
|
||||||
await console.log("合并数据成功,开始写入数据...");
|
}
|
||||||
|
});
|
||||||
|
// 更新成就系列
|
||||||
|
mergeSeriesMap.forEach(seriesMap => {
|
||||||
|
let completed = 0;
|
||||||
|
seriesMap.achievements.map(achievement => {
|
||||||
|
if (mergeAchievementMap.get(achievement).completed) {
|
||||||
|
completed++;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
seriesMap.completed_count = completed;
|
||||||
|
seriesMap.total_count = seriesMap.achievements.length;
|
||||||
|
mergeSeriesMap.set(seriesMap.id, seriesMap);
|
||||||
|
});
|
||||||
// 写入数据
|
// 写入数据
|
||||||
await fs.writeTextFile(localPath, JSON.stringify(mergedData, null, 2));
|
await fs.writeTextFile(
|
||||||
await console.log("写入数据成功,导入完成");
|
appStore.mergePath.achievements,
|
||||||
await console.log("正在刷新数据...");
|
JSON.stringify(mergeAchievementMap.getMap(), null, 4)
|
||||||
|
);
|
||||||
|
await fs.writeTextFile(
|
||||||
|
appStore.mergePath.achievementSeries,
|
||||||
|
JSON.stringify(mergeSeriesMap.getMap(), null, 4)
|
||||||
|
);
|
||||||
// 刷新数据
|
// 刷新数据
|
||||||
await this.flushStore(mergedData.length);
|
await this.loadData();
|
||||||
} else {
|
|
||||||
await dialog.message("文件格式不正确,请检查文件是否符合 UIAF 格式");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// 导出
|
// 导出
|
||||||
@@ -156,97 +180,9 @@ export default defineComponent({
|
|||||||
],
|
],
|
||||||
});
|
});
|
||||||
if (is_save) {
|
if (is_save) {
|
||||||
await fs.writeTextFile(is_save, JSON.stringify(achievements, null, 2));
|
await fs.writeTextFile(is_save, JSON.stringify(achievements, null, 4));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// 获取 MergeData
|
|
||||||
async mergeJson() {
|
|
||||||
const appStore = useAppStore();
|
|
||||||
const localPath = appStore.userPath.achievements;
|
|
||||||
// 读取用户的 UIAF 数据
|
|
||||||
const localRaw: string | false = await UIAF_Oper.importOper.readUIAFData(localPath);
|
|
||||||
if (localRaw === false) {
|
|
||||||
await dialog.message("读取用户数据失败,请检查文件是否符合 UIAF 格式");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const localData: UIAF_Achievement[] = JSON.parse(localRaw);
|
|
||||||
// 读取 MergeData
|
|
||||||
const mergeAchievementRaw = await fs.readTextFile(appStore.mergePath.achievements);
|
|
||||||
const mergeSeriesRaw = await fs.readTextFile(appStore.mergePath.achievementSeries);
|
|
||||||
const mergeAchievementData: TGAchievementDisplay[] = JSON.parse(mergeAchievementRaw);
|
|
||||||
const mergeSeriesData: TGAchievementSeriesDisplay[] = JSON.parse(mergeSeriesRaw);
|
|
||||||
// 遍历 localData,对 MergeData 进行更新
|
|
||||||
localData.map(localAchievement => {
|
|
||||||
const achievementSingle = mergeAchievementData.find(
|
|
||||||
achievement => achievement.id === localAchievement.id
|
|
||||||
);
|
|
||||||
if (achievementSingle) {
|
|
||||||
achievementSingle.completed = true;
|
|
||||||
achievementSingle.completed_time = new Date(
|
|
||||||
localAchievement.timestamp * 1000
|
|
||||||
).toLocaleString();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// 遍历 mergeSeries 对 mergeSeries 进行更新
|
|
||||||
// todo 缺乏拓展性
|
|
||||||
mergeSeriesData.map(mergeSeries => {
|
|
||||||
let completed = 0;
|
|
||||||
// 更新成就
|
|
||||||
mergeSeries.achievements.map(achievement => {
|
|
||||||
const findAchievement = mergeAchievementData.find(achievementSingle => {
|
|
||||||
return achievementSingle.id === achievement.id;
|
|
||||||
});
|
|
||||||
if (findAchievement) {
|
|
||||||
if (findAchievement !== achievement) {
|
|
||||||
achievement.completed = findAchievement.completed;
|
|
||||||
achievement.completed_time = findAchievement.completed_time;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (achievement.completed) {
|
|
||||||
completed++;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// 更新系列
|
|
||||||
mergeSeries.completed_count = completed;
|
|
||||||
});
|
|
||||||
// 写入数据
|
|
||||||
await fs.writeTextFile(
|
|
||||||
appStore.mergePath.achievements,
|
|
||||||
JSON.stringify(mergeAchievementData, null, 4)
|
|
||||||
);
|
|
||||||
await fs.writeTextFile(
|
|
||||||
appStore.mergePath.achievementSeries,
|
|
||||||
JSON.stringify(mergeSeriesData, null, 4)
|
|
||||||
);
|
|
||||||
await dialog.message("合并数据成功");
|
|
||||||
},
|
|
||||||
// 获取标题
|
|
||||||
getTitle() {
|
|
||||||
const achievementsStore = useAchievementsStore();
|
|
||||||
const achievementsAll = achievementsStore.total_achievements;
|
|
||||||
const achievementsDone = achievementsStore.fin_achievements;
|
|
||||||
return `成就完成数:${achievementsDone}/${achievementsAll} 完成率:${(
|
|
||||||
(achievementsDone / achievementsAll) *
|
|
||||||
100
|
|
||||||
).toFixed(2)}%`;
|
|
||||||
},
|
|
||||||
// 刷新数据
|
|
||||||
async flushStore(fin_num: number) {
|
|
||||||
const achievementsStore = useAchievementsStore();
|
|
||||||
achievementsStore.fin_achievements = fin_num;
|
|
||||||
const appStore = useAppStore();
|
|
||||||
const localPath = appStore.appPath.achievements;
|
|
||||||
const localRaw: string = await fs.readTextFile(localPath);
|
|
||||||
const localData: TGAchievement[] = JSON.parse(localRaw);
|
|
||||||
achievementsStore.total_achievements = localData.length;
|
|
||||||
this.title = this.getTitle();
|
|
||||||
},
|
|
||||||
// 加载数据
|
|
||||||
async loadData() {
|
|
||||||
this.title = this.getTitle();
|
|
||||||
// this.seriesList = TGAppData.MergeData.achievementSeries;
|
|
||||||
// this.achievementsAll = TGAppData.MergeData.achievements;
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { fs } from "@tauri-apps/api";
|
|||||||
/**
|
/**
|
||||||
* @description 检测是否存在 UIAF 数据
|
* @description 检测是否存在 UIAF 数据
|
||||||
* @description 粗略检测,不保证数据完整性
|
* @description 粗略检测,不保证数据完整性
|
||||||
|
* @since Alpha
|
||||||
* @param {string} path - UIAF 数据路径
|
* @param {string} path - UIAF 数据路径
|
||||||
* @return {Promise<boolean>} 是否存在 UIAF 数据
|
* @return {Promise<boolean>} 是否存在 UIAF 数据
|
||||||
*/
|
*/
|
||||||
@@ -22,6 +23,7 @@ export async function checkUIAFData(path: string): Promise<boolean> {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @description 读取 UIAF 数据
|
* @description 读取 UIAF 数据
|
||||||
|
* @since Alpha
|
||||||
* @param {string} userPath - UIAF 数据路径
|
* @param {string} userPath - UIAF 数据路径
|
||||||
* @return {Promise<string|false>} UIAF 数据
|
* @return {Promise<string|false>} UIAF 数据
|
||||||
*/
|
*/
|
||||||
@@ -40,14 +42,15 @@ export async function readUIAFData(userPath: string): Promise<string | false> {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @description 数据合并
|
* @description 数据合并
|
||||||
|
* @since Alpha
|
||||||
* @param {UIAF_Achievement[]} localData - 本地数据
|
* @param {UIAF_Achievement[]} localData - 本地数据
|
||||||
* @param {Achievements} remoteData - 远程数据
|
* @param {Achievements} remoteData - 远程数据
|
||||||
* @return {Promise<UIAF_Achievement[]|false>} 合并后的数据,如果合并失败则返回 false
|
* @return {Promise<UIAF_Achievement[]>} 合并后的数据
|
||||||
*/
|
*/
|
||||||
export async function mergeUIAFData(
|
export async function mergeUIAFData(
|
||||||
localData: UIAF_Achievement[],
|
localData: UIAF_Achievement[],
|
||||||
remoteData: Achievements
|
remoteData: Achievements
|
||||||
): Promise<UIAF_Achievement[] | false> {
|
): Promise<UIAF_Achievement[]> {
|
||||||
// 遍历 remoteData.list
|
// 遍历 remoteData.list
|
||||||
remoteData.list.map((remoteAchievement: UIAF_Achievement) => {
|
remoteData.list.map((remoteAchievement: UIAF_Achievement) => {
|
||||||
// 查找 id 相同的 localAchievement
|
// 查找 id 相同的 localAchievement
|
||||||
|
|||||||
@@ -6,6 +6,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { defineStore } from "pinia";
|
import { defineStore } from "pinia";
|
||||||
|
import TGMap from "../../utils/TGMap";
|
||||||
|
import { SeriesMap } from "../../interface/Achievements";
|
||||||
|
|
||||||
const useAchievementsStore = defineStore({
|
const useAchievementsStore = defineStore({
|
||||||
id: "achievements",
|
id: "achievements",
|
||||||
@@ -13,10 +15,23 @@ const useAchievementsStore = defineStore({
|
|||||||
return {
|
return {
|
||||||
total_achievements: 899,
|
total_achievements: 899,
|
||||||
fin_achievements: 0,
|
fin_achievements: 0,
|
||||||
|
// 这个数据用于说明当前的数据版本,不会被渲染
|
||||||
last_version: "v3.5",
|
last_version: "v3.5",
|
||||||
UIAF_Version: "v1.1",
|
UIAF_Version: "v1.1",
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
actions: {
|
||||||
|
flushData(seriesMap: TGMap<SeriesMap>) {
|
||||||
|
let total = 0;
|
||||||
|
let fin = 0;
|
||||||
|
seriesMap.forEach(series => {
|
||||||
|
total += series.total_count;
|
||||||
|
fin += series.completed_count;
|
||||||
|
});
|
||||||
|
this.total_achievements = total;
|
||||||
|
this.fin_achievements = fin;
|
||||||
|
},
|
||||||
|
},
|
||||||
persist: true,
|
persist: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user