feat: migrate app routes and business modules
This commit is contained in:
@@ -0,0 +1,346 @@
|
||||
<template>
|
||||
<view
|
||||
class="person-detail-page"
|
||||
:class="`person-detail-state--${personState}`"
|
||||
>
|
||||
<ModulePageBackground module="records" />
|
||||
<view class="person-detail-header">
|
||||
<PageHeader title="人物详情" custom-back @back="requestBack" />
|
||||
</view>
|
||||
|
||||
<view v-if="personState === 'loading'" class="person-detail-loading">
|
||||
<AppLoading
|
||||
text="正在读取人物档案"
|
||||
description="请稍候,正在整理人物资料。"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<view v-else class="person-detail-content">
|
||||
<template v-if="personState === 'detail'">
|
||||
<view class="person-identity-card">
|
||||
<view class="person-identity-card__copy">
|
||||
<text class="person-identity-card__name">{{
|
||||
person.name || "待填写姓名"
|
||||
}}</text>
|
||||
<text class="person-identity-card__meta"
|
||||
>{{ person.relation || "人物预览" }} · 第
|
||||
{{ person.generation || "—" }} 世</text
|
||||
>
|
||||
<text class="person-identity-card__hint">人物录档案</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<template v-if="personState === 'detail'">
|
||||
<view
|
||||
v-for="item in detailSections"
|
||||
:key="item.title"
|
||||
class="person-archive-card"
|
||||
>
|
||||
<view
|
||||
><text>{{ item.title }}</text
|
||||
><text>{{ item.copy || "未填写" }}</text></view
|
||||
>
|
||||
</view>
|
||||
<view class="person-related-actions">
|
||||
<AppButton
|
||||
type="secondary"
|
||||
block
|
||||
label="成长日志"
|
||||
@click="toGrowthJournal"
|
||||
/>
|
||||
<AppButton
|
||||
type="secondary"
|
||||
block
|
||||
label="人生大事"
|
||||
@click="toLifeEvents"
|
||||
/>
|
||||
</view>
|
||||
<view class="person-edit-action" @click="toMemberProfile"
|
||||
><AppButton block label="查看成员档案"
|
||||
/></view>
|
||||
</template>
|
||||
|
||||
<view v-else class="person-state-card">
|
||||
<view>
|
||||
<text>{{
|
||||
personState === "expired" ? "人物档案已失效" : "人物档案暂不可用"
|
||||
}}</text>
|
||||
<text>{{
|
||||
personState === "expired"
|
||||
? "这份人物资料不存在或不属于当前家谱。"
|
||||
: "请返回人物录重新选择,页面不会回退到其他人物。"
|
||||
}}</text>
|
||||
</view>
|
||||
<view class="person-state-action"
|
||||
><AppButton
|
||||
type="secondary"
|
||||
block
|
||||
label="返回人物录"
|
||||
@click="returnToPeople"
|
||||
/></view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, reactive, ref } from "vue";
|
||||
import { onBackPress, onLoad, onUnload } 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 {
|
||||
createRequestController,
|
||||
isRequestCancelled
|
||||
} from "@/services/api/request-controller.js";
|
||||
import { lineageApi } from "@/services/api/lineage-service.js";
|
||||
import {
|
||||
goBack,
|
||||
handleBackPress,
|
||||
openPage,
|
||||
returnTo,
|
||||
} from "@/utils/navigation/gateway.js";
|
||||
|
||||
const genealogyId = ref("");
|
||||
const personId = ref("");
|
||||
const personState = ref("loading");
|
||||
const personDetailRequestController = createRequestController();
|
||||
let loadSequence = 0;
|
||||
const person = reactive({
|
||||
id: "",
|
||||
name: "",
|
||||
relation: "",
|
||||
generationName: "",
|
||||
generation: "",
|
||||
aliasName: "",
|
||||
sex: "",
|
||||
sexLabel: "",
|
||||
personStatus: "",
|
||||
personStatusLabel: "",
|
||||
birthDate: "",
|
||||
birthLunar: "",
|
||||
birthLunarLabel: "",
|
||||
birthplace: "",
|
||||
deathDate: "",
|
||||
deathLunar: "",
|
||||
deathLunarLabel: "",
|
||||
deathPlace: "",
|
||||
burialPlace: "",
|
||||
spouseNames: "",
|
||||
biography: "",
|
||||
remark: "",
|
||||
});
|
||||
const detailSections = computed(() => [
|
||||
{ title: "别名", copy: person.aliasName },
|
||||
{ title: "字辈", copy: person.generationName },
|
||||
{ title: "性别", copy: person.sexLabel },
|
||||
{ title: "人物状态", copy: person.personStatusLabel },
|
||||
{ title: "出生日期", copy: person.birthDate },
|
||||
{ title: "出生农历", copy: person.birthLunarLabel },
|
||||
{ title: "出生地", copy: person.birthplace },
|
||||
{ title: "逝世日期", copy: person.deathDate },
|
||||
{ title: "逝世农历", copy: person.deathLunarLabel },
|
||||
{ title: "逝世地", copy: person.deathPlace },
|
||||
{ title: "安葬地", copy: person.burialPlace },
|
||||
{ title: "配偶", copy: person.spouseNames },
|
||||
{ title: "人物小传", copy: person.biography },
|
||||
{ title: "档案备注", copy: person.remark },
|
||||
]);
|
||||
const requestBack = () => goBack();
|
||||
|
||||
const returnToPeople = () =>
|
||||
genealogyId.value
|
||||
? returnTo("R01", { genealogyId: genealogyId.value })
|
||||
: goBack();
|
||||
const toGrowthJournal = () =>
|
||||
person.id
|
||||
? openPage(
|
||||
"R08",
|
||||
{ genealogyId: genealogyId.value, personId: personId.value },
|
||||
"R02",
|
||||
)
|
||||
: Promise.resolve(false);
|
||||
const toLifeEvents = () =>
|
||||
person.id
|
||||
? openPage(
|
||||
"R09",
|
||||
{ genealogyId: genealogyId.value, personId: personId.value },
|
||||
"R02",
|
||||
)
|
||||
: Promise.resolve(false);
|
||||
const toMemberProfile = () =>
|
||||
person.id
|
||||
? openPage(
|
||||
"T03",
|
||||
{ genealogyId: genealogyId.value, personId: person.id },
|
||||
"R02",
|
||||
)
|
||||
: Promise.resolve(false);
|
||||
|
||||
const loadPerson = async () => {
|
||||
const activeLoad = ++loadSequence;
|
||||
personState.value = "loading";
|
||||
try {
|
||||
const personDetail = await lineageApi.getPerson(genealogyId.value, personId.value, {
|
||||
requestController: personDetailRequestController,
|
||||
});
|
||||
if (activeLoad !== loadSequence) return;
|
||||
Object.assign(person, personDetail);
|
||||
personState.value = "detail";
|
||||
} catch (error) {
|
||||
if (activeLoad !== loadSequence || isRequestCancelled(error)) return;
|
||||
personState.value = "expired";
|
||||
}
|
||||
};
|
||||
|
||||
onLoad((query) => {
|
||||
genealogyId.value = String(query.genealogyId || "");
|
||||
personId.value = String(query.personId || "");
|
||||
if (
|
||||
query.mode !== "view" ||
|
||||
!genealogyId.value ||
|
||||
!personId.value
|
||||
) {
|
||||
personState.value = "error";
|
||||
return;
|
||||
}
|
||||
void loadPerson();
|
||||
});
|
||||
|
||||
onBackPress((event) => handleBackPress(event, requestBack));
|
||||
onUnload(() => {
|
||||
loadSequence += 1;
|
||||
personDetailRequestController.abort();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "../../styles/adaptive-frame-profiles.scss";
|
||||
|
||||
.person-detail-page {
|
||||
display: flex;
|
||||
min-height: 100vh;
|
||||
flex-direction: column;
|
||||
background: $paper;
|
||||
}
|
||||
.person-detail-header,
|
||||
.person-detail-loading,
|
||||
.person-detail-content {
|
||||
z-index: 1;
|
||||
}
|
||||
.person-detail-loading {
|
||||
min-height: calc(100vh - 100rpx);
|
||||
}
|
||||
.person-detail-content {
|
||||
padding: 18rpx 24rpx 72rpx;
|
||||
}
|
||||
.person-identity-card {
|
||||
@include adaptive-records-person;
|
||||
display: flex;
|
||||
min-height: 190rpx;
|
||||
padding: 30rpx 10%;
|
||||
}
|
||||
.person-identity-card__copy {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
.person-identity-card__copy text {
|
||||
display: block;
|
||||
}
|
||||
.person-identity-card__name {
|
||||
color: $ink;
|
||||
font-family: STKaiti, KaiTi, serif;
|
||||
font-size: clamp(20px, 38rpx, 26px);
|
||||
font-weight: 700;
|
||||
}
|
||||
.person-identity-card__meta {
|
||||
margin-top: 8rpx;
|
||||
color: $ink-muted;
|
||||
font-size: clamp(15px, 25rpx, 18px);
|
||||
font-weight: 600;
|
||||
}
|
||||
.person-identity-card__hint {
|
||||
margin-top: 8rpx;
|
||||
color: #806a51;
|
||||
font-size: clamp(13px, 21rpx, 16px);
|
||||
}
|
||||
.person-archive-card {
|
||||
min-height: 154rpx;
|
||||
margin-top: 14rpx;
|
||||
padding: 32rpx 42rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.person-archive-card,
|
||||
.person-state-card {
|
||||
@include adaptive-records-content;
|
||||
}
|
||||
.person-archive-card text {
|
||||
display: block;
|
||||
}
|
||||
.person-archive-card text:first-child {
|
||||
color: $brand-red;
|
||||
font-size: clamp(15px, 24rpx, 18px);
|
||||
font-weight: 700;
|
||||
}
|
||||
.person-archive-card text:last-child {
|
||||
margin-top: 11rpx;
|
||||
color: $ink;
|
||||
font-size: clamp(15px, 24rpx, 18px);
|
||||
line-height: 1.55;
|
||||
}
|
||||
.person-edit-action {
|
||||
margin-top: 20rpx;
|
||||
}
|
||||
.person-related-actions {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 14rpx;
|
||||
margin-top: 18rpx;
|
||||
}
|
||||
.person-state-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 300rpx;
|
||||
margin-top: 26rpx;
|
||||
padding: 72rpx 54rpx 42rpx;
|
||||
box-sizing: border-box;
|
||||
text-align: center;
|
||||
}
|
||||
.person-state-card text {
|
||||
display: block;
|
||||
}
|
||||
.person-state-card text:first-child {
|
||||
color: $ink;
|
||||
font-family: STKaiti, KaiTi, serif;
|
||||
font-size: clamp(19px, 34rpx, 24px);
|
||||
font-weight: 700;
|
||||
}
|
||||
.person-state-card text:last-child {
|
||||
margin-top: 16rpx;
|
||||
color: $ink-muted;
|
||||
font-size: clamp(15px, 24rpx, 18px);
|
||||
line-height: 1.6;
|
||||
}
|
||||
.person-state-action {
|
||||
margin: 24rpx 48rpx 0;
|
||||
}
|
||||
@media (min-width: 400px) {
|
||||
.person-detail-content {
|
||||
padding-right: 32rpx;
|
||||
padding-left: 32rpx;
|
||||
}
|
||||
}
|
||||
@media (max-width: 340px) {
|
||||
.person-detail-content {
|
||||
padding-right: 18rpx;
|
||||
padding-left: 18rpx;
|
||||
}
|
||||
.person-identity-card__name {
|
||||
font-size: clamp(19px, 35rpx, 24px);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user