tinyqc/app/Controllers/Api/ReportApiController.php
mahdahar 0a96b04bdf feat: Implement Monthly Entry interface and consolidate Entry API controller
- Implement Monthly Entry interface with full data entry grid
    - Add batch save with validation and statistics for monthly results
    - Support daily comments per day per test
    - Add result status indicators and validation summaries
  - Consolidate Entry API controller
    - Refactor EntryApiController to handle both daily/monthly operations
    - Add batch save endpoints with comprehensive validation
    - Implement statistics calculation for result entries
  - Add Control Test master data management
    - Create MasterControlsController for CRUD operations
    - Add dialog forms for control test configuration
    - Implement control-test associations with QC parameters
  - Refactor Report API and views
    - Implement new report index with Levey-Jennings charts placeholder
    - Add monthly report functionality with result statistics
    - Include QC summary with mean, SD, and CV calculations
  - UI improvements
    - Overhaul dashboard with improved layout
    - Update daily entry interface with inline editing
    - Enhance master data management with DaisyUI components
    - Add proper modal dialogs and form validation
  - Database and seeding
    - Update migration for control_tests table schema
    - Remove redundant migration and seed files
    - Update seeders with comprehensive test data
  - Documentation
    - Update CLAUDE.md with comprehensive project documentation
    - Add architecture overview and conventions

  BREAKING CHANGES:
  - Refactored Entry API endpoints structure
  - Removed ReportApiController::view() - consolidated into new report index
2026-01-21 13:41:37 +07:00

120 lines
4.5 KiB
PHP

<?php
namespace App\Controllers\Api;
use App\Controllers\BaseController;
use CodeIgniter\API\ResponseTrait;
use App\Models\Master\MasterControlsModel;
use App\Models\Master\MasterTestsModel;
use App\Models\Qc\ControlTestsModel;
use App\Models\Qc\ResultsModel;
use App\Models\Qc\ResultCommentsModel;
class ReportApiController extends BaseController
{
use ResponseTrait;
protected $dictControlModel;
protected $dictTestModel;
protected $controlTestModel;
protected $resultModel;
protected $commentModel;
public function __construct()
{
$this->dictControlModel = new MasterControlsModel();
$this->dictTestModel = new MasterTestsModel();
$this->controlTestModel = new ControlTestsModel();
$this->resultModel = new ResultsModel();
$this->commentModel = new ResultCommentsModel();
}
public function getReport()
{
try {
$control1 = $this->request->getGet('control1') ?? 0;
$control2 = $this->request->getGet('control2') ?? 0;
$control3 = $this->request->getGet('control3') ?? 0;
$dates = $this->request->getGet('dates') ?? date('Y-m');
$test = $this->request->getGet('test') ?? 0;
$controlIds = array_filter([$control1, $control2, $control3]);
$reportData = [];
foreach ($controlIds as $controlId) {
$control = $this->dictControlModel->find($controlId);
if (!$control) continue;
$controlTest = $this->controlTestModel->getByControlAndTest($control['controlId'], $test);
$results = $this->resultModel->getByControlAndMonth($control['controlId'], $test, $dates);
$comment = $this->commentModel->getByControlTestMonth($control['controlId'], $test, $dates);
$testInfo = $this->dictTestModel->find($test);
$outOfRangeCount = 0;
$processedResults = [];
if ($controlTest && $controlTest['sd'] > 0) {
foreach ($results as $res) {
$zScore = ($res['resValue'] - $controlTest['mean']) / $controlTest['sd'];
$outOfRange = abs($zScore) > 2;
if ($outOfRange) $outOfRangeCount++;
$processedResults[] = [
'resdate' => $res['resDate'],
'resvalue' => $res['resValue'],
'zScore' => round($zScore, 2),
'outOfRange' => $outOfRange,
'status' => $zScore === null ? '-' : (abs($zScore) > 2 ? 'Out' : (abs($zScore) > 1 ? 'Warn' : 'OK'))
];
}
} else {
foreach ($results as $res) {
$processedResults[] = [
'resdate' => $res['resDate'],
'resvalue' => $res['resValue'],
'zScore' => null,
'outOfRange' => false,
'status' => '-'
];
}
}
$daysInMonth = date('t', strtotime($dates . '-01'));
$values = [];
for ($day = 1; $day <= $daysInMonth; $day++) {
$value = null;
foreach ($processedResults as $res) {
if (date('j', strtotime($res['resdate'])) == $day) {
$value = $res['resvalue'];
break;
}
}
$values[] = $value;
}
$reportData[] = [
'control' => $control,
'controlTest' => $controlTest,
'results' => $processedResults,
'values' => $values,
'test' => $testInfo,
'comment' => $comment,
'outOfRange' => $outOfRangeCount
];
}
return $this->respond([
'status' => 'success',
'message' => 'fetch success',
'data' => [
'reportData' => $reportData,
'dates' => $dates,
'test' => $test,
'daysInMonth' => $daysInMonth
]
], 200);
} catch (\Exception $e) {
return $this->failServerError('Something went wrong: ' . $e->getMessage());
}
}
}