电影院选座,是一个非常经典但实现难度并不低的交互场景。
它不仅需要:
动态展示座位布局
实时更新座位状态
区分“自己已购买”和“别人已占用”
更关键的是:必须解决并发问题。
例如:
两个用户同时点击同一个座位时, 系统必须保证:
最终只有一个人下单成功。
很多系统会尝试通过前端刷新解决, 但实际上真正可靠的方案, 一定来自数据库底层约束。
本文将带你使用 Zion:
通过 “嵌套列表 + 条件式容器 + 联合唯一约束” ,
搭建一个真正具备防冲突能力的选座系统。
如何在 Zion 中构建
数据模型设计
我们需要五张表来管理用户、场次、物理布局和交易记录。
数据库表结构
1. 帐户表系统自带,记录用户信息。
2. 场次表用于区分不同时间段的占用情况。
3. 排表外层列表数据源,定义座位的纵向层级。
4. 座位表内层列表数据源,定义具体的物理坐标。
5. 订单表业务核心表,通过“唯一约束”实现防冲突。
配置唯一约束
为了防止物理重叠和重复预订,需要配置两项约束:
物理空间约束:在“座位表”中添加名为 uk_row_seat 的联合唯一约束,选择字段 排_id + 序号。确保同一排下不会出现重复位置。
业务逻辑约束:在“订单表”中添加名为 uk_session_seat 的联合唯一约束,选择字段 场次_id + 座位_id。确保同一场次下,一个座位只能产生一笔订单。
使用 Zion 的“导入”功能,通过 Excel/CSV 文件可以快速填充行和座位数据。
点击文末【阅读原文】获取
[排数据样例.xlsx]
[座位数据样例.xlsx]
UI搭建与交互配置
外层列表:排
在画布中添加一个列表组件。
在右侧“数据”面板:
数据源:选择“远程数据”。
数据表:选择“排”。
排序:添加按“序号”升序排列。
在列表项内添加一个文本组件,内容绑定为 [当前项].[名称]。
内层列表:座位
在“列表”的列表项内部嵌套第二个列表组件。
在“设计”面板将布局设置为横向排列。
在右侧“数据”面板:
数据表:选择“座位”。
数据筛选:添加条件 排_id等于[外层列表.当前项].[id]。这是实现嵌套显示的核心。
排序:按“序号”升序排列。
交互逻辑配置
在内层“列表 座位”中放入一个条件式容器,根据座位的不同状态显示对应的 UI。
1. 无 (走廊/空位) 分支
条件:[当前项].[类型]等于none。
UI:保持空白或隐藏,作为走廊。
2. 已购买 (当前用户) 分支
条件:查询“订单表”,筛选 座位_id 等于当前项 ID,场次_id 等于当前场次,且 用户_id 等于 [当前用户].[id]。若数量等于 1,则当前用户拥有此座。
UI:显示蓝色勾选图标。
3. 已占用 (其他用户) 分支
条件:查询“订单表”,筛选 座位_id 等于当前项 ID,场次_id 等于当前场次,且 用户_id不等于[当前用户].[id]。若数量不等于 0,则他人已占。
UI:显示灰色图标。
4. 可选 (默认) 分支
作为默认分支,无需条件。显示空座位图标。
行为流 (Actionflow) 建设
针对不同状态的点击事件,配置以下逻辑:
取消订单 (已购买状态)
显示弹窗:确认是否取消。
删除 订单:筛选条件为 用户_id 等于当前用户且 座位_id 等于当前座位。
切换视图条件:切回“可选”状态。
占座拦截 (已占用状态)
显示提示:显示“当前座位已被预定”。
提交下单 (可选状态)
显示弹窗:确认选座。
添加 订单:映射 用户_id、场次_id 和 座位_id。
关键步骤:在冲突行为中选择 uk_session_seat,行为类型选“无”。
条件分支:
下单成功:判断 [添加动作].[id] 是否非空。若是,显示成功提示并切换视图至“已购买”。
下单失败:若 ID 为空(触发了数据库唯一约束),显示“座位已被抢占”并切换视图至“已占用”。
验证
第一步:初始预订 (用户 1)
以用户 1 身份登录,选择 A 排 2 座,确认预订。
座位图标立即变为蓝色(已购买状态)。
第二步:并发会话 (用户 2)
开启无痕窗口以用户 2 身份登录。
观察到 A 排 2 座已显示为灰色(已占用),证明条件式容器生效。
用户 2 成功预订 B 排 3 座。
第三步:冲突拦截 (用户 1)
回到用户 1 的窗口(页面未刷新),B 排 3 座仍显示为黑色(可选)。
用户 1 尝试点击并确认预订 B 排 3 座。
点击确认后,数据库拦截器介入:
uk_session_seat 约束阻止了插入。
行为流检测到 ID 为空,触发失败分支。
弹出提示:“该座位已被预定”。
状态回滚:座位图标无需刷新即刻由黑变灰。
第四步:释放资源
用户 1 取消其 A 排 2 座的订单。
唯一约束释放,该座位对所有用户恢复为“可选”状态。
动手尝试并深入学习
嵌套列表非常适合二维布局
条件式容器适合复杂状态 UI
联合唯一约束是防冲突核心
页面状态不能替代数据库约束
数据一致性必须由数据库保证