完成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
+67 -43
View File
@@ -4,6 +4,7 @@
class="people-page"
:class="{
'people-state--ready': peopleState === 'ready',
'people-state--loading': peopleState === 'loading',
'people-state--empty': peopleState === 'empty',
'people-state--error': peopleState === 'error',
}"
@@ -12,7 +13,12 @@
<view class="people-page__header"><PageHeader title="人物录" /></view>
<view class="people-content">
<template v-if="peopleState === 'ready'">
<AppLoading
v-if="peopleState === 'loading'"
text="正在读取人物录"
description="请稍候,正在读取当前家谱的人物资料。"
/>
<template v-else-if="peopleState === 'ready'">
<view class="people-search">
<input
v-model="keywordInput"
@@ -30,9 +36,9 @@
>
</view>
<view v-if="filteredPeople.length" class="people-list">
<view v-if="people.length" class="people-list">
<view
v-for="person in filteredPeople"
v-for="person in people"
:key="person.id"
class="person-card"
@click="openPerson(person)"
@@ -46,10 +52,12 @@
</view>
</view>
<AppButton
v-if="hasMore"
class="people-primary-action"
type="secondary"
block
label="填写人物预览"
@click="createPersonPreview"
:label="loadingMore ? '正在加载…' : '加载更多人物'"
@click="loadMore"
/>
</view>
@@ -85,9 +93,10 @@
}}</text>
</view>
<AppButton
v-if="peopleState !== 'empty'"
:type="peopleState === 'empty' ? 'primary' : 'secondary'"
block
:label="peopleState === 'error' ? '重新查看' : peopleState === 'invalid' ? '返回上一页' : '填写人物预览'"
:label="peopleState === 'error' ? '重新查看' : '返回上一页'"
@click="handleStateAction"
/>
</view>
@@ -96,15 +105,13 @@
</template>
<script setup>
import { onLoad } from "@dcloudio/uni-app";
import { onLoad, onUnload } from "@dcloudio/uni-app";
import { computed, ref } from "vue";
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 {
getGenealogyFixtureAccess,
listTreeMemberPresentationFixtures,
} from "@/data/mock.js";
import { appApi, createRequestController, isRequestCancelled } from "@/utils/api.js";
import { goBack, openPage } from "@/utils/navigation.js";
const genealogyId = ref("");
@@ -112,17 +119,13 @@ const people = ref([]);
const peopleState = ref("ready");
const keywordInput = ref("");
const keyword = ref("");
const hasValidContext = computed(() => peopleState.value !== "invalid");
const filteredPeople = computed(() => {
const value = keyword.value.trim().toLowerCase();
if (!value) return people.value;
return people.value.filter((person) =>
`${person.name} ${person.relation} ${person.branch || ""} ${person.generationName || ""}${person.generation}${person.generation}`
.toLowerCase()
.includes(value),
);
});
const total = ref(0);
const pageNum = ref(1);
const loadingMore = ref(false);
const peopleRequestController = createRequestController();
let loadSequence = 0;
const hasValidContext = computed(() => Boolean(genealogyId.value));
const hasMore = computed(() => people.value.length < total.value);
const applySearch = () => {
if (keyword.value) {
@@ -130,14 +133,42 @@ const applySearch = () => {
return;
}
keyword.value = keywordInput.value.trim();
pageNum.value = 1;
void loadPeople();
};
const clearSearch = () => {
keywordInput.value = "";
keyword.value = "";
pageNum.value = 1;
void loadPeople();
};
const restoreList = () => {
people.value = listTreeMemberPresentationFixtures(genealogyId.value);
peopleState.value = people.value.length ? "ready" : "empty";
const loadPeople = async ({ append = false } = {}) => {
if (!hasValidContext.value) return;
const activeLoad = ++loadSequence;
if (append) loadingMore.value = true;
else peopleState.value = "loading";
try {
const result = await appApi.getPersonPage(
genealogyId.value,
{ pageNum: pageNum.value, pageSize: 10, keyword: keyword.value },
{ requestController: peopleRequestController },
);
if (activeLoad !== loadSequence) return;
people.value = append ? [...people.value, ...result.rows] : result.rows;
total.value = result.total;
peopleState.value = people.value.length ? "ready" : "empty";
} catch (error) {
if (activeLoad !== loadSequence || isRequestCancelled(error)) return;
if (!append) people.value = [];
peopleState.value = "error";
} finally {
if (activeLoad === loadSequence) loadingMore.value = false;
}
};
const loadMore = () => {
if (loadingMore.value || !hasMore.value) return;
pageNum.value += 1;
void loadPeople({ append: true });
};
const openPerson = (person) =>
hasValidContext.value
@@ -151,34 +182,27 @@ const openPerson = (person) =>
"R01",
)
: Promise.resolve(false);
const createPersonPreview = () =>
hasValidContext.value
? openPage(
"R02",
{ genealogyId: genealogyId.value, mode: "create" },
"R01",
)
: Promise.resolve(false);
const handleStateAction = () => {
if (peopleState.value === "invalid") return goBack();
if (peopleState.value === "error") return restoreList();
return createPersonPreview();
if (peopleState.value === "error") {
pageNum.value = 1;
return loadPeople();
}
return goBack();
};
onLoad((query) => {
genealogyId.value = String(query.genealogyId || "");
const access = getGenealogyFixtureAccess(genealogyId.value);
if (!["owner", "member"].includes(access.accessRole)) {
if (!hasValidContext.value || query.state === "error") {
people.value = [];
peopleState.value = "invalid";
return;
}
people.value = listTreeMemberPresentationFixtures(genealogyId.value);
peopleState.value = ["empty", "error"].includes(query.state)
? query.state
: people.value.length
? "ready"
: "empty";
void loadPeople();
});
onUnload(() => {
loadSequence += 1;
peopleRequestController.abort();
});
</script>