
本文介绍如何对多条含相同服务名称但不同时长/价格的数据进行预处理,按服务名称分组、合并时长与价格,并动态生成结构正确的html表格,避免重复行、实现“一行一服务、一列一时长”的标准二维布局。
本文介绍如何对多条含相同服务名称但不同时长/价格的数据进行预处理,按服务名称分组、合并时长与价格,并动态生成结构正确的html表格,避免重复行、实现“一行一服务、一列一时长”的标准二维布局。
在构建服务类价格表格(如SPA护理、按摩项目)时,原始数据常以扁平化方式存储:每个「服务名 + 时长 + 价格」为独立数组项。直接遍历渲染会导致同一服务多次重复出现在不同行中,无法形成「服务名横向展开、时长纵向对齐」的专业表格结构。核心问题在于:需先按服务名称归组,再按预定义时长维度(如 '45min'、'1h'、'1,5h'、'2h')填充对应单元格。
✅ 正确思路:两阶段处理
- 预聚合(Group & Normalize):将原始 $tableRow 按 name 合并,使每个服务对应一个包含 slot[] 和 price[] 的子数组;
-
结构化渲染(Matrix Fill):遍历预定义的时长键(如 ['45min','1h','1,5h','2h']),对每行服务查找匹配时长索引,填入对应价格;未匹配则留空
。
? 实现代码(优化版)
// Step 1: 按服务名归组,构建 slot-price 映射
$grouped = [];
foreach ($tableRow as $item) {
$name = $item['name'];
if (!isset($grouped[$name])) {
$grouped[$name] = [
'id' => $item['id'],
'slot' => [],
'price'=> []
];
}
$grouped[$name]['slot'][] = $item['slot'];
$grouped[$name]['price'][] = $item['price'];
}
// 转为索引数组便于 foreach
$grouped = array_values($grouped);
// Step 2: 定义标准时长序列(确保表头与列顺序一致)
$standardSlots = ['45min', '1h', '1,5h', '2h', '2,5h', '3h'];
// Step 3: 渲染表头(仅显示数据中存在的时长)
$table = '<div class="product-table-wrap product-table-responsive">
<table class="product-table">
<thead class="product-table-head"><tr class="product-table-row">
<th class="product-table-cell category-title"><span class="product-pricing-text">'.$cat_name.'</span></th>';
foreach ($standardSlots as $slot) {
// 统计该时长是否在原始数据中出现过(更健壮:遍历 $tableRow 而非依赖 $arr_a)
$hasSlot = false;
foreach ($tableRow as $row) {
if ($row['slot'] === $slot) {
$hasSlot = true;
break;
}
}
if ($hasSlot) {
$table .= '<th class="product-table-cell product-duration"><span class="product-pricing-text">'.htmlspecialchars($slot).'</span></th>';
}
}
$table .= '</tr></thead>
<tbody class="product-table-body">';
// Step 4: 渲染每行服务(关键:按 standardSlots 顺序逐列匹配)
foreach ($grouped as $service) {
$table .= '<tr>';
$table .= '<td class="product-table-cell category-title"><span class="product-pricing-text">'.htmlspecialchars($service['name']).'</span></td>';
foreach ($standardSlots as $slot) {
$index = array_search($slot, $service['slot']);
if ($index !== false && isset($service['price'][$index])) {
$price = htmlspecialchars($service['price'][$index]);
$table .= '<td class="product-table-cell product-duration"><a href="#" class="product-pricing-text">'.$price.'</a></td>';
} else {
$table .= '<td class="product-table-cell product-duration"></td>';
}
}
$table .= '</tr>';
}
$table .= '</tbody>
</table>
</div>';
⚠️ 注意事项与最佳实践
- 安全输出:始终对 $service['name'] 和 $price 使用 htmlspecialchars(),防止 XSS;
- 时长标准化:确保 $standardSlots 与后端/数据库中的时长格式完全一致(如 '1,5h' vs '1.5h');
- 空值鲁棒性:array_search() 返回 false(非 -1),需用 !== false 严格判断;
- 性能提示:若数据量极大(>1000 行),可预先构建 slot → index 哈希映射提升查找效率;
- 扩展性:如需支持多货币、含税价等,可将 price 改为关联数组(如 ['amount'=>'77', 'currency'=>'€'])。
通过此方案,原始 10 条扁平数据被精准聚合成 5 行结构化表格,每行代表唯一服务,每列对应标准时长,真正实现「所见即所需」的专业展示效果。











