This commit is contained in:
freedakgmail
2025-12-22 00:38:20 +08:00
parent 5a604e89f9
commit c2b890994d
9 changed files with 507 additions and 240 deletions
+4 -2
View File
@@ -695,7 +695,8 @@ export function MemberForm({ initialData, existingMembers = [], onSubmit, onCanc
value={formData.birthDate || ""}
isLunar={formData.isLunarDate || false}
onChange={(value) => handleChange("birthDate", value)}
showLunarToggle={false}
onLunarChange={(isLunar) => handleChange("isLunarDate", isLunar)}
showLunarToggle={true}
/>
<DateInputWithLunar
id="deathDate"
@@ -703,7 +704,8 @@ export function MemberForm({ initialData, existingMembers = [], onSubmit, onCanc
value={formData.deathDate || ""}
isLunar={formData.isLunarDate || false}
onChange={(value) => handleChange("deathDate", value)}
showLunarToggle={false}
onLunarChange={(isLunar) => handleChange("isLunarDate", isLunar)}
showLunarToggle={true}
/>
</div>
</ChineseCardContent>
+51 -23
View File
@@ -1,7 +1,7 @@
"use client"
import Link from "next/link"
import { BookOpen, Search, Settings, LogOut, User, ChevronDown, Plus, Trash2, Network, LayoutGrid, Calculator, HelpCircle, Calendar, Menu, X, Home, Users as UsersIcon, Clock, TreePine } from "lucide-react"
import { BookOpen, Search, Settings, LogOut, User, ChevronDown, Plus, Trash2, Network, LayoutGrid, Calculator, HelpCircle, Calendar, Menu, X, Home, Users as UsersIcon, Clock, TreePine, MapPin } from "lucide-react"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
@@ -34,7 +34,7 @@ interface FamilyTree {
}
export function SiteHeader() {
const { searchMembers, searchResults, currentTree: familyCurrentTree } = useFamily()
const { searchMembers, searchResults, currentTree: familyCurrentTree, setHighlightedMemberId } = useFamily()
const { data: session, status } = useSession()
const { showAlert, showConfirm, showPrompt } = useDialog()
const pathname = usePathname()
@@ -241,6 +241,21 @@ export function SiteHeader() {
setShowResults(false)
}
// 在族谱图中定位成员
const handleLocateMember = (memberId: string) => {
setHighlightedMemberId(memberId)
// 如果不在族谱页面,跳转到族谱页面
if (pathname !== '/tree') {
const params = new URLSearchParams()
if (currentTree?.id) {
params.set('treeId', currentTree.id)
}
router.push(`/tree?${params.toString()}`)
}
setSearchQuery("")
setShowResults(false)
}
// 导航菜单项配置
const navItems = [
{ href: "/", label: "总览", icon: Home },
@@ -474,31 +489,44 @@ export function SiteHeader() {
{showResults && searchResults.length > 0 && (
<div className="absolute top-full mt-2 w-full bg-background border border-border rounded-lg shadow-lg max-h-96 overflow-y-auto z-50">
{searchResults.map((member) => (
<button
<div
key={member.id}
onClick={() => handleSelectMember(member.id)}
className="w-full px-4 py-3 text-left hover:bg-muted transition-colors border-b border-border last:border-0"
className="w-full px-4 py-3 hover:bg-muted transition-colors border-b border-border last:border-0 flex items-center gap-2"
>
<div className="flex items-center gap-3">
<div className="flex-1">
<div className="flex items-center gap-2">
<MemberNameWithStatus
name={member.fullName}
isDead={!!member.deathDate}
className="font-medium"
/>
<span className={`text-xs px-1.5 py-0.5 rounded ${member.gender === "MALE" ? "bg-blue-100 text-blue-700" : "bg-pink-100 text-pink-700"}`}>
{member.gender === "MALE" ? "男" : "女"}
</span>
<span className="text-xs text-muted-foreground">{member.generation}</span>
<button
onClick={() => handleSelectMember(member.id)}
className="flex-1 text-left"
>
<div className="flex items-center gap-3">
<div className="flex-1">
<div className="flex items-center gap-2">
<MemberNameWithStatus
name={member.fullName}
isDead={!!member.deathDate}
className="font-medium"
/>
<span className={`text-xs px-1.5 py-0.5 rounded ${member.gender === "MALE" ? "bg-blue-100 text-blue-700" : "bg-pink-100 text-pink-700"}`}>
{member.gender === "MALE" ? "男" : "女"}
</span>
<span className="text-xs text-muted-foreground">{member.generation}</span>
</div>
<p className="text-xs text-muted-foreground mt-1">
{member.birthDate && `生于 ${member.birthDate}`}
{member.birthPlace && ` · ${member.birthPlace}`}
</p>
</div>
<p className="text-xs text-muted-foreground mt-1">
{member.birthDate && `生于 ${member.birthDate}`}
{member.birthPlace && ` · ${member.birthPlace}`}
</p>
</div>
</div>
</button>
</button>
<Button
variant="ghost"
size="icon"
className="h-8 w-8 flex-shrink-0 text-muted-foreground hover:text-primary"
onClick={() => handleLocateMember(member.id)}
title="在族谱图中定位"
>
<MapPin className="h-4 w-4" />
</Button>
</div>
))}
</div>
)}
+12 -5
View File
@@ -26,6 +26,7 @@ interface FamilyNodeProps {
isRoot?: boolean
onSelect?: (member: FamilyMember) => void
isHighlighted?: boolean
highlightedMemberId?: string | null
relationMode?: boolean
isSelected?: boolean
selectedMembers?: string[]
@@ -502,6 +503,7 @@ export function FamilyNode({
isRoot,
onSelect,
isHighlighted,
highlightedMemberId,
relationMode,
isSelected,
selectedMembers = [],
@@ -535,6 +537,11 @@ export function FamilyNode({
// 有配偶时,合并到一个卡片中显示(类似D3布局)
const isMale = member.gender === 'MALE'
const isDead = !!member.deathDate
// 检查是否有任何配偶被高亮,如果是则整个卡片高亮
const isAnySpouseHighlighted = spouseList.some(sp => sp.id === highlightedMemberId)
const isCardHighlighted = isHighlighted || isAnySpouseHighlighted
// 使用 isRoot prop 而不是 isFounder 字段
const isFounder = isRoot === true
const avatarUrl = member.avatarUrl
@@ -552,8 +559,8 @@ export function FamilyNode({
"relative rounded-xl overflow-hidden transition-all duration-300",
"shadow-[0_4px_20px_rgba(0,0,0,0.08)] hover:shadow-[0_12px_40px_rgba(0,0,0,0.15)]",
"hover:scale-[1.02] hover:-translate-y-1",
isHighlighted
? "bg-gradient-to-br from-yellow-50 via-amber-50 to-yellow-100 ring-2 ring-yellow-400"
isCardHighlighted
? "bg-gradient-to-br from-yellow-50 via-amber-50 to-yellow-100 ring-2 ring-yellow-400 shadow-[0_8px_30px_rgba(234,179,8,0.4)]"
: isFounder || isRoot
? "bg-gradient-to-br from-amber-50 via-orange-50 to-yellow-50"
: "bg-gradient-to-br from-slate-50 via-gray-50 to-slate-100"
@@ -562,7 +569,7 @@ export function FamilyNode({
{/* 顶部装饰条 */}
<div className={cn(
"h-1.5",
isHighlighted ? "bg-gradient-to-r from-yellow-400 via-amber-500 to-yellow-400"
isCardHighlighted ? "bg-gradient-to-r from-yellow-400 via-amber-500 to-yellow-400"
: isFounder || isRoot ? "bg-gradient-to-r from-amber-400 via-orange-500 to-amber-400"
: "bg-gradient-to-r from-slate-400 via-gray-500 to-slate-400"
)} />
@@ -669,8 +676,8 @@ export function FamilyNode({
{/* 配偶卡片 */}
<div
className={cn(
"flex flex-col items-center cursor-pointer min-w-[80px] relative",
relationMode && "hover:ring-2 hover:ring-primary/50 rounded-lg p-1"
"flex flex-col items-center cursor-pointer min-w-[80px] relative p-2 rounded-lg transition-all",
relationMode && "hover:ring-2 hover:ring-primary/50"
)}
data-member-id={sp.id}
onClick={() => onSelect?.(sp)}
+1
View File
@@ -86,6 +86,7 @@ export const TreeNode = memo(function TreeNode({
onSelect={handleSelect}
isRoot={isRoot}
isHighlighted={isHighlighted}
highlightedMemberId={highlightedMemberId}
relationMode={relationMode}
isSelected={isSelected}
selectedMembers={selectedMembers}