fix(achievement): 导入导出逻辑完成

This commit is contained in:
BTMuli
2023-03-09 13:14:50 +08:00
parent 6ec61108c2
commit 3ff531f418
3 changed files with 124 additions and 170 deletions

View File

@@ -10,37 +10,16 @@
<v-btn @click="importJson" prepend-icon="mdi-import" class="bg-green-accent-2">
导入
</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>
</template>
</v-app-bar>
<!-- 主体内容 -->
<!-- 侧边成就系列列表 -->
<!-- 主体内容 考虑 tabs?-->
<v-layout>
<!-- 成就列表 -->
<!-- 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>
<!-- 左侧菜单 todo -->
<!-- 右侧内容 todo -->
</v-layout>
</template>
@@ -52,11 +31,11 @@ import UIAF_Oper from "../plugins/UIAF";
import { dialog, fs } from "@tauri-apps/api";
import { UIAF_Achievement, Achievements } from "../plugins/UIAF/interface/UIAF";
import {
Achievement as TGAchievement,
AchievementSeries as TGAchievementSeries,
AchievementDisplay as TGAchievementDisplay,
AchievementSeriesDisplay as TGAchievementSeriesDisplay,
AchievementMap as TGAchievementMap,
SeriesMap as TGSeriesMap,
} from "../interface/Achievements";
import TGMap from "../utils/TGMap";
import { Map } from "../interface/Base";
export default defineComponent({
name: "Achievements",
@@ -65,16 +44,45 @@ export default defineComponent({
// 标题 成就完成数/成就总数 完成率
title: "" as string,
// 成就系列列表,用于侧边栏
seriesList: [] as TGAchievementSeries[],
// 成就列表-所有
achievementsAll: [] as TGAchievementDisplay[],
seriesList: {} as Map<TGSeriesMap>,
// 成就列表-所有成就的数据
achievementsList: {} as Map<TGAchievementMap>,
// 选中的成就系列 id用于决定右侧显示的成就列表
selectedSeries: -1 as number,
};
},
async mounted() {
await this.loadData();
},
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() {
const appStore = useAppStore();
const localPath = appStore.userPath.achievements;
@@ -87,55 +95,71 @@ export default defineComponent({
},
],
});
// 选中文件
if (selectedFile) {
console.log("正在读取本地文件...");
// 读取应用内文件
if (selectedFile && (await UIAF_Oper.importOper.checkUIAFData(<string>selectedFile))) {
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(
<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) {
await dialog.message("文件格式不正确,导入失败");
return;
}
remoteData = JSON.parse(remoteRaw);
// 数据合并
const mergedData = await UIAF_Oper.importOper.mergeUIAFData(
localData,
remoteData
);
if (mergedData === false) {
await dialog.message("合并数据失败,请检查文件是否符合 UIAF 格式");
return;
}
await console.log("合并数据成功,开始写入数据...");
// 写入数据
await fs.writeTextFile(localPath, JSON.stringify(mergedData, null, 2));
await console.log("写入数据成功,导入完成");
await console.log("正在刷新数据...");
// 刷新数据
await this.flushStore(mergedData.length);
} else {
await dialog.message("文件格式不正确,请检查文件是否符合 UIAF 格式");
const remoteRaw: string | false = await UIAF_Oper.importOper.readUIAFData(
<string>selectedFile
);
if (remoteRaw === false) {
await dialog.message("文件格式不正确,导入失败");
return;
}
let remoteData: Achievements = JSON.parse(remoteRaw);
let localData: UIAF_Achievement[] = JSON.parse(localRaw || "[]");
// 因为
const mergeUIAF: UIAF_Achievement[] = await UIAF_Oper.importOper.mergeUIAFData(
localData,
remoteData
);
await fs.writeTextFile(localPath, JSON.stringify(mergeUIAF, null, 4));
// 读取本地 mergeData
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);
}
}
});
// 更新成就系列
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(
appStore.mergePath.achievements,
JSON.stringify(mergeAchievementMap.getMap(), null, 4)
);
await fs.writeTextFile(
appStore.mergePath.achievementSeries,
JSON.stringify(mergeSeriesMap.getMap(), null, 4)
);
// 刷新数据
await this.loadData();
}
},
// 导出
@@ -156,97 +180,9 @@ export default defineComponent({
],
});
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>

View File

@@ -11,6 +11,7 @@ import { fs } from "@tauri-apps/api";
/**
* @description 检测是否存在 UIAF 数据
* @description 粗略检测,不保证数据完整性
* @since Alpha
* @param {string} path - UIAF 数据路径
* @return {Promise<boolean>} 是否存在 UIAF 数据
*/
@@ -22,6 +23,7 @@ export async function checkUIAFData(path: string): Promise<boolean> {
/**
* @description 读取 UIAF 数据
* @since Alpha
* @param {string} userPath - UIAF 数据路径
* @return {Promise<string|false>} UIAF 数据
*/
@@ -40,14 +42,15 @@ export async function readUIAFData(userPath: string): Promise<string | false> {
/**
* @description 数据合并
* @since Alpha
* @param {UIAF_Achievement[]} localData - 本地数据
* @param {Achievements} remoteData - 远程数据
* @return {Promise<UIAF_Achievement[]|false>} 合并后的数据,如果合并失败则返回 false
* @return {Promise<UIAF_Achievement[]>} 合并后的数据
*/
export async function mergeUIAFData(
localData: UIAF_Achievement[],
remoteData: Achievements
): Promise<UIAF_Achievement[] | false> {
): Promise<UIAF_Achievement[]> {
// 遍历 remoteData.list
remoteData.list.map((remoteAchievement: UIAF_Achievement) => {
// 查找 id 相同的 localAchievement

View File

@@ -6,6 +6,8 @@
*/
import { defineStore } from "pinia";
import TGMap from "../../utils/TGMap";
import { SeriesMap } from "../../interface/Achievements";
const useAchievementsStore = defineStore({
id: "achievements",
@@ -13,10 +15,23 @@ const useAchievementsStore = defineStore({
return {
total_achievements: 899,
fin_achievements: 0,
// 这个数据用于说明当前的数据版本,不会被渲染
last_version: "v3.5",
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,
});