Files
jiapuapp/pages/records/r06-ritual-detail.vue
T
2026-07-23 08:24:07 +08:00

253 lines
7.2 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.
<!-- 页面编号R-06用途当前家谱礼仪详情受邀信息与受控状态 -->
<template>
<view class="ritual-detail-page" :class="stateClasses">
<ModulePageBackground module="records" />
<view class="page-header">
<PageHeader
title="礼仪详情"
:action="ceremonyState === 'ready' ? '制作预览' : ''"
custom-back
@back="requestBack"
@action="editCeremony"
/>
</view>
<view v-if="ceremonyState === 'loading'" class="page-loading">
<AppLoading
text="正在读取礼仪详情"
description="请稍候,正在核对活动身份与受邀信息。"
/>
</view>
<view v-else class="page-content">
<template v-if="ceremonyState === 'ready' && ceremonyDetail">
<view class="detail-card">
<text>{{ ceremonyDetail.ceremonyType }}</text>
<text>{{ ceremonyDetail.ceremonyTitle }}</text>
<text>
{{ ceremonyDetail.ceremonyTime }} ·
{{ ceremonyDetail.location || "地点待定" }}
</text>
<text>{{ ceremonyDetail.ceremonyDesc || "暂无活动说明" }}</text>
</view>
<view class="participant-card">
<view>
<text>受邀家人</text>
<text>{{ invitees.length }} </text>
</view>
<view v-for="invitee in invitees" :key="invitee.inviteeUserId">
<text>{{ invitee.displayName }} · {{ invitee.relationName }}</text>
<text>{{ invitee.statusText }}</text>
</view>
<view v-if="!invitees.length"><text>尚无受邀记录</text><text></text></view>
</view>
<AppButton block label="制作编辑预览" @click="editCeremony" />
</template>
<view v-else class="state-card">
<text>{{ stateCopy.title }}</text>
<text>{{ stateCopy.copy }}</text>
<AppButton
type="secondary"
block
:label="ceremonyState === 'error' ? '重新查看' : '返回礼仪列表'"
@click="ceremonyState === 'error' ? restoreCeremony() : returnToCeremonies()"
/>
</view>
</view>
</view>
</template>
<script setup>
import { computed, ref } from "vue";
import { onLoad } from "@dcloudio/uni-app";
import AppButton from "@/components/AppButton.vue";
import AppLoading from "@/components/AppLoading.vue";
import ModulePageBackground from "@/components/ModulePageBackground.vue";
import PageHeader from "@/components/PageHeader.vue";
import {
findCeremonyFixture,
getGenealogyFixtureAccess,
listTreeMemberPresentationFixtures,
} from "@/data/mock.js";
import { goBack, openPage, returnTo } from "@/utils/navigation.js";
const genealogyId = ref("");
const ceremonyId = ref("");
const ceremonyDetail = ref(null);
const memberOptions = ref([]);
const ceremonyState = ref("loading");
const invitees = computed(() => {
const memberByAppUserId = new Map(
memberOptions.value.map((member) => [String(member.appUserId), member]),
);
return (ceremonyDetail.value?.invitees || []).map((invitation) => {
const member = memberByAppUserId.get(String(invitation.inviteeUserId));
return {
inviteeUserId: String(invitation.inviteeUserId),
displayName: member?.name || "受邀成员信息不可用",
relationName: member?.relation || "未完成同谱成员联接",
statusText: invitation.inviteStatus
? "受邀状态字典待后端确认"
: "受邀状态未提供",
};
});
});
const stateClasses = computed(() => ({
"ceremony-state--expired": ceremonyState.value === "expired",
"ceremony-state--error": ceremonyState.value === "error",
}));
const stateCopy = computed(
() =>
({
expired: {
title: "活动已失效",
copy: "活动不存在或不属于当前家谱,页面不会回退到其他活动。",
},
error: {
title: "礼仪详情暂不可用",
copy: "请稍后重新查看,已有活动不会受到影响。",
},
})[ceremonyState.value] || {
title: "礼仪详情暂不可用",
copy: "缺少家谱或活动身份,请返回列表重新选择。",
},
);
onLoad((query) => {
genealogyId.value = String(query.genealogyId || "");
ceremonyId.value = String(query.ceremonyId || "");
if (query.state === "loading") return;
const access = getGenealogyFixtureAccess(genealogyId.value);
if (!["owner", "member"].includes(access.accessRole) || !ceremonyId.value) {
ceremonyState.value = "expired";
return;
}
memberOptions.value = listTreeMemberPresentationFixtures(genealogyId.value);
ceremonyDetail.value = findCeremonyFixture(
genealogyId.value,
ceremonyId.value,
);
if (!ceremonyDetail.value) {
ceremonyState.value = "expired";
return;
}
ceremonyState.value = query.state === "error" ? "error" : "ready";
});
const editCeremony = () =>
ceremonyState.value === "ready" && ceremonyDetail.value
? openPage(
"R07",
{
genealogyId: genealogyId.value,
mode: "edit",
ceremonyId: ceremonyId.value,
},
"R06",
)
: Promise.resolve(false);
const restoreCeremony = () => {
ceremonyDetail.value = findCeremonyFixture(
genealogyId.value,
ceremonyId.value,
);
ceremonyState.value = ceremonyDetail.value ? "ready" : "expired";
};
const requestBack = () => goBack();
const returnToCeremonies = () =>
genealogyId.value
? returnTo("R05", { genealogyId: genealogyId.value })
: goBack();
</script>
<style scoped lang="scss">
@use "../../styles/adaptive-frame-profiles.scss" as adaptive;
.ritual-detail-page {
display: flex;
min-height: 100vh;
flex-direction: column;
background: $paper;
}
.page-header,
.page-loading,
.page-content {
z-index: 1;
}
.page-loading {
min-height: calc(100vh - 100rpx);
}
.page-content {
display: flex;
flex-direction: column;
gap: 16rpx;
padding: 18rpx 24rpx 72rpx;
}
.detail-card,
.participant-card,
.state-card {
box-sizing: border-box;
padding: 42rpx 46rpx;
@include adaptive.adaptive-records-content;
}
.detail-card > text {
display: block;
}
.detail-card > text:first-child {
color: $brand-red;
font-size: 21rpx;
}
.detail-card > text:nth-child(2) {
margin-top: 8rpx;
color: $ink;
font-size: 36rpx;
font-weight: 700;
}
.detail-card > text:nth-child(3) {
margin-top: 10rpx;
color: $ink-muted;
font-size: 23rpx;
}
.detail-card > text:last-child {
margin-top: 20rpx;
color: $ink;
font-size: 24rpx;
line-height: 1.7;
}
.participant-card > view {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
gap: 8rpx 18rpx;
min-height: 52rpx;
align-items: center;
color: $ink;
font-size: 23rpx;
}
.participant-card > view:first-child {
color: $brand-red;
font-weight: 700;
}
.participant-card > view + view {
margin-top: 9rpx;
padding-top: 9rpx;
border-top: 1px solid rgba(136, 84, 42, 0.18);
}
.state-card {
min-height: 340rpx;
padding-top: 78rpx;
text-align: center;
}
.state-card > text {
display: block;
}
.state-card > text:first-child {
color: $ink;
font-size: 35rpx;
font-weight: 700;
}
.state-card > text:nth-child(2) {
margin-top: 18rpx;
color: $ink-muted;
font-size: 24rpx;
line-height: 1.65;
}
.state-card .app-button {
margin-top: 28rpx;
}
</style>