73 lines
5.5 KiB
Vue
73 lines
5.5 KiB
Vue
<!-- 页面编号:M-10;用途:协议、隐私、版本与退出登录。 -->
|
||
<template>
|
||
<view class="about-page" :class="{ 'about-state--logging-out': logoutSubmitting }">
|
||
<ModulePageBackground module="profile" />
|
||
<view class="page-layer"><PageHeader title="关于家谱" custom-back @back="requestBack" /></view>
|
||
<view class="page-content page-layer">
|
||
<view class="brand-card"><image src="/static/assets/foundation/transparent/brand-seal.png" mode="aspectFit" /><text>家谱</text><text>传承每一段值得珍藏的家族记忆</text><text>版本 {{ appVersion }}</text></view>
|
||
<view class="settings-list">
|
||
<view v-for="item in agreementItems" :key="item.key" class="settings-row" role="button" :aria-label="item.label" @click="openAgreement(item)"><view><text>{{ item.label }}</text><text>{{ item.note }}</text></view><image src="/static/assets/foundation/transparent/chevron-right.png" mode="aspectFit" /></view>
|
||
</view>
|
||
<AppButton block type="secondary" label="退出登录" @click="logoutVisible = true" />
|
||
</view>
|
||
<AppDialog :visible="agreementVisible" :close-on-mask="false" eyebrow="协议与说明" :title="activeAgreement.label" :message="activeAgreement.copy" confirm-text="关闭" @confirm="agreementVisible = false" @close="agreementVisible = false" />
|
||
<AppDialog :visible="logoutVisible" eyebrow="账号操作" title="确认退出登录?" message="退出后需要重新验证账号;本机保存的密码不会被保留。" :confirm-text="logoutSubmitting ? '正在退出' : '确认退出'" cancel-text="取消" show-cancel :close-on-mask="false" @confirm="confirmLogout" @cancel="logoutVisible = false" @close="logoutVisible = false" />
|
||
</view>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { reactive, ref } from "vue";
|
||
import { onBackPress, onUnload } from "@dcloudio/uni-app";
|
||
import AppButton from "@/components/AppButton.vue";
|
||
import AppDialog from "@/components/AppDialog.vue";
|
||
import ModulePageBackground from "@/components/ModulePageBackground.vue";
|
||
import PageHeader from "@/components/PageHeader.vue";
|
||
import manifest from "@/manifest.json";
|
||
import { appApi, createRequestController } from "@/utils/api.js";
|
||
import { goRoot, handleBackPress, runBackGuard } from "@/utils/navigation.js";
|
||
import { session } from "@/utils/session.js";
|
||
|
||
const appVersion = manifest.versionName;
|
||
const agreementItems = [
|
||
{ key: "terms", label: "用户协议", note: "了解账号与服务使用规则", copy: "用户协议正文将在正式协议服务接入后展示。当前页面不代表最终法律文本。" },
|
||
{ key: "privacy", label: "隐私政策", note: "了解个人资料如何使用与保护", copy: "隐私政策正文将在正式协议服务接入后展示。敏感资料默认按权限与脱敏规则展示。" },
|
||
{ key: "version", label: "版本说明", note: `当前版本 ${appVersion}`, copy: `当前安装版本为 ${appVersion}。基础版本采用浅色国风主题。` },
|
||
];
|
||
const activeAgreement = reactive({ label: "", copy: "" });
|
||
const agreementVisible = ref(false);
|
||
const logoutVisible = ref(false);
|
||
const logoutSubmitting = ref(false);
|
||
const logoutRequestController = createRequestController();
|
||
const openAgreement = (item) => { activeAgreement.label = item.label; activeAgreement.copy = item.copy; agreementVisible.value = true; };
|
||
const confirmLogout = async () => {
|
||
if (logoutSubmitting.value) return false;
|
||
logoutSubmitting.value = true;
|
||
try {
|
||
await appApi.logout({ requestController: logoutRequestController });
|
||
} catch {
|
||
// 退出请求的结果未知时仍必须撤销本机会话,不能保留旧授权或自动重试。
|
||
} finally {
|
||
session.clear();
|
||
logoutVisible.value = false;
|
||
logoutSubmitting.value = false;
|
||
}
|
||
return goRoot("A01");
|
||
};
|
||
const closeActiveDialog = () => {
|
||
if (logoutVisible.value) logoutVisible.value = false;
|
||
else agreementVisible.value = false;
|
||
};
|
||
const requestBack = () =>
|
||
runBackGuard({
|
||
transientOpen: agreementVisible.value || logoutVisible.value,
|
||
"close-transient": closeActiveDialog,
|
||
});
|
||
onBackPress((event) => handleBackPress(event, requestBack));
|
||
onUnload(() => logoutRequestController.abort());
|
||
</script>
|
||
|
||
<style scoped lang="scss">
|
||
@use "../../styles/adaptive-frame-profiles.scss" as adaptive;
|
||
.about-page{display:flex;min-height:100vh;flex-direction:column;background:$paper}.page-layer{z-index:1}.page-content{flex:1;padding:28rpx 30rpx 72rpx}.brand-card{@include adaptive.adaptive-profile-summary;display:flex;min-height:300rpx;flex-direction:column;align-items:center;justify-content:center;padding:36rpx 44rpx;text-align:center}.brand-card image{width:92rpx;height:106rpx}.brand-card text{display:block}.brand-card text:nth-child(2){margin-top:6rpx;color:$ink;font-family:STKaiti,KaiTi,serif;font-size:40rpx;font-weight:700;letter-spacing:4rpx}.brand-card text:nth-child(3){margin-top:8rpx;color:$ink-muted;font-size:22rpx;line-height:1.5}.brand-card text:last-child{margin-top:10rpx;color:$ink-muted;font-size:20rpx}.settings-list{display:flex;flex-direction:column;gap:12rpx;margin-top:22rpx}.settings-row{@include adaptive.adaptive-profile-field;display:grid;grid-template-columns:minmax(0,1fr) 32rpx;min-height:104rpx;align-items:center;gap:18rpx;padding:18rpx 30rpx}.settings-row view{min-width:0}.settings-row text{display:block;overflow-wrap:anywhere}.settings-row text:first-child{color:$ink;font-size:24rpx;font-weight:700}.settings-row text:last-child{margin-top:6rpx;color:$ink-muted;font-size:20rpx}.settings-row image{width:30rpx;height:30rpx}.page-content>.app-button{margin-top:28rpx}@media(max-width:340px){.page-content{padding-right:22rpx;padding-left:22rpx}}
|
||
</style>
|