嵌套列表选座功能
项目访问链接
https://zion.functorz.com/tool/nwLdKMXK0yg/WEB?code=c8sKlFmEB1qY2&ref=5316313
场景与目标
- 目标:实现具备防冲突能力的选座功能,利用嵌套列表展示布局,并通过数据库唯一约束拦截重复下单。
- 适用场景:电影选座、场馆预约、餐厅订座或任何基于网格的资源分配场景。
- 核心逻辑:使用“嵌套列表”(排 -> 座位)实现布局。利用数据库的“联合唯一约束”在底层确保数据一致性,从根本上杜绝同一座位被多人同时预订。
实现步骤
数据模型设计
我们需要五张表来管理用户、场次、物理布局和交易记录。
数据库表结构
1. 帐户表 系统自带,记录用户信息。
| 字段名称 | 类型 | 说明 |
|---|---|---|
id | 长整数 | 用户唯一标识 |
2. 场次表 用于区分不同时间段的占用情况。
| 字段名称 | 类型 | 说明 |
|---|---|---|
id | 长整数 | 区分不同场次 |
3. 排表 外层列表数据源,定义座位的纵向层级。
| 字段名称 | 类型 | 说明 |
|---|---|---|
名称 | 文本 | 如:A排、1排 |
序号 | 长整数 | 决定排在界面上的显示先后顺序 |
4. 座位表 内层列表数据源,定义具体的物理坐标。
| 字段名称 | 类型 | 说明 |
|---|---|---|
序号 | 长整数 | 决定该排内座位的横向排列顺序 |
类型 | 文本 | seat (座位) 或 none (走廊/空位) |
排_id | 长整数 | 关联关系:多对一关联至“排表” |
5. 订单表 业务核心表,通过“唯一约束”实现防冲突。
| 字段名称 | 类型 | 说明 |
|---|---|---|
用户_id | 长整数 | 关联至“帐户表”,记录购买者 |
场次_id | 长整数 | 关联至“场次表”,锁定特定场次 |
座位_id | 长整数 | 关联至“座位表”,锁定特定座位 |

配置唯一约束
为了防止物理重叠和重复预订,需要配置两项约束:
- 物理空间约束:在“座位表”中添加名为
uk_row_seat的联合唯一约束,选择字段排_id+序号。确保同一排下不会出现重复位置。
- 业务逻辑约束:在“订单表”中添加名为
uk_session_seat的联合唯一约束,选择字段场次_id+座位_id。确保同一场次下,一个座位只能产生一笔订单。
使用 Zion 的“导入”功能,通过 Excel/CSV 文件可以快速填充行和座位数据。
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 座的订单。
- 唯一约束释放,该座位对所有用户恢复为“可选”状态。



Last updated on