Ionic 3 数据展示问题:按学生分组显示扫描时间
Ionic 3 考勤数据分组展示解决方案
我来帮你搞定这个数据展示的问题!目前你的代码会把每个学生的每条扫描记录都单独渲染一次姓名,导致重复显示。核心问题是数据没有按学生分组,我们只需要把同一个学生的所有扫描时间聚合到一起,就能实现你想要的效果。
问题分析
当前你的API返回的是扁平结构的数组,每条扫描记录对应一条学生数据(比如Wafi Dania有两条扫描记录,就会返回两条带她姓名的条目)。前端*ngFor循环时会逐条渲染,所以姓名重复出现。我们需要把数据整理成「学生→多条扫描时间」的层级结构。
解决方案步骤
1. 前端处理数据分组(TS代码修改)
在获取到API数据后,我们先按pelajar_id(学生ID,比姓名更可靠)分组,把同一个学生的所有扫描时间收集到一个数组里:
getAttendance(){ this.restProvider.getAttendance().then(data => { // 初始化分组对象 const groupedStudents = {}; // 遍历原始数据,按学生ID分组 (data as any[]).forEach(record => { // 如果该学生还没在分组里,先创建基础结构 if (!groupedStudents[record.pelajar_id]) { groupedStudents[record.pelajar_id] = { pelajar_id: record.pelajar_id, pelajar_nama: record.pelajar_nama, scanTimes: [] }; } // 格式化扫描时间为 hh:mm:ss 格式,添加到对应学生的时间数组 const formattedTime = new Date(record.jadual_scan).toLocaleTimeString('en-GB', { hour: '2-digit', minute: '2-digit', second: '2-digit' }); groupedStudents[record.pelajar_id].scanTimes.push(formattedTime); }); // 把分组对象转换为数组,供前端模板循环使用 this.data = Object.values(groupedStudents); console.log('分组后的数据:', this.data); }); }
2. 修改HTML模板,渲染分组后的数据
现在数据已经是「学生+多条时间」的结构,模板可以先循环每个学生,再循环该学生的所有扫描时间:
<ion-label> Date: {{myDate}} </ion-label> <!-- 循环每个学生 --> <ion-list *ngFor="let student of data"> <!-- 学生姓名标题行 --> <ion-item color="primary"> <ion-label><h2>{{student.pelajar_nama}}</h2></ion-label> </ion-item> <!-- 扫描时间表格 --> <ion-grid> <!-- 表头 --> <ion-row color="primary"> <ion-col> Scan </ion-col> <ion-col> Time </ion-col> </ion-row> <!-- 循环该学生的所有扫描时间 --> <ion-row *ngFor="let time of student.scanTimes"> <ion-col> Scan </ion-col> <ion-col> {{ time }} </ion-col> </ion-row> </ion-grid> </ion-list>
可选:后端API直接返回分组数据(Laravel优化)
如果你想在后端完成分组,减少前端逻辑,可以修改Laravel的查询代码,用GROUP_CONCAT聚合扫描时间:
$parentId = \Auth::guard('api')->user()->id; $student = DB::table('pelajar') ->join('jadual','jadual.pelajar_id','pelajar.pelajar_id') ->select( 'pelajar.pelajar_id', 'pelajar.pelajar_nama', // 聚合扫描时间为逗号分隔的字符串 DB::raw("GROUP_CONCAT(DATE_FORMAT(jadual.jadual_scan, '%H:%i:%s') SEPARATOR ',') as scan_times") ) ->whereDate('jadual.jadual_scan', DB::raw('CURDATE()')) ->where('pelajar.penjaga_id',$parentId) ->groupBy('pelajar.pelajar_id', 'pelajar.pelajar_nama') ->orderBy('pelajar.pelajar_id','asc') ->get(); // 把聚合的字符串拆分为数组,方便前端使用 $student = $student->map(function($item) { $item->scan_times = explode(',', $item->scan_times); return $item; }); return $student;
这种情况下,前端TS代码不需要做分组,直接用student.scan_times循环即可。
最终效果
修改完成后,页面会按你期望的方式展示:每个学生姓名只显示一次,下方列出该学生当天所有的扫描时间。
内容的提问来源于stack exchange,提问作者MrlinY
相关产品推荐
相关产品推荐

