完成70%

This commit is contained in:
2026-07-24 07:56:22 +08:00
parent bb6431b319
commit c7f278fe79
92 changed files with 4741 additions and 14440 deletions
+63 -35
View File
@@ -14,7 +14,7 @@
<view v-if="hasValidContext" class="directory-context">
<text class="directory-context__name">汤氏家谱</text>
<text class="directory-context__meta"
>主支 · {{ members.length }} 位成员</text
>已加载 {{ members.length }} / {{ total }} 位成员</text
>
</view>
<view
@@ -46,10 +46,10 @@
<template v-else-if="directoryState === 'list'">
<view class="directory-summary"
><text>家谱成员</text
><text>{{ filteredMembers.length }} · 按世代排列</text></view
><text>{{ members.length }} / {{ total }} · 按世代排列</text></view
>
<view
v-for="item in filteredMembers"
v-for="item in members"
:key="item.id"
class="directory-card"
@click="openMember(item)"
@@ -60,6 +60,13 @@
<text class="directory-card__status">{{ memberStatus(item) }}</text>
</view>
</view>
<AppButton
v-if="hasMore"
block
type="secondary"
:label="loadingMore ? '正在加载…' : '加载更多成员'"
@click="loadMore"
/>
</template>
<view v-else class="directory-state-card">
<view
@@ -85,61 +92,82 @@
</template>
<script setup>
import { computed, ref } from "vue";
import { onLoad } from "@dcloudio/uni-app";
import { 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 { listTreeMemberPresentationFixtures } from "@/data/mock.js";
import { appApi, createRequestController, isRequestCancelled } from "@/utils/api.js";
import { goBack, openPage } from "@/utils/navigation.js";
const genealogyId = ref("");
const keyword = ref("");
const directoryState = ref("loading");
const members = ref([]);
const total = ref(0);
const pageNum = ref(1);
const loadingMore = ref(false);
const directoryRequestController = createRequestController();
let loadSequence = 0;
const hasValidContext = computed(() => Boolean(genealogyId.value));
const members = computed(() => listTreeMemberPresentationFixtures(genealogyId.value));
const isRestrictedMember = (member) =>
["privacy", "forbidden"].includes(member.status);
const memberMeta = (member) =>
isRestrictedMember(member)
? `${member.generation} 世 · ${member.relation}`
: `${member.generation} 世 · ${member.generationName} · ${member.branch}`;
`${member.generation} 世 · ${member.generationName || "字辈待补"} · ${member.branch}`;
const memberStatus = (member) =>
isRestrictedMember(member)
? member.status === "forbidden"
? "访问受限"
: "隐私资料"
: member.note;
const filteredMembers = computed(() => {
const value = keyword.value.trim();
if (!value) return members.value;
return members.value.filter((item) =>
`${item.name}${item.relation}${item.generation}${item.generationName || ""}${item.branch || ""}`.includes(value),
);
});
member.personStatus ? `人物状态:${member.personStatus}` : "人物状态待补";
const hasMore = computed(() => members.value.length < total.value);
const loadMembers = async ({ append = false } = {}) => {
if (!hasValidContext.value) return;
const activeLoad = ++loadSequence;
if (append) loadingMore.value = true;
else directoryState.value = "loading";
try {
const result = await appApi.getPersonPage(
genealogyId.value,
{ pageNum: pageNum.value, pageSize: 10, keyword: keyword.value },
{ requestController: directoryRequestController },
);
if (activeLoad !== loadSequence) return;
members.value = append ? [...members.value, ...result.rows] : result.rows;
total.value = result.total;
directoryState.value = members.value.length ? "list" : "empty";
} catch (error) {
if (activeLoad !== loadSequence || isRequestCancelled(error)) return;
if (!append) members.value = [];
directoryState.value = "error";
} finally {
if (activeLoad === loadSequence) loadingMore.value = false;
}
};
onLoad((query) => {
genealogyId.value = String(query.genealogyId || "");
directoryState.value =
!hasValidContext.value ? "error" : query.state === "loading"
? "loading"
: query.state === "empty"
? "empty"
: query.state === "error"
? "error"
: members.value.length
? "list"
: "empty";
if (!hasValidContext.value || query.state === "error") {
directoryState.value = "error";
return;
}
void loadMembers();
});
const searchMembers = () => {
directoryState.value = filteredMembers.value.length ? "list" : "empty";
pageNum.value = 1;
void loadMembers();
};
const loadMore = () => {
if (loadingMore.value || !hasMore.value) return;
pageNum.value += 1;
void loadMembers({ append: true });
};
const retryDirectory = () => {
if (!hasValidContext.value) return goBack();
directoryState.value = "list";
pageNum.value = 1;
return loadMembers();
};
const openMember = (item) =>
hasValidContext.value
? openPage("T03", { genealogyId: genealogyId.value, personId: String(item.id) }, "T07")
: Promise.resolve(false);
onUnload(() => {
loadSequence += 1;
directoryRequestController.abort();
});
</script>
<style scoped lang="scss">
@use "../../styles/adaptive-frame-profiles.scss" as adaptive;