完成40%
This commit is contained in:
@@ -16,8 +16,8 @@
|
||||
|
||||
<view v-if="treeState !== 'loading'" class="tree-toolbar">
|
||||
<view class="tree-toolbar__title">
|
||||
<text>汤氏家谱</text>
|
||||
<text>主支 · 第 12—14 世</text>
|
||||
<text>世系成员</text>
|
||||
<text>{{ generationRangeLabel }}</text>
|
||||
</view>
|
||||
<view class="tree-toolbar__actions">
|
||||
<text
|
||||
@@ -177,12 +177,16 @@
|
||||
|
||||
<script setup>
|
||||
import { computed, ref } from "vue";
|
||||
import { onLoad, onUnload } from "@dcloudio/uni-app";
|
||||
import { onLoad, onShow, 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 { getGenealogyFixtureAccess, listTreeMemberFixtures } from "@/data/mock.js";
|
||||
import {
|
||||
appApi,
|
||||
createRequestController,
|
||||
isRequestCancelled,
|
||||
} from "@/utils/api.js";
|
||||
import { genealogyContext } from "@/utils/genealogy-context.js";
|
||||
import { openPage } from "@/utils/navigation.js";
|
||||
|
||||
@@ -195,15 +199,14 @@ const centeredTreeScrollLeft = ref(90);
|
||||
const treeHasDrifted = ref(false);
|
||||
let ignoreTreeScroll = false;
|
||||
let recenterTimer = null;
|
||||
const treeRequestController = createRequestController();
|
||||
let treeLoadGeneration = 0;
|
||||
let pageActive = true;
|
||||
let skipNextShowRefresh = true;
|
||||
const GRID_UNIT = 5;
|
||||
const NODE_HALF_HEIGHT = 47;
|
||||
const MEMBER_GAP = 250;
|
||||
const GENERATION_GAP = 220;
|
||||
const generationMeta = {
|
||||
12: { label: "第十二世", summary: "始祖" },
|
||||
13: { label: "第十三世", summary: "两房" },
|
||||
14: { label: "第十四世", summary: "三支" },
|
||||
};
|
||||
const members = ref([]);
|
||||
|
||||
const snapToGrid = (value) => Math.ceil(value / GRID_UNIT) * GRID_UNIT;
|
||||
@@ -218,8 +221,8 @@ const layoutMembers = computed(() => {
|
||||
.filter((member) => Number(member.generation) === generation)
|
||||
.sort(
|
||||
(left, right) =>
|
||||
Number(left.parentId || 0) - Number(right.parentId || 0) ||
|
||||
Number(left.id) - Number(right.id),
|
||||
String(left.parentId || "").localeCompare(String(right.parentId || "")) ||
|
||||
String(left.id).localeCompare(String(right.id)),
|
||||
),
|
||||
]),
|
||||
);
|
||||
@@ -275,12 +278,19 @@ const generationRows = computed(() => {
|
||||
const y = Math.min(...group.map((member) => member.y));
|
||||
return {
|
||||
generation,
|
||||
label: generationMeta[generation]?.label || `第 ${generation} 世`,
|
||||
summary: generationMeta[generation]?.summary || `${group.length} 位成员`,
|
||||
label: `第 ${generation} 世`,
|
||||
summary: `${group.length} 位成员`,
|
||||
y,
|
||||
};
|
||||
});
|
||||
});
|
||||
const generationRangeLabel = computed(() => {
|
||||
const rows = generationRows.value;
|
||||
if (!rows.length) return "世系关系";
|
||||
const first = rows[0].generation;
|
||||
const last = rows[rows.length - 1].generation;
|
||||
return first === last ? `第 ${first} 世` : `第 ${first}—${last} 世`;
|
||||
});
|
||||
const generationBandStyle = (row) => ({
|
||||
gridRow: `${Math.max(1, Math.round((row.y - 88) / GRID_UNIT) + 1)} / span 12`,
|
||||
});
|
||||
@@ -351,7 +361,9 @@ const stateCopy = computed(
|
||||
})[treeState.value] || {},
|
||||
);
|
||||
|
||||
onLoad((query) => {
|
||||
const loadTree = async (query = {}) => {
|
||||
const generation = ++treeLoadGeneration;
|
||||
treeRequestController.abort();
|
||||
if (genealogyContext.isCurrentGenealogyInvalidated()) {
|
||||
genealogyId.value = "";
|
||||
members.value = [];
|
||||
@@ -366,15 +378,6 @@ onLoad((query) => {
|
||||
treeState.value = "empty";
|
||||
return;
|
||||
}
|
||||
const access = getGenealogyFixtureAccess(genealogyId.value);
|
||||
if (!["owner", "member"].includes(access.accessRole)) {
|
||||
genealogyContext.invalidateCurrentGenealogyId();
|
||||
genealogyId.value = "";
|
||||
members.value = [];
|
||||
treeState.value = "error";
|
||||
return;
|
||||
}
|
||||
members.value = listTreeMemberFixtures(genealogyId.value);
|
||||
if (
|
||||
query.state === "loading" ||
|
||||
["landscape", "empty", "error"].includes(query.state)
|
||||
@@ -382,15 +385,45 @@ onLoad((query) => {
|
||||
treeState.value = query.state;
|
||||
return;
|
||||
}
|
||||
genealogyContext.setCurrentGenealogyId(genealogyId.value);
|
||||
selected.value =
|
||||
layoutMembers.value.find(
|
||||
(item) => String(item.id) === String(query.selectedId),
|
||||
) || layoutMembers.value[0];
|
||||
treeState.value = members.value.length ? "tree" : "empty";
|
||||
try {
|
||||
const result = await appApi.getTree(genealogyId.value, {
|
||||
requestController: treeRequestController,
|
||||
});
|
||||
if (!pageActive || generation !== treeLoadGeneration) return;
|
||||
members.value = result;
|
||||
genealogyContext.setCurrentGenealogyId(genealogyId.value);
|
||||
selected.value =
|
||||
layoutMembers.value.find(
|
||||
(item) => String(item.id) === String(query.selectedId),
|
||||
) || layoutMembers.value[0] || null;
|
||||
treeState.value = members.value.length ? "tree" : "empty";
|
||||
} catch (error) {
|
||||
if (
|
||||
!pageActive ||
|
||||
generation !== treeLoadGeneration ||
|
||||
isRequestCancelled(error)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
members.value = [];
|
||||
selected.value = null;
|
||||
treeState.value = "error";
|
||||
}
|
||||
};
|
||||
|
||||
onLoad(loadTree);
|
||||
onShow(() => {
|
||||
if (skipNextShowRefresh) {
|
||||
skipNextShowRefresh = false;
|
||||
return;
|
||||
}
|
||||
if (genealogyId.value) loadTree({ genealogyId: genealogyId.value });
|
||||
});
|
||||
|
||||
onUnload(() => {
|
||||
pageActive = false;
|
||||
treeLoadGeneration += 1;
|
||||
treeRequestController.abort();
|
||||
if (recenterTimer) clearTimeout(recenterTimer);
|
||||
});
|
||||
|
||||
@@ -443,6 +476,9 @@ const handleStateAction = () => {
|
||||
"T01",
|
||||
);
|
||||
}
|
||||
if (treeState.value === "error") {
|
||||
return loadTree({ genealogyId: genealogyId.value });
|
||||
}
|
||||
selected.value = layoutMembers.value[0];
|
||||
treeState.value = "tree";
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user