完成全项目响应式审核与换机交接

This commit is contained in:
2026-07-22 07:41:27 +08:00
parent a127280ce6
commit eced3d1e6e
77 changed files with 2052 additions and 378 deletions
+69 -9
View File
@@ -20,6 +20,15 @@
<text>主支 · 1214 </text>
</view>
<view class="tree-toolbar__actions">
<text
v-if="treeState === 'tree' && treeHasDrifted && selected"
class="tree-recenter"
role="button"
aria-label="回到当前成员"
hover-class="tree-action--pressed"
@click="recenterSelectedMember"
>回到当前</text
>
<text @click="treeState = 'landscape'">阅读提示</text>
<text @click="toRelationship">关系维护</text>
</view>
@@ -51,18 +60,23 @@
</view>
</view>
<view v-if="treeState === 'tree'" class="lineage-pan-cue">
<text>同代分支可左右查看</text>
</view>
<scroll-view
class="tree-scroll"
:class="{ 'tree-scroll--lineage': treeState === 'tree' }"
scroll-x
:scroll-left="initialScrollLeft"
:scroll-left="treeState === 'tree' ? treeScrollLeft : 0"
:show-scrollbar="false"
:style="treeScrollStyle"
@scroll="handleTreeScroll"
>
<view
class="tree-canvas"
:class="{ 'tree-canvas--state': treeState !== 'tree' }"
:style="treeMetricsStyle"
:style="treeState === 'tree' ? treeMetricsStyle : undefined"
>
<AppLoading
v-if="treeState === 'loading'"
@@ -71,10 +85,6 @@
/>
<template v-else-if="treeState === 'tree'">
<view class="lineage-pan-cue">
<text>同代分支可左右查看</text>
</view>
<view
v-for="connector in lineageConnectors"
:key="connector.id"
@@ -85,6 +95,7 @@
<view
v-for="member in layoutMembers"
:key="member.id"
:id="`tree-member-${member.id}`"
class="member-node"
:class="{ 'member-node--selected': selected?.id === member.id }"
:style="nodeGridStyle(member)"
@@ -166,7 +177,7 @@
<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";
@@ -176,7 +187,12 @@ import { genealogyContext } from "@/utils/genealogy-context.js";
const genealogyId = ref("");
const treeState = ref("loading");
const selected = ref(null);
const initialScrollLeft = ref(90);
const treeScrollLeft = ref(90);
const currentTreeScrollLeft = ref(90);
const centeredTreeScrollLeft = ref(90);
const treeHasDrifted = ref(false);
let ignoreTreeScroll = false;
let recenterTimer = null;
const GRID_UNIT = 5;
const NODE_HALF_HEIGHT = 47;
const MEMBER_GAP = 250;
@@ -409,6 +425,46 @@ onLoad((query) => {
treeState.value = "tree";
});
onUnload(() => {
if (recenterTimer) clearTimeout(recenterTimer);
});
const handleTreeScroll = (event) => {
if (ignoreTreeScroll || treeState.value !== "tree") return;
const scrollLeft = Number(event?.detail?.scrollLeft || 0);
currentTreeScrollLeft.value = scrollLeft;
treeHasDrifted.value = Math.abs(scrollLeft - centeredTreeScrollLeft.value) > 80;
};
const recenterSelectedMember = async () => {
if (!selected.value) return;
ignoreTreeScroll = true;
const [scrollRect, nodeRect] = await new Promise((resolve) => {
const query = uni.createSelectorQuery();
query.select(".tree-scroll").boundingClientRect();
query
.select(`#tree-member-${selected.value.id}`)
.boundingClientRect();
query.exec(resolve);
});
if (scrollRect && nodeRect) {
const centeredScrollLeft = Math.max(
0,
currentTreeScrollLeft.value +
nodeRect.left + nodeRect.width / 2 - (scrollRect.left + scrollRect.width / 2),
);
treeScrollLeft.value = centeredScrollLeft;
currentTreeScrollLeft.value = centeredScrollLeft;
centeredTreeScrollLeft.value = centeredScrollLeft;
}
treeHasDrifted.value = false;
if (recenterTimer) clearTimeout(recenterTimer);
recenterTimer = setTimeout(() => {
ignoreTreeScroll = false;
recenterTimer = null;
}, 320);
};
const nodeGridStyle = (member) => ({
gridColumn: `${member.x / 5 + 1}`,
gridRow: `${member.y / 5 + 1}`,
@@ -484,6 +540,9 @@ const toAddRelative = () =>
min-height: 0;
overflow-y: auto;
}
.tree-action--pressed {
opacity: 0.72;
}
.tree-stage--lineage {
display: grid;
grid-template-columns: 190rpx minmax(0, 1fr);
@@ -503,6 +562,7 @@ const toAddRelative = () =>
border-right: 1rpx solid rgba(143, 108, 63, 0.2);
}
.tree-scroll--lineage {
grid-area: 1 / 2;
min-width: 0;
}
.tree-canvas {
@@ -514,7 +574,7 @@ const toAddRelative = () =>
width: calc(100vw - 32rpx);
}
.lineage-pan-cue {
grid-area: 1 / 1 / -1 / -1;
grid-area: 1 / 2;
align-self: start;
justify-self: end;
z-index: 3;