267 lines
6.8 KiB
Vue
267 lines
6.8 KiB
Vue
<!-- 页面编号:T-08;用途:展示指定成员的隐私、纪念或无权限状态。 -->
|
||
<template>
|
||
<view
|
||
class="member-status-page"
|
||
:class="{
|
||
'member-status--available': statusState === 'available',
|
||
'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">
|
||
<AppLoading
|
||
v-if="statusState === 'loading'"
|
||
text="正在读取成员状态"
|
||
description="请稍候,正在读取人物详情中的状态字段。"
|
||
/>
|
||
<view v-else class="status-card__copy">
|
||
<text>{{ activeStatus.eyebrow }}</text>
|
||
<text>{{ activeStatus.title }}</text>
|
||
<text>{{ activeStatus.copy }}</text>
|
||
</view>
|
||
</view>
|
||
|
||
<view v-if="statusState !== 'loading'" class="status-guidance">
|
||
<view>
|
||
<text>{{ activeStatus.guideTitle }}</text>
|
||
<text v-for="line in activeStatus.guides" :key="line">{{ line }}</text>
|
||
</view>
|
||
</view>
|
||
|
||
<view
|
||
v-if="statusState !== 'loading'"
|
||
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, onUnload } from "@dcloudio/uni-app";
|
||
import AppLoading from "@/components/AppLoading.vue";
|
||
import ModulePageBackground from "@/components/ModulePageBackground.vue";
|
||
import PageHeader from "@/components/PageHeader.vue";
|
||
import {
|
||
appApi,
|
||
createRequestController,
|
||
isRequestCancelled,
|
||
} from "@/utils/api.js";
|
||
import { goBack } from "@/utils/navigation.js";
|
||
|
||
const genealogyId = ref("");
|
||
const personId = ref("");
|
||
const statusState = ref("loading");
|
||
const genealogyName = ref("汤氏家谱");
|
||
const member = ref(null);
|
||
const statusRequestController = createRequestController();
|
||
let loadSequence = 0;
|
||
|
||
const states = {
|
||
loading: {
|
||
eyebrow: "正在读取",
|
||
title: "正在读取成员状态",
|
||
copy: "",
|
||
guideTitle: "",
|
||
guides: [],
|
||
action: "",
|
||
},
|
||
available: {
|
||
eyebrow: "人物状态",
|
||
title: "暂无法展示状态说明",
|
||
copy: "服务端返回了状态字段,但未提供可读名称或说明;本页不会向家人展示内部状态值。",
|
||
guideTitle: "当前合同范围",
|
||
guides: [
|
||
"状态由服务端维护",
|
||
"状态展示需要后端提供可读字典",
|
||
"当前页不执行停用或任何状态写入",
|
||
],
|
||
action: "返回成员档案",
|
||
},
|
||
error: {
|
||
eyebrow: "成员状态不可用",
|
||
title: "没有找到要查看的成员",
|
||
copy: "请从成员档案或世系树重新选择成员。",
|
||
guideTitle: "重新进入方式",
|
||
guides: [
|
||
"从世系树选择成员节点",
|
||
"从成员目录打开成员档案",
|
||
"确认当前家谱仍然有效",
|
||
],
|
||
action: "返回上一页",
|
||
},
|
||
};
|
||
const activeStatus = computed(() => states[statusState.value] || states.error);
|
||
const pageTitle = computed(() => "成员状态");
|
||
const hasValidContext = computed(() =>
|
||
Boolean(genealogyId.value && personId.value),
|
||
);
|
||
const memberIdentityCopy = computed(() => {
|
||
if (!member.value) return "";
|
||
return `${member.value.name} · 第 ${member.value.generation} 世`;
|
||
});
|
||
|
||
const loadMember = async () => {
|
||
const activeLoad = ++loadSequence;
|
||
statusState.value = "loading";
|
||
try {
|
||
const result = await appApi.getPerson(genealogyId.value, personId.value, {
|
||
requestController: statusRequestController,
|
||
});
|
||
if (activeLoad !== loadSequence) return;
|
||
member.value = result;
|
||
genealogyName.value = result.genealogyName;
|
||
statusState.value = "available";
|
||
} catch (error) {
|
||
if (activeLoad !== loadSequence || isRequestCancelled(error)) return;
|
||
member.value = null;
|
||
statusState.value = "error";
|
||
}
|
||
};
|
||
|
||
onLoad((query) => {
|
||
genealogyId.value = String(query.genealogyId || "");
|
||
personId.value = String(query.personId || "");
|
||
if (!hasValidContext.value || query.state === "error") {
|
||
statusState.value = "error";
|
||
return;
|
||
}
|
||
void loadMember();
|
||
});
|
||
|
||
onUnload(() => {
|
||
loadSequence += 1;
|
||
statusRequestController.abort();
|
||
});
|
||
|
||
const handleAction = () => goBack();
|
||
</script>
|
||
|
||
<style scoped lang="scss">
|
||
@import "../../styles/adaptive-frame-profiles.scss";
|
||
|
||
.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-tree-field;
|
||
width: calc(100% - 32rpx);
|
||
margin: 18rpx auto 0;
|
||
padding: 16rpx 24rpx;
|
||
}
|
||
.member-status-context text {
|
||
display: block;
|
||
color: $ink-muted;
|
||
font-size: clamp(14px, 23rpx, 17px);
|
||
line-height: 1.45;
|
||
}
|
||
.member-status-context text:first-child {
|
||
color: $ink;
|
||
font-size: clamp(16px, 26rpx, 20px);
|
||
font-weight: 700;
|
||
}
|
||
.status-card {
|
||
@include 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: clamp(15px, 24rpx, 18px);
|
||
line-height: 1.55;
|
||
text-align: center;
|
||
}
|
||
.status-card__copy text:first-child {
|
||
color: $brand-red;
|
||
font-size: clamp(14px, 22rpx, 17px);
|
||
letter-spacing: 3rpx;
|
||
}
|
||
.status-card__copy text:nth-child(2) {
|
||
margin-top: 12rpx;
|
||
color: $ink;
|
||
font-family: "STKaiti", "KaiTi", serif;
|
||
font-size: clamp(17px, 32rpx, 22px);
|
||
font-weight: 700;
|
||
}
|
||
.status-card__copy text:last-child {
|
||
margin-top: 14rpx;
|
||
font-size: clamp(15px, 24rpx, 18px);
|
||
}
|
||
.status-guidance {
|
||
@include 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: clamp(15px, 24rpx, 18px);
|
||
line-height: 1.6;
|
||
}
|
||
.status-guidance text:first-child {
|
||
margin-bottom: 8rpx;
|
||
color: $ink;
|
||
font-size: clamp(16px, 26rpx, 20px);
|
||
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: clamp(15px, 24rpx, 18px);
|
||
font-weight: 700;
|
||
}
|
||
@media (min-width: 400px) {
|
||
.member-status-context,
|
||
.status-card {
|
||
width: calc(100% - 48rpx);
|
||
}
|
||
}
|
||
</style>
|