216 lines
9.3 KiB
PHP
216 lines
9.3 KiB
PHP
<?php
|
|||
|
|
|
||
|
|
declare(strict_types=1);
|
||
|
|
|
||
|
|
namespace plugin\produce\app\service\admin;
|
||
|
|
|
||
|
|
use Illuminate\Database\Query\Builder;
|
||
|
|
use plugin\produce\app\model\ProductRecord;
|
||
|
|
use plugin\produce\app\model\ScanData;
|
||
|
|
|
||
|
|
class WorkStatisticsService
|
||
|
|
{
|
||
|
|
public function monthly(array $params): array
|
||
|
|
{
|
||
|
|
$month = $this->normalizeMonth($params['month'] ?? null);
|
||
|
|
$days = (int) date('t', strtotime($month . '-01'));
|
||
|
|
$start = strtotime($month . '-01 00:00:00');
|
||
|
|
$end = strtotime(date('Y-m-t 23:59:59', $start));
|
||
|
|
$rows = $this->collectRows($params, $start, $end, static fn (string $column): string => "DATE_FORMAT(FROM_UNIXTIME({$column}), '%Y-%m-%d')");
|
||
|
|
|
||
|
|
return $this->formatRows($rows, $days, static fn (int $index): string => (string) $index);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function daily(array $params): array
|
||
|
|
{
|
||
|
|
$date = $this->normalizeDate($params['date'] ?? null);
|
||
|
|
$start = strtotime($date . ' 00:00:00');
|
||
|
|
$end = strtotime($date . ' 23:59:59');
|
||
|
|
$rows = $this->collectRows($params, $start, $end, static fn (string $column): string => "HOUR(FROM_UNIXTIME({$column}))");
|
||
|
|
|
||
|
|
return $this->formatRows($rows, 24, static fn (int $index): string => str_pad((string) $index, 2, '0', STR_PAD_LEFT) . ':00');
|
||
|
|
}
|
||
|
|
|
||
|
|
private function collectRows(array $params, int $start, int $end, callable $periodExpression): array
|
||
|
|
{
|
||
|
|
$dataType = (string) ($params['data_type'] ?? 'all');
|
||
|
|
$rows = [];
|
||
|
|
|
||
|
|
if ($dataType === 'all' || $dataType === 'order') {
|
||
|
|
$rows = array_merge($rows, $this->queryScanData($params, $start, $end, $periodExpression)->get()->all());
|
||
|
|
}
|
||
|
|
|
||
|
|
if ($dataType === 'all' || $dataType === 'machine') {
|
||
|
|
$rows = array_merge($rows, $this->queryProductRecord($params, $start, $end, $periodExpression)->get()->all());
|
||
|
|
}
|
||
|
|
|
||
|
|
return $rows;
|
||
|
|
}
|
||
|
|
|
||
|
|
private function queryScanData(array $params, int $start, int $end, callable $periodExpression): Builder
|
||
|
|
{
|
||
|
|
$scanDataModel = new ScanData();
|
||
|
|
$connection = $scanDataModel->getConnection();
|
||
|
|
$scanDataTable = $scanDataModel->getTable();
|
||
|
|
$processTable = 'produce_process';
|
||
|
|
$stepTable = 'produce_process_step';
|
||
|
|
|
||
|
|
$query = $connection->table($scanDataTable)
|
||
|
|
->leftJoin($processTable, $processTable . '.id', '=', $scanDataTable . '.process_id')
|
||
|
|
->leftJoin($stepTable, $stepTable . '.id', '=', $scanDataTable . '.step_id')
|
||
|
|
->whereBetween($scanDataTable . '.scan_time', [$start, $end])
|
||
|
|
->whereNull($scanDataTable . '.deleted_at');
|
||
|
|
|
||
|
|
foreach (['process_id', 'step_id', 'scan_result'] as $field) {
|
||
|
|
if (($params[$field] ?? '') !== '') {
|
||
|
|
$query->where($scanDataTable . '.' . $field, $params[$field]);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
foreach (['user_code', 'operator'] as $field) {
|
||
|
|
if (($params[$field] ?? '') !== '') {
|
||
|
|
$query->where($scanDataTable . '.' . $field, 'like', '%' . $params[$field] . '%');
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
foreach (['process_name' => $processTable . '.process_name', 'step_name' => $stepTable . '.step_name'] as $field => $column) {
|
||
|
|
if (($params[$field] ?? '') !== '') {
|
||
|
|
$query->where($column, 'like', '%' . $params[$field] . '%');
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return $query->select([
|
||
|
|
$scanDataTable . '.user_code',
|
||
|
|
$scanDataTable . '.operator',
|
||
|
|
$connection->raw($connection->getTablePrefix() . $processTable . '.process_name as process_name'),
|
||
|
|
$connection->raw($connection->getTablePrefix() . $stepTable . '.step_name as step_name'),
|
||
|
|
])
|
||
|
|
->selectRaw($periodExpression($connection->getTablePrefix() . $scanDataTable . '.scan_time') . ' as period')
|
||
|
|
->selectRaw('SUM(' . $connection->getTablePrefix() . $scanDataTable . '.quantity) as amount')
|
||
|
|
->groupBy('user_code', 'operator', 'process_name', 'step_name', 'period')
|
||
|
|
->orderBy('user_code')
|
||
|
|
->orderBy('process_name')
|
||
|
|
->orderBy('step_name');
|
||
|
|
}
|
||
|
|
|
||
|
|
private function queryProductRecord(array $params, int $start, int $end, callable $periodExpression): Builder
|
||
|
|
{
|
||
|
|
$productRecordModel = new ProductRecord();
|
||
|
|
$connection = $productRecordModel->getConnection();
|
||
|
|
$productRecordTable = $productRecordModel->getTable();
|
||
|
|
$processTable = 'produce_process';
|
||
|
|
$stepTable = 'produce_process_step';
|
||
|
|
|
||
|
|
$query = $connection->table($productRecordTable)
|
||
|
|
->leftJoin($processTable, $processTable . '.id', '=', $productRecordTable . '.process_id')
|
||
|
|
->leftJoin($stepTable, $stepTable . '.id', '=', $productRecordTable . '.step_id')
|
||
|
|
->whereBetween($productRecordTable . '.created_at', [$start, $end])
|
||
|
|
->whereNull($productRecordTable . '.deleted_at');
|
||
|
|
|
||
|
|
foreach (['process_id', 'step_id', 'scan_result'] as $field) {
|
||
|
|
if (($params[$field] ?? '') !== '') {
|
||
|
|
$query->where($productRecordTable . '.' . $field, $params[$field]);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
foreach (['user_code', 'operator'] as $field) {
|
||
|
|
if (($params[$field] ?? '') !== '') {
|
||
|
|
$query->where($productRecordTable . '.' . $field, 'like', '%' . $params[$field] . '%');
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
foreach (['process_name' => $processTable . '.process_name', 'step_name' => $stepTable . '.step_name'] as $field => $column) {
|
||
|
|
if (($params[$field] ?? '') !== '') {
|
||
|
|
$query->where($column, 'like', '%' . $params[$field] . '%');
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return $query->select([
|
||
|
|
$productRecordTable . '.user_code',
|
||
|
|
$productRecordTable . '.operator',
|
||
|
|
$connection->raw($connection->getTablePrefix() . $processTable . '.process_name as process_name'),
|
||
|
|
$connection->raw($connection->getTablePrefix() . $stepTable . '.step_name as step_name'),
|
||
|
|
])
|
||
|
|
->selectRaw($periodExpression($connection->getTablePrefix() . $productRecordTable . '.created_at') . ' as period')
|
||
|
|
->selectRaw('SUM(' . $connection->getTablePrefix() . $productRecordTable . '.quantity) as amount')
|
||
|
|
->groupBy('user_code', 'operator', 'process_name', 'step_name', 'period')
|
||
|
|
->orderBy('user_code')
|
||
|
|
->orderBy('process_name')
|
||
|
|
->orderBy('step_name');
|
||
|
|
}
|
||
|
|
|
||
|
|
private function formatRows(iterable $rows, int $periodCount, callable $periodLabel): array
|
||
|
|
{
|
||
|
|
$grouped = [];
|
||
|
|
$summaryRows = [];
|
||
|
|
|
||
|
|
foreach ($rows as $row) {
|
||
|
|
$productionProcess = $this->formatProductionProcess((string) $row->process_name, (string) $row->step_name);
|
||
|
|
$key = implode('|', [(string) $row->user_code, (string) $row->operator, (string) $row->process_name, (string) $row->step_name]);
|
||
|
|
if (!isset($grouped[$key])) {
|
||
|
|
$grouped[$key] = [
|
||
|
|
'user_code' => $row->user_code,
|
||
|
|
'operator' => $row->operator,
|
||
|
|
'production_process' => $productionProcess,
|
||
|
|
'process_name' => $row->process_name,
|
||
|
|
'step_name' => $row->step_name,
|
||
|
|
'total' => 0,
|
||
|
|
];
|
||
|
|
for ($index = 1; $index <= $periodCount; $index++) {
|
||
|
|
$grouped[$key][$periodLabel($index)] = 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (!isset($summaryRows[$productionProcess])) {
|
||
|
|
$summaryRows[$productionProcess] = [
|
||
|
|
'user_code' => '总计',
|
||
|
|
'operator' => '',
|
||
|
|
'production_process' => $productionProcess,
|
||
|
|
'process_name' => $row->process_name,
|
||
|
|
'step_name' => $row->step_name,
|
||
|
|
'total' => 0,
|
||
|
|
];
|
||
|
|
for ($index = 1; $index <= $periodCount; $index++) {
|
||
|
|
$summaryRows[$productionProcess][$periodLabel($index)] = 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
$period = (string) $row->period;
|
||
|
|
$period = $periodCount === 24 ? str_pad($period, 2, '0', STR_PAD_LEFT) . ':00' : (string) ((int) substr($period, -2));
|
||
|
|
if (array_key_exists($period, $grouped[$key])) {
|
||
|
|
$amount = (int) $row->amount;
|
||
|
|
$grouped[$key][$period] += $amount;
|
||
|
|
$grouped[$key]['total'] += $amount;
|
||
|
|
$summaryRows[$productionProcess][$period] += $amount;
|
||
|
|
$summaryRows[$productionProcess]['total'] += $amount;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
$items = array_values($grouped);
|
||
|
|
if ($items !== []) {
|
||
|
|
$items = array_merge($items, array_values($summaryRows));
|
||
|
|
}
|
||
|
|
|
||
|
|
return $items;
|
||
|
|
}
|
||
|
|
|
||
|
|
private function formatProductionProcess(string $processName, string $stepName): string
|
||
|
|
{
|
||
|
|
if ($processName !== '' && $stepName !== '') {
|
||
|
|
return $processName . '-' . $stepName;
|
||
|
|
}
|
||
|
|
|
||
|
|
return $processName !== '' ? $processName : $stepName;
|
||
|
|
}
|
||
|
|
|
||
|
|
private function normalizeMonth(mixed $month): string
|
||
|
|
{
|
||
|
|
$month = is_string($month) && preg_match('/^\d{4}-\d{2}$/', $month) ? $month : date('Y-m');
|
||
|
|
return date('Y-m', strtotime($month . '-01'));
|
||
|
|
}
|
||
|
|
|
||
|
|
private function normalizeDate(mixed $date): string
|
||
|
|
{
|
||
|
|
$date = is_string($date) && preg_match('/^\d{4}-\d{2}-\d{2}$/', $date) ? $date : date('Y-m-d');
|
||
|
|
return date('Y-m-d', strtotime($date));
|
||
|
|
}
|
||
|
|
}
|