Files
jiapuapp/pages/tree/t08-member-states.vue
T
2026-07-23 08:24:07 +08:00

144 lines
6.8 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!-- 页面编号T-08用途展示指定成员的隐私纪念或无权限状态 -->
<template>
<view
class="member-status-page"
:class="{
'member-status--privacy': statusState === 'privacy',
'member-status--deceased': statusState === 'deceased',
'member-status--forbidden': statusState === 'forbidden',
'member-status--error': statusState === 'error',
}"
>
<ModulePageBackground module="tree" />
<view class="member-status-page__header"><PageHeader :title="pageTitle" /></view>
<view v-if="hasValidContext" class="member-status-context">
<text>{{ genealogyName }}</text>
<text v-if="member">{{ memberIdentityCopy }}</text>
<text v-else>未找到成员身份</text>
</view>
<view class="status-card">
<view class="status-card__copy">
<text>{{ activeStatus.eyebrow }}</text>
<text>{{ activeStatus.title }}</text>
<text>{{ activeStatus.copy }}</text>
</view>
</view>
<view class="status-guidance">
<view>
<text>{{ activeStatus.guideTitle }}</text>
<text v-for="line in activeStatus.guides" :key="line">{{ line }}</text>
</view>
</view>
<view class="status-action" @click="handleAction">
<image src="/static/assets/foundation/transparent/a01-scroll-primary-v3.png" mode="scaleToFill" />
<text>{{ activeStatus.action }}</text>
</view>
</view>
</template>
<script setup>
import { computed, ref } from "vue";
import { onLoad } from "@dcloudio/uni-app";
import ModulePageBackground from "@/components/ModulePageBackground.vue";
import PageHeader from "@/components/PageHeader.vue";
import { findTreeMemberPresentationFixture } from "@/data/mock.js";
import { goBack, goRoot } from "@/utils/navigation.js";
const genealogyId = ref("");
const personId = ref("");
const statusState = ref("loading");
const genealogyName = ref("汤氏家谱");
const member = ref(null);
const states = {
privacy: {
eyebrow: "隐私成员",
title: "敏感资料只向授权成员展示",
copy: "该成员姓名和世系位置仍然保留,出生信息、联系方式和生平内容按权限隐藏。",
guideTitle: "当前可见范围",
guides: ["姓名、世代与家族关系可见", "联系方式和详细生平已隐藏", "本人或谱主可维护授权范围"],
action: "返回成员档案",
},
deceased: {
eyebrow: "离世纪念",
title: "这位家人的生命记录被温和保留",
copy: "离世状态不会删除成员关系;有权限的家人仍可共同维护生卒年月、生平和追思资料。",
guideTitle: "纪念资料范围",
guides: ["生卒年月与世系关系继续保留", "生平内容由有权限家人维护", "敏感资料继续遵守原有隐私设置"],
action: "返回成员档案",
},
forbidden: {
eyebrow: "访问受限",
title: "当前账号没有查看该档案的权限",
copy: "页面不会展示被隐藏字段,也不会提供绕过家谱权限的入口。",
guideTitle: "如何申请查看",
guides: ["先确认已经加入对应家谱", "联系谱主说明亲属关系和用途", "权限变更后重新进入成员档案"],
action: "返回我的家谱",
},
error: {
eyebrow: "成员状态不可用",
title: "没有找到要查看的成员",
copy: "请从成员档案或世系树重新选择成员。",
guideTitle: "重新进入方式",
guides: ["从世系树选择成员节点", "从成员目录打开成员档案", "确认当前家谱仍然有效"],
action: "返回上一页",
},
};
const activeStatus = computed(() => states[statusState.value] || states.error);
const pageTitle = computed(() => statusState.value === "deceased" ? "成员纪念" : statusState.value === "privacy" ? "隐私资料" : "成员状态");
const hasValidContext = computed(() => Boolean(genealogyId.value && personId.value));
const memberIdentityCopy = computed(() => {
if (!member.value) return "";
const identity = `${member.value.name} · 第 ${member.value.generation} 世`;
return ["privacy", "forbidden"].includes(member.value.status)
? `${identity} · ${member.value.relation}`
: `${identity} · ${member.value.branch}`;
});
onLoad((query) => {
genealogyId.value = String(query.genealogyId || "");
personId.value = String(query.personId || "");
member.value = hasValidContext.value
? findTreeMemberPresentationFixture(genealogyId.value, personId.value)
: null;
const requestedState = ["privacy", "deceased", "forbidden"].includes(query.state) ? query.state : "";
const derivedState = member.value?.status || "";
statusState.value = member.value && (!requestedState || requestedState === derivedState)
? requestedState || derivedState
: "error";
});
const handleAction = () => {
if (statusState.value === "forbidden") {
return goRoot("G01");
}
return goBack();
};
</script>
<style scoped lang="scss">
@use "../../styles/adaptive-frame-profiles.scss" as adaptive;
.member-status-page { display: flex; min-height: 100vh; flex-direction: column; padding-bottom: 34rpx; box-sizing: border-box; background: $paper; }
.member-status-page__header, .member-status-context, .status-card, .status-guidance, .status-action { z-index: 2; }
.member-status-context { @include adaptive.adaptive-tree-field; width: calc(100% - 32rpx); margin: 18rpx auto 0; padding: 16rpx 24rpx; }
.member-status-context text { display: block; color: $ink-muted; font-size: 23rpx; line-height: 1.45; }
.member-status-context text:first-child { color: $ink; font-size: 26rpx; font-weight: 700; }
.status-card { @include adaptive.adaptive-tree-panel; width: calc(100% - 32rpx); min-height: 330rpx; margin: 18rpx auto 0; padding: 12% 10%; }
.status-card__copy text { display: block; color: $ink-muted; font-size: 24rpx; line-height: 1.55; text-align: center; }
.status-card__copy text:first-child { color: $brand-red; font-size: 22rpx; letter-spacing: 3rpx; }
.status-card__copy text:nth-child(2) { margin-top: 12rpx; color: $ink; font-family: "STKaiti", "KaiTi", serif; font-size: 32rpx; font-weight: 700; }
.status-card__copy text:last-child { margin-top: 14rpx; font-size: 24rpx; }
.status-guidance { @include adaptive.adaptive-genealogy-list-card; width: calc(100% - 48rpx); margin: 16rpx auto 0; padding: 24rpx 28rpx; }
.status-guidance text { display: block; color: $ink-muted; font-size: 24rpx; line-height: 1.6; }
.status-guidance text:first-child { margin-bottom: 8rpx; color: $ink; font-size: 26rpx; font-weight: 700; }
.status-action { display: grid; width: calc(100% - 72rpx); min-height: 76rpx; margin: 22rpx auto 0; }
.status-action image, .status-action text { grid-area: 1 / 1; width: 100%; height: 100%; }
.status-action text { z-index: 1; display: flex; align-items: center; justify-content: center; color: #fff9ed; font-size: 24rpx; font-weight: 700; }
@media (min-width: 400px) { .member-status-context, .status-card { width: calc(100% - 48rpx); } }
</style>