
本文介绍如何将分散的同名服务(如“coconut care”)按不同服务时长(如“1h”“1,5h”)归并为单行,并在对应时长列中精准填入价格,避免重复行和错位显示。核心在于预处理数据结构,实现按服务名称分组、按时间槽位对齐。
本文介绍如何将分散的同名服务(如“coconut care”)按不同服务时长(如“1h”“1,5h”)归并为单行,并在对应时长列中精准填入价格,避免重复行和错位显示。核心在于预处理数据结构,实现按服务名称分组、按时间槽位对齐。
在构建动态服务价格表(如按摩项目按45分钟、1小时、1.5小时等分栏展示)时,原始数据常以扁平化数组形式存在——每个服务时长单独占一行。但理想表格应每项服务仅占一行,各时长价格横向对齐至对应列。直接 foreach 遍历原始数组会导致同一服务重复出现多行,且价格无法自动匹配到正确列。解决方案是:先重组数据结构,再按槽位顺序渲染单元格。
✅ 步骤一:按服务名称归并数据
使用 array_reduce() 将原始 $tableRow 数组按 'name' 字段聚合成分组结构。每组包含:
- 'name' 和 'id'(保留唯一标识)
- 'slot' => array(...):该服务支持的所有时长列表
- 'price' => array(...):对应时长的价格列表(严格一一对应)
$tableRow = array_reduce($tableRow, function($carry, $item) {
// 查找是否已存在同名服务
$matchIndex = -1;
foreach ($carry as $i => $row) {
if ($row['name'] === $item['name']) {
$matchIndex = $i;
break;
}
}
if ($matchIndex >= 0) {
// 已存在:追加 slot 和 price
$carry[$matchIndex]['slot'][] = $item['slot'];
$carry[$matchIndex]['price'][] = $item['price'];
} else {
// 新服务:初始化 slot 和 price 为数组
$carry[] = [
'name' => $item['name'],
'id' => $item['id'],
'slot' => [$item['slot']],
'price'=> [$item['price']]
];
}
return $carry;
}, []);
? 提示:array_replace() 在此场景易出错(键覆盖风险),推荐直接构造关联数组,语义更清晰、容错性更强。
✅ 步骤二:动态生成表头(仅含实际存在的时长)
基于预定义的时长模板(如 ["45min", "1h", "1,5h", "2h"]),用 array_count_values() 统计各时长出现频次,仅渲染频次 > 0 的列:
$availableSlots = ["45min", "1h", "1,5h", "2h", "2,5h", "3h"];
$arrA = array_count_values(array_column($originalTableRows, 'slot')); // 更健壮:从原始数据提取
$table .= '<thead><tr>
<th class="category-title">'.$cat_name.'</th>';
foreach ($availableSlots as $slot) {
if (isset($arrA[$slot]) && $arrA[$slot] > 0) {
$table .= '<th class="product-duration"><span>'.$slot.'</span></th>';
}
}
$table .= '</tr></thead>';
✅ 步骤三:逐行渲染,按槽位精确匹配价格
遍历归并后的 $tableRow,对每个服务项,依次检查其 'slot' 数组中是否包含当前列时长。若匹配,则填入对应索引的 'price';否则填空
$table .= '<tbody>';
foreach ($tableRow as $row) {
$table .= '<tr>';
$table .= '<td class="category-title">'.$row['name'].'</td>';
foreach ($availableSlots as $slot) {
$index = array_search($slot, $row['slot']);
if ($index !== false) {
$price = htmlspecialchars($row['price'][$index]); // 防XSS
$table .= '<td class="product-duration"><a href="#" class="product-pricing-text">'.$price.'</a></td>';
} else {
$table .= '<td></td>';
}
}
$table .= '</tr>';
}
$table .= '</tbody>';
⚠️ 注意事项与优化建议
- 时长格式一致性:确保所有 'slot' 值(如 "1h" 与 "1,5h")严格匹配表头定义,避免空格、大小写或符号差异导致匹配失败。
- HTML 安全性:对 $row['price'] 等用户输入内容使用 htmlspecialchars() 转义,防止 XSS。
- 性能考量:若数据量极大(>1000 行),可将 $availableSlots 转为 array_flip() 哈希表加速查找。
- 扩展性:后续支持新增时长(如 "30min")只需扩展 $availableSlots 数组,无需修改核心逻辑。
通过以上三步重构,你将得到结构清晰、列对齐准确的服务价格表——每个服务一行,价格精准落入对应时长列,彻底解决原始代码中“一服务多行”和“价格错列”的问题。











