♻️ 组件合并

This commit is contained in:
BTMuli
2026-04-21 19:27:56 +08:00
parent 73009d68b4
commit 6093954050
6 changed files with 378 additions and 431 deletions

View File

@@ -1,208 +0,0 @@
<!-- 首页实时便笺卡片 -->
<template>
<THomeCard :append="isLogin" title="实时便笺">
<template v-if="isLogin" #title-append>
<PhUserSwitch
:current-uid="uid ?? ''"
:nickname="briefInfo.nickname"
@switch-user="handleUserSwitch"
/>
</template>
<template #default>
<div v-if="!isLogin" class="dn-not-login">请先登录</div>
<div v-else-if="gameAccounts.length === 0" class="dn-not-login">暂无游戏账户</div>
<div v-else-if="loading" class="dn-loading">
<div class="loading-content">
<v-progress-linear :model-value="loadingProgress" color="blue" height="6" rounded />
<div class="loading-text">{{ loadingText }}</div>
</div>
</div>
<div v-else class="dn-container">
<PhDailyNoteItem
v-for="item in sortedDailyNoteAccounts"
:key="`${item.account.gameBiz}_${item.account.gameUid}`"
:account="item.account"
:data="item.data"
:cur="item.account.gameUid === currentGameUid"
@refresh="handleRefresh(item.account)"
/>
</div>
</template>
</THomeCard>
</template>
<script lang="ts" setup>
import showSnackbar from "@comp/func/snackbar.js";
import recordReq from "@req/recordReq.js";
import TSUserAccount from "@Sqlm/userAccount.js";
import useAppStore from "@store/app.js";
import useUserStore from "@store/user.js";
import TGHttps from "@utils/TGHttps.js";
import TGLogger from "@utils/TGLogger.js";
import { storeToRefs } from "pinia";
import { computed, onMounted, ref, watch } from "vue";
import THomeCard from "./ph-comp-card.vue";
import PhDailyNoteItem from "./ph-daily-note-item.vue";
import PhUserSwitch from "./ph-user-switch.vue";
type DailyNoteAccount = {
account: TGApp.Sqlite.Account.Game;
data?: TGApp.Game.DailyNote.DnRes;
};
type TDailyNoteEmits = {
(e: "success"): void;
(e: "delete", gameUid: string): void;
};
const emits = defineEmits<TDailyNoteEmits>();
const { cookie, uid, briefInfo, account } = storeToRefs(useUserStore());
const { isLogin } = storeToRefs(useAppStore());
const loading = ref<boolean>(false);
const loadingProgress = ref<number>(0);
const loadingText = ref<string>("");
const gameAccounts = ref<Array<TGApp.Sqlite.Account.Game>>([]);
const dailyNoteAccounts = ref<Array<DailyNoteAccount>>([]);
const currentGameUid = computed(() => account.value?.gameUid || "");
const sortedDailyNoteAccounts = computed(() => {
if (!currentGameUid.value) return dailyNoteAccounts.value;
return [...dailyNoteAccounts.value].sort((a, b) => {
const aIsCurrent = a.account.gameUid === currentGameUid.value;
const bIsCurrent = b.account.gameUid === currentGameUid.value;
if (aIsCurrent && !bIsCurrent) return -1;
if (!aIsCurrent && bIsCurrent) return 1;
return 0;
});
});
watch(
() => uid.value,
async () => await loadData(),
);
onMounted(async () => await loadData());
async function loadData(): Promise<void> {
if (!isLogin.value || uid.value === undefined || !cookie.value) {
gameAccounts.value = [];
dailyNoteAccounts.value = [];
return;
}
dailyNoteAccounts.value = [];
try {
const accounts = await TSUserAccount.game.getAccount(uid.value);
const genshinAccounts = accounts.filter((ac) => ac.gameBiz === "hk4e_cn");
gameAccounts.value = genshinAccounts;
if (genshinAccounts.length === 0) {
await TGLogger.Warn("[Daily Note Card] No Genshin Impact accounts found");
emits("success");
return;
}
emits("success");
loading.value = true;
loadingProgress.value = 0;
for (let i = 0; i < genshinAccounts.length; i++) {
const account = genshinAccounts[i];
loadingText.value = `正在加载 ${account.gameBiz} - ${account.regionName} - ${account.gameUid}...`;
loadingProgress.value = (i / genshinAccounts.length) * 100;
let data: TGApp.Game.DailyNote.DnRes | undefined;
let dataResp: TGApp.Game.DailyNote.DnResp | undefined;
try {
dataResp = await recordReq.daily(cookie.value, account);
if (dataResp.retcode !== 0) {
await TGLogger.Warn(
`[Daily Note Card] ${account.gameBiz}: [${dataResp.retcode}] ${dataResp.message}`,
);
} else {
data = dataResp.data;
}
} catch (e) {
const errMsg = TGHttps.getErrMsg(e);
await TGLogger.Error(`[Daily Note Card] ${account.gameBiz}: ${errMsg}`);
await TGLogger.Error(`[Daily Note Card] ${e}`);
}
dailyNoteAccounts.value.push({ account, data });
}
} catch (error) {
await TGLogger.Error(`[Daily Note Card] Error loading data: ${error}`);
} finally {
loadingProgress.value = 100;
loadingText.value = "加载完成";
await new Promise<void>((resolve) => setTimeout(resolve, 200));
loading.value = false;
loadingProgress.value = 0;
loadingText.value = "";
}
}
async function handleUserSwitch(newUid: string): Promise<void> {
await TGLogger.Info(`[Daily Note Card] User switched to ${newUid}`);
}
async function handleRefresh(account: TGApp.Sqlite.Account.Game): Promise<void> {
let dataResp: TGApp.Game.DailyNote.DnResp | undefined;
try {
dataResp = await recordReq.daily(cookie.value!, account);
if (dataResp.retcode !== 0) {
await TGLogger.Warn(`[Daily Note Card] [${dataResp.retcode}] ${dataResp.message}`);
showSnackbar.error(`刷新失败:[${dataResp.retcode}] ${dataResp.message}`);
return;
}
} catch (e) {
const errMsg = TGHttps.getErrMsg(e);
await TGLogger.Error(`[Daily Note Card] 刷新失败:${errMsg}`);
await TGLogger.Error(`[Daily Note Card] ${e}`);
showSnackbar.error(`刷新失败:${errMsg}`);
return;
}
const item = dailyNoteAccounts.value.find(
(i) => i.account.gameUid === account.gameUid && i.account.gameBiz === account.gameBiz,
);
if (item) {
item.data = dataResp.data;
}
showSnackbar.success("刷新成功");
}
</script>
<style lang="scss" scoped>
.dn-not-login {
display: flex;
align-items: center;
justify-content: center;
padding: 40px 20px;
color: var(--box-text-1);
font-size: 16px;
}
.dn-loading {
display: flex;
align-items: center;
justify-content: center;
padding: 20px;
}
.loading-content {
display: flex;
width: 100%;
max-width: 400px;
flex-direction: column;
gap: 12px;
}
.loading-text {
color: var(--box-text-2);
font-size: 14px;
text-align: center;
}
.dn-container {
position: relative;
display: grid;
padding: 8px;
gap: 8px;
grid-template-columns: repeat(2, 1fr);
}
</style>

View File

@@ -0,0 +1,357 @@
<!-- 首页便笺签到卡片 -->
<template>
<THomeCard :append="isLogin" title="便笺签到">
<template v-if="isLogin" #title-append>
<v-switch v-model="isDailyNote" class="tns-switch"></v-switch>
<span>{{ isDailyNote ? "实时便笺" : "游戏签到" }}</span>
</template>
<template #default>
<div v-show="isDailyNote">
<div v-if="!isLogin" class="tns-not-login">请先登录</div>
<div v-else-if="loadingDailyNote" class="tns-loading">
<div class="loading-content">
<v-progress-linear :model-value="loadingProgress" color="blue" height="6" rounded />
<div class="loading-text">{{ loadingText }}</div>
</div>
</div>
<div v-else-if="gameAccounts.length === 0" class="tns-not-login">暂无游戏账户</div>
<div v-else class="tns-dn-container">
<PhDailyNoteItem
v-for="item in sortedDailyNoteAccounts"
:key="`${item.account.gameBiz}_${item.account.gameUid}`"
:account="item.account"
:data="item.data"
:cur="item.account.gameUid === currentGameUid"
@refresh="handleRefreshDailyNote(item.account)"
/>
</div>
</div>
<div v-show="!isDailyNote">
<div v-if="!isLogin" class="tns-not-login">请先登录</div>
<div v-else-if="loadingSign" class="tns-loading">
<div class="loading-content">
<v-progress-linear :model-value="loadingProgress" color="blue" height="6" rounded />
<div class="loading-text">{{ loadingText }}</div>
</div>
</div>
<div v-else-if="signAccounts.length === 0" class="tns-not-login">暂无游戏账户</div>
<div v-else class="tns-sign-container">
<PhSignItem
v-for="item in sortedSignAccounts"
:key="`${item.account.gameBiz}_${item.account.gameUid}`"
:account="item.account"
:info="item.info"
:stat="item.stat"
:cur="item.account.gameUid === currentGameUid && item.account.gameBiz === 'hk4e_cn'"
@delete="handleDeleteSignAccount"
/>
</div>
</div>
</template>
</THomeCard>
</template>
<script lang="ts" setup>
import showSnackbar from "@comp/func/snackbar.js";
import lunaReq from "@req/lunaReq.js";
import recordReq from "@req/recordReq.js";
import TSUserAccount from "@Sqlm/userAccount.js";
import useAppStore from "@store/app.js";
import useUserStore from "@store/user.js";
import TGHttps from "@utils/TGHttps.js";
import TGLogger from "@utils/TGLogger.js";
import { storeToRefs } from "pinia";
import { computed, onMounted, ref, watch } from "vue";
import THomeCard from "./ph-comp-card.vue";
import PhDailyNoteItem from "./ph-daily-note-item.vue";
import PhSignItem from "./ph-sign-item.vue";
type DailyNoteAccount = {
account: TGApp.Sqlite.Account.Game;
data?: TGApp.Game.DailyNote.DnRes;
};
type SignAccount = {
account: TGApp.Sqlite.Account.Game;
info?: TGApp.BBS.Sign.HomeRes;
stat?: TGApp.BBS.Sign.InfoRes;
};
type TNoteSignEmits = {
(e: "success"): void;
};
const emits = defineEmits<TNoteSignEmits>();
const { cookie, uid, account } = storeToRefs(useUserStore());
const { isLogin } = storeToRefs(useAppStore());
const isDailyNote = ref<boolean>(true);
const dailyNoteLoaded = ref<boolean>(false);
const signLoaded = ref<boolean>(false);
const loadingDailyNote = ref<boolean>(false);
const loadingSign = ref<boolean>(false);
const loadingProgress = ref<number>(0);
const loadingText = ref<string>("");
const gameAccounts = ref<Array<TGApp.Sqlite.Account.Game>>([]);
const dailyNoteAccounts = ref<Array<DailyNoteAccount>>([]);
const signAccounts = ref<Array<SignAccount>>([]);
const currentGameUid = computed(() => account.value?.gameUid || "");
const sortedDailyNoteAccounts = computed(() => {
if (!currentGameUid.value) return dailyNoteAccounts.value;
return [...dailyNoteAccounts.value].sort((a, b) => {
const aIsCurrent = a.account.gameUid === currentGameUid.value;
const bIsCurrent = b.account.gameUid === currentGameUid.value;
if (aIsCurrent && !bIsCurrent) return -1;
if (!aIsCurrent && bIsCurrent) return 1;
return 0;
});
});
const sortedSignAccounts = computed(() => {
return [...signAccounts.value].sort((a, b) => {
const aIsGenshin = a.account.gameBiz === "hk4e_cn";
const bIsGenshin = b.account.gameBiz === "hk4e_cn";
if (aIsGenshin && !bIsGenshin) return -1;
if (!aIsGenshin && bIsGenshin) return 1;
const aIsCurrent = a.account.gameUid === currentGameUid.value;
const bIsCurrent = b.account.gameUid === currentGameUid.value;
if (aIsCurrent && !bIsCurrent) return -1;
if (!aIsCurrent && bIsCurrent) return 1;
return 0;
});
});
watch(
() => uid.value,
async () => {
dailyNoteLoaded.value = false;
signLoaded.value = false;
await loadDailyNoteData();
await loadSignData();
},
);
watch(
() => isDailyNote.value,
async (newVal) => {
if (newVal) {
if (!dailyNoteLoaded.value) await loadDailyNoteData();
} else {
if (!signLoaded.value) await loadSignData();
}
},
);
onMounted(async () => {
await loadDailyNoteData();
emits("success");
});
async function loadDailyNoteData(): Promise<void> {
if (!isLogin.value || uid.value === undefined || !cookie.value) {
gameAccounts.value = [];
dailyNoteAccounts.value = [];
return;
}
if (dailyNoteLoaded.value && dailyNoteAccounts.value.length > 0) return;
dailyNoteAccounts.value = [];
try {
const accounts = await TSUserAccount.game.getAccount(uid.value);
const genshinAccounts = accounts.filter((ac) => ac.gameBiz === "hk4e_cn");
gameAccounts.value = genshinAccounts;
if (genshinAccounts.length === 0) {
await TGLogger.Warn("[Note Sign Card] No Genshin Impact accounts found");
dailyNoteLoaded.value = true;
return;
}
loadingDailyNote.value = true;
loadingProgress.value = 0;
for (let i = 0; i < genshinAccounts.length; i++) {
const acc = genshinAccounts[i];
loadingText.value = `正在加载 ${acc.gameBiz} - ${acc.regionName} - ${acc.gameUid}...`;
loadingProgress.value = (i / genshinAccounts.length) * 100;
let data: TGApp.Game.DailyNote.DnRes | undefined;
let dataResp: TGApp.Game.DailyNote.DnResp | undefined;
try {
dataResp = await recordReq.daily(cookie.value, acc);
if (dataResp.retcode !== 0) {
await TGLogger.Warn(
`[Note Sign Card] ${acc.gameBiz}: [${dataResp.retcode}] ${dataResp.message}`,
);
} else {
data = dataResp.data;
}
} catch (e) {
const errMsg = TGHttps.getErrMsg(e);
await TGLogger.Error(`[Game Status Card] ${acc.gameBiz}: ${errMsg}`);
await TGLogger.Error(`[Game Status Card] ${e}`);
}
dailyNoteAccounts.value.push({ account: acc, data });
}
} catch (error) {
await TGLogger.Error(`[Game Status Card] Error loading daily note data: ${error}`);
} finally {
loadingProgress.value = 100;
loadingText.value = "加载完成";
await new Promise<void>((resolve) => setTimeout(resolve, 200));
loadingDailyNote.value = false;
loadingProgress.value = 0;
loadingText.value = "";
dailyNoteLoaded.value = true;
}
}
async function loadSignData(): Promise<void> {
if (!isLogin.value || uid.value === undefined || !cookie.value) {
signAccounts.value = [];
return;
}
if (signLoaded.value && signAccounts.value.length > 0) return;
signAccounts.value = [];
const accounts = await TSUserAccount.game.getAccount(uid.value);
if (accounts.length === 0) {
await TGLogger.Warn("[Game Status Card] No game accounts found for sign");
signLoaded.value = true;
return;
}
loadingSign.value = true;
loadingProgress.value = 0;
const ck = { cookie_token: cookie.value.cookie_token, account_id: cookie.value.account_id };
for (let i = 0; i < accounts.length; i++) {
const acc = accounts[i];
loadingText.value = `正在加载 ${acc.gameBiz} - ${acc.regionName} - ${acc.gameUid}...`;
loadingProgress.value = (i / accounts.length) * 100;
let info, stat;
let infoResp: TGApp.BBS.Sign.HomeResp | undefined;
try {
infoResp = await lunaReq.sign.info(acc, ck);
if (infoResp.retcode !== 0) {
await TGLogger.Warn(
`[Game Status Card] Failed to get rewards for ${acc.gameBiz}: [${infoResp.retcode}] ${infoResp.message}`,
);
} else info = infoResp.data;
} catch (error) {
const errMsg = TGHttps.getErrMsg(error);
await TGLogger.Error(`[Game Status Card] Error loading info for ${acc.gameBiz}: ${errMsg}`);
}
let statResp: TGApp.BBS.Sign.InfoResp | undefined;
try {
statResp = await lunaReq.sign.stat(acc, ck);
if (statResp.retcode !== 0) {
await TGLogger.Warn(
`[Game Status Card] Failed to get status for ${acc.gameBiz}: [${statResp.retcode}] ${statResp.message}`,
);
} else stat = statResp.data;
} catch (error) {
const errMsg = TGHttps.getErrMsg(error);
await TGLogger.Error(`[Game Status Card] Error loading stat for ${acc.gameBiz}: ${errMsg}`);
}
signAccounts.value.push({ account: acc, info, stat });
}
await endLoadSign();
signLoaded.value = true;
}
async function endLoadSign(): Promise<void> {
loadingProgress.value = 100;
loadingText.value = "加载完成";
await new Promise<void>((resolve) => setTimeout(resolve, 200));
loadingSign.value = false;
loadingProgress.value = 0;
loadingText.value = "";
}
async function handleRefreshDailyNote(acc: TGApp.Sqlite.Account.Game): Promise<void> {
let dataResp: TGApp.Game.DailyNote.DnResp | undefined;
try {
dataResp = await recordReq.daily(cookie.value!, acc);
if (dataResp.retcode !== 0) {
await TGLogger.Warn(`[Game Status Card] [${dataResp.retcode}] ${dataResp.message}`);
showSnackbar.error(`刷新失败:[${dataResp.retcode}] ${dataResp.message}`);
return;
}
} catch (e) {
const errMsg = TGHttps.getErrMsg(e);
await TGLogger.Error(`[Game Status Card] 刷新失败:${errMsg}`);
await TGLogger.Error(`[Game Status Card] ${e}`);
showSnackbar.error(`刷新失败:${errMsg}`);
return;
}
const item = dailyNoteAccounts.value.find(
(i) => i.account.gameUid === acc.gameUid && i.account.gameBiz === acc.gameBiz,
);
if (item) {
item.data = dataResp.data;
}
showSnackbar.success("刷新成功");
}
async function handleDeleteSignAccount(acc: TGApp.Sqlite.Account.Game): Promise<void> {
try {
await TSUserAccount.game.deleteAccount(acc);
signAccounts.value = signAccounts.value.filter(
(item) => item.account.gameUid !== acc.gameUid || item.account.gameBiz !== acc.gameBiz,
);
showSnackbar.success("账号已删除");
} catch (error) {
await TGLogger.Error(`[Game Status Card] Delete account error: ${error}`);
showSnackbar.error("删除账号失败");
}
}
</script>
<style lang="scss" scoped>
.tns-switch {
display: flex;
height: 36px;
align-items: center;
justify-content: center;
margin-right: 4px;
}
.tns-not-login {
display: flex;
align-items: center;
justify-content: center;
padding: 40px 20px;
color: var(--box-text-1);
font-size: 16px;
}
.tns-loading {
display: flex;
align-items: center;
justify-content: center;
padding: 20px;
}
.loading-content {
display: flex;
width: 100%;
max-width: 400px;
flex-direction: column;
gap: 12px;
}
.loading-text {
color: var(--box-text-2);
font-size: 14px;
text-align: center;
}
.tns-dn-container {
position: relative;
display: grid;
padding: 8px;
gap: 8px;
grid-template-columns: repeat(2, 1fr);
}
.tns-sign-container {
display: grid;
padding: 8px;
gap: 8px;
grid-template-columns: repeat(auto-fit, minmax(350px, 0.34fr));
}
</style>

View File

@@ -1,193 +0,0 @@
<!-- 首页签到卡片 -->
<template>
<THomeCard :append="isLogin" title="游戏签到">
<template v-if="isLogin" #title-append>
<PhUserSwitch
:current-uid="uid ?? ''"
:nickname="briefInfo.nickname"
@switch-user="handleUserSwitch"
/>
</template>
<template #default>
<div v-if="!isLogin" class="sign-not-login">请先登录</div>
<div v-else-if="gameAccounts.length === 0" class="sign-not-login">暂无游戏账户</div>
<div v-else-if="loading" class="sign-loading">
<div class="loading-content">
<v-progress-linear :model-value="loadingProgress" color="blue" height="6" rounded />
<div class="loading-text">{{ loadingText }}</div>
</div>
</div>
<div v-else class="sign-container">
<PhSignItem
v-for="item in signAccounts"
:key="`${item.account.gameBiz}_${item.account.gameUid}`"
:account="item.account"
:info="item.info"
:stat="item.stat"
@delete="handleDelete"
/>
</div>
</template>
</THomeCard>
</template>
<script lang="ts" setup>
import showSnackbar from "@comp/func/snackbar.js";
import lunaReq from "@req/lunaReq.js";
import TSUserAccount from "@Sqlm/userAccount.js";
import useAppStore from "@store/app.js";
import useUserStore from "@store/user.js";
import TGHttps from "@utils/TGHttps.js";
import TGLogger from "@utils/TGLogger.js";
import { storeToRefs } from "pinia";
import { onMounted, ref, watch } from "vue";
import THomeCard from "./ph-comp-card.vue";
import PhSignItem from "./ph-sign-item.vue";
import PhUserSwitch from "./ph-user-switch.vue";
type SignAccount = {
account: TGApp.Sqlite.Account.Game;
info?: TGApp.BBS.Sign.HomeRes;
stat?: TGApp.BBS.Sign.InfoRes;
};
type TSignEmits = {
(e: "success"): void;
(e: "delete", gameUid: string): void;
};
const emits = defineEmits<TSignEmits>();
const { cookie, uid, briefInfo } = storeToRefs(useUserStore());
const { isLogin } = storeToRefs(useAppStore());
const loading = ref<boolean>(false);
const loadingProgress = ref<number>(0);
const loadingText = ref<string>("");
const gameAccounts = ref<Array<TGApp.Sqlite.Account.Game>>([]);
const signAccounts = ref<Array<SignAccount>>([]);
watch(
() => uid.value,
async () => await loadData(),
);
onMounted(async () => await loadData());
async function endLoad(): Promise<void> {
loadingProgress.value = 100;
loadingText.value = "加载完成";
await new Promise<void>((resolve) => setTimeout(resolve, 200));
loading.value = false;
loadingProgress.value = 0;
loadingText.value = "";
}
async function loadData(): Promise<void> {
if (!isLogin.value || uid.value === undefined || !cookie.value) {
gameAccounts.value = [];
signAccounts.value = [];
return;
}
signAccounts.value = [];
const accounts = await TSUserAccount.game.getAccount(uid.value);
gameAccounts.value = accounts;
if (accounts.length === 0) {
await TGLogger.Warn("[Sign Card] No game accounts found");
emits("success");
await endLoad();
return;
}
emits("success");
loading.value = true;
loadingProgress.value = 0;
const ck = { cookie_token: cookie.value.cookie_token, account_id: cookie.value.account_id };
for (let i = 0; i < accounts.length; i++) {
const account = accounts[i];
loadingText.value = `正在加载 ${account.gameBiz} - ${account.regionName} - ${account.gameUid}...`;
loadingProgress.value = (i / accounts.length) * 100;
let info, stat;
let infoResp: TGApp.BBS.Sign.HomeResp | undefined;
try {
infoResp = await lunaReq.sign.info(account, ck);
if (infoResp.retcode !== 0) {
await TGLogger.Warn(
`[Sign Card] Failed to get rewards for ${account.gameBiz}: [${infoResp.retcode}] ${infoResp.message}`,
);
} else info = infoResp.data;
} catch (error) {
const errMsg = TGHttps.getErrMsg(error);
await TGLogger.Error(`[Sign Card] Error loading info for ${account.gameBiz}: ${errMsg}`);
}
let statResp: TGApp.BBS.Sign.InfoResp | undefined;
try {
statResp = await lunaReq.sign.stat(account, ck);
if (statResp.retcode !== 0) {
await TGLogger.Warn(
`[Sign Card] Failed to get status for ${account.gameBiz}: [${statResp.retcode}] ${statResp.message}`,
);
} else stat = statResp.data;
} catch (error) {
const errMsg = TGHttps.getErrMsg(error);
await TGLogger.Error(`[Sign Card] Error loading stat for ${account.gameBiz}: ${errMsg}`);
}
signAccounts.value.push({ account, info, stat });
}
await endLoad();
}
async function handleUserSwitch(newUid: string): Promise<void> {
await TGLogger.Info(`[Sign Card] User switched to ${newUid}`);
}
async function handleDelete(account: TGApp.Sqlite.Account.Game): Promise<void> {
try {
await TSUserAccount.game.deleteAccount(account);
signAccounts.value = signAccounts.value.filter(
(item) =>
item.account.gameUid !== account.gameUid || item.account.gameBiz !== account.gameBiz,
);
showSnackbar.success("账号已删除");
} catch (error) {
await TGLogger.Error(`[Sign Card] Delete account error: ${error}`);
showSnackbar.error("删除账号失败");
}
}
</script>
<style lang="scss" scoped>
.sign-not-login {
display: flex;
align-items: center;
justify-content: center;
padding: 40px 20px;
color: var(--box-text-1);
font-size: 16px;
}
.sign-loading {
display: flex;
align-items: center;
justify-content: center;
padding: 20px;
}
.loading-content {
display: flex;
width: 100%;
max-width: 400px;
flex-direction: column;
gap: 12px;
}
.loading-text {
color: var(--box-text-2);
font-size: 14px;
text-align: center;
}
.sign-container {
display: grid;
padding: 8px;
gap: 8px;
grid-template-columns: repeat(auto-fit, minmax(350px, 0.34fr));
}
</style>

View File

@@ -1,6 +1,6 @@
<!-- 单个游戏账户签到卡片 -->
<template>
<div ref="signItemRef" class="ph-si-box">
<div ref="signItemRef" :class="{ 'ph-si-current': props.cur }" class="ph-si-box">
<div class="ph-si-top">
<div :title="gameInfo.title" class="ph-sit-icon" @click="shareItem()">
<img :alt="gameInfo.title" :src="gameInfo.icon" />
@@ -126,6 +126,7 @@ type PhSignItemProps = {
account: TGApp.Sqlite.Account.Game;
info?: TGApp.BBS.Sign.HomeRes;
stat?: TGApp.BBS.Sign.InfoRes;
cur?: boolean;
};
type PhSignItemEmits = {
(e: "delete", account: TGApp.Sqlite.Account.Game): void;
@@ -540,6 +541,12 @@ async function shareItem(): Promise<void> {
border-radius: 4px;
background: var(--box-bg-1);
row-gap: 8px;
transition: border-color 0.3s ease;
&.ph-si-current {
border-width: 2px;
border-color: var(--common-shadow-2);
}
}
.ph-si-top {

View File

@@ -54,7 +54,7 @@
density="compact"
label="首页组件显示"
variant="outlined"
width="440px"
width="360px"
/>
<v-btn :rounded="true" class="select-btn" variant="elevated" @click="submitHome">
确定
@@ -72,10 +72,9 @@ import showDialog from "@comp/func/dialog.js";
import showLoading from "@comp/func/loading.js";
import showSnackbar from "@comp/func/snackbar.js";
import PhCompCalendar from "@comp/pageHome/ph-comp-calendar.vue";
import PhCompDailyNote from "@comp/pageHome/ph-comp-daily-note.vue";
import PhCompGameStatus from "@comp/pageHome/ph-comp-game-status.vue";
import PhCompPool from "@comp/pageHome/ph-comp-pool.vue";
import PhCompPosition from "@comp/pageHome/ph-comp-position.vue";
import PhCompSign from "@comp/pageHome/ph-comp-sign.vue";
import TSUserAccount from "@Sqlm/userAccount.js";
import useAppStore from "@store/app.js";
import useBBSStore from "@store/bbs.js";
@@ -116,7 +115,7 @@ const games = shallowRef<Array<SelectItem>>();
const loadItems = shallowRef<Array<string>>([]);
const components = shallowRef<Array<SFComp>>([]);
const showItems = shallowRef<Array<string>>([]);
const showItemsAll = shallowRef<Array<string>>(["素材日历", "限时祈愿", "近期活动"]);
const showItemsAll = shallowRef<Array<string>>(["素材日历", "限时祈愿", "近期活动", "便笺签到"]);
const oldItems = shallowRef<Array<string>>([]);
onMounted(async () => {
@@ -130,9 +129,9 @@ onMounted(async () => {
await showLoading.start("正在加载首页小部件");
games.value = gameList.value.map((i) => ({ icon: i.app_icon, title: i.name, gid: i.id }));
showItems.value = homeStore.getShowItems();
showItemsAll.value = ["游戏签到", "实时便笺", "素材日历", "限时祈愿", "近期活动"];
showItemsAll.value = ["便笺签到", "素材日历", "限时祈愿", "近期活动"];
} else {
showItems.value = homeStore.getShowItems().filter((i) => i !== "游戏签到");
showItems.value = homeStore.getShowItems().filter((i) => i !== "便笺签到");
showItemsAll.value = ["素材日历", "限时祈愿", "近期活动"];
}
oldItems.value = showItems.value;
@@ -152,18 +151,11 @@ async function loadComp(): Promise<void> {
const temp: Array<SFComp> = [];
for (const item of showItems.value) {
switch (item) {
case "游戏签到":
case "便笺签到":
if (isLogin.value) {
temp.push(PhCompSign);
temp.push(PhCompGameStatus);
} else {
showSnackbar.warn("未登录不可设置游戏签到组件");
}
break;
case "实时便笺":
if (isLogin.value) {
temp.push(PhCompDailyNote);
} else {
showSnackbar.warn("未登录不可设置实时便笺组件");
showSnackbar.warn("未登录不可设置便笺签到组件");
}
break;
case "限时祈愿":
@@ -198,10 +190,8 @@ async function submitHome(): Promise<void> {
function getName(name: string): string | undefined {
switch (name) {
case "ph-comp-sign":
return "游戏签到";
case "ph-comp-daily-note":
return "实时便笺";
case "ph-comp-game-status":
return "便笺签到";
case "ph-comp-pool":
return "限时祈愿";
case "ph-comp-position":

View File

@@ -1,6 +1,6 @@
/**
* 首页组件状态
* @since Beta v0.10.0
* @since Beta v0.10.1
*/
import { defineStore } from "pinia";
@@ -13,8 +13,7 @@ const defaultHomeShow: Array<TGApp.Store.Home.ShowItem> = [
{ show: true, order: 1, label: "限时祈愿" },
{ show: true, order: 2, label: "近期活动" },
{ show: true, order: 3, label: "素材日历" },
{ show: false, order: 4, label: "游戏签到" },
{ show: false, order: 5, label: "实时便笺" },
{ show: false, order: 4, label: "便笺签到" },
];
const useHomeStore = defineStore("home", () => {
@@ -29,25 +28,20 @@ const useHomeStore = defineStore("home", () => {
try {
const storedItems: Array<TGApp.Store.Home.ShowItem> = JSON.parse(homeShowLocal);
if (!Array.isArray(storedItems)) {
// Invalid data, reset to default
localStorage.setItem("homeShow", JSON.stringify(homeShow.value));
} else {
// Merge with default items to add new items
const storedLabels = storedItems.map((i) => i.label);
// Add new items from default that don't exist in stored
for (const defaultItem of homeShow.value) {
if (!storedLabels.includes(defaultItem.label)) {
storedItems.push({ ...defaultItem });
if (defaultHomeShow.includes(defaultItem)) storedItems.push({ ...defaultItem });
}
}
// Remove items that no longer exist in default
const defaultLabels = homeShow.value.map((i) => i.label);
homeShow.value = storedItems.filter((item) => defaultLabels.includes(item.label));
localStorage.setItem("homeShow", JSON.stringify(homeShow.value));
}
} catch (e) {
console.error(e);
// Invalid JSON, reset to default
localStorage.setItem("homeShow", JSON.stringify(homeShow.value));
}
}