Laravel按月统计员工出勤天数问题及代码优化需求
修复Laravel按月统计员工出勤天数的功能
我看了你的代码,现在的问题主要集中在没有按选中的年月筛选请假记录、视图里的日期判断逻辑错误,还有一些可以优化的地方。下面是修正后的完整实现:
第一步:优化控制器代码
首先,我们用Laravel自带的Carbon来计算工作日(比自定义函数更简洁可靠),同时按选中的年月筛选请假记录,避免加载所有数据:
use Carbon\Carbon; use Illuminate\Support\Facades\DB; public function employeeAttendance(Request $request) { // 获取选中的年月,默认设为当前年月 $countMonth = $request->get('month', date('m')); $countYear = $request->get('year', date('Y')); // 计算当月工作日总数(排除周六周日) $startDate = Carbon::create($countYear, $countMonth, 1); $endDate = $startDate->copy()->endOfMonth(); $totalWorkingDays = $startDate->diffInDaysFiltered(function(Carbon $date) { return !$date->isWeekend(); }, $endDate); // 获取所有非管理员员工 $employees = User::where('username', '!=', 'admin')->get(); // 按年月统计每个员工的请假天数 $leaveStats = LeaveManagement::whereYear('start', $countYear) ->whereMonth('start', $countMonth) ->select('name', 'type', DB::raw('count(*) as total')) ->groupBy('name', 'type') ->get() ->groupBy('name'); return view('pages.attendance', compact('employees', 'totalWorkingDays', 'leaveStats', 'countMonth', 'countYear')); }
控制器改进点:
- 用
Carbon替代自定义的countDays函数,代码更简洁且不易出错 - 只查询选中年月的请假记录,并用分组统计直接算出每个员工的事假/病假数量,避免视图里的嵌套循环
- 提前过滤掉管理员用户,减少视图里的冗余判断
第二步:修正视图代码
接下来修复视图里的选中状态、请假天数显示逻辑:
<div class="col-md-5 align-self-center"> <h4 class="text-themecolor">{{__('Employee Attendance')}}</h4> </div> </div> <div class="card"> <div class="card-body"> <form action="{{ route('employee_attendance') }}" method="GET"> <select class="custom-select col-md-2" name="month"> <option value="">Select Month</option> <option value="01" {{ $countMonth == '01' ? 'selected' : '' }}>January</option> <option value="02" {{ $countMonth == '02' ? 'selected' : '' }}>February</option> <option value="03" {{ $countMonth == '03' ? 'selected' : '' }}>March</option> <option value="04" {{ $countMonth == '04' ? 'selected' : '' }}>April</option> <option value="05" {{ $countMonth == '05' ? 'selected' : '' }}>May</option> <option value="06" {{ $countMonth == '06' ? 'selected' : '' }}>June</option> <option value="07" {{ $countMonth == '07' ? 'selected' : '' }}>July</option> <option value="08" {{ $countMonth == '08' ? 'selected' : '' }}>August</option> <option value="09" {{ $countMonth == '09' ? 'selected' : '' }}>September</option> <option value="10" {{ $countMonth == '10' ? 'selected' : '' }}>October</option> <option value="11" {{ $countMonth == '11' ? 'selected' : '' }}>November</option> <option value="12" {{ $countMonth == '12' ? 'selected' : '' }}>December</option> </select> <select class="custom-select col-md-2" name="year"> <option value="">Select Year</option> <?php for ($year = 2000; $year <= 2050; $year++) { $selected = ($countYear == $year) ? 'selected' : ''; echo "<option value=$year $selected>$year</option>"; } ?> </select> <button class="btn btn-info" type="submit"><i class="fa fa-search "></i></button> <span style="float:right" class = "btn btn-info" disabled>Total Working Days : {{ $totalWorkingDays }} </span> </form> <div class="table-responsive m-t-40"> <table class="table table-bordered table-striped "> <thead> <tr> <th>Employee Name</th> <th>Present Day</th> <th>Casual Leave</th> <th>Medical Leave</th> </tr> </thead> <tbody> @foreach ($employees as $emp) @php $empName = $emp['personal_detail']['first_name']; // 获取该员工当月的请假统计,默认0 $casualCount = $leaveStats->get($empName)?->where('type', 'casual')->first()?->total ?? 0; $medicalCount = $leaveStats->get($empName)?->where('type', 'medical')->first()?->total ?? 0; $totalLeave = $casualCount + $medicalCount; $presentDay = $totalWorkingDays - $totalLeave; // 确保出勤天数不为负数 $presentDay = max($presentDay, 0); @endphp <tr> <td> {{ $empName }} </td> <td> {{ $presentDay }} </td> <td> {{ $casualCount }} </td> <td> {{ $medicalCount }} </td> </tr> @endforeach </tbody> </table> </div> </div> </div> </div> </div>
视图改进点:
- 修复了年月选择框的选中状态,现在选中后会保持高亮
- 移除了嵌套循环,直接用控制器提前统计好的
$leaveStats获取每个员工的请假数,性能更好 - 修复了之前视图里日期判断的错误(之前在循环外引用
$empleave会拿到最后一条记录的日期) - 添加了
max($presentDay, 0)确保出勤天数不会出现负数(比如请假天数超过工作日的情况)
额外建议
如果你的LeaveManagement模型和User模型之间有关联(比如user_id字段),建议用关联查询替代按name匹配,这样更可靠(避免重名问题):
- 在
LeaveManagement模型里添加关联:public function user() { return $this->belongsTo(User::class); } - 控制器里的请假统计改为按
user_id分组,视图里用用户ID匹配
内容的提问来源于stack exchange,提问作者amin devloper
相关产品推荐
相关产品推荐

