分析日期: 2026年4月30日
分析对象:
mobile/ 为App客户端根目录,Flutter源代码(代码于阿里云效托管,有自2025-12起完整Git提交记录)wx3f22282982586c02_unpacked/逆向解包项目代码根目录说明: 喜程记小程序代码已被混淆打包为JavaScript bundle(app-service.js),字段名大部分已保留,但代码逻辑经过压缩。以下相似点均基于可验证的代码证据,请审核人员参阅。
相似点:两个应用的功能模块高度对应。常见婚礼筹备工具通常会覆盖任务、宾客、预算等基础能力,但“礼金账本 / 座位表 / 座位查询 / 回忆记录”组合在同一产品中并不属于纯通用配置;对方小程序将这些模块以相近入口和页面矩阵组织起来,适合作为整体产品形态相似的背景证据。
我方功能模块出处:mobile/lib/features/
mobile/lib/features/
├── tasks/ # 任务清单
├── budget/ # 预算管理
├── family_friend/ # 宾客管理
├── gift_ledger/ # 礼金账本
├── anniversary/ # 纪念日
├── calendar/ # 日历
├── seating_chart/ # 座位表
├── memory/ # 回忆记录
└── home/ # 首页对方页面路由出处:wx3f22282982586c02_unpacked/app-config.json:3
"pages": [
"pages/home/index",
"pages/tasks/index",
"pages/budget/index",
"pages/guests/index",
"pages/gifts/index",
"pages/events/index",
"pages/calendar/index",
"pages/budgetRecords/index",
"pages/seating/index",
"pages/seatLookup/index",
"pages/memories/index",
"pages/memoriesEditor/index"
]功能对应关系:
| 我方功能 | 对方页面 | 说明 |
|---|---|---|
| 任务清单 | pages/tasks/index | 基础筹备清单能力 |
| 预算管理 | pages/budget/index、pages/budgetRecords/index | 预算与支出记录拆分 |
| 宾客管理 | pages/guests/index | 宾客/亲友信息管理 |
| 礼金账本 | pages/gifts/index | 非纯通用工具,和亲友维度联动 |
| 纪念日 | pages/events/index | 婚期相关日期管理 |
| 日历 | pages/calendar/index | 聚合日期、任务等信息 |
| 座位表 | pages/seating/index | 排座与场地布局能力 |
| 座位查询 | pages/seatLookup/index | 排座后给亲友自助查座 |
| 回忆记录 | pages/memories/index、pages/memoriesEditor/index | 图文/视频素材记录 |
结论:功能矩阵整体高度对应,尤其是礼金账本、座位表、座位查询、回忆记录这几类非单一基础功能同时出现,能为后续代码逻辑和交互路径相似点提供产品形态背景。
相似点:双方都将座位表抽象为桌型枚举,并提供圆桌、方桌、长桌类桌型。我方包含圆桌、方桌、长桌、主位长桌、单边长桌;对方包含圆桌、方桌、单边长桌、双边长桌、端位长桌。对方还实现了“已满桌 / 暂无宾客 / 还可安排 N 位”这类与我方座位分配状态同类的容量交互文案。
我方出处:mobile/lib/features/seating_chart/models/seating_table_shape.dart:1
enum SeatingTableShape {
round('round', '圆桌'),
square('square', '方桌'),
long('long', '长桌'),
headLong('head_long', '主位长桌'),
singleSideLong('single_side_long', '单边长桌');
}对方出处:wx3f22282982586c02_unpacked/app-service.js:30423
u = {
round: "圆桌",
square: "方桌",
"long-single": "单边长桌",
"long-double": "双边长桌",
"long-end": "端位长桌"
}对方出处:wx3f22282982586c02_unpacked/app-service.js:30670
r = a >= e.capacity ? "已满" : 0 === a ? "待安排" : "可继续安排",
l = a >= e.capacity ? "已满桌" : 0 === a ? "暂无宾客" : "还可安排 ".concat(o, " 位"),
tableTypeLabel: u[h] || "圆桌",
seatText: "".concat(a, "/").concat(e.capacity)相似点:我方将座位表分享为公开座位查询页面/接口,对方也有独立 seatLookup 页面,并从座位表页生成查座路径和二维码。该点不是普通座位编辑,而是“排座完成后给亲友自助查座”的完整链路。
我方出处:mobile/lib/core/config/env_config.dart:158
// ===== 座位查询 Web 版本 =====
static const String seatingQueryWebUrl = String.fromEnvironment(
'SEATING_QUERY_WEB_URL',
defaultValue: 'https://wp-seating.fegotech.com:38443',
);我方出处:backend/app/api/v2/endpoints/public_seating.py:35
@router.get(
"/{chart_id}",
response_model=APIResponse[PublicSeatingResponse],
summary="公开查询座位表数据(供亲友H5页面使用)",
)
async def get_public_seating(chart_id: str, db: AsyncSession = Depends(get_db)):
...对方出处:wx3f22282982586c02_unpacked/app-config.json:11
"pages/budgetRecords/index",
"pages/seating/index",
"pages/seatLookup/index",
"pages/memories/index"对方出处:wx3f22282982586c02_unpacked/app-service.js:28944
onShareAppMessage: function() {
var e = this.data,
t = e.eventId,
n = e.title,
a = t ? "/pages/seatLookup/index?eventId=".concat(encodeURIComponent(t)) : "/pages/seatLookup/index";
return {
title: n ? "「".concat(n, "」查座位") : "查找我的座位",
path: a
}
}相似点:双方宾客关系分类的核心类目高度重合。我方枚举包含家人、亲戚、朋友、同事、同学、邻里、家长圈、合作伙伴/客户、其他等;对方数组包含家人、亲戚、朋友、同学、同事、邻里、父母好友、商务伙伴、其他。9 个对方类目中,7 个文案完全相同,2 个语义高度接近。
我方出处:mobile/lib/features/family_friend/models/family_relation_type.dart:33
String get title {
switch (this) {
case FamilyRelationType.relative:
return '亲戚';
case FamilyRelationType.family:
return '家人';
case FamilyRelationType.friend:
return '朋友';
case FamilyRelationType.colleague:
return '同事';
case FamilyRelationType.classmate:
return '同学';
case FamilyRelationType.neighbor:
return '邻里';
case FamilyRelationType.parentCommunity:
return '家长圈';
case FamilyRelationType.business:
return '合作伙伴/客户';
case FamilyRelationType.other:
return '其他';
}
}对方出处:wx3f22282982586c02_unpacked/app-service.js:40007
u = ["家人", "亲戚", "朋友", "同学", "同事", "邻里", "父母好友", "商务伙伴", "其他"]相似点:双方礼金记录都采用“收/送”双向结构,并在列表侧提供“全部 / 收礼 / 送礼”筛选。相比单纯记录收到的礼金,这是一种更具体的账本产品设计。
我方出处:mobile/lib/features/gift_ledger/models/gift_direction.dart:5
@HiveType(typeId: 23)
enum GiftDirection {
@HiveField(0)
receive,
@HiveField(1)
give,
}对方出处:wx3f22282982586c02_unpacked/app-service.js:40009
f = ["收礼", "送礼"]对方出处:wx3f22282982586c02_unpacked/app-service.js:40054
typeFilter: "全部",
typeFilters: ["全部", "收礼", "送礼"]对方出处:wx3f22282982586c02_unpacked/app-service.js:40141
l = a.sent, u = l.items.filter((function(t) {
return "收礼" === t.type
})).reduce(...), d = l.items.filter((function(t) {
return "送礼" === t.type
})).reduce(...)相似点:我方明确设计“礼金簿和座位表共享亲友名单”,座位表初始化会加载亲友,并确保默认亲友组;对方在宾客、礼金、座位表之间也复用“宾客/亲友”数据,座位表逻辑中包含“出席宾客已排座”等文案。
我方出处:mobile/lib/features/seating_chart/views/seating_chart_screen.dart:33
await ref.read(familyFriendControllerProvider.notifier).load();
// 确保默认的"新郎和新娘"亲友组存在(用于座位表功能)
await ref.read(familyFriendControllerProvider.notifier).ensureDefaultCoupleFamily();
await ref.read(seatingChartControllerProvider.notifier).load();我方出处:mobile/lib/features/seating_chart/widgets/friend_list_panel.dart:357
Text('可到场亲友'),
_SeatFilterToggle(label: '共 $totalMembers 位'),
_SeatFilterToggle(label: '已安排 $assignedCount'),
_SeatFilterToggle(label: '未安排 $unassignedCount'),
FilledButton(onPressed: () => context.push('/toolkit/family-friends'), child: Text('亲友管理')),对方出处:wx3f22282982586c02_unpacked/app-service.js:32739
content: "当前所有出席宾客已排座,无需重新安排。"对方出处:wx3f22282982586c02_unpacked/app-service.js:32122
i = r.guest.contactName || "该宾客",
o = Number(r.guest.plusOnes || 0) > 0,
l = o ? "移出 ".concat(i, " 及随行") : "移出 ".concat(i),
itemList: [l, "换到其他桌"]相似点:双方都将任务系统组织为备婚阶段,并在任务模型/页面中按阶段推进。对方阶段名称是“决策定档 / 资源筹备 / 流程设计 / 执行筹备 / 婚礼执行 / 收尾回顾”;我方任务模型是婚礼阶段枚举,包含“策划阶段 / 筹备阶段 / 确认阶段”等,并通过 TaskStage 驱动任务筛选、阶段进度和新增任务默认阶段。
我方出处:mobile/lib/features/tasks/models/task.dart:579
enum TaskStage {
dating(name: '恋爱阶段', value: 'dating', icon: '💕', description: '确定婚姻关系与家庭见面'),
planning(name: '策划阶段', value: 'planning', icon: '📋', description: '确定婚礼日期、预算与场地'),
preparation(name: '筹备阶段', value: 'preparation', icon: '🎊', description: '采购婚品、拍照、准备物料'),
confirmation(name: '确认阶段', value: 'confirmation', icon: '✨', description: '最终确认与婚礼彩排');
}对方出处:wx3f22282982586c02_unpacked/app-service.js:34351
d = require("../../utils/task"),
l = d.buildTimelineItems,
u = d.compareTaskByDeadline,
c = d.normalizeTaskItem,
p = ["决策定档", "资源筹备", "流程设计", "执行筹备", "婚礼执行", "收尾回顾"],
h = ["未开始", "进行中", "已完成"];相似点:双方都对宾客设置了归属方。我方模型将亲友归属为 groom / bride / unknown,并提供“新郎 / 新娘”展示;对方在宾客和礼金相关表单中使用“男方 / 女方”数组和筛选 tab。
我方出处:mobile/lib/features/family_friend/models/family.dart:8
enum FamilyReferrer {
groom,
bride,
unknown,
}
extension FamilyReferrerX on FamilyReferrer {
String get label => switch (this) {
FamilyReferrer.groom => '新郎',
FamilyReferrer.bride => '新娘',
FamilyReferrer.unknown => '未设置关系人',
};
}对方出处:wx3f22282982586c02_unpacked/app-service.js:40007
d = ["男方", "女方"]对方出处:wx3f22282982586c02_unpacked/app-service.js:40941
d = ["家人", "亲戚", "朋友", "同学", "同事", "邻里", "父母好友", "商务伙伴", "其他"],
p = ["男方", "女方"];相似点:我方礼金簿以亲友/成员为核心,支持收入支出记录、亲友管理入口和按亲友维度统计;对方小程序有独立“喜程礼金”页面,首页快捷入口描述为“人情往来与礼金收支记录”,与我方礼金簿定位基本一致。
我方出处:mobile/lib/features/gift_ledger/views/gift_ledger_screen.dart:46
await ref.read(familyFriendControllerProvider.notifier).load();
await ref.read(familyFriendControllerProvider.notifier).ensureDefaultCoupleFamily();
await ref.read(giftLedgerControllerProvider.notifier).load();我方出处:mobile/lib/features/gift_ledger/views/gift_ledger_screen.dart:152
appBar: AppBar(
title: const Text('礼金簿'),
actions: [
IconButton(tooltip: '亲友管理', icon: const Icon(Icons.group_outlined)),
IconButton(tooltip: '添加记录', icon: const Icon(Icons.add)),
],
)对方出处:wx3f22282982586c02_unpacked/app-config.json:49
"pages/gifts/index.html": {
"window": {
"navigationBarTitleText": "喜程礼金",
"navigationBarBackgroundColor": "#FFF7EB"
}
}对方出处:wx3f22282982586c02_unpacked/app-service.js:21500
badge: "🧧",
desc: "人情往来与礼金收支记录",
label: "礼金",
path: "/pages/gifts/index"相似点:双方都有“回忆/时光”模块,并围绕婚礼筹备过程记录图文/视频素材。我方模型有婚纱照、求婚瞬间、订婚仪式、试衣试妆、场地考察、购物记录、聚会聚餐、筹备过程、特殊时刻、其他回忆;对方小程序暴露“时光小记 / 记录时光”页面和一组记忆分类,覆盖日常、约会、美食、旅行、求婚、领证、婚礼筹备、婚礼当天等。
我方出处:mobile/lib/features/memory/models/memory.dart:257
enum MemoryType {
weddingPhoto(name: '婚纱照', apiValue: 'weddingPhoto'),
proposal(name: '求婚瞬间', apiValue: 'proposal'),
engagement(name: '订婚仪式', apiValue: 'engagement'),
fitting(name: '试衣试妆', apiValue: 'fitting'),
venueVisit(name: '场地考察', apiValue: 'venueVisit'),
shopping(name: '购物记录', apiValue: 'shopping'),
gathering(name: '聚会聚餐', apiValue: 'gathering'),
preparation(name: '筹备过程', apiValue: 'preparation'),
specialMoment(name: '特殊时刻', apiValue: 'specialMoment'),
other(name: '其他回忆', apiValue: 'other');
}对方出处:wx3f22282982586c02_unpacked/app-config.json:120
"pages/memories/index.html": {
"window": { "navigationBarTitleText": "时光小记", "disableScroll": true }
},
"pages/memoriesEditor/index.html": {
"window": { "navigationBarTitleText": "记录时光" }
}对方出处:wx3f22282982586c02_unpacked/app-service.js:2710
MEMORY_CATEGORY_OPTIONS: [
"日常碎片", "约会", "美食", "旅行", "节日纪念", "礼物惊喜",
"家人朋友", "求婚", "领证", "婚礼筹备", "婚礼当天", "其他"
]相似点:双方都把日历作为婚礼筹备的聚合视图:围绕婚期倒计时、当日任务、纪念日/回忆/支出等多维信息做日期标记和详情展开。该模块不只是普通日历,而是与备婚任务、花销、回忆联动的婚礼日历。
我方出处:mobile/lib/features/calendar/widgets/today_detail/countdown_section.dart:24
if (weddingDate == null) {
return _buildEmptyState(palette);
}
final daysRemaining = daysBetween(weddingDate!, currentDate);
if (daysRemaining < 0) return _buildPassedState(palette, daysRemaining.abs());
if (daysRemaining == 0) return _buildTodayState(palette, primary);
return _buildCountdown(palette, primary, daysRemaining);我方出处:mobile/lib/features/calendar/widgets/today_detail/countdown_section.dart:119
Text('距离大喜之日'),
RichText(
text: TextSpan(children: [
const TextSpan(text: '还有 '),
TextSpan(text: '$days'),
TextSpan(text: ' 天'),
]),
)我方出处:mobile/lib/features/calendar/widgets/multi_dimension_marker.dart:46
// 1. 添加任务标签
for (final task in [...activeTasks, ...completedTasks]) {
markerItems.add(_MarkerItem(type: _MarkerType.task, text: task.displayTitle));
}
// 2. 添加回忆标签
for (final memory in data.memories) {
markerItems.add(_MarkerItem(type: _MarkerType.memory, text: memory.displayTitle));
}
// 3. 添加支出标签
if (data.expenses.isNotEmpty) {
final totalAmount = data.totalExpenseAmount;
}对方出处:wx3f22282982586c02_unpacked/app-service.js:21205
if (!e) return "倒计时";
return Number.isNaN(a.getTime()) ? "倒计时" :
new Date(a.getFullYear(), a.getMonth(), a.getDate()).getTime() < n.getTime()
? "我们已经结婚"
: "距离婚礼还有"对方出处:wx3f22282982586c02_unpacked/app-service.js:38498
y.push({
dateKey: b,
isAnniversary: C.length > 0,
isSelected: b === t,
isTaskDeadline: M.length > 0,
isToday: b === o,
isWeddingDate: r === b,
taskCount: M.length
})对方出处:wx3f22282982586c02_unpacked/app-service.js:38610
this.setData({
calendarDays: M(i, d, t, c, u, p),
selectedCalendarDate: t,
selectedDateAnniversaries: x(t, u),
selectedDateTasks: p && p[t] || [],
upcomingMarriageDates: h.items
})相似点:我方工具包明确包含“亲友管理 / 座位表 / 礼金簿”,首页快捷入口包含今日事项、记录回忆、记录支出、备婚工具包;对方首页快捷入口包含座位表、礼金、时光小记等,且描述都围绕亲友、座位、礼金往来、回忆记录。
我方出处:mobile/lib/features/home/views/toolkit_screen.dart:68
_ToolkitCard(title: '亲友管理', description: '管理亲友信息和婚礼到场状态;礼金簿和座位表共享亲友名单,避免重复录入'),
_ToolkitCard(title: '座位表', description: '安排婚宴座位,拖拽分配宾客到各个桌子,设计宴会厅布局'),
_ToolkitCard(title: '礼金簿', description: '记录收到和送出的礼金,按亲友维度统计收支情况,清晰了解往来账目'),对方出处:wx3f22282982586c02_unpacked/app-service.js:21491
quickActions: [{
badge: "🪑",
desc: "排座扫码查座、场地规划",
label: "座位表",
path: "/pages/seating/index"
}, {
badge: "🧧",
desc: "人情往来与礼金收支记录",
label: "礼金",
path: "/pages/gifts/index"
}, {
badge: "📸",
desc: "记录我们的时光",
label: "时光小记",
path: "/pages/memories/index"
}]相似点:双方礼金表单都有事项类型字段。我方送礼方向包含“结婚 / 乔迁 / 其他”,对方事项数组包含“结婚 / 生育 / 学业 / 乔迁 / 寿庆 / 其他”,其中 3 个与我方完全重合。
我方出处:mobile/lib/features/gift_ledger/widgets/gift_record_form_sheet.dart:139
List<String> get _giftEventOptions {
if (_direction == GiftDirection.receive) {
return [
'本次婚礼',
'其他',
];
}
return [
'结婚',
'乔迁',
'其他'
];
}对方出处:wx3f22282982586c02_unpacked/app-service.js:40010
p = ["结婚", "生育", "学业", "乔迁", "寿庆", "其他"];相似点:双方都有婚礼预算模块和支出记录模块。我方预算分类包含婚庆场地、交通住宿、婚纱摄影、婚宴酒水、婚礼执行、珠宝首饰、服饰道具、礼仪习俗、其他杂项等;对方也有“喜程预算”“支出记录”页面,并在首页、预算估算等场景使用婚礼预算语义。该相似点偏信息架构与业务域复刻。
我方出处:mobile/lib/features/budget/constants/budget_category_config.dart:25
const List<BudgetCategoryInfo> budgetCategoryConfigs = [
BudgetCategoryInfo(code: 'venue', displayName: '婚庆场地', description: '婚礼场地租赁及布置相关费用'),
BudgetCategoryInfo(code: 'trans_accom', displayName: '交通住宿', description: '婚车、宾客接送及住宿费用'),
BudgetCategoryInfo(code: 'photography', displayName: '婚纱摄影', description: '婚礼摄影摄像及婚纱照费用'),
BudgetCategoryInfo(code: 'catering', displayName: '婚宴酒水', description: '婚宴餐饮及酒水费用'),
BudgetCategoryInfo(code: 'wedding_service', displayName: '婚礼执行', description: '婚礼策划、主持、化妆及花艺等服务'),
];我方出处:mobile/lib/features/budget/widgets/budget_overview_card.dart:68
Text('预算总览'),
Text('剩余预算'),
Text('已支出'),对方出处:wx3f22282982586c02_unpacked/app-config.json:35
"pages/budget/index.html": {
"window": { "navigationBarTitleText": "喜程预算" }
},
"pages/budgetRecords/index.html": {
"window": { "navigationBarTitleText": "支出记录" }
}对方出处:wx3f22282982586c02_unpacked/app-service.js:37911
s = "".concat(wx.env.USER_DATA_PATH, "/支出明细_喜程记_").concat(c, ".xlsx")相似点:对方小程序将主 Tab 配置为“首页 / 清单 / 预算 / 宾客”,并在页面矩阵中继续包含日历、礼金、座位表、回忆等模块;我方 App 主导航为“首页 / 日历 / 任务 / 回忆 / 预算”,工具包补充亲友、座位表、礼金簿。这不是单个通用功能相似,而是婚礼筹备产品的模块组合与入口组织高度接近。
我方出处:mobile/lib/shared/widgets/main_navigation.dart:96
_NavigationItem(icon: Icons.home, label: '首页', onTap: () => context.go('/home')),
_NavigationItem(icon: Icons.calendar_today, label: '日历', onTap: () => context.go('/calendar')),
_NavigationItem(icon: Icons.task_alt, label: '任务', onTap: () => context.go('/tasks')),
_NavigationItem(icon: Icons.photo_library, label: '回忆', onTap: () => context.go('/memory')),
_NavigationItem(icon: Icons.account_balance_wallet, label: '预算', onTap: () => context.go('/budget')),对方出处:wx3f22282982586c02_unpacked/app-config.json:3
"pages": [
"pages/home/index",
"pages/tasks/index",
"pages/budget/index",
"pages/guests/index",
"pages/gifts/index",
"pages/events/index",
"pages/calendar/index",
"pages/seating/index",
"pages/memories/index"
]对方出处:wx3f22282982586c02_unpacked/app-config.json:149
"tabBar": {
"color": "#D0A0B0",
"selectedColor": "#FF8FAD",
"list": [
{ "pagePath": "pages/home/index.html", "text": "首页" },
{ "pagePath": "pages/tasks/index.html", "text": "清单" },
{ "pagePath": "pages/budget/index.html", "text": "预算" },
{ "pagePath": "pages/guests/index.html", "text": "宾客" }
]
}相似点:双方首页都把高频动作做成快捷入口。我方是“今日事项 / 记录回忆 / 记录支出 / 备婚工具包”;对方首页快捷入口包含“座位表 / 礼金 / 时光小记”等。交互目标都是从首页直接进入具体备婚工具,减少层级。
我方出处:mobile/lib/features/home/widgets/quick_actions.dart:28
_buildActionItem(title: '今日事项', subtitle: '日程安排', onTap: () {
context.push('/calendar?selectedDate=$today');
});
_buildActionItem(title: '记录回忆', subtitle: '拍照记录', onTap: () {
context.push('/memory/add');
});
_buildActionItem(title: '记录支出', subtitle: '预算管理', onTap: () {
context.push('/budget/add-expense');
});
_buildActionItem(title: '备婚工具包', subtitle: '礼金簿、座位表', onTap: () {
context.go('/toolkit');
});对方出处:wx3f22282982586c02_unpacked/app-service.js:21491
quickActions: [{
badge: "🪑",
desc: "排座扫码查座、场地规划",
label: "座位表",
path: "/pages/seating/index"
}, {
badge: "🧧",
desc: "人情往来与礼金收支记录",
label: "礼金",
path: "/pages/gifts/index"
}, {
badge: "📸",
desc: "记录我们的时光",
label: "时光小记",
path: "/pages/memories/index"
}]交互路径:
我方路径证据 1:工具包入口与路由。出处:mobile/lib/features/home/views/toolkit_screen.dart:90
_ToolkitCard(
title: '座位表',
description: '安排婚宴座位,拖拽分配宾客到各个桌子,设计宴会厅布局',
onTap: () => context.push('/toolkit/seating-chart'),
)出处:mobile/lib/core/routes/app_router.dart:727
GoRoute(
path: 'seating-chart',
builder: (context, state) => const SeatingChartScreen(),
routes: [
GoRoute(path: 'assign', builder: (context, state) => SeatAssignmentView(fromLayout: fromLayout)),
GoRoute(path: 'layout', builder: (context, state) => TableLayoutView(...)),
],
)我方路径证据 2:座位表进入排座页,并提供亲友管理入口。出处:mobile/lib/features/seating_chart/views/seating_chart_screen.dart:62
Future<void> _openAssignment(String chartId) async {
await notifier.load(preferredChartId: chartId);
await context.push('/toolkit/seating-chart/assign');
await notifier.flushAllDirtyTables();
await notifier.load();
}出处:mobile/lib/features/seating_chart/views/seating_chart_screen.dart:160
IconButton(
tooltip: '亲友管理',
onPressed: () async {
await context.push('/toolkit/family-friends');
ref.read(familyFriendControllerProvider.notifier).load();
},
)我方路径证据 3:排座页只取“可到场亲友”,点击/拖拽分配座位,下一步进入布局页。出处:mobile/lib/features/seating_chart/views/seat_assignment_view.dart:738
final attendingFamilies = familyState.families.where((f) => f.canAttend).toList();
final attendingMembers = familyState.members
.where((m) => attendingFamilyIds.contains(m.familyId))
.toList();出处:mobile/lib/features/seating_chart/views/seat_assignment_view.dart:300
onAssignSeat: (chairId, memberId) async {
final success = await ref.read(seatingChartControllerProvider.notifier).assignMemberToChair(
chairId: chairId,
friendMemberId: memberId,
);
},
onSeatDragStart: () { setState(() { _isSeatDragging = true; }); },
onSeatDragEnd: () { setState(() { _isSeatDragging = false; }); },出处:mobile/lib/features/seating_chart/views/seat_assignment_view.dart:683
if (!hasAssigned) {
context.showText('请先添加亲友入座');
return;
}
await context.push('/toolkit/seating-chart/layout', extra: const TableLayoutRouteArgs(fromAssignment: true));我方路径证据 4:布局页导出/分享给亲友,支持链接和二维码。出处:mobile/lib/features/seating_chart/views/table_layout_view.dart:1350
IconOption(
title: '分享给亲友',
subtitle: '分享链接、分享二维码',
onTap: () async { await _showShareToFriendsSheet(); },
)出处:mobile/lib/features/seating_chart/widgets/share_to_friends_bottom_sheet.dart:706
PrimaryButton(text: '分享链接', onPressed: () async { await _handleShare(asQr: false); }),
PrimaryButton(text: '分享二维码', onPressed: () async { await _handleShare(asQr: true); }),对方路径证据 1:座位表页可回到宾客页。出处:wx3f22282982586c02_unpacked/app-service.js:31524
goToGuests: function() {
wx.switchTab({ url: "/pages/guests/index" })
}对方路径证据 2:拖拽/分配宾客到桌位,并调用云函数保存。出处:wx3f22282982586c02_unpacked/app-service.js:31829
if (i.dragFromAssignment && o && t._pointInRect(o.clientX, o.clientY, t._pendingDropRect)) return l(), void t.doRemoveAssignment(i.dragFromAssignment);
l(), t._completeGuestDragDrop(i)出处:wx3f22282982586c02_unpacked/app-service.js:31838
doAssign: function(n, i, o) {
c = { tableId: i, guestId: n._id, contactName: n.contact ? n.contact.name : "未命名", plusOnes: Number(n.plusOnes || 0), seatPosition: ... }
r.callCloud("seating", "assignGuest", {
eventId: g,
tableId: i,
guestId: n._id,
seatPosition: "number" == typeof o ? o : null
});
}对方路径证据 3:生成查座码,并进入查座页。出处:wx3f22282982586c02_unpacked/app-service.js:33056
wx.navigateTo({
url: "/pages/seatLookup/index?eventId=".concat(s)
})出处:wx3f22282982586c02_unpacked/app-service.js:33074
generateSeatCode: function() {
wx.showLoading({ title: "生成二维码…", mask: !0 })
r.callCloud("seating", "generateSeatCode", { eventId: n, title: a.data.seatCodeTitle });
a.setData({ seatCodeImageUrl: "data:image/png;base64,".concat(s.base64) })
}交互路径:
我方路径证据 1:工具包进入礼金簿。出处:mobile/lib/features/home/views/toolkit_screen.dart:101
_ToolkitCard(
title: '礼金簿',
description: '记录收到和送出的礼金,按亲友维度统计收支情况,清晰了解往来账目',
onTap: () => context.push('/toolkit/gift-ledger'),
)我方路径证据 2:礼金簿页可进入亲友管理,也可新增记录。出处:mobile/lib/features/gift_ledger/views/gift_ledger_screen.dart:152
IconButton(
tooltip: '亲友管理',
onPressed: () async {
await context.push('/toolkit/family-friends');
ref.read(giftLedgerControllerProvider.notifier).load();
},
),
IconButton(
tooltip: '添加记录',
onPressed: () async {
final saved = await GiftRecordFormSheet.show(context, mode: GiftRecordFormMode.create);
if (saved == true) ref.read(giftLedgerControllerProvider.notifier).load();
},
)我方路径证据 3:礼金表单字段链路。出处:mobile/lib/features/gift_ledger/widgets/gift_record_form_sheet.dart:634
_RadioItem(label: '收到', onTap: () => _setDirection(GiftDirection.receive)),
_RadioItem(label: '送出', onTap: () => _setDirection(GiftDirection.give)),
FamilyMemberSelector(onMemberSelected: (member) { unawaited(_handleMemberSelected(member)); }),
_SelectField<String>(items: _giftEventOptions, onChanged: (opt) => _setGiftEvent(opt)),
_InputField(prefixText: '¥', hintText: '0.00'),
_SelectField<GiftMethod>(items: GiftMethod.values, itemLabel: (m) => m.title),
_DateButton(date: _eventDate, onTap: _pickDate),我方路径证据 4:保存按钮。出处:mobile/lib/features/gift_ledger/widgets/gift_record_form_sheet.dart:1251
ElevatedButton(
onPressed: canSave ? onSave : null,
)对方路径证据 1:宾客页打开礼金页/座位页。出处:wx3f22282982586c02_unpacked/app-service.js:41837
openGiftBook: function() {
wx.navigateTo({ url: "/pages/gifts/index" })
},
openSeatEditor: function() {
wx.navigateTo({ url: "/pages/seating/index" })
}对方路径证据 2:礼金页打开表单、选择类型/事项/日期/金额。出处:wx3f22282982586c02_unpacked/app-service.js:40211
openGiftSheet: function() {
this.setData({ "giftSheet.visible": !0, giftForm: h(), selectedGiftOccasionLabel: p[0] })
},
onGiftTypeChange: function(t) { this.setData({ "giftForm.typeIndex": Number(t.detail.value) }) },
onGiftOccasionPillChange: function(t) { this.setData({ "giftForm.occasionIndex": a >= 0 ? a : 0 }) },
onGiftDateChange: function(t) { this.setData({ "giftForm.date": t.detail.value }) },
onGiftInput: function(t) { ... this.setData({ "giftForm.amount": e }) }对方路径证据 3:校验联系人和金额后保存。出处:wx3f22282982586c02_unpacked/app-service.js:40401
if (!t.data.giftForm.selectedContactId) return wx.showToast({ title: "请先选择联系人", icon: "none" })
if (n = Number(t.data.giftForm.amount)) { ... } else return wx.showToast({ title: "请输入金额", icon: "none" })
r.callCloud("contacts", "createGift", {
amount: n,
contactId: t.data.giftForm.selectedContactId,
date: t.data.giftForm.date || c(new Date),
occasion: p[t.data.giftForm.occasionIndex],
remark: t.data.giftForm.remark.trim(),
type: f[t.data.giftForm.typeIndex]
});交互路径:
我方路径证据 1:任务页 Tab 和任务列表点击。出处:mobile/lib/features/tasks/views/tasks_screen.dart:235
IconButton(onPressed: () => context.push('/tasks/add'), tooltip: '添加任务'),
TabBar(tabs: const [Tab(text: '总览'), Tab(text: '待开始'), Tab(text: '进行中'), Tab(text: '已完成')]),
TaskProgress(tasks: taskState.tasks, currentStage: ...),
StageProgress(tasks: taskState.tasks),
TaskListView(onTaskTap: (task) => context.push('/tasks/detail/${task.id}')),我方路径证据 2:任务模板动作直达座位表能力。出处:mobile/lib/features/tasks/utils/task_actions.dart:101
if (task.templateId == 'TPL_CONFIRMATION_14') {
return TaskActionConfig(label: '安排座位', action: (ctx, r) async => ctx.push('/toolkit/seating-chart'));
}对方路径证据 1:任务编辑弹层与阶段字段。出处:wx3f22282982586c02_unpacked/app-service.js:34480
taskEditorSheet: {
visible: !1,
stage: "",
taskId: "",
title: "添加任务",
submitText: "添加",
form: { deadline: "", description: "", name: "" }
}对方路径证据 2:添加/编辑任务弹层。出处:wx3f22282982586c02_unpacked/app-service.js:34756
this.setData({
taskEditorSheet: {
mode: "create",
visible: !0,
stage: t,
title: "添加任务",
submitText: "添加",
form: { deadline: a && a.date ? r(a.date) : r(new Date), description: "", name: "" }
}
})出处:wx3f22282982586c02_unpacked/app-service.js:34772
openEditTaskSheet: function(e) {
a && this.setData({
taskEditorSheet: {
mode: "edit",
visible: !0,
stage: a.stage,
taskId: a._id,
title: "编辑任务",
submitText: "保存"
}
})
}对方路径证据 3:从阶段时间线聚焦任务。出处:wx3f22282982586c02_unpacked/app-service.js:34808
focusTaskFromTimeline: function(e) {
var n = a.stage, s = a.taskId;
if (s && n) {
var i = f(n);
this.closeTimelineSheet();
setTimeout(function() {
t.applyTaskViews(t.data.allTasks, { expandedState: i, onRendered: function() { return t.scrollToTask(s) } })
}, 220)
}
}对方路径证据 4:提交任务时校验名称、日期和当前婚礼活动。出处:wx3f22282982586c02_unpacked/app-service.js:34836
submitTaskEditor: function() {
if (!(u && u.trim())) return wx.showToast({ title: "请输入任务名称", icon: "none" })
if (!d) return wx.showToast({ title: "请选择截止日期", icon: "none" })
if (p = getApp().globalData.currentEvent) { ... } else return wx.showToast({ title: "请先选择婚礼", icon: "none" })
}交互路径:
我方路径证据:mobile/lib/features/budget/views/budget_screen.dart:170
if (_tabController.index == 1)
IconButton(
icon: Icon(Icons.add, size: 24),
onPressed: () => context.push('/budget/add-expense'),
),
ExpenseListView(
onExpenseTap: (control) => context.push('/budget/expense/${control.id}'),
onExpenseEdit: (control) => context.push('/budget/edit-expense/${control.id}'),
)我方路径证据:mobile/lib/features/budget/views/add_edit_expense_screen.dart:1086
return ExpenseEventEditorSheet(
title: item == null ? '新增支出记录' : '编辑支出记录',
initialDate: item?.expenseDate ?? DateTime.now(),
)对方路径证据:wx3f22282982586c02_unpacked/app-service.js:36307
openRecords: function() {
wx.navigateTo({ url: "/pages/budgetRecords/index" })
}对方路径证据:wx3f22282982586c02_unpacked/app-service.js:37586
return wx.showToast({ title: "请选择支出分类", icon: "none" })
return wx.showToast({ title: "请选择支出日期", icon: "none" })对方路径证据:wx3f22282982586c02_unpacked/app-service.js:37830
wx.showModal({
title: "删除记录",
content: "确定删除这条支出记录?",
confirmText: "删除",
cancelText: "取消"
});交互路径:
我方路径证据 1:首页“今日事项”直达日历指定日期。出处:mobile/lib/features/home/widgets/quick_actions.dart:28
_buildActionItem(
title: '今日事项',
subtitle: '日程安排',
onTap: () {
final today = DateTime.now().millisecondsSinceEpoch;
context.push('/calendar?selectedDate=$today');
},
)我方路径证据 2:日历日期下聚合任务、回忆、支出标记。出处:mobile/lib/features/calendar/widgets/multi_dimension_marker.dart:46
for (final task in [...activeTasks, ...completedTasks]) {
markerItems.add(_MarkerItem(type: _MarkerType.task, text: task.displayTitle));
}
for (final memory in data.memories) {
markerItems.add(_MarkerItem(type: _MarkerType.memory, text: memory.displayTitle));
}
if (data.expenses.isNotEmpty) {
final totalAmount = data.totalExpenseAmount;
}我方路径证据 3:当日任务列表点击进入任务详情。出处:mobile/lib/features/calendar/widgets/today_detail/today_tasks_section.dart:91
onTap: () {
context.push('/tasks/detail/${task.id}');
}对方路径证据 1:首页打开日历页。出处:wx3f22282982586c02_unpacked/app-service.js:22635
openCalendarPage: function(e) {
var t = "string" == typeof e ? e.trim() : "";
wx.navigateTo({
url: t ? "/pages/calendar/index?date=".concat(t) : "/pages/calendar/index"
})
}对方路径证据 2:日历页构建日期格,包含婚期、纪念日、任务截止标记。出处:wx3f22282982586c02_unpacked/app-service.js:38498
y.push({
dateKey: I,
isAnniversary: L.length > 0,
isSelected: I === t,
isTaskDeadline: N.length > 0,
isToday: I === o,
isWeddingDate: r === I,
taskCount: N.length
})对方路径证据 3:点击日历任务跳转清单页并携带定位信息。出处:wx3f22282982586c02_unpacked/app-service.js:38753
openTaskInTasks: function(e) {
var a = e.currentTarget.dataset,
t = a.stage,
n = a.taskId,
r = getApp(),
s = r.globalData.currentEvent;
s && s._id && n && (r.globalData.pendingTaskJump = {
eventId: s._id,
stage: t || "",
taskId: n
}, wx.switchTab({ url: "/pages/tasks/index" }))
}