feat: migrate app routes and business modules

This commit is contained in:
2026-08-12 18:22:59 +08:00
parent 555aa00043
commit cc706378c2
247 changed files with 28623 additions and 14988 deletions
+98
View File
@@ -0,0 +1,98 @@
const familyFeeds = [
{
feedId: '1', genealogyId: '1001', feedType: '团圆记忆', createTime: '今天 10:24',
feedContent: '今年端午全家相聚,长辈讲起祖居旧事,孩子们也为大家拍下了新的全家福。饭后我们把照片和口述片段整理进家族档案,让这份热闹成为往后仍能翻看的共同记忆。',
publisherNickName: '汤正国', mediaOssIds: '', likedByMe: false, likeCount: 0, commentCount: 2, pinned: '0'
},
{
feedId: '2', genealogyId: '1001', feedType: '家族通知', createTime: '昨天 18:02',
feedContent: '请家人补充老照片中的人物姓名、拍摄时间和地点。无法确认的信息也可以先写下线索,由熟悉往事的长辈共同核对。',
publisherNickName: '谱主', mediaOssIds: '', likedByMe: false, likeCount: 0, commentCount: 0, pinned: '0'
}
]
const familyArticles = [
{
id: '101', genealogyId: '1001', category: '家风家训', title: '孝友传家的日常',
summary: '从敬老、睦亲与守信的小事里,看见家风如何代代相传。', author: '汤文正',
updatedAt: '2024 年 5 月 12 日',
paragraphs: [
'孝友传家,不只在族谱序言里,也在一家人每日的言行中。长辈以宽厚待晚辈,晚辈以耐心照料长辈,亲友之间守信互助,便是最朴素也最长久的家风。',
'勤俭并非一味节省,而是珍惜所得、量入为出,也愿意在家人需要时伸出援手。家中每一代人都可以用自己的方式,把这份分寸与担当继续传下去。',
'敬祖睦宗,最终是为了让今天的家人彼此认识、彼此关心。记录姓名与世代之外,也应留下真实的生活、共同经历和温暖记忆。'
]
},
{
id: '102', genealogyId: '1001', category: '家族往事', title: '祖居门前的那棵桂花树',
summary: '长辈口述的旧居记忆,以及每年中秋一家人相聚的故事。', author: '汤淑华',
updatedAt: '2024 年 5 月 10 日',
paragraphs: [
'祖居门前曾有一棵桂花树。每到中秋,院里都是清甜的香气,远道回来的家人也总能循着那股味道找到家门。',
'后来房屋几经修缮,桂花树仍被大家小心保留下来。它见过孩子长大,也见过长辈把往事一遍遍讲给后来人。'
]
},
{
id: '103', genealogyId: '1001', category: '族谱序言', title: '续修族谱序',
summary: '说明本次续修的缘起、资料来源与共同参与的家人。', author: '谱主',
updatedAt: '2024 年 5 月 8 日',
paragraphs: [
'本次续修以旧谱、碑记、户籍资料和长辈口述为基础,由家人共同核对补充。凡暂不能确认之处,均保留来源和疑问,留待后续查证。',
'愿这份记录不仅理清世系,也能保存家风、人物与共同记忆。'
]
}
]
const familyAlbums = [
{
id: '201', genealogyId: '1001', name: '2024 春节团圆', updatedAt: '今天更新',
description: '三代家人的团圆饭与院前合影', cover: '/static/assets/modules/family/albums/reunion-hero.png',
photos: [
{ id: '20101', src: '/static/assets/modules/family/albums/reunion-hero.png', alt: '春节团圆时三代家人的合影', caption: '除夕团圆 · 2024' },
{ id: '20102', src: '/static/assets/modules/family/albums/family-portrait.png', alt: '家人在院落前的春节合影', caption: '院前合影 · 2024' },
{ id: '20103', src: '/static/assets/modules/family/albums/reunion-table.png', alt: '家人围坐吃年夜饭', caption: '围桌守岁 · 2024' },
{ id: '20104', src: '/static/assets/modules/family/albums/ancestral-home.png', alt: '祖居院落的复古旧照', caption: '祖居旧影 · 1968' },
{ id: '20105', src: '/static/assets/modules/family/albums/ancestral-portrait.png', alt: '老一辈家人在祖居门前的合影', caption: '门前合影 · 1972' }
]
},
{
id: '202', genealogyId: '1001', name: '祖居旧影', updatedAt: '5 月 10 日更新',
description: '祖居、旧物与长辈珍藏的老照片', cover: '/static/assets/modules/family/albums/ancestral-home.png',
photos: [
{ id: '20201', src: '/static/assets/modules/family/albums/ancestral-home.png', alt: '祖居院落的复古旧照', caption: '祖居旧影 · 1968' },
{ id: '20202', src: '/static/assets/modules/family/albums/ancestral-portrait.png', alt: '老一辈家人在祖居门前的合影', caption: '门前合影 · 1972' }
]
},
{
id: '203', genealogyId: '1001', name: '儿童成长', updatedAt: '持续更新',
description: '记录孩子们每一个值得珍藏的瞬间', cover: '/static/assets/modules/family/albums/family-portrait.png',
photos: [
{ id: '20301', src: '/static/assets/modules/family/albums/family-portrait.png', alt: '家人在院落前的春节合影', caption: '院前合影 · 2024' }
]
}
]
const clonePreviewFamilyFeed = (feed) => ({ ...feed })
const clonePreviewFamilyArticle = (article) => ({
...article,
paragraphs: [...article.paragraphs]
})
const clonePreviewFamilyAlbum = (album) => ({
...album,
photoCount: album.photos.length,
photos: album.photos.map((photo) => ({ ...photo }))
})
const listScopedPreviewFamilyContent = (items, clone, genealogyId) => {
const normalizedGenealogyId = String(genealogyId || '')
if (!normalizedGenealogyId) return []
return items
.filter((item) => item.genealogyId === normalizedGenealogyId)
.map(clone)
}
export const listPreviewFamilyFeeds = (genealogyId) =>
listScopedPreviewFamilyContent(familyFeeds, clonePreviewFamilyFeed, genealogyId)
export const listPreviewFamilyArticles = (genealogyId) =>
listScopedPreviewFamilyContent(familyArticles, clonePreviewFamilyArticle, genealogyId)
export const listPreviewFamilyAlbums = (genealogyId) =>
listScopedPreviewFamilyContent(familyAlbums, clonePreviewFamilyAlbum, genealogyId)
+128
View File
@@ -0,0 +1,128 @@
import {
GENEALOGY_ACCESS_PRESET,
} from '../../utils/genealogy/access-policy.js'
const genealogies = [
{
id: '1001',
surname: '汤',
name: '汤氏家谱',
hall: '敦睦堂',
location: '河南·洛阳',
memberCount: 158,
updatedAt: '2024-05-12',
activeCount: 8,
accessPreset: GENEALOGY_ACCESS_PRESET.MEMBER_ONLY,
membership: 'created',
motto: '敦亲睦族,敬祖传家。',
ancestorName: '汤文远',
parentName: '汤氏中华总谱',
branchName: '洛阳主支',
source: '由洛阳汤氏族人整理并维护',
publicDescription: '公开展示家谱身份、地区、堂号与支系信息。'
},
{
id: '1002',
surname: '汤',
name: '汤氏宗谱',
hall: '承志堂',
location: '山东·济宁',
memberCount: 286,
updatedAt: '2024-04-28',
activeCount: 15,
accessPreset: GENEALOGY_ACCESS_PRESET.PUBLIC_APPLY,
membership: 'joined',
motto: '继往开来,世守家风。',
ancestorName: '汤正明',
parentName: '汤氏鲁西总谱',
branchName: '济宁主支',
source: '由济宁汤氏族人整理并维护',
publicDescription: '公开展示家谱身份、地区、堂号与支系信息。'
}
]
// 家谱列表与公开搜索共用预览数据。成员关系只存在于 genealogies
// 公开搜索投影不能携带该字段,避免本地预览误授予管理能力。
const toPublicProjection = ({ membership: _membership, ...genealogy }) => genealogy
const previewPublicGenealogies = [
{
id: '2001',
surname: '汤',
name: '汤氏南阳宗谱',
hall: '敦睦堂',
location: '河南·南阳',
parentName: '汤氏中华总谱',
branchName: '南阳主支',
manager: '管理员 汤文礼',
certification: '资料已认证',
memberCount: 428,
activeCount: 316,
updatedAt: '2026-07-12',
relation: 'available',
source: '由南阳汤氏族人整理并维护',
publicDescription: '公开展示家谱身份、地区、堂号与支系信息;成员资料和世系详情仅向已加入成员开放。',
motto: '敦亲睦族,敬祖传家。',
accessPreset: GENEALOGY_ACCESS_PRESET.PUBLIC_APPLY,
ancestorName: '汤文远'
},
{
...toPublicProjection(genealogies[1]),
manager: '管理员 汤文远',
certification: '资料已认证',
relation: 'joined'
},
{
id: '2003',
surname: '汤',
name: '汤氏济宁宗谱',
hall: '敬宗堂',
location: '山东·济宁',
parentName: '汤氏鲁西总谱',
branchName: '济宁主支',
manager: '管理员 汤正明',
certification: '管理员已实名',
memberCount: 286,
updatedAt: '2026-07-08',
relation: 'pending',
accessPreset: GENEALOGY_ACCESS_PRESET.PUBLIC_APPLY,
},
{
id: '2004',
surname: '汤',
name: '汤氏清河家谱',
hall: '思源堂',
location: '山东·临清',
parentName: '汤氏鲁西总谱',
branchName: '清河支系',
manager: '管理员 汤志成',
certification: '资料已认证',
memberCount: 96,
updatedAt: '2026-07-05',
relation: 'rejected',
accessPreset: GENEALOGY_ACCESS_PRESET.PUBLIC_APPLY,
},
{
id: '2005',
surname: '汤',
name: '汤氏汝南支谱',
hall: '崇本堂',
location: '河南·驻马店',
parentName: '汤氏中原总谱',
branchName: '汝南三支',
manager: '管理员 汤国安',
certification: '管理员已实名',
memberCount: 72,
updatedAt: '2026-07-02',
relation: 'removed',
accessPreset: GENEALOGY_ACCESS_PRESET.PUBLIC_APPLY,
},
{
...toPublicProjection(genealogies[0]),
manager: '创建者 当前用户',
certification: '资料待完善',
relation: 'owned'
}
]
export const listPreviewPublicGenealogies = () =>
previewPublicGenealogies.map((genealogy) => ({ ...genealogy }))
+16
View File
@@ -0,0 +1,16 @@
export const previewCurrentUser = Object.freeze({
id: 1,
name: '汤文远',
phone: '138****1024',
role: '创建者'
})
const previewPendingJoinApplications = [
{ id: '1', genealogyId: '1001', name: '汤志成', phone: '139****6421', relation: '自述为汤正华堂侄', appliedAt: '今天 10:24', status: '0' },
{ id: '2', genealogyId: '1001', name: '汤雨薇', phone: '136****2798', relation: '自述为汤正国之女', appliedAt: '昨天 18:02', status: '0' }
]
export const createPreviewPendingJoinApplications = () =>
previewPendingJoinApplications.map((application) => ({ ...application }))
export const createPreviewMyJoinApplications = () => []
+60
View File
@@ -0,0 +1,60 @@
// 这些数据只用于本地视觉预览,不模拟 OpenAPI 响应。每个实体都携带
// genealogyId,详情必须由家谱与实体 ID 共同定位,调用方只能取得副本。
const previewCeremonies = [
{
ceremonyId: '501', genealogyId: '1001', ceremonyType: '祭祖', ceremonyTitle: '清明祭祖',
ceremonyTime: '2025-04-04', location: '汤氏宗祠',
ceremonyDesc: '缅怀先祖,整理祭扫礼序,并由长辈讲述家族往事。',
invitees: [
{ inviteeUserId: '2001', inviteStatus: '1' },
{ inviteeUserId: '2002', inviteStatus: '0' }
]
},
{
ceremonyId: '502', genealogyId: '1001', ceremonyType: '家宴', ceremonyTitle: '中秋家宴',
ceremonyTime: '2025-09-17', location: '祖居院落',
ceremonyDesc: '家人团聚,共叙近况并整理年度家族影像。',
invitees: [{ inviteeUserId: '2003', inviteStatus: '1' }]
},
{
ceremonyId: '503', genealogyId: '1001', ceremonyType: '团拜', ceremonyTitle: '新春团拜',
ceremonyTime: '2025-01-29', location: '家族礼堂',
ceremonyDesc: '新春相聚,向长辈问安并记录家族近况。', invitees: []
}
]
const previewGrowthRecords = [
{
recordId: '701', genealogyId: '1001', lineagePersonId: '101', recordTitle: '整理第一册旧谱',
recordDate: '1988-03', recordContent: '第一次独立整理家中保存的旧谱与口述线索。'
},
{
recordId: '702', genealogyId: '1001', lineagePersonId: '104', recordTitle: '第一次参与修谱',
recordDate: '2024-06', recordContent: '协助长辈核对照片人物与出生年份。'
}
]
const clonePreviewRecord = (record) => ({
...record,
...(Array.isArray(record.invitees)
? { invitees: record.invitees.map((invitee) => ({ ...invitee })) }
: {})
})
const listScopedPreviewRecords = (records, genealogyId) => {
const normalizedGenealogyId = String(genealogyId || '')
if (!normalizedGenealogyId) return []
return records
.filter((record) => record.genealogyId === normalizedGenealogyId)
.map(clonePreviewRecord)
}
export const listPreviewCeremonies = (genealogyId) =>
listScopedPreviewRecords(previewCeremonies, genealogyId)
export const listPreviewGrowthRecords = (genealogyId, lineagePersonId = '') => {
const records = listScopedPreviewRecords(previewGrowthRecords, genealogyId)
const normalizedPersonId = String(lineagePersonId || '')
return normalizedPersonId
? records.filter((record) => record.lineagePersonId === normalizedPersonId)
: records
}