♻️ 重构成就表格,支持多存档

#126
This commit is contained in:
目棃
2024-09-20 15:57:02 +08:00
parent a8a667871a
commit 1dc5aa0ef8
28 changed files with 1198 additions and 1239 deletions

View File

@@ -1,127 +1,73 @@
<template>
<div class="top-bar">
<div class="top-title" @click="switchHideFin">{{ title }}</div>
<v-text-field
v-model="search"
append-icon="mdi-magnify"
label="搜索"
:hide-details="true"
variant="outlined"
@click:append="searchCard"
@keyup.enter="searchCard"
/>
<div class="top-btns">
<v-btn prepend-icon="mdi-import" class="top-btn" @click="importJson"> 导入</v-btn>
<v-btn prepend-icon="mdi-export" class="top-btn" @click="exportJson"> 导出</v-btn>
</div>
</div>
<ToLoading v-model="loading" :title="loadingTitle" />
<v-app-bar>
<div class="top-title" @click="switchHideFin">{{ title }}</div>
<template #append>
<div class="achi-search">
<v-text-field
v-model="search"
append-icon="mdi-magnify"
label="搜索"
:hide-details="true"
:single-line="true"
/>
</div>
</template>
<template #extension>
<v-btn prepend-icon="mdi-import" class="top-btn" @click="importJson()">导入</v-btn>
<v-btn prepend-icon="mdi-export" class="top-btn" @click="exportJson()">导出</v-btn>
<div class="uid-select">
<v-select
variant="outlined"
v-model="uidCur"
:items="uidList"
:hide-details="true"
label="存档UID"
/>
</div>
<v-btn prepend-icon="mdi-plus" class="top-btn" @click="createUid()">新建存档</v-btn>
<v-btn prepend-icon="mdi-delete" class="top-btn" @click="deleteUid()">删除存档</v-btn>
<v-spacer />
</template>
</v-app-bar>
<div class="wrap">
<!-- 左侧菜单 -->
<div class="left-wrap">
<div
v-for="series in allSeriesData"
:key="series.id"
class="card-series"
@click="selectSeries(series.id)"
>
<div class="series-version">v{{ series.version }}</div>
<img alt="icon" class="series-icon" :src="getIcon(series.id)" />
<div class="series-content">
<span :title="series.name">
{{ series.name }}
</span>
<span> {{ series.finCount }} / {{ series.totalCount }} </span>
</div>
</div>
</div>
<!-- 右侧内容-->
<div class="right-wrap">
<div v-if="curCardName !== '' && selectedSeries !== -1 && !loading">
<TopNamecard :data="curCard" @selected="openImg()" v-if="curCard" />
</div>
<div
v-for="(achievement, index) in renderSelect"
:key="achievement.id"
class="card-achi"
:title="allSeriesData.find((item) => item.id === achievement.series)?.name ?? ''"
@click="showAchiInfo(achievement, index)"
>
<div class="achi-version">v{{ achievement.version }}</div>
<div class="achi-pre">
<div class="achi-pre-icon">
<v-icon
v-if="!achievement.isCompleted"
color="var(--tgc-blue-3)"
@click="setAchi(achievement, true)"
style="cursor: pointer"
>
mdi-circle
</v-icon>
<v-icon
v-else
class="achievement-finish"
style="cursor: pointer"
@click="setAchi(achievement, false)"
>
<img alt="finish" src="/source/UI/finish.webp" />
</v-icon>
</div>
<div class="achi-pre-info">
<span>
<span>{{ achievement.name }}</span>
<span v-if="achievement.progress !== 0">
{{ achievement.progress }}
</span>
</span>
<span>{{ achievement.description }}</span>
</div>
</div>
<div class="achi-append">
<span v-show="achievement.isCompleted">
{{ achievement.completedTime }}
</span>
<div class="achi-append-icon">
<img alt="icon" src="/icon/material/201.webp" />
<span>{{ achievement.reward }}</span>
</div>
</div>
</div>
<div class="left-wrap" v-if="uidCur">
<TuaSeries
v-for="(series, index) in seriesList"
:key="index"
@click="selectSeries(series)"
v-model:cur="selectedSeries"
:uid="uidCur"
:series="series"
/>
</div>
<TuaAchiList
v-if="uidCur"
:uid="uidCur"
:hideFin="hideFin"
v-model:series="selectedSeries"
v-model:search="search"
/>
</div>
<ToNamecard v-model="showNameCard" :data="curCard" />
<ToAchiInfo v-model="showAchi" :data="showAchiData" @select-s="selectSeries">
<template #left>
<div class="card-arrow left" @click="switchAchiInfo(false)">
<img src="../../assets/icons/arrow-right.svg" alt="right" />
</div>
</template>
<template #right>
<div class="card-arrow" @click="switchAchiInfo(true)">
<img src="../../assets/icons/arrow-right.svg" alt="right" />
</div>
</template>
</ToAchiInfo>
</template>
<script lang="ts" setup>
import { path } from "@tauri-apps/api";
import { UnlistenFn, listen } from "@tauri-apps/api/event";
import { open, save } from "@tauri-apps/plugin-dialog";
import { writeTextFile } from "@tauri-apps/plugin-fs";
import { computed, nextTick, onMounted, ref } from "vue";
import { onMounted, ref, computed, onUnmounted } from "vue";
import { useRoute, useRouter } from "vue-router";
import showConfirm from "../../components/func/confirm.js";
import showSnackbar from "../../components/func/snackbar.js";
import ToAchiInfo from "../../components/overlay/to-achiInfo.vue";
import ToLoading from "../../components/overlay/to-loading.vue";
import ToNamecard from "../../components/overlay/to-namecard.vue";
import TopNamecard from "../../components/overlay/top-namecard.vue";
import { AppAchievementSeriesData, AppNameCardsData } from "../../data/index.js";
import TuaAchiList from "../../components/userAchi/tua-achi-list.vue";
import TuaSeries from "../../components/userAchi/tua-series.vue";
import { AppAchievementSeriesData } from "../../data/index.js";
import TSUserAchi from "../../plugins/Sqlite/modules/userAchi.js";
import { useAchievementsStore } from "../../store/modules/achievements.js";
import TGLogger from "../../utils/TGLogger.js";
import { getNowStr } from "../../utils/toolFunc.js";
import {
getUiafHeader,
readUiafData,
@@ -129,214 +75,67 @@ import {
verifyUiafDataClipboard,
} from "../../utils/UIAF.js";
// Store
const achievementsStore = useAchievementsStore();
// loading
const loading = ref<boolean>(true);
const loadingTitle = ref<string>("正在加载数据");
const search = ref<string>("");
const hideFin = ref<boolean>(false);
const showNameCard = ref<boolean>(false);
const showAchi = ref<boolean>(false);
// data
const title = ref(achievementsStore.title);
const curCardName = ref<string>("");
let curCard = ref<TGApp.App.NameCard.Item>();
// series
const allSeriesData = ref<TGApp.Sqlite.Achievement.SeriesTable[]>([]);
const uidList = ref<number[]>([]);
const uidCur = ref<number>(0);
const overview = ref<TGApp.Sqlite.Achievement.Overview>({ fin: 0, total: 1 });
const seriesList = AppAchievementSeriesData.sort((a, b) => a.order - b.order).map((s) => s.id);
const selectedSeries = ref<number>(-1);
const selectedAchievement = ref<TGApp.Sqlite.Achievement.SingleTable[]>([]);
const showAchiData = ref<TGApp.Sqlite.Achievement.SingleTable>();
const curAchiDataIndex = ref<number>(0);
const renderSelect = computed(() => {
if (hideFin.value) {
return selectedAchievement.value.filter((item) => item.isCompleted === 0);
}
return selectedAchievement.value;
const title = computed<string>(() => {
const percentage = ((overview.value.fin * 100) / overview.value.total).toFixed(2);
return `${overview.value.fin}/${overview.value.total} ${percentage}%`;
});
// route
const route = useRoute();
const router = useRouter();
// 更改是否隐藏已完成
let achiListener: UnlistenFn | null = null;
async function switchHideFin() {
const text = hideFin.value ? "显示已完成" : "隐藏已完成";
const res = await showConfirm({
title: "是否切换显示已完成?",
text,
});
const res = await showConfirm({ title: "是否切换显示已完成?", text });
if (!res) {
showSnackbar({
color: "cancel",
text: "已取消切换",
});
showSnackbar({ color: "cancel", text: "已取消切换" });
return;
}
hideFin.value = !hideFin.value;
showSnackbar({
text: `${text}`,
});
}
// 刷新概况
async function flushOverview(): Promise<void> {
const { total, fin } = await TSUserAchi.getOverview();
achievementsStore.flushData(total, fin);
title.value = achievementsStore.title;
showSnackbar({ text: `${text}`, color: "success" });
}
onMounted(async () => {
await TGLogger.Info("[Achievements][onMounted] 打开成就页面");
await TGLogger.Info(`[Achievements][onMounted] 当前版本:${achievementsStore.lastVersion}`);
loading.value = true;
loadingTitle.value = "正在获取成就系列数据";
await flushOverview();
await TGLogger.Info(`[Achievements][onMounted] ${title.value}`);
allSeriesData.value = await TSUserAchi.getSeries();
achievementsStore.lastVersion = await TSUserAchi.getLatestAchiVersion();
loadingTitle.value = "正在获取成就数据";
selectedAchievement.value = await getAchiData("all");
uidList.value = await TSUserAchi.getAllUid();
if (uidList.value.length === 0) uidList.value = [0];
uidCur.value = uidList.value[0];
await refreshOverview();
loading.value = false;
if (route.query.app && typeof route.query.app === "string") {
await handleImportOuter(route.query.app);
} else {
// 等 500ms 动画
setTimeout(() => {
showSnackbar({
text: `已获取 ${renderSelect.value.length} 条成就数据`,
});
}, 500);
}
achiListener = await listen<number>("updateAchi", async () => await refreshOverview());
});
onUnmounted(async () => {
if (achiListener !== null) {
achiListener();
achiListener = null;
}
});
// 渲染选中的成就系列
async function selectSeries(index: number): Promise<void> {
// 如果选中的是已经选中的系列,则不进行操作
if (selectedSeries.value === index) {
showSnackbar({
color: "warn",
text: "已经选中该系列",
});
return;
}
loading.value = true;
loadingTitle.value = "正在获取对应的成就数据";
selectedSeries.value = index;
selectedAchievement.value = await getAchiData("series", index.toString());
loadingTitle.value = "正在查找对应的成就名片";
curCardName.value = await TSUserAchi.getSeriesNameCard(String(index));
if (curCardName.value !== "") {
curCard.value = AppNameCardsData.find((item) => item.name === curCardName.value);
}
// 右侧滚动到顶部
const rightWrap = document.querySelector(".right-wrap");
if (rightWrap) {
rightWrap.scrollTop = 0;
}
// 刷新overlay数据
curAchiDataIndex.value = selectedAchievement.value.findIndex(
(i) => i.id === showAchiData.value?.id,
);
await nextTick(() => {
loading.value = false;
// 等 500ms 动画
setTimeout(() => {
showSnackbar({
text: `已获取 ${renderSelect.value.length} 条成就数据`,
});
}, 500);
});
async function refreshOverview(): Promise<void> {
overview.value = await TSUserAchi.getOverview(uidCur.value);
}
// 打开图片
function openImg(): void {
showNameCard.value = true;
function selectSeries(series: number): void {
selectedSeries.value = series;
}
// 打开成就详情
function showAchiInfo(item: TGApp.Sqlite.Achievement.SingleTable, index: number): void {
showAchiData.value = item;
showAchi.value = true;
curAchiDataIndex.value = index;
}
// 切换成就详情
function switchAchiInfo(next: boolean) {
if (next) {
if (curAchiDataIndex.value === renderSelect.value.length - 1) {
showSnackbar({
color: "warn",
text: "已经是最后一个了",
});
return;
}
curAchiDataIndex.value++;
} else {
if (curAchiDataIndex.value === 0) {
showSnackbar({
color: "warn",
text: "已经是第一个了",
});
return;
}
curAchiDataIndex.value--;
}
showAchiData.value = renderSelect.value[curAchiDataIndex.value];
}
async function searchAll(): Promise<void> {
if (selectedAchievement.value.length === achievementsStore.totalAchievements) {
showSnackbar({
color: "warn",
text: "已经是全部成就",
});
return;
}
loading.value = true;
loadingTitle.value = "正在获取全部成就数据";
selectedSeries.value = -1;
selectedAchievement.value = await getAchiData("all");
await nextTick(() => {
loading.value = false;
setTimeout(() => {
showSnackbar({
text: `已获取 ${renderSelect.value.length} 条成就数据`,
});
}, 500);
});
}
async function searchCard(): Promise<void> {
if (search.value === "") {
await searchAll();
return;
}
selectedSeries.value = -1;
loadingTitle.value = "正在搜索";
loading.value = true;
await TGLogger.Info(`[Achievements][searchCard] 搜索内容:${search.value}`);
selectedAchievement.value = await getAchiData("search", search.value);
await nextTick(() => {
loading.value = false;
setTimeout(() => {
if (renderSelect.value.length === 0) {
showSnackbar({
color: "error",
text: "没有搜索到相关成就",
});
return;
}
showSnackbar({
text: `已获取 ${renderSelect.value.length} 条成就数据`,
});
}, 500);
});
await TGLogger.Info(`[Achievements][searchCard] 搜索到 ${renderSelect.value.length} 条成就数据`);
}
// 导入 UIAF 数据,进行数据合并、刷新
async function importJson(): Promise<void> {
await TGLogger.Info("[Achievements][importJson] 导入 UIAF 数据");
const selectedFile = await open({
@@ -361,40 +160,50 @@ async function importJson(): Promise<void> {
}
const check = await verifyUiafData(selectedFile);
if (!check) return;
let uidInput = await showConfirm({
mode: "input",
title: "请输入存档UID",
text: "UID:",
input: uidCur.value.toString(),
});
if (uidInput === false) {
showSnackbar({ text: "已取消存档导入!", color: "cancel" });
return;
}
if (uidInput === undefined) uidInput = uidCur.value.toString();
else if (isNaN(Number(uidInput))) {
showSnackbar({ text: "请输入合法数字", color: "warn" });
return;
}
const remoteRaw = await readUiafData(selectedFile);
await TGLogger.Info("[Achievements][importJson] 读取 UIAF 数据成功");
await TGLogger.Info(`[Achievements][importJson] 导入来源:${remoteRaw.info.export_app}`);
await TGLogger.Info(`[Achievements][importJson] 导入版本:${remoteRaw.info.export_app_version}`);
await TGLogger.Info(`[Achievements][importJson] 导入时间:${remoteRaw.info.export_timestamp}`);
await TGLogger.Info(`[Achievements][importJson] 导入数据:${remoteRaw.list.length}`);
await TGLogger.Info(`[Achievements][importJson] 导入存档:${uidInput}`);
loadingTitle.value = "正在解析数据";
loading.value = true;
loadingTitle.value = "正在合并成就数据";
await TSUserAchi.mergeUIAF(remoteRaw.list);
await TSUserAchi.mergeUiaf(remoteRaw.list, Number(uidInput));
loadingTitle.value = "即将刷新页面";
setTimeout(() => {
window.location.reload();
}, 1000);
}
// 导出
async function exportJson(): Promise<void> {
await TGLogger.Info("[Achievements][exportJson] 导出 UIAF 数据");
// 判断是否有数据
if (achievementsStore.finAchievements === 0) {
showSnackbar({
color: "error",
text: "没有可导出的数据",
});
if (overview.value.fin === 0) {
showSnackbar({ color: "error", text: "没有可导出的数据" });
await TGLogger.Warn("[Achievements][exportJson] 没有可导出的数据");
return;
}
// 获取本地数据
const UiafData = {
info: await getUiafHeader(),
list: await TSUserAchi.getUIAF(),
list: await TSUserAchi.getUiafData(uidCur.value),
};
const fileName = `UIAF_${UiafData.info.export_app}_${UiafData.info.export_app_version}_${UiafData.info.export_timestamp}`;
const fileName = `UIAF_${UiafData.info.export_app}_${UiafData.info.export_app_version}_${uidCur.value}`;
const isSave = await save({
title: "导出 UIAF 数据",
filters: [
@@ -406,24 +215,16 @@ async function exportJson(): Promise<void> {
defaultPath: `${await path.downloadDir()}${path.sep()}${fileName}.json`,
});
if (isSave === null) {
showSnackbar({
color: "warn",
text: "已取消导出",
});
showSnackbar({ color: "warn", text: "已取消导出" });
await TGLogger.Info("[Achievements][exportJson] 已取消导出");
return;
}
await writeTextFile(isSave, JSON.stringify(UiafData));
showSnackbar({ text: "导出成功" });
showSnackbar({ text: "导出成功", color: "success" });
await TGLogger.Info("[Achievements][exportJson] 导出成功");
await TGLogger.Info(`[Achievements][exportJson] 导出路径:${isSave}`);
}
function getIcon(series: number): string | undefined {
return AppAchievementSeriesData.find((item) => item.id === series)?.icon;
}
// 处理外部导入
async function handleImportOuter(app: string): Promise<void> {
await TGLogger.Info(`[Achievements][handleImportOuter] 导入来源:${app}`);
const confirm = await showConfirm({
@@ -442,110 +243,85 @@ async function handleImportOuter(app: string): Promise<void> {
const clipboard = await window.navigator.clipboard.readText();
const check = await verifyUiafDataClipboard();
if (!check) return;
let uidInput = await showConfirm({
mode: "input",
title: "请输入存档UID",
text: "UID:",
input: uidCur.value.toString(),
});
if (uidInput === false) {
showSnackbar({ text: "已取消存档导入!", color: "cancel" });
return;
}
if (uidInput === undefined) uidInput = uidCur.value.toString();
else if (isNaN(Number(uidInput))) {
showSnackbar({ text: "请输入合法数字", color: "warn" });
return;
}
const data: TGApp.Plugins.UIAF.Data = JSON.parse(clipboard);
loadingTitle.value = "正在导入数据";
loading.value = true;
await TSUserAchi.mergeUIAF(data.list);
await TSUserAchi.mergeUiaf(data.list, Number(uidInput));
loading.value = false;
showSnackbar({
color: "success",
text: "导入成功,即将刷新页面",
});
showSnackbar({ color: "success", text: "导入成功,即将刷新页面" });
await TGLogger.Info("[Achievements][handleImportOuter] 导入成功");
setTimeout(async () => {
await router.push("/achievements");
}, 1500);
}
// 改变成就状态
async function setAchi(
achievement: TGApp.Sqlite.Achievement.SingleTable,
target: boolean,
): Promise<void> {
const newAchievement = achievement;
if (target) {
// 取消已完成
newAchievement.isCompleted = 1;
newAchievement.completedTime = getNowStr();
} else {
newAchievement.isCompleted = 0;
newAchievement.completedTime = "";
}
renderSelect.value[renderSelect.value.findIndex((item) => item.id === achievement.id)] =
newAchievement;
await TSUserAchi.updateAchievement(newAchievement);
await flushOverview();
const seriesIndex = allSeriesData.value.findIndex((item) => item.id === newAchievement.series);
if (seriesIndex === -1) return;
const seriesGet = await TSUserAchi.getSeries(newAchievement.series);
allSeriesData.value[seriesIndex] = seriesGet[0];
showSnackbar({
text: `已将成就 ${newAchievement.name}[${newAchievement.id}] 标记为 ${
target ? "已完成" : "未完成"
}`,
});
await TGLogger.Info(
`[Achievements][setAchi] 已将成就 ${newAchievement.name}[${newAchievement.id}] 标记为 ${
target ? "已完成" : "未完成"
}`,
);
async function createUid(): Promise<void> {
// todo
}
// 获取成就(某个系列)
async function getAchiData(
type: "all" | "series" | "search",
value?: string,
): Promise<TGApp.Sqlite.Achievement.SingleTable[]> {
if (type !== "search") {
return TSUserAchi.getAchievements(value);
}
if (value === undefined) {
showSnackbar({
color: "error",
text: "搜索内容不能为空",
});
return [];
}
return TSUserAchi.searchAchievements(value);
async function deleteUid(): Promise<void> {
// todo
}
</script>
<!-- 顶部栏跟 wrap 大概布局 -->
<style lang="css" scoped>
.top-bar {
.achi-search {
position: relative;
display: flex;
width: 100%;
height: 80px;
width: 400px;
height: 50px;
align-items: center;
justify-content: space-between;
justify-content: center;
padding: 10px;
border-radius: 5px;
margin-bottom: 10px;
background: var(--box-bg-1);
column-gap: 50px;
font-family: var(--font-title);
font-size: 20px;
margin: 0 10px;
color: var(--box-text-1);
}
.top-title {
margin-left: 15px;
color: var(--common-text-title);
cursor: pointer;
}
.top-btns {
display: flex;
column-gap: 10px;
font-family: var(--font-title);
font-size: 18px;
}
.top-btn {
border-radius: 5px;
background: var(--tgc-btn-1);
color: var(--btn-text);
height: 40px;
border: 1px solid var(--common-shadow-2);
margin-left: 15px;
background: var(--btn-bg-1);
color: var(--btn-text-1);
font-family: var(--font-title);
}
.uid-select {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 15px;
margin-left: 15px;
gap: 10px;
}
/* 内容区域 */
.wrap {
display: flex;
height: calc(100vh - 130px);
height: calc(100vh - 150px);
column-gap: 10px;
}
@@ -559,222 +335,4 @@ async function getAchiData(
overflow-y: auto;
row-gap: 10px;
}
/* 右侧成就 */
.right-wrap {
display: flex;
width: 100%;
height: 100%;
flex-direction: column;
padding-right: 10px;
overflow-y: scroll;
row-gap: 10px;
}
</style>
<!-- 左侧成就系列 wrap -->
<style lang="css" scoped>
.card-series {
position: relative;
display: flex;
align-items: center;
justify-content: center;
padding: 10px;
border-radius: 10px;
background: var(--box-bg-1);
color: var(--box-text-1);
column-gap: 10px;
cursor: pointer;
}
/* 版本信息 */
.series-version {
position: absolute;
right: 0;
bottom: 0;
width: 80px;
border-top: 1px solid var(--common-shadow-1);
border-left: 1px solid var(--common-shadow-1);
background: var(--box-bg-2);
border-bottom-right-radius: 10px;
border-top-left-radius: 20px;
color: var(--tgc-yellow-1);
font-family: var(--font-title);
font-size: 10px;
text-align: center;
text-shadow: 1px 1px 1px var(--common-shadow-1);
}
.series-icon {
width: 40px;
height: 40px;
padding: 5px;
border-radius: 50%;
background: var(--tgc-dark-7);
}
.series-content {
display: flex;
width: 100%;
flex-flow: column wrap;
align-items: flex-start;
justify-content: center;
color: var(--box-text-1);
text-align: left;
}
.series-content :nth-child(1) {
font-family: var(--font-title);
font-size: 14px;
}
.series-content :nth-child(2) {
font-size: 12px;
opacity: 0.8;
}
</style>
<!-- 右侧成就 -->
<style lang="css" scoped>
/* 成就卡片 */
.card-achi {
position: relative;
display: flex;
align-items: center;
justify-content: space-between;
padding: 10px;
border-radius: 10px;
background: var(--box-bg-1);
color: var(--box-text-7);
cursor: pointer;
}
/* 成就进度 */
.achi-version {
position: absolute;
top: 0;
left: 0;
width: 50px;
border-right: 1px solid var(--common-shadow-1);
border-bottom: 1px solid var(--common-shadow-1);
background: var(--box-bg-2);
border-bottom-right-radius: 20px;
border-top-left-radius: 10px;
color: var(--tgc-pink-1);
font-family: var(--font-title);
font-size: 10px;
text-align: center;
}
.achi-pre {
display: flex;
align-items: center;
justify-content: flex-start;
column-gap: 10px;
}
.achi-pre-icon {
display: flex;
width: 30px;
height: 30px;
align-items: center;
justify-content: center;
}
.achievement-finish img {
width: 30px;
height: 30px;
filter: invert(51%) sepia(100%) saturate(353%) hue-rotate(42deg) brightness(107%) contrast(91%);
}
.achi-pre-info {
display: flex;
width: 100%;
flex-flow: column wrap;
align-items: flex-start;
justify-content: center;
text-align: left;
}
.achi-pre-info :nth-child(1) {
display: flex;
align-items: flex-end;
column-gap: 5px;
font-family: var(--font-title);
font-size: 14px;
}
.achi-pre-info :nth-child(1) :nth-child(2) {
color: var(--tgc-blue-2);
font-size: 12px;
}
.achi-pre-info :nth-child(2) {
font-size: 12px;
opacity: 0.8;
}
.achi-append-icon span {
position: absolute;
bottom: 0;
left: 0;
display: flex;
width: 100%;
height: 10px;
align-items: center;
justify-content: center;
background: rgb(0 0 0 / 50%);
border-bottom-left-radius: 5px;
border-bottom-right-radius: 5px;
color: var(--tgc-white-1);
font-size: 8px;
}
.achi-append {
display: flex;
align-items: center;
justify-content: flex-end;
column-gap: 10px;
}
.achi-append :nth-last-child(2) {
margin-right: 10px;
color: var(--box-text-4);
font-size: small;
}
.achi-append-icon {
position: relative;
width: 40px;
height: 40px;
border-radius: 5px;
background-image: url("/icon/bg/5-Star.webp");
background-size: cover;
}
.achi-append-icon img {
width: 40px;
height: 40px;
}
.card-arrow {
position: relative;
display: flex;
width: 30px;
height: 30px;
align-items: center;
justify-content: center;
cursor: pointer;
}
.dark .card-arrow {
filter: invert(11%) sepia(73%) saturate(11%) hue-rotate(139deg) brightness(97%) contrast(81%);
}
.card-arrow img {
width: 100%;
height: 100%;
}
.card-arrow.left img {
transform: rotate(180deg);
}
</style>

View File

@@ -121,8 +121,6 @@ import showConfirm from "../../components/func/confirm.js";
import showSnackbar from "../../components/func/snackbar.js";
import ToLoading from "../../components/overlay/to-loading.vue";
import TGSqlite from "../../plugins/Sqlite/index.js";
import TSUserAchi from "../../plugins/Sqlite/modules/userAchi.js";
import { useAchievementsStore } from "../../store/modules/achievements.js";
import { useAppStore } from "../../store/modules/app.js";
import { useHomeStore } from "../../store/modules/home.js";
import { backUpUserData, restoreUserData } from "../../utils/dataBS.js";
@@ -134,7 +132,6 @@ import TGRequest from "../../web/request/TGRequest.js";
// Store
const appStore = useAppStore();
const homeStore = useHomeStore();
const achievementsStore = useAchievementsStore();
const isDevEnv = ref<boolean>(import.meta.env.MODE === "development");
@@ -257,7 +254,6 @@ async function confirmUpdate(title?: string): Promise<void> {
loadingTitle.value = "正在更新数据库...";
loading.value = true;
await TGSqlite.update();
achievementsStore.lastVersion = await TSUserAchi.getLatestAchiVersion();
appStore.buildTime = getBuildTime();
loading.value = false;
showSnackbar({
@@ -398,7 +394,6 @@ async function confirmResetApp(): Promise<void> {
}
appStore.init();
homeStore.init();
achievementsStore.init();
await TGLogger.Info("[Config][confirmResetApp] 恢复默认设置完成");
showSnackbar({ text: "已恢复默认配置!即将刷新页面..." });
setTimeout(() => {

View File

@@ -19,7 +19,7 @@
append-icon="mdi-magnify"
label="请输入帖子 ID 或搜索词"
:single-line="true"
hide-details
:hide-details="true"
@keyup.enter="searchPost()"
@click:append="searchPost()"
/>
@@ -47,7 +47,7 @@
</div>
</div>
<div class="load-news">
<v-btn class="news-top-btn" rounded :loading="loadingSub" @click="loadMore(value)">
<v-btn class="news-top-btn" :rounded="true" :loading="loadingSub" @click="loadMore(value)">
已加载{{ rawData[value].lastId }}加载更多
</v-btn>
</div>