Files
jiapuapp/pages/tree/t01-tree-overview.vue
T
2026-07-13 17:31:11 +08:00

64 lines
4.3 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!-- 页面编号T-01用途世系树总览 -->
<template>
<view class="tree-page">
<PageHeader title="世系树" action="树形视图" />
<view class="tree-toolbar"><view class="branch-select">当前家谱世系</view><view class="tree-tools"><text @click="showSoon">查找</text><text @click="showSoon">编辑</text></view></view>
<scroll-view class="tree-scroll" scroll-x scroll-y>
<view class="tree-canvas">
<view v-if="!members.length" class="tree-empty">{{ loadError || '暂未录入族人' }}</view>
<view v-for="member in members" :key="member.id" class="member-node" :class="{ selected: selected && selected.id === member.id }" :style="nodeStyle(member)" @click="selected = member"><text class="node-name">{{ member.name }}</text><text class="node-relation">{{ member.relation }}</text><text class="node-years">{{ member.years }}</text></view>
</view>
</scroll-view>
<view v-if="selected" class="member-sheet"><view><text class="sheet-name">{{ selected.name }}</text><text class="sheet-meta">第 {{ selected.generation }} 世 · {{ selected.relation }} · {{ selected.branch }}</text></view><view class="sheet-actions"><text @click="toMember">查看资料</text><text @click="showSoon">添加亲属</text></view></view>
</view>
</template>
<script setup>
import { ref } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import PageHeader from '@/components/PageHeader.vue'
import { appApi } from '@/utils/api.js'
import { genealogyContext } from '@/utils/genealogy-context.js'
const members = ref([])
const selected = ref(null)
const genealogyId = ref('')
const loadError = ref('')
const loadTree = async (query) => {
genealogyId.value = query.genealogyId || genealogyContext.getCurrentGenealogyId()
if (!genealogyId.value) { loadError.value = '未找到当前家谱。'; return }
genealogyContext.setCurrentGenealogyId(genealogyId.value)
try {
members.value = await appApi.getTree(genealogyId.value)
selected.value = members.value.find((item) => String(item.id) === String(query.selectedId)) || members.value[0] || null
} catch (error) {
loadError.value = error.message || '世系树加载失败。'
}
}
onLoad(loadTree)
const nodeStyle = (member) => ({ left: `${member.x}%`, top: `${member.y}%` })
const toMember = () => uni.navigateTo({ url: `/pages/tree/t03-member-profile?genealogyId=${genealogyId.value}&personId=${selected.value.id}` })
const showSoon = () => uni.showToast({ title: '亲属关系编辑将在下一阶段接入', icon: 'none' })
</script>
<style scoped lang="scss">
.tree-page { height: 100vh; overflow: hidden; background: $paper; }
.tree-toolbar { display: flex; align-items: center; justify-content: space-between; padding: 20rpx 28rpx; border-bottom: 1rpx solid $gold-soft; background: #fffaf0; }
.branch-select { padding: 12rpx 18rpx; border: 1rpx solid $gold; color: $ink; font-size: 25rpx; }
.tree-tools { display: flex; gap: 24rpx; color: $brand-red; font-size: 26rpx; }
.tree-scroll { height: calc(100vh - 382rpx); white-space: nowrap; }
.tree-canvas { position: relative; width: 1180rpx; height: 1120rpx; background: $paper; }
.tree-empty { padding: 240rpx 0; color: $ink-muted; font-size: 28rpx; text-align: center; }
.member-node { position: absolute; width: 150rpx; min-height: 148rpx; padding: 20rpx 12rpx; box-sizing: border-box; border: 2rpx solid $gold-soft; background: #fffaf0; transform: translateX(-50%); white-space: normal; text-align: center; }
.member-node.selected { border-color: $brand-red; box-shadow: 0 0 0 6rpx #f2dfcf; }
.node-name { display: block; color: $ink; font-family: serif; font-size: 32rpx; font-weight: 700; }
.node-relation { display: block; margin-top: 10rpx; color: $brand-red; font-size: 22rpx; }
.node-years { display: block; margin-top: 8rpx; color: $ink-muted; font-size: 20rpx; }
.member-sheet { position: fixed; right: 0; bottom: 0; left: 0; display: flex; align-items: center; justify-content: space-between; padding: 26rpx 28rpx calc(26rpx + env(safe-area-inset-bottom)); border-top: 1rpx solid $gold; background: $navy; color: #fff8ec; }
.sheet-name { display: block; font-family: serif; font-size: 36rpx; font-weight: 700; }
.sheet-meta { display: block; margin-top: 8rpx; color: #dfc590; font-size: 21rpx; }
.sheet-actions { display: flex; flex-direction: column; gap: 12rpx; color: #f3dba7; font-size: 24rpx; text-align: right; }
</style>