- 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
88 lines
3.0 KiB
PHP
88 lines
3.0 KiB
PHP
<?php
|
|
|
|
namespace App\Controllers\Api;
|
|
|
|
use App\Controllers\BaseController;
|
|
use CodeIgniter\API\ResponseTrait;
|
|
use App\Models\Qc\ResultsModel;
|
|
use App\Models\Qc\ControlTestsModel;
|
|
|
|
class DashboardApiController extends BaseController
|
|
{
|
|
use ResponseTrait;
|
|
|
|
protected $resultModel;
|
|
protected $controlTestModel;
|
|
|
|
public function __construct()
|
|
{
|
|
$this->resultModel = new ResultsModel();
|
|
$this->controlTestModel = new ControlTestsModel();
|
|
}
|
|
|
|
public function getRecent()
|
|
{
|
|
try {
|
|
$limit = $this->request->getGet('limit') ?? 10;
|
|
|
|
$builder = $this->resultModel->db->table('results r');
|
|
$builder->select('
|
|
r.result_id as id,
|
|
r.res_date,
|
|
r.res_value,
|
|
r.created_at,
|
|
c.control_name as controlName,
|
|
c.lot,
|
|
t.test_name as testName,
|
|
ct.mean,
|
|
ct.sd
|
|
');
|
|
$builder->join('master_controls c', 'c.control_id = r.control_id');
|
|
$builder->join('master_tests t', 't.test_id = r.test_id');
|
|
$builder->join('control_tests ct', 'ct.control_id = r.control_id AND ct.test_id = r.test_id', 'left');
|
|
$builder->where('r.deleted_at', null);
|
|
$builder->orderBy('r.created_at', 'DESC');
|
|
$builder->limit((int) $limit);
|
|
|
|
$results = $builder->get()->getResultArray();
|
|
|
|
// Calculate QC status for each result
|
|
$data = [];
|
|
foreach ($results as $row) {
|
|
$inRange = false;
|
|
$rangeDisplay = 'N/A';
|
|
|
|
if (!empty($row['mean']) && !empty($row['sd']) && $row['res_value'] !== null) {
|
|
$lower = $row['mean'] - (2 * $row['sd']);
|
|
$upper = $row['mean'] + (2 * $row['sd']);
|
|
$resValue = (float) $row['res_value'];
|
|
$inRange = ($resValue >= $lower && $resValue <= $upper);
|
|
$rangeDisplay = number_format($lower, 2) . ' - ' . number_format($upper, 2);
|
|
}
|
|
|
|
$data[] = [
|
|
'id' => $row['id'],
|
|
'resDate' => $row['res_date'],
|
|
'resValue' => $row['res_value'],
|
|
'createdAt' => $row['created_at'],
|
|
'controlName' => $row['controlName'],
|
|
'lot' => $row['lot'],
|
|
'testName' => $row['testName'],
|
|
'mean' => $row['mean'],
|
|
'sd' => $row['sd'],
|
|
'inRange' => $inRange,
|
|
'rangeDisplay' => $rangeDisplay
|
|
];
|
|
}
|
|
|
|
return $this->respond([
|
|
'status' => 'success',
|
|
'message' => 'fetch success',
|
|
'data' => $data
|
|
], 200);
|
|
} catch (\Exception $e) {
|
|
return $this->failServerError('Something went wrong: ' . $e->getMessage());
|
|
}
|
|
}
|
|
}
|