
本文介绍如何从数据库动态加载旅游景点、住宿等服务选项为复选框列表,并针对“按人计费”(如门票、酒店)和“按团计费”(如整箱啤酒、包车接送)两类价格策略,实现精准、可扩展的总价计算逻辑。
本文介绍如何从数据库动态加载旅游景点、住宿等服务选项为复选框列表,并针对“按人计费”(如门票、酒店)和“按团计费”(如整箱啤酒、包车接送)两类价格策略,实现精准、可扩展的总价计算逻辑。
在定制化船旅服务系统中,需灵活呈现可选项目(如景点、住宿、附加服务),并支持客户通过复选框自主选择。关键挑战在于:多数费用(如景区门票、酒店房费)需乘以游客人数($ppl),而部分服务(如“Case of beer”“Van Transfer Sibaltan”)属整团一次性收费,与人数无关。若硬编码判断条件(如 if ($place === 'Case of beer')),将导致逻辑耦合度高、难以维护。
推荐采用数据驱动 + 策略映射方式实现解耦与可扩展性。核心思路是:将计费规则(per-person 或 per-boat)作为元数据,与地点数据一同存入数据库(例如新增字段 charge_mode ENUM('per_person', 'per_group')),或在 PHP 层维护一个轻量级配置数组:
// 定义按团计费的服务列表(可来自数据库配置表)
$per_group_services = [
'Case of beer',
'Van Transfer Sibaltan',
'Boat Fuel Surcharge',
'Captain Gratuity'
];
// 从数据库获取所有可选项目(含名称、单价、计费模式)
$places = $pdo->query("
SELECT name, price, charge_mode
FROM tour_options
WHERE status = 'active'
")->fetchAll(PDO::FETCH_ASSOC);渲染复选框时,结合用户已选状态(如来自 $_POST['spots'] 或会话缓存),统一输出:
<?php foreach ($places as $spot): ?>
<?php
$is_checked = in_array($spot['name'], $spotsarray ?? []);
$price = (float)$spot['price'];
$is_per_group = in_array($spot['name'], $per_group_services);
$item_cost = $is_per_group ? $price : $price * $ppl;
?>
<label>
<input
type="checkbox"
name="spots[]"
value="<?= htmlspecialchars($spot['name']) ?>"
<?= $is_checked ? 'checked' : '' ?>
>
<?= htmlspecialchars($spot['name']) ?>
– ₱<?= number_format($price, 2) ?>
(<?= $is_per_group ? 'Per group' : "Per person × {$ppl}" ?>)
</label><br>
<?php endforeach; ?>总价计算应在服务端严格校验后执行(切勿依赖前端传入的金额)。使用循环遍历已选项目,依据其计费模式动态累加:
$total_cost = 0.0;
$selected_spots = $_POST['spots'] ?? [];
foreach ($selected_spots as $selected_name) {
// 从数据库或预加载数组中查找对应项(含 price 和 charge_mode)
$matched = array_filter($places, fn($p) => $p['name'] === $selected_name);
if (empty($matched)) continue;
$item = current($matched);
$price = (float)$item['price'];
if ($item['charge_mode'] === 'per_group') {
$total_cost += $price;
} else {
$total_cost += $price * $ppl;
}
}
echo "<p><strong>Total Estimated Cost:</strong> ₱" . number_format($total_cost, 2) . "</p>";⚠️ 重要注意事项:
-
安全第一:始终对输出到 HTML 的
$spot['name']和$price执行htmlspecialchars(),防止 XSS;数据库查询使用 PDO 预处理语句防 SQL 注入。 -
数据一致性:确保数据库中
charge_mode字段值标准化(如仅允许'per_person'/'per_group'),避免运行时类型判断错误。 -
扩展性设计:未来若新增计费模式(如“按房间”“按小时”),只需扩展
charge_mode枚举及计算分支,无需修改渲染逻辑。 - 用户体验:在复选框旁清晰标注计费单位(如“Per group”),避免客户误解费用构成。
通过将业务规则(计费模式)外置为数据而非硬编码逻辑,系统既保持了代码简洁性,又具备面向变化的健壮性——这正是动态旅游报价系统可持续演进的关键基础。



















