diff --git a/controllers/LogsController.php b/controllers/LogsController.php index 6e43f199..d79a62a3 100644 --- a/controllers/LogsController.php +++ b/controllers/LogsController.php @@ -12,6 +12,9 @@ use app\models\Device; use app\models\EventType; use app\models\Department; use app\models\common; +use app\models\StaffSearch; +use yii\helpers\Url; +use app\models\Staff; /** * LogsController implements the CRUD actions for Logs model. @@ -91,6 +94,38 @@ class LogsController extends Controller { ]); } + public function actionStatistics($day = "") { + $day = $day === "" ? date("d/m/Y") : $day; + $f = date_format(date_create_from_format('H:i:s d/m/Y', "00:00:00 " . $day), 'U'); + $t = date_format(date_create_from_format('H:i:s d/m/Y', "23:59:59 " . $day), 'U'); + $query = Logs::find(); + $query->andWhere(["BETWEEN", 'time', $f, $t]); + $query->orderBy(["time" => SORT_ASC]); + $logs = $query->all(); + $staffID = []; + $staffLogs = []; + foreach ($logs as $key => $value) { + if ($value->staff_id && $value->event_type == 0) { + $staffID[] = $value->staff_id; + $staffLogs[$value->staff_id][] = $value->time; + } + } + $staffID = array_unique($staffID); + + $this->view->title = 'Báo cáo chấm công'; + $searchModel = new StaffSearch(); + $dataProvider = $searchModel->search(Yii::$app->request->queryParams); + $dataProvider->query->andWhere(["IN", "id", $staffID]); + + return $this->render('statistics', [ + 'searchModel' => $searchModel, + 'dataProvider' => $dataProvider, + "departmentArray" => Department::departmentArray(), + "day" => $day, + "staffLogs" => $staffLogs + ]); + } + public function actionExport($from = "", $to = "") { $f = date_format(date_create_from_format('H:i:s d/m/Y', $from), 'U'); $t = date_format(date_create_from_format('H:i:s d/m/Y', $to), 'U'); @@ -172,4 +207,230 @@ class LogsController extends Controller { throw new NotFoundHttpException('The requested page does not exist.'); } + public function actionExportStatisticsForm() { + if (Yii::$app->request->isAjax) { + Yii::$app->response->format = "json"; + return [ + "title" => "Xuất dữ liệu chấm công tháng", + "form" => $this->renderPartial("export", [ + "url" => Url::to(['export-statistics']) + ]) + ]; + } + } + + public function formatLogs($month) { + $month = $month === "" ? date("m/Y") : $month; + $m = explode("/", $month); + $totalsDayOfMonth = cal_days_in_month(CAL_GREGORIAN, $m[0], $m[1]); + $f = date_format(date_create_from_format('H:i:s d/m/Y', "00:00:00 01/" . $month), 'U'); + $t = date_format(date_create_from_format('H:i:s d/m/Y', "23:59:59 " . $totalsDayOfMonth . "/" . $month), 'U'); + $query = Logs::find(); + $query->andWhere(['event_type' => 0]); + $query->andWhere(["BETWEEN", "time", $f, $t]); + $query->orderBy(["time" => SORT_ASC]); + $logs = $query->all(); + + $datas = []; + foreach ($logs as $key => $value) { + $datas[$value->staff_id][date("d", $value->time)][] = $value->time; + } + return $datas; + } + + public function actionExportStatistics($month = "") { + $month = $month === "" ? date("m/Y") : $month; + $m = explode("/", $month); + $totalsDayOfMonth = cal_days_in_month(CAL_GREGORIAN, $m[0], $m[1]); + + $datas = $this->formatLogs($month); + + $objPHPExcel = new \PHPExcel(); + $objPHPExcel->setActiveSheetIndex(0); + $header = ["STT", "Mã nhân viên", "Tên nhân viên", "Phòng ban", "Chỉ số"]; + for ($i = 1; $i <= $totalsDayOfMonth; $i++) { + $header[] = strval($i); + } + $header[] = "Tổng công"; + $header[] = "Tổng giờ công"; + $toExcelFile[] = $header; + + $departmentArray = Department::departmentArray(); + + $staffs = Staff::find()->all(); + $count = 1; + foreach ($staffs as $key => $value) { + $stats = []; + for ($i = 1; $i <= $totalsDayOfMonth; $i++) { + $in = $out = $manHour = $manDay = 0; + if (isset($datas[$value->id][sprintf("%02d", $i)])) { + $in = $datas[$value->id][sprintf("%02d", $i)][0]; + $totalLogsOfDay = count($datas[$value->id][sprintf("%02d", $i)]); + if ($totalLogsOfDay > 1) + $out = $datas[$value->id][sprintf("%02d", $i)][$totalLogsOfDay - 1]; + if ($in && $out) { + $manHour = number_format(($out - $in) / (60 * 60), 2); + $manDay = number_format(($out - $in) / (60 * 60) / 8, 2); + } + } + $stats[$i] = ["in" => $in, "out" => $out, "manHour" => $manHour, "manDay" => $manDay]; + } + $ExportData[] = $count++; + $ExportData[] = $value->code; + $ExportData[] = $value->name; + $ExportData[] = isset($departmentArray[$value->department_id]) ? $departmentArray[$value->department_id] : ""; + $ExportData[] = "Vào"; + for ($i = 1; $i <= $totalsDayOfMonth; $i++) { + $ExportData[] = $stats[$i]["in"] ? date("H:i", $stats[$i]["in"]) : ""; + } + $toExcelFile[] = $ExportData; + unset($ExportData); + $ExportData[] = ""; + $ExportData[] = ""; + $ExportData[] = ""; + $ExportData[] = ""; + $ExportData[] = "Ra"; + for ($i = 1; $i <= $totalsDayOfMonth; $i++) { + $ExportData[] = $stats[$i]["out"] ? date("H:i", $stats[$i]["out"]) : ""; + } + $toExcelFile[] = $ExportData; + unset($ExportData); + $ExportData[] = ""; + $ExportData[] = ""; + $ExportData[] = ""; + $ExportData[] = ""; + $ExportData[] = "GC"; + for ($i = 1; $i <= $totalsDayOfMonth; $i++) { + $ExportData[] = $stats[$i]["manHour"] ? $stats[$i]["manHour"] : ""; + } + $toExcelFile[] = $ExportData; + unset($ExportData); + $ExportData[] = ""; + $ExportData[] = ""; + $ExportData[] = ""; + $ExportData[] = ""; + $ExportData[] = "TC"; + for ($i = 1; $i <= $totalsDayOfMonth; $i++) { + $ExportData[] = $stats[$i]["manDay"] ? $stats[$i]["manDay"] : ""; + } + $toExcelFile[] = $ExportData; + unset($ExportData); + } + $totals = count($staffs) + 1; + $activeSheet = $objPHPExcel->getActiveSheet(); + $activeSheet->getColumnDimension('A')->setWidth(6); + $activeSheet->getColumnDimension('B')->setWidth(10); +// $activeSheet->getStyle("A1:I" . $totals)->getFont()->setName('Time New Roman')->setSize(10); +// $activeSheet->getStyle("A1:I1")->applyFromArray([ +// 'fill' => array( +// 'type' => \PHPExcel_Style_Fill::FILL_SOLID, +// 'color' => array('rgb' => '7ac3ec') +// ) +// ]); + $rowCount = 2; + for ($i = 0; $i < count($toExcelFile); $i++) { + $column = 'A'; + $column2 = ''; + $row = $toExcelFile[$i]; + for ($j = 0; $j < count($row); $j++) { + if (!isset($row[$j])) + $value = NULL; + elseif ($row[$j] != "") + $value = strip_tags($row[$j]); + else + $value = ""; + $activeSheet->setCellValue($column . $column2 . $rowCount, $value); + if ($column === "Z") { + $column = "A"; + $column2 = "A"; + } elseif ($column2 !== "") { + $column2 = chr(ord($column2) + 1); + } else { + $column = chr(ord($column) + 1); + } + } + $rowCount++; + } + $tempCol = $column; + $tempCol2 = $column2; + if ($column !== "A") { + $tempCol = chr(ord($tempCol) - 1); + } + if ($column2 !== "") { + $tempCol2 = chr(ord($tempCol2) - 1); + } + $lastDayCol = $tempCol . $tempCol2; + + $beforeMaxCol = $column . $column2; + if ($column2 !== "") { + $column2 = chr(ord($column2) + 1); + } + if ($column !== "A") { + $column = chr(ord($column) + 1); + } + $maxCol = $column . $column2; + + $activeSheet->setCellValue("A1", "BẢNG CHẤM CÔNG CHI TIẾT THÁNG " . $month); + $activeSheet->mergeCells('A1:' . $maxCol . '1'); + $activeSheet->getStyle("A1:" . $maxCol . "1")->applyFromArray([ + 'fill' => array( + 'type' => \PHPExcel_Style_Fill::FILL_SOLID, + 'color' => array('rgb' => '7ac3ec') + ), + 'font' => [ + 'bold' => true + ], + 'alignment' => [ + 'horizontal' => \PHPExcel_Style_Alignment::HORIZONTAL_CENTER + ] + ]); + $currentRow = 3; + foreach ($staffs as $key => $value) { + $activeSheet->mergeCells('A' . $currentRow . ':A' . ($currentRow + 3)); + $activeSheet->mergeCells('B' . $currentRow . ':B' . ($currentRow + 3)); + $activeSheet->mergeCells('C' . $currentRow . ':C' . ($currentRow + 3)); + $activeSheet->mergeCells('D' . $currentRow . ':D' . ($currentRow + 3)); + $activeSheet->getStyle("A" . $currentRow . ":" . $maxCol . ($currentRow + 3))->applyFromArray([ + 'borders' => [ + 'top' => [ + 'style' => \PHPExcel_Style_Border::BORDER_THIN + ], + 'bottom' => [ + 'style' => \PHPExcel_Style_Border::BORDER_THIN + ] + ] + ]); + $activeSheet->setCellValue($beforeMaxCol . $currentRow, "=SUM(F" . ($currentRow + 3) . ":" . $lastDayCol . ($currentRow + 3) . ")"); + $activeSheet->setCellValue($maxCol . $currentRow, "=SUM(F" . ($currentRow + 2) . ":" . $lastDayCol . ($currentRow + 2) . ")"); + $activeSheet->mergeCells($beforeMaxCol . $currentRow . ':' . $beforeMaxCol . ($currentRow + 3)); + $activeSheet->mergeCells($maxCol . $currentRow . ':' . $maxCol . ($currentRow + 3)); + $currentRow += 4; + } + $maxRow = ($totals * 4) + 2; + $activeSheet->getRowDimension('2')->setRowHeight(30); + $activeSheet->getStyle("A2:" . $maxCol . "2")->applyFromArray(['alignment' => ['wrap' => true], 'font' => ['bold' => true]]); + $activeSheet->getStyle("A2:B" . $maxRow)->applyFromArray(['alignment' => ['horizontal' => \PHPExcel_Style_Alignment::HORIZONTAL_CENTER]]); + $activeSheet->getStyle("E2:E" . $maxRow)->applyFromArray(['alignment' => ['horizontal' => \PHPExcel_Style_Alignment::HORIZONTAL_CENTER]]); + $activeSheet->getStyle("A2:E" . $maxRow)->applyFromArray(['alignment' => ['vertical' => \PHPExcel_Style_Alignment::VERTICAL_CENTER]]); + $activeSheet->getStyle("F2:" . $maxCol . $maxRow)->applyFromArray(['alignment' => ['vertical' => \PHPExcel_Style_Alignment::VERTICAL_CENTER, 'horizontal' => \PHPExcel_Style_Alignment::HORIZONTAL_CENTER]]); +// $activeSheet->getStyle("A1:I" . $totals)->applyFromArray([ +// 'alignment' => [ +// 'vertical' => \PHPExcel_Style_Alignment::VERTICAL_CENTER, +// ], +// 'borders' => [ +// 'allborders' => [ +// 'style' => \PHPExcel_Style_Border::BORDER_THIN +// ] +// ] +// ]); + + $objWriter = \PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel2007'); + ob_end_clean(); + header('Content-type: application/vnd.ms-excel'); + header('Content-Disposition: attachment; filename="bang_cham_cong_' . date("YmdHis") . '.xlsx"'); + header('Cache-Control: max-age=0'); + common::SaveViaTempFile($objWriter); + exit(); + } + } diff --git a/helpers/LogsGrid.php b/helpers/LogsGrid.php index 5f3edb72..322daefd 100644 --- a/helpers/LogsGrid.php +++ b/helpers/LogsGrid.php @@ -41,6 +41,13 @@ class LogsGrid extends CommonGrid { }; } + public static function code() { + return function($model) { + $staff = $model->staff; + return $staff ? $staff->code : ""; + }; + } + public static function department($array) { return function($model) use ($array) { $staff = $model->staff; diff --git a/helpers/StaffGrid.php b/helpers/StaffGrid.php index f5aafca1..4e3c5579 100644 --- a/helpers/StaffGrid.php +++ b/helpers/StaffGrid.php @@ -2,6 +2,8 @@ namespace app\helpers; +use app\models\Logs; + class StaffGrid extends CommonGrid { public static function department($array) { @@ -34,4 +36,41 @@ class StaffGrid extends CommonGrid { }; } + public static function timeIn($logs) { + return function($model) use ($logs) { + return date("H:i:s d/m/Y", $logs[$model->id][0]); + }; + } + + public static function timeOut($logs) { + return function($model) use ($logs) { + if (count($logs[$model->id]) > 1) + return date("H:i:s d/m/Y", $logs[$model->id][count($logs[$model->id]) - 1]); + }; + } + + public static function manHour($logs) { + return function($model) use ($logs) { + $begin = $logs[$model->id][0]; + if (count($logs[$model->id]) > 1) { + $end = $logs[$model->id][count($logs[$model->id]) - 1]; + return number_format(($end - $begin) / (60 * 60), 2); + } else { + return ""; + } + }; + } + + public static function manDay($logs) { + return function($model) use ($logs) { + $begin = $logs[$model->id][0]; + if (count($logs[$model->id]) > 1) { + $end = $logs[$model->id][count($logs[$model->id]) - 1]; + return number_format(($end - $begin) / (60 * 60) / 8, 2); + } else { + return ""; + } + }; + } + } diff --git a/models/Logs.php b/models/Logs.php index ce8ebe40..fb86808e 100644 --- a/models/Logs.php +++ b/models/Logs.php @@ -50,6 +50,7 @@ class Logs extends \yii\db\ActiveRecord { 'event_type' => 'Mô tả sự kiện', 'staff_name' => 'Tên nhân viên', 'staff_department' => 'Phòng ban', + 'staff_code' => 'Mã nhân viên' ]; } diff --git a/models/LogsSearch.php b/models/LogsSearch.php index d8cb2bba..317f5334 100644 --- a/models/LogsSearch.php +++ b/models/LogsSearch.php @@ -14,13 +14,14 @@ class LogsSearch extends Logs { public $staff_name; public $staff_department; + public $staff_code; /** * {@inheritdoc} */ public function rules() { return [ - [['id', 'staff_id', 'device_id', 'in_out_state', 'event_type', 'card_number', 'staff_department'], 'integer'], + [['id', 'staff_id', 'device_id', 'in_out_state', 'event_type', 'card_number', 'staff_department', 'staff_code'], 'integer'], [['staff_name'], 'safe'], ]; } @@ -62,6 +63,8 @@ class LogsSearch extends Logs { $query->andFilterWhere(['LIKE', 'name', $this->staff_name]); if ($this->staff_department) $query->andFilterWhere(['department_id' => $this->staff_department]); + if ($this->staff_code) + $query->andFilterWhere(['code' => $this->staff_code]); // grid filtering conditions $query->andFilterWhere([ diff --git a/models/Staff.php b/models/Staff.php index 12ce66cc..fc8bcf2a 100644 --- a/models/Staff.php +++ b/models/Staff.php @@ -65,7 +65,11 @@ class Staff extends \yii\db\ActiveRecord { 'address' => 'Địa chỉ', 'created_at' => 'Thời gian tạo', 'modified_at' => 'Thời gian sửa', - 'card_register_time' => 'Ngày đăng ký thẻ' + 'card_register_time' => 'Ngày đăng ký thẻ', + 'time_in' => "Thời gian vào", + 'time_out' => "Thời gian ra", + 'man_hour' => "Giờ công", + 'man_day' => "Ngày công" ]; } diff --git a/vendor/dmstr/yii2-adminlte-asset/example-views/yiisoft/yii2-app/layouts/left.php b/vendor/dmstr/yii2-adminlte-asset/example-views/yiisoft/yii2-app/layouts/left.php index 49e38c1d..96f8daab 100644 --- a/vendor/dmstr/yii2-adminlte-asset/example-views/yiisoft/yii2-app/layouts/left.php +++ b/vendor/dmstr/yii2-adminlte-asset/example-views/yiisoft/yii2-app/layouts/left.php @@ -44,7 +44,8 @@ ['label' => 'Sự kiện 3 ngày gần đây', 'url' => ['/logs', 'type' => '3days'], 'icon' => 'calendar'], ['label' => 'Sự kiện tuần này', 'url' => ['/logs', 'type' => 'thisWeek'], 'icon' => 'calendar'], ['label' => 'Sự kiện tuần trước', 'url' => ['/logs', 'type' => 'lastWeek'], 'icon' => 'calendar'], - ['label' => 'Tất cả', 'url' => ['/logs', 'type' => 'all'], 'icon' => 'calendar'] + ['label' => 'Tất cả', 'url' => ['/logs', 'type' => 'all'], 'icon' => 'calendar'], + ['label' => 'Báo cáo chấm công', 'url' => ['/logs/statistics'], 'icon' => 'bar-chart'] ]; } ?> diff --git a/views/logs/export.tpl b/views/logs/export.tpl new file mode 100644 index 00000000..114e5b51 --- /dev/null +++ b/views/logs/export.tpl @@ -0,0 +1,11 @@ +
+
+
Chọn tháng
+ +
+ +
+
+
\ No newline at end of file diff --git a/views/logs/index.tpl b/views/logs/index.tpl index ba1d58b9..42e0b4ed 100644 --- a/views/logs/index.tpl +++ b/views/logs/index.tpl @@ -62,9 +62,11 @@ 'value' => \app\helpers\LogsGrid::time() ], [ - 'attribute' => 'staff_id', + 'attribute' => 'staff_code', + 'format' => 'raw', 'contentOptions' => ['class' => 'text-center'], - 'headerOptions' => ['style' => 'width:5%'] + 'headerOptions' => ['style' => 'width:5%'], + 'value' => \app\helpers\LogsGrid::code() ], [ 'attribute' => 'staff_name', diff --git a/views/logs/statistics.tpl b/views/logs/statistics.tpl new file mode 100644 index 00000000..4cafb795 --- /dev/null +++ b/views/logs/statistics.tpl @@ -0,0 +1,79 @@ +{extends file=$smarty.current_dir|cat:'/../extends.tpl'} +{use class="yii\helpers\Url"} +{use class="yii\grid\GridView"} +{use class="yii\widgets\Pjax" type="block"} +{use class="app\assets\LogsAsset"} +{LogsAsset::register($this)|void} +{block name='content'} + +
+
+
+ +
+
+
+
+
+ +
+ +
+
+
+
+
+
+ {Pjax id="staff-list"} + {GridView::widget([ + 'dataProvider' => $dataProvider, + 'filterModel' => $searchModel, + 'layout'=> \app\helpers\CommonGrid::getLayout(), + 'tableOptions' => [ + 'class' => 'table table-striped table-bordered table-hover', + 'style' => 'background:#fff;min-width:700px;' + ], + 'columns' => [ + [ + 'class' => 'yii\grid\SerialColumn', + 'contentOptions' => ['class' => 'text-center'], + 'headerOptions' => ['class' => 'text-center', 'style' => 'width:3%'] + ], + 'code', + 'name', + [ + 'attribute' => 'department_id', + 'filter' => $departmentArray, + 'value' => \app\helpers\StaffGrid::department($departmentArray) + ], + [ + 'attribute' => 'time_in', + 'value' => \app\helpers\StaffGrid::timeIn($staffLogs) + ], + [ + 'attribute' => 'time_out', + 'value' => \app\helpers\StaffGrid::timeOut($staffLogs) + ], + [ + 'attribute' => 'man_hour', + 'contentOptions' => ['class' => 'text-center'], + 'value' => \app\helpers\StaffGrid::manHour($staffLogs) + ], + [ + 'attribute' => 'man_day', + 'contentOptions' => ['class' => 'text-center'], + 'value' => \app\helpers\StaffGrid::manDay($staffLogs) + ] + ] + ])} + {/Pjax} +
+{/block} \ No newline at end of file diff --git a/web/js/common.js b/web/js/common.js index f500256b..94de34bb 100644 --- a/web/js/common.js +++ b/web/js/common.js @@ -255,6 +255,9 @@ common.form = function (e, obj, bigSize) { if (obj === 'user') { $('#role').select2({tags: true, tokenSeparators: [',']}); } + if (obj === 'statistics') { + common.dateTimePickerById("month", "MM/YYYY"); + } }, error: function (jqXHR, textStatus, errorThrown) { common.modalBlock(false); diff --git a/web/js/logs.js b/web/js/logs.js index 63a088d6..63f49faf 100644 --- a/web/js/logs.js +++ b/web/js/logs.js @@ -1,5 +1,6 @@ $(function () { common.dateTimePickerByClass("time-picker", "HH:mm:ss DD/MM/YYYY"); + common.dateTimePickerById("date", "DD/MM/YYYY"); }); function _export(e) { @@ -8,4 +9,12 @@ function _export(e) { function search(e) { window.location = $(e).attr("data-href") + "?type=all" + "&from=" + $("input[name='FromTime']").val() + "&to=" + $("input[name='ToTime']").val(); +} + +function statistics(e) { + window.location = $(e).attr("data-href") + "?day=" + $("input[name='Date']").val(); +} + +function exportStatistics(e) { + window.location = $(e).attr("data-href") + "?month=" + $("input[name='Month']").val(); } \ No newline at end of file