66 lines
4.6 KiB
Vue
66 lines
4.6 KiB
Vue
<!-- 页面编号: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="toDirectory">查找</text><text @click="toRelationship">编辑</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="toAddRelative">添加亲属</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 toDirectory = () => uni.navigateTo({ url: `/pages/tree/t07-member-directory?genealogyId=${genealogyId.value}` })
|
||
const toRelationship = () => uni.navigateTo({ url: `/pages/tree/t06-edit-relationship?genealogyId=${genealogyId.value}` })
|
||
const toAddRelative = () => uni.navigateTo({ url: `/pages/tree/t04-add-relative?genealogyId=${genealogyId.value}&personId=${selected.value.id}` })
|
||
</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>
|