0.0.8.5
This commit is contained in:
+42
-34
@@ -17,6 +17,7 @@ import { Badge } from "@/components/ui/badge"
|
||||
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"
|
||||
import type { FamilyMember } from "@/types/family"
|
||||
import { permissions } from "@/lib/permissions"
|
||||
import { MemberNameWithStatus } from "@/components/member-name-with-status"
|
||||
|
||||
// 占位符类型
|
||||
interface PlaceholderMember {
|
||||
@@ -72,7 +73,7 @@ const MemberCard = memo(function MemberCard({
|
||||
onLocateInTree: (id: string) => void
|
||||
}) {
|
||||
// 判断是否是配偶
|
||||
const isFounder = member.tags?.includes('始祖')
|
||||
const isFounder = member.isFounder === true
|
||||
const isSpouse = !member.fatherId && !member.motherId &&
|
||||
member.spouseIds && member.spouseIds.length > 0 &&
|
||||
!isFounder
|
||||
@@ -85,7 +86,7 @@ const MemberCard = memo(function MemberCard({
|
||||
|
||||
return (
|
||||
<div className="relative group">
|
||||
<Link href={`/members/${member.id}`}>
|
||||
<Link href={`/members/${member.id}${typeof window !== 'undefined' ? window.location.search : ''}`}>
|
||||
<Card className={`hover:border-primary transition-colors cursor-pointer h-full ${
|
||||
isSpouse
|
||||
? 'bg-pink-50/50 dark:bg-pink-950/20 border-pink-200/50 dark:border-pink-800/30'
|
||||
@@ -94,24 +95,21 @@ const MemberCard = memo(function MemberCard({
|
||||
<CardContent className="p-3 flex items-center gap-5">
|
||||
<div className="relative flex-shrink-0">
|
||||
<AvatarDisplay
|
||||
imageId={member.avatarImageId}
|
||||
fallbackUrl={member.avatarUrl}
|
||||
imageUrl={member.avatarUrl}
|
||||
fallbackText={member.surname}
|
||||
gender={member.gender}
|
||||
className="h-20 w-20 border-2 border-border"
|
||||
/>
|
||||
{/* 在世/去世标识 */}
|
||||
{member.deathDate && (
|
||||
<div className="absolute -bottom-1 -right-1 w-4 h-4 rounded-full bg-gray-500 border-2 border-white" title="已故" />
|
||||
)}
|
||||
{!member.deathDate && (
|
||||
<div className="absolute -bottom-1 -right-1 w-4 h-4 rounded-full bg-green-500 border-2 border-white" title="在世" />
|
||||
)}
|
||||
</div>
|
||||
<div className="flex-1 min-w-0 flex flex-col justify-center">
|
||||
<div className="flex items-baseline justify-between gap-1.5">
|
||||
<h3 className="text-lg font-bold font-serif truncate">
|
||||
{member.fullName}
|
||||
<h3 className="text-lg font-bold font-serif truncate flex items-center gap-1">
|
||||
{isFounder && <span className="text-amber-600">👑</span>}
|
||||
<MemberNameWithStatus
|
||||
name={member.fullName}
|
||||
isDead={!!member.deathDate}
|
||||
dotPosition="top-left"
|
||||
/>
|
||||
{member.courtesyName && (
|
||||
<span className="text-xs font-normal text-muted-foreground ml-1">
|
||||
字 {member.courtesyName}
|
||||
@@ -120,7 +118,7 @@ const MemberCard = memo(function MemberCard({
|
||||
</h3>
|
||||
</div>
|
||||
{isFounder ? (
|
||||
<p className="text-xs text-amber-700 font-medium mt-0.5 truncate">
|
||||
<p className="text-xs text-amber-700 font-semibold mt-0.5 truncate">
|
||||
家族始祖
|
||||
</p>
|
||||
) : isSpouse && spouseName ? (
|
||||
@@ -140,10 +138,17 @@ const MemberCard = memo(function MemberCard({
|
||||
{/* 生卒年和年龄 */}
|
||||
{(member.birthDate || member.deathDate) && (
|
||||
<div className="text-xs text-muted-foreground text-right space-y-0.5 flex-shrink-0">
|
||||
<div>
|
||||
{member.birthDate && new Date(member.birthDate).getFullYear()}
|
||||
{member.deathDate && ` - ${new Date(member.deathDate).getFullYear()}`}
|
||||
{!member.deathDate && member.birthDate && ' - '}
|
||||
<div className="flex items-center gap-1 justify-end">
|
||||
<span>
|
||||
{member.birthDate && new Date(member.birthDate).getFullYear()}
|
||||
{member.deathDate && ` - ${new Date(member.deathDate).getFullYear()}`}
|
||||
{!member.deathDate && member.birthDate && ' - '}
|
||||
</span>
|
||||
{member.isLunarDate && (
|
||||
<span className="text-[10px] text-amber-600 bg-amber-50 px-1 py-0.5 rounded border border-amber-200">
|
||||
农历
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
{(() => {
|
||||
if (!member.birthDate) return null
|
||||
@@ -165,9 +170,11 @@ const MemberCard = memo(function MemberCard({
|
||||
{member.tags.map((tag) => (
|
||||
<span
|
||||
key={tag}
|
||||
className="text-xs bg-primary/10 text-primary px-2 py-0.5 rounded border border-primary/20"
|
||||
className={tag === '始祖'
|
||||
? "text-xs bg-amber-100 text-amber-800 px-2 py-0.5 rounded border border-amber-300 font-semibold"
|
||||
: "text-xs bg-primary/10 text-primary px-2 py-0.5 rounded border border-primary/20"}
|
||||
>
|
||||
{tag}
|
||||
{tag === '始祖' ? '👑 始祖' : tag}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
@@ -303,7 +310,7 @@ export default function MembersPage() {
|
||||
.map(([generation, members]) => {
|
||||
// 区分家族成员和配偶
|
||||
const familyMembers = members.filter(m => {
|
||||
const isFounder = m.tags?.includes('始祖')
|
||||
const isFounder = m.isFounder === true
|
||||
const hasFamilyParents = m.fatherId || m.motherId
|
||||
|
||||
if (hasFamilyParents || isFounder) return true
|
||||
@@ -314,8 +321,8 @@ export default function MembersPage() {
|
||||
|
||||
// 对家族成员按年龄排序
|
||||
const sortedFamilyMembers = familyMembers.sort((a, b) => {
|
||||
const aIsFounder = a.tags?.includes('始祖')
|
||||
const bIsFounder = b.tags?.includes('始祖')
|
||||
const aIsFounder = a.isFounder === true
|
||||
const bIsFounder = b.isFounder === true
|
||||
if (aIsFounder && !bIsFounder) return -1
|
||||
if (!aIsFounder && bIsFounder) return 1
|
||||
|
||||
@@ -388,7 +395,7 @@ export default function MembersPage() {
|
||||
)}
|
||||
</Button>
|
||||
{permissions.canCreate(currentTree?.currentUserRole) && (
|
||||
<Link href="/members/new">
|
||||
<Link href={`/members/new${typeof window !== 'undefined' ? window.location.search : ''}`}>
|
||||
<Button className="gap-2 bg-primary text-primary-foreground">
|
||||
<Plus className="h-4 w-4" />
|
||||
新增成员
|
||||
@@ -409,13 +416,13 @@ export default function MembersPage() {
|
||||
</div>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
|
||||
<div className="space-y-2">
|
||||
<Label className="text-xs">姓氏 (Surname)</Label>
|
||||
<Label className="text-xs">姓氏</Label>
|
||||
<Select value={selectedSurname} onValueChange={setSelectedSurname}>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="全部" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="all">全部 (All)</SelectItem>
|
||||
<SelectItem value="all">全部</SelectItem>
|
||||
{uniqueSurnames.map((s) => (
|
||||
<SelectItem key={s} value={s}>
|
||||
{s}
|
||||
@@ -426,13 +433,13 @@ export default function MembersPage() {
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label className="text-xs">籍贯 (Ancestral Home)</Label>
|
||||
<Label className="text-xs">籍贯</Label>
|
||||
<Select value={selectedHome} onValueChange={setSelectedHome}>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="全部" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="all">全部 (All)</SelectItem>
|
||||
<SelectItem value="all">全部</SelectItem>
|
||||
{uniqueHomes.map((h) => (
|
||||
<SelectItem key={h} value={h}>
|
||||
{h}
|
||||
@@ -443,22 +450,22 @@ export default function MembersPage() {
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label className="text-xs">状态 (Status)</Label>
|
||||
<Label className="text-xs">状态</Label>
|
||||
<Select value={statusFilter} onValueChange={setStatusFilter}>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="全部" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="all">全部 (All)</SelectItem>
|
||||
<SelectItem value="living">在世 (Living)</SelectItem>
|
||||
<SelectItem value="deceased">已故 (Deceased)</SelectItem>
|
||||
<SelectItem value="all">全部</SelectItem>
|
||||
<SelectItem value="living">在世</SelectItem>
|
||||
<SelectItem value="deceased">已故</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<div className="flex justify-between">
|
||||
<Label className="text-xs">世系范围 (Generation)</Label>
|
||||
<Label className="text-xs">世系范围</Label>
|
||||
<span className="text-xs text-muted-foreground">
|
||||
{generationRange[0]} - {generationRange[1]} 世
|
||||
</span>
|
||||
@@ -511,7 +518,8 @@ export default function MembersPage() {
|
||||
allMembers={allMembers}
|
||||
onLocateInTree={(id) => {
|
||||
setHighlightedMemberId(id)
|
||||
router.push('/tree')
|
||||
const params = new URLSearchParams(window.location.search)
|
||||
router.push(`/tree?${params.toString()}`)
|
||||
}}
|
||||
/>
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user