refactor: standardize codebase with BaseModel and new conventions
- Add BaseModel with automatic camel/snake case conversion - Add stringcase_helper with camel_to_snake(), snake_to_camel() functions - Update all models to extend BaseModel for consistent data handling - Update API controllers with standardized JSON response format - Remove legacy v1 PHP application directory - Consolidate documentation into AGENTS.md, delete VIEWS_RULES.md
This commit is contained in:
parent
ff90e0eb29
commit
18b85815ce
837
AGENTS.md
837
AGENTS.md
@ -1,340 +1,597 @@
|
||||
# AGENTS.md - QC Application Development Guide
|
||||
# AGENTS.md - AI Agent Guidelines for [PROJECT NAME]
|
||||
|
||||
This document provides guidelines for agentic coding agents working on this PHP QC (Quality Control) application built with CodeIgniter 4.
|
||||
## AI Agent Guidelines
|
||||
|
||||
## Project Overview
|
||||
1. **Readability**: Write code that is easy to read and understand.
|
||||
2. **Maintainability**: Write code that is easy to maintain and update.
|
||||
3. **Performance**: Write code that is fast and efficient.
|
||||
4. **Security**: Write code that is secure and protected against attacks.
|
||||
5. **Testing**: Write code that is tested and verified.
|
||||
|
||||
This is a CodeIgniter 4 PHP application using SQL Server database for quality control data management. The app handles control tests, daily/monthly entries, and reporting. Uses Tailwind CSS and Alpine.js for UI.
|
||||
## Technology Stack
|
||||
|
||||
## Build/Lint/Test Commands
|
||||
| Layer | Technology |
|
||||
|-------|------------|
|
||||
| Backend | CodeIgniter 4 (PHP 8.1+) |
|
||||
| Frontend | Alpine.js + TailwindCSS |
|
||||
| Database | MySQL/MariaDB |
|
||||
|
||||
```bash
|
||||
# PHP syntax check single file
|
||||
php -l app/Controllers/Dashboard.php
|
||||
## Key Files & Locations
|
||||
|
||||
# PHP syntax check all files recursively
|
||||
find . -name "*.php" -exec php -l {} \; 2>&1 | grep -v "No syntax errors"
|
||||
### Backend
|
||||
|
||||
# Run all PHPUnit tests
|
||||
./vendor/bin/phpunit
|
||||
|
||||
# Run single test class
|
||||
./vendor/bin/phpunit tests/unit/HealthTest.php
|
||||
|
||||
# Run single test method
|
||||
./vendor/bin/phpunit tests/unit/HealthTest.php --filter=testIsDefinedAppPath
|
||||
|
||||
# Run with coverage report
|
||||
./vendor/bin/phpunit --coverage-html coverage/
|
||||
|
||||
# Start development server
|
||||
php spark serve
|
||||
```
|
||||
app/Controllers/ # API & page controllers
|
||||
app/Models/ # Eloquent-style models
|
||||
app/Database/Migrations/ # Schema definitions
|
||||
app/Config/Routes.php # All routes defined here
|
||||
app/Helpers/ # Helper functions
|
||||
```
|
||||
|
||||
## Code Style Guidelines
|
||||
### Frontend
|
||||
|
||||
### General Principles
|
||||
```
|
||||
app/Views/ # PHP views with Alpine.js
|
||||
app/Views/layout/ # Base templates
|
||||
public/ # Static assets (css, js)
|
||||
```
|
||||
|
||||
- Follow CodeIgniter 4 MVC patterns
|
||||
- Maintain consistency with surrounding code
|
||||
- Keep files focused (<200 lines preferred)
|
||||
- Use clear, descriptive names
|
||||
## Coding Conventions
|
||||
|
||||
### PHP Style
|
||||
### PHP / CodeIgniter 4
|
||||
|
||||
- Use `<?php` opening tag (not `<?` short tags)
|
||||
- Enable strict types: `declare(strict_types=1);` at top of PHP files
|
||||
- Use strict comparison (`===`, `!==`) over loose comparison
|
||||
- Use `elseif` (one word) not `else if`
|
||||
- Use parentheses with control structures for single statements
|
||||
- Use 4 spaces for indentation (not tabs)
|
||||
- Return types and typed properties required for new code:
|
||||
1. **Controllers** extend `BaseController` and use `ResponseTrait`
|
||||
2. **Models** extend `App\Models\BaseModel` (custom base with auto camel/snake conversion)
|
||||
3. **Soft deletes** are enabled on all tables (`deleted_at`)
|
||||
4. **Timestamps** are automatic (`created_at`, `updated_at`)
|
||||
5. **Validation** happens in controllers, not models
|
||||
6. **JSON API responses** follow this structure:
|
||||
```php
|
||||
public function index(): string
|
||||
{
|
||||
return view('layout', [...]);
|
||||
}
|
||||
return $this->respond([
|
||||
'status' => 'success',
|
||||
'message' => 'fetch success',
|
||||
'data' => $rows
|
||||
], 200);
|
||||
```
|
||||
|
||||
### Naming Conventions
|
||||
7. **Use camelCase for input/output**, snake_case for database:
|
||||
- Controllers convert camel→snake before insert/update
|
||||
- Models convert snake→camel after fetch
|
||||
- Use helper functions: `camel_to_snake()`, `camel_to_snake_array()`, `snake_to_camel()`
|
||||
|
||||
- Classes: `PascalCase` (e.g., `Dashboard`, `DictTestModel`)
|
||||
- Methods/functions: `$camelCase` (e.g., `getWithDept`, `saveResult`)
|
||||
- Variables: `$camelCase` (e.g., `$dictTestModel`, `$resultData`)
|
||||
- Constants: `UPPER_SNAKE_CASE`
|
||||
- Views: `lowercase_with_underscores` (e.g., `dashboard.php`, `test_index.php`)
|
||||
- Routes: kebab-case URLs (e.g., `/test/edit/(:num)` → `/test/edit/1`)
|
||||
### Database
|
||||
|
||||
### CodeIgniter 4 Patterns
|
||||
1. **Primary keys**: `{table_singular}_id` (e.g., `item_id`, `pat_id`)
|
||||
2. **Foreign keys**: Match the referenced primary key name
|
||||
3. **Naming**: All lowercase, underscores
|
||||
4. **Soft deletes**: All tables have `deleted_at` DATETIME column
|
||||
5. **Master data tables**: Prefix with `master_` (e.g., `master_items`)
|
||||
6. **Timestamps**: `created_at`, `updated_at` DATETIME columns
|
||||
7. **Unique constraints**: Add on code fields (e.g., `item_code`)
|
||||
|
||||
### Frontend / Alpine.js
|
||||
|
||||
1. **x-data** on container elements
|
||||
2. **Fetch API** for AJAX calls (no jQuery)
|
||||
3. **DaisyUI components** for UI elements
|
||||
4. **camelCase** for JavaScript, **snake_case** for PHP/DB
|
||||
5. **Modals** with x-show and x-transition
|
||||
6. **ES6 modules** importing Alpine from `app.js`
|
||||
|
||||
### File Naming
|
||||
|
||||
| Component | Pattern | Example |
|
||||
|-----------|---------|---------|
|
||||
| Controller | `PascalCase + Controller` | `ItemsController` |
|
||||
| Model | `PascalCase + Model` | `ItemsModel` |
|
||||
| Migration | `YYYY-MM-DD-XXXXXX_Description.php` | `2026-01-15-000001_Items.php` |
|
||||
| View | `module/action.php` | `items/index.php` |
|
||||
| Helper | `snake_case + _helper.php` | `stringcase_helper.php` |
|
||||
| Filter | `PascalCase + Filter.php` | `JwtAuthFilter.php` |
|
||||
|
||||
### Directory Structure
|
||||
|
||||
```
|
||||
app/
|
||||
├── Config/
|
||||
│ ├── Routes.php
|
||||
│ └── Filters.php
|
||||
├── Controllers/
|
||||
│ ├── BaseController.php
|
||||
│ ├── ItemsController.php
|
||||
│ └── Master/
|
||||
│ └── ItemsController.php
|
||||
├── Database/
|
||||
│ └── Migrations/
|
||||
├── Filters/
|
||||
│ └── JwtAuthFilter.php
|
||||
├── Helpers/
|
||||
│ ├── stringcase_helper.php
|
||||
│ └── utc_helper.php
|
||||
├── Models/
|
||||
│ ├── BaseModel.php
|
||||
│ ├── ItemsModel.php
|
||||
│ └── Master/
|
||||
│ └── ItemsModel.php
|
||||
└── Views/
|
||||
├── layout/
|
||||
│ ├── main_layout.php
|
||||
│ └── form_layout.php
|
||||
├── items/
|
||||
│ ├── items_index.php
|
||||
│ └── dialog_items_form.php
|
||||
└── login.php
|
||||
```
|
||||
|
||||
## Common Tasks
|
||||
|
||||
### Adding a New Master Data Entity
|
||||
|
||||
1. Create migration in `app/Database/Migrations/`
|
||||
2. Create model in `app/Models/[Module]/`
|
||||
3. Create controller in `app/Controllers/[Module]/`
|
||||
4. Add routes in `app/Config/Routes.php`
|
||||
5. Create view in `app/Views/[module]/`
|
||||
|
||||
### Adding a New API Endpoint
|
||||
|
||||
**Controllers** extend `App\Controllers\BaseController`:
|
||||
```php
|
||||
namespace App\Controllers;
|
||||
|
||||
use App\Models\DictTestModel;
|
||||
|
||||
class Test extends BaseController
|
||||
{
|
||||
protected $dictTestModel;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->dictTestModel = new DictTestModel();
|
||||
}
|
||||
|
||||
public function index(): string
|
||||
{
|
||||
$data = [
|
||||
'title' => 'Test Dictionary',
|
||||
'tests' => $this->dictTestModel->findAll(),
|
||||
];
|
||||
|
||||
return view('layout', [
|
||||
'content' => view('test/index', $data),
|
||||
'page_title' => 'Test Dictionary',
|
||||
'active_menu' => 'test'
|
||||
]);
|
||||
}
|
||||
}
|
||||
// In Routes.php
|
||||
$routes->get('api/resource', 'ResourceController::index');
|
||||
$routes->get('api/resource/(:num)', 'ResourceController::show/$1');
|
||||
$routes->post('api/resource', 'ResourceController::create');
|
||||
$routes->patch('api/resource/(:num)', 'ResourceController::update/$1');
|
||||
```
|
||||
|
||||
**Models** extend `CodeIgniter\Model`:
|
||||
```php
|
||||
namespace App\Models;
|
||||
### Controller Template
|
||||
|
||||
use CodeIgniter\Model;
|
||||
|
||||
class TestModel extends Model
|
||||
{
|
||||
protected $table = 'dict_test';
|
||||
protected $primaryKey = 'id';
|
||||
protected $returnType = 'array';
|
||||
protected $useSoftDeletes = false;
|
||||
protected $allowedFields = ['deptid', 'name', 'unit', 'method'];
|
||||
}
|
||||
```
|
||||
|
||||
**Views** use PHP short tags `<?= ?>` for output:
|
||||
```php
|
||||
<div class="space-y-6">
|
||||
<h1 class="text-2xl font-bold"><?= $title ?></h1>
|
||||
<?php foreach ($tests as $test): ?>
|
||||
<div><?= $test['name'] ?></div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
```
|
||||
|
||||
### Database Operations
|
||||
|
||||
- Configure connections in `app/Config/Database.php`
|
||||
- Use CodeIgniter's Query Builder for queries
|
||||
- Use parameterized queries to prevent SQL injection:
|
||||
```php
|
||||
$builder = $this->db->table('results');
|
||||
$builder->select('*');
|
||||
$builder->where('control_ref_id', $controlId);
|
||||
$results = $builder->get()->getResultArray();
|
||||
```
|
||||
- For SQL Server, set `DBDriver` to `'SQLSRV'` in config
|
||||
|
||||
### Error Handling
|
||||
|
||||
- Use CodeIgniter's exception handling: `throw new \CodeIgniter\Exceptions\PageNotFoundException('Not found')`
|
||||
- Return JSON responses for AJAX endpoints:
|
||||
```php
|
||||
return $this->response->setJSON(['success' => true, 'data' => $results]);
|
||||
```
|
||||
- Use `log_message('error', $message)` for logging
|
||||
- Validate input with `$this->validate()` in controllers
|
||||
|
||||
### Frontend (Tailwind CSS + Alpine.js)
|
||||
|
||||
The layout already includes Tailwind via CDN and Alpine.js:
|
||||
```html
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
|
||||
```
|
||||
|
||||
**Common JavaScript (`public/js/app.js`):**
|
||||
- Contains global `App` object with shared utilities
|
||||
- Handles sidebar toggle functionality
|
||||
- Provides `App.showToast()`, `App.confirmSave()`, `App.closeAllModals()`
|
||||
- Initialize with `App.init()` on DOMContentLoaded
|
||||
|
||||
**Page-Specific Alpine.js:**
|
||||
- Complex Alpine.js components should be defined inline in the view PHP file
|
||||
- Use `x-data` with an object containing all properties and methods
|
||||
- Example:
|
||||
```html
|
||||
<div x-data="{
|
||||
property1: '',
|
||||
property2: [],
|
||||
|
||||
init() {
|
||||
// Initialization code
|
||||
},
|
||||
|
||||
async loadData() {
|
||||
// Fetch and handle data
|
||||
App.showToast('Loaded successfully');
|
||||
}
|
||||
}">
|
||||
<!-- Component markup -->
|
||||
</div>
|
||||
```
|
||||
|
||||
### File Organization
|
||||
|
||||
- Controllers: `app/Controllers/`
|
||||
- Models: `app/Models/`
|
||||
- Views: `app/Views/` (subfolders for modules: `entry/`, `test/`, `control/`, `report/`, `dept/`)
|
||||
- Config: `app/Config/`
|
||||
- Routes: `app/Config/Routes.php`
|
||||
|
||||
### Modal-based CRUD Pattern
|
||||
|
||||
All CRUD operations use a single modal dialog file (`dialog.php`) that handles both add and edit modes.
|
||||
|
||||
**File Naming:**
|
||||
- Single dialog: `dialog.php` (no `_add` or `_edit` suffix)
|
||||
|
||||
**Controller Pattern:**
|
||||
```php
|
||||
class Dept extends BaseController
|
||||
{
|
||||
protected $dictDeptModel;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->dictDeptModel = new DictDeptModel();
|
||||
}
|
||||
|
||||
public function index(): string
|
||||
{
|
||||
$data = [
|
||||
'title' => 'Department Dictionary',
|
||||
'depts' => $this->dictDeptModel->findAll(),
|
||||
];
|
||||
|
||||
return view('layout', [
|
||||
'content' => view('dept/index', $data),
|
||||
'page_title' => 'Department Dictionary',
|
||||
'active_menu' => 'dept'
|
||||
]);
|
||||
}
|
||||
|
||||
public function save(): \CodeIgniter\HTTP\RedirectResponse
|
||||
{
|
||||
$data = ['name' => $this->request->getPost('name')];
|
||||
$this->dictDeptModel->insert($data);
|
||||
return redirect()->to('/dept');
|
||||
}
|
||||
|
||||
public function update($id): \CodeIgniter\HTTP\RedirectResponse
|
||||
{
|
||||
$data = ['name' => $this->request->getPost('name')];
|
||||
$this->dictDeptModel->update($id, $data);
|
||||
return redirect()->to('/dept');
|
||||
}
|
||||
|
||||
public function delete($id): \CodeIgniter\HTTP\RedirectResponse
|
||||
{
|
||||
$this->dictDeptModel->delete($id);
|
||||
return redirect()->to('/dept');
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Dialog View Pattern (`dialog.php`):**
|
||||
```php
|
||||
<?php
|
||||
$isEdit = isset($record);
|
||||
$action = $isEdit ? '/controller/update/' . $record['id'] : '/controller/save';
|
||||
$title = $isEdit ? 'Edit Title' : 'Add Title';
|
||||
?>
|
||||
namespace App\Controllers\Module;
|
||||
|
||||
<div x-data="{ open: false }">
|
||||
<?php if (!$isEdit): ?>
|
||||
<button @click="open = true" class="...">Add</button>
|
||||
<?php endif; ?>
|
||||
use CodeIgniter\API\ResponseTrait;
|
||||
use App\Controllers\BaseController;
|
||||
use App\Models\Module\ItemModel;
|
||||
|
||||
<div x-show="open" class="fixed inset-0 z-50 ..." style="display: none;">
|
||||
<h2 class="text-xl font-bold mb-4"><?= $title ?></h2>
|
||||
<form action="<?= $action ?>" method="post">
|
||||
<!-- Form fields with values from $record if edit mode -->
|
||||
<input type="text" name="name" value="<?= $record['name'] ?? '' ?>">
|
||||
<button type="submit"><?= $isEdit ? 'Update' : 'Save' ?></button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
class ItemsController extends BaseController {
|
||||
use ResponseTrait;
|
||||
|
||||
protected $model;
|
||||
protected $rules;
|
||||
|
||||
public function __construct() {
|
||||
$this->model = new ItemsModel();
|
||||
$this->rules = [
|
||||
'itemCode' => 'required|min_length[1]',
|
||||
'itemName' => 'required',
|
||||
];
|
||||
}
|
||||
|
||||
public function index() {
|
||||
$keyword = $this->request->getGet('keyword');
|
||||
try {
|
||||
$rows = $this->model->getItems($keyword);
|
||||
return $this->respond([
|
||||
'status' => 'success',
|
||||
'message' => 'fetch success',
|
||||
'data' => $rows
|
||||
], 200);
|
||||
} catch (\Exception $e) {
|
||||
return $this->failServerError('Exception: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function show($id = null) {
|
||||
try {
|
||||
$rows = $this->model->where('item_id', $id)->findAll();
|
||||
if (empty($rows)) {
|
||||
return $this->respond([
|
||||
'status' => 'success',
|
||||
'message' => 'data not found.'
|
||||
], 200);
|
||||
}
|
||||
return $this->respond([
|
||||
'status' => 'success',
|
||||
'message' => 'fetch success',
|
||||
'data' => $rows
|
||||
], 200);
|
||||
} catch (\Exception $e) {
|
||||
return $this->failServerError('Something went wrong: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function create() {
|
||||
$input = $this->request->getJSON(true);
|
||||
$input = camel_to_snake_array($input);
|
||||
if (!$this->validate($this->rules)) {
|
||||
return $this->failValidationErrors($this->validator->getErrors());
|
||||
}
|
||||
try {
|
||||
$id = $this->model->insert($input, true);
|
||||
return $this->respondCreated([
|
||||
'status' => 'success',
|
||||
'message' => $id
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return $this->failServerError('Something went wrong: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function update($id = null) {
|
||||
$input = $this->request->getJSON(true);
|
||||
$input = camel_to_snake_array($input);
|
||||
if (!$this->validate($this->rules)) {
|
||||
return $this->failValidationErrors($this->validator->getErrors());
|
||||
}
|
||||
try {
|
||||
$this->model->update($id, $input);
|
||||
return $this->respondCreated([
|
||||
'status' => 'success',
|
||||
'message' => 'update success',
|
||||
'data' => $id
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return $this->failServerError('Something went wrong: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Index View Pattern (`index.php`):**
|
||||
### Model Template
|
||||
|
||||
```php
|
||||
<div class="space-y-6">
|
||||
<!-- Table with data attributes for edit/delete -->
|
||||
<table>
|
||||
<tbody>
|
||||
<?php foreach ($records as $record): ?>
|
||||
<?php
|
||||
namespace App\Models\Module;
|
||||
|
||||
use App\Models\BaseModel;
|
||||
|
||||
class ItemsModel extends BaseModel {
|
||||
protected $table = 'module_items';
|
||||
protected $primaryKey = 'item_id';
|
||||
protected $allowedFields = [
|
||||
'item_code',
|
||||
'item_name',
|
||||
'created_at',
|
||||
'updated_at',
|
||||
'deleted_at'
|
||||
];
|
||||
protected $useTimestamps = true;
|
||||
protected $useSoftDeletes = true;
|
||||
|
||||
public function getItems($keyword = null) {
|
||||
if ($keyword) {
|
||||
return $this->groupStart()
|
||||
->like('item_code', $keyword)
|
||||
->orLike('item_name', $keyword)
|
||||
->groupEnd()
|
||||
->findAll();
|
||||
}
|
||||
return $this->findAll();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Migration Template
|
||||
|
||||
```php
|
||||
<?php
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class ModuleItems extends Migration {
|
||||
|
||||
public function up() {
|
||||
$this->forge->addField([
|
||||
'item_id' => [
|
||||
'type' => 'int',
|
||||
'unsigned' => true,
|
||||
'auto_increment' => true
|
||||
],
|
||||
'item_code' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 50
|
||||
],
|
||||
'item_name' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 150
|
||||
],
|
||||
'created_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => true
|
||||
],
|
||||
'updated_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => true
|
||||
],
|
||||
'deleted_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => true
|
||||
]
|
||||
]);
|
||||
$this->forge->addKey('item_id', true);
|
||||
$this->forge->addUniqueKey('item_code');
|
||||
$this->forge->createTable('module_items');
|
||||
}
|
||||
|
||||
public function down() {
|
||||
$this->forge->dropTable('module_items', true);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Routes Template
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
use CodeIgniter\Router\RouteCollection;
|
||||
|
||||
$routes = get('/login', 'PagesController::login');
|
||||
$routes->post('/login', 'AuthController::login');
|
||||
$routes->get('/logout', 'AuthController::logout');
|
||||
|
||||
$routes->group('', ['filter' => 'jwt-auth'], function ($routes) {
|
||||
$routes->get('/', 'PagesController::dashboard');
|
||||
$routes->get('/module', 'PagesController::module');
|
||||
$routes->get('/master/items', 'PagesController::masterItems');
|
||||
});
|
||||
|
||||
$routes->group('api', function ($routes) {
|
||||
$routes->get('module/items', 'Module\ItemsController::index');
|
||||
$routes->get('module/items/(:num)', 'Module\ItemsController::show/$1');
|
||||
$routes->post('module/items', 'Module\ItemsController::create');
|
||||
$routes->patch('module/items/(:num)', 'Module\ItemsController::update/$1');
|
||||
});
|
||||
```
|
||||
|
||||
### View Template (Index with Alpine.js)
|
||||
|
||||
```php
|
||||
<?= $this->extend("layout/main_layout"); ?>
|
||||
|
||||
<?= $this->section("content"); ?>
|
||||
<main class="flex-1 p-6 overflow-auto bg-slate-50/50" x-data="items()">
|
||||
<div class="flex justify-between items-center mb-6">
|
||||
<div>
|
||||
<h1 class="text-2xl font-bold text-slate-800 tracking-tight">Items</h1>
|
||||
<p class="text-slate-500 text-sm mt-1">Manage your items</p>
|
||||
</div>
|
||||
<button
|
||||
class="btn btn-sm gap-2 shadow-sm border-0 bg-gradient-to-r from-blue-600 to-blue-500 hover:from-blue-700 hover:to-blue-600 text-white transition-all duration-200"
|
||||
@click="showForm()"
|
||||
>
|
||||
<i class="fa-solid fa-plus"></i> New Item
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="bg-white rounded-xl border border-slate-100 shadow-sm p-4 mb-6">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="relative flex-1 max-w-md">
|
||||
<i class="fa-solid fa-magnifying-glass absolute left-3 top-1/2 -translate-y-1/2 text-slate-400 text-sm"></i>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Search by name or code..."
|
||||
class="w-full pl-10 pr-4 py-2.5 text-sm bg-slate-50 border border-slate-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition-all"
|
||||
x-model="keyword"
|
||||
@keyup.enter="fetchList()"
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
class="px-4 py-2.5 text-sm font-medium bg-slate-800 text-white rounded-lg hover:bg-slate-700 transition-all duration-200 flex items-center gap-2"
|
||||
@click="fetchList()"
|
||||
>
|
||||
<i class="fa-solid fa-magnifying-glass text-xs"></i> Search
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-white rounded-xl border border-slate-100 shadow-sm overflow-hidden">
|
||||
<template x-if="list">
|
||||
<div class="overflow-x-auto">
|
||||
<table class="w-full text-sm text-left">
|
||||
<thead class="bg-slate-50 text-slate-500 text-xs uppercase tracking-wider">
|
||||
<tr>
|
||||
<td><?= $record['name'] ?></td>
|
||||
<td>
|
||||
<button data-edit-id="<?= $record['id'] ?>"
|
||||
data-name="<?= $record['name'] ?>"
|
||||
class="...">Edit</button>
|
||||
<button data-delete-id="<?= $record['id'] ?>"
|
||||
class="...">Delete</button>
|
||||
<th class="py-3 px-5 font-semibold">Code</th>
|
||||
<th class="py-3 px-5 font-semibold">Name</th>
|
||||
<th class="py-3 px-5 font-semibold text-right">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="text-slate-600 divide-y divide-slate-100">
|
||||
<template x-for="item in list" :key="item.itemId">
|
||||
<tr class="hover:bg-slate-50/50 transition-colors">
|
||||
<td class="py-3 px-5">
|
||||
<span class="font-mono text-xs bg-slate-100 text-slate-600 px-2 py-1 rounded" x-text="item.itemCode"></span>
|
||||
</td>
|
||||
<td class="py-3 px-5 font-medium text-slate-700" x-text="item.itemName"></td>
|
||||
<td class="py-3 px-5 text-right">
|
||||
<button
|
||||
class="inline-flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium text-amber-700 bg-amber-50 hover:bg-amber-100 rounded-lg transition-colors"
|
||||
@click="showForm(item.itemId)"
|
||||
>
|
||||
<i class="fa-solid fa-pencil"></i> Edit
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</template>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<!-- Dialog for add (no data passed) -->
|
||||
<?= view('module/dialog') ?>
|
||||
<?= $this->include('module/items/dialog_items_form'); ?>
|
||||
</main>
|
||||
<?= $this->endSection(); ?>
|
||||
|
||||
<script>
|
||||
// All modal-related JS in index.php
|
||||
document.querySelectorAll('[data-edit-id]').forEach(btn => {
|
||||
btn.addEventListener('click', function() {
|
||||
document.getElementById('editId').value = this.dataset.editId;
|
||||
document.getElementById('editName').value = this.dataset.name;
|
||||
document.getElementById('editModal').classList.remove('hidden');
|
||||
<?= $this->section("script"); ?>
|
||||
<script type="module">
|
||||
import Alpine from '<?= base_url('/assets/js/app.js'); ?>';
|
||||
|
||||
document.addEventListener('alpine:init', () => {
|
||||
Alpine.data("items", () => ({
|
||||
loading: false,
|
||||
showModal: false,
|
||||
errors: {},
|
||||
error: null,
|
||||
part: "items",
|
||||
keyword: "",
|
||||
list: null,
|
||||
item: null,
|
||||
form: {
|
||||
itemCode: "",
|
||||
itemName: "",
|
||||
},
|
||||
|
||||
async fetchList() {
|
||||
this.loading = true;
|
||||
this.error = null;
|
||||
this.list = null;
|
||||
try {
|
||||
const params = new URLSearchParams({ keyword: this.keyword });
|
||||
const response = await fetch(`${window.BASEURL}api/module/${this.part}?${params}`, {
|
||||
method: "GET",
|
||||
headers: { "Content-Type": "application/json" }
|
||||
});
|
||||
});
|
||||
|
||||
document.querySelectorAll('[data-delete-id]').forEach(btn => {
|
||||
btn.addEventListener('click', function() {
|
||||
if (confirm('Delete this record?')) {
|
||||
window.location.href = '/controller/delete/' + this.dataset.deleteId;
|
||||
if (!response.ok) throw new Error("Failed to load data");
|
||||
const data = await response.json();
|
||||
this.list = data.data;
|
||||
} catch (err) {
|
||||
this.error = err.message;
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
|
||||
async loadData(id) {
|
||||
this.loading = true;
|
||||
try {
|
||||
const response = await fetch(`${window.BASEURL}api/module/${this.part}/${id}`, {
|
||||
method: "GET",
|
||||
headers: { "Content-Type": "application/json" }
|
||||
});
|
||||
if (!response.ok) throw new Error("Failed to load item");
|
||||
const data = await response.json();
|
||||
this.form = data.data[0];
|
||||
} catch (err) {
|
||||
this.error = err.message;
|
||||
this.form = {};
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
|
||||
async showForm(id = null) {
|
||||
this.showModal = true;
|
||||
if (id) {
|
||||
await this.loadData(id);
|
||||
} else {
|
||||
this.form = {};
|
||||
}
|
||||
},
|
||||
|
||||
closeModal() {
|
||||
this.showModal = false;
|
||||
this.form = {};
|
||||
},
|
||||
|
||||
validate() {
|
||||
this.errors = {};
|
||||
if (!this.form.itemCode) this.errors.itemCode = "Code is required.";
|
||||
if (!this.form.itemName) this.errors.itemName = "Name is required.";
|
||||
return Object.keys(this.errors).length === 0;
|
||||
},
|
||||
|
||||
async save() {
|
||||
if (!this.validate()) return;
|
||||
this.loading = true;
|
||||
let method = '';
|
||||
let url = '';
|
||||
if (this.form.itemId) {
|
||||
method = 'patch';
|
||||
url = `${BASEURL}api/module/${this.part}/${this.form.itemId}`;
|
||||
} else {
|
||||
method = 'post';
|
||||
url = `${BASEURL}api/module/${this.part}`;
|
||||
}
|
||||
try {
|
||||
const res = await fetch(url, {
|
||||
method: method,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(this.form),
|
||||
});
|
||||
const data = await res.json();
|
||||
if (data.status === 'success') {
|
||||
alert("Data saved successfully!");
|
||||
this.closeModal();
|
||||
this.list = null;
|
||||
} else {
|
||||
alert(data.message || "Something went wrong.");
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
alert("Failed to save data.");
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
}
|
||||
}));
|
||||
});
|
||||
|
||||
Alpine.start();
|
||||
</script>
|
||||
<?= $this->endSection(); ?>
|
||||
```
|
||||
|
||||
**Searchable Multi-Select:**
|
||||
- Use Select2 for searchable dropdowns (already included in layout.php)
|
||||
- Initialize with: `$('#selectId').select2({ placeholder: 'Search...', allowClear: true })`
|
||||
### Running Migrations
|
||||
|
||||
### Security Considerations
|
||||
```bash
|
||||
php spark migrate # Run all pending
|
||||
php spark migrate:rollback # Rollback last batch
|
||||
php spark migrate:refresh # Rollback all + re-run
|
||||
```
|
||||
|
||||
- Use CodeIgniter's built-in CSRF protection (`$this->validate('csrf')`)
|
||||
- Escape all output in views with `<?= ?>` (auto-escaped)
|
||||
- Use `$this->request->getPost()` instead of `$_POST`
|
||||
- Never commit `.env` files with credentials
|
||||
## Testing
|
||||
|
||||
## Common Operations
|
||||
```bash
|
||||
# Run all tests
|
||||
./vendor/bin/phpunit
|
||||
|
||||
**Add a new CRUD resource:**
|
||||
1. Create model in `app/Models/`
|
||||
2. Create controller in `app/Controllers/`
|
||||
3. Add routes in `app/Config/Routes.php`
|
||||
4. Create views in `app/Views/[module]/`
|
||||
# Run specific test file
|
||||
./vendor/bin/phpunit tests/unit/SomeTest.php
|
||||
```
|
||||
|
||||
**Add a menu item:**
|
||||
- Add to sidebar in `app/Views/layout.php`
|
||||
- Add route in `app/Config/Routes.php`
|
||||
- Create controller method
|
||||
- Set `active_menu` parameter in view() call
|
||||
## Things to Avoid
|
||||
|
||||
1. **Don't use jQuery** - Use Alpine.js or vanilla JS
|
||||
2. **Don't over-engineer** - This is a "no-nonsense" project
|
||||
3. **Don't skip soft deletes** - Always use `deleted_at`
|
||||
4. **Don't hardcode** - Use `.env` for configuration
|
||||
5. **Don't mix concerns** - Controllers handle HTTP, Models handle data
|
||||
6. **Don't forget camel/snake conversion** - Frontend uses camelCase, DB uses snake_case
|
||||
|
||||
## Questions to Ask Before Making Changes
|
||||
|
||||
1. Does this follow the existing patterns?
|
||||
2. Is there a simpler way to do this?
|
||||
3. Did I add the route?
|
||||
4. Did I handle errors gracefully?
|
||||
5. Does the API response match the standard format?
|
||||
6. Did I convert camelCase to snake_case before DB operations?
|
||||
7. Did I convert snake_case to camelCase after fetching?
|
||||
|
||||
## Post-Change Requirements
|
||||
|
||||
**After every significant code change, update `README.md`:**
|
||||
|
||||
| Change Type | README Section to Update |
|
||||
|-------------|--------------------------|
|
||||
| New Controller | Project Structure, API Endpoints |
|
||||
| New Model | Project Structure |
|
||||
| New Migration/Table | Database Schema |
|
||||
| New View | Project Structure |
|
||||
| New Route | API Endpoints |
|
||||
| New Command | Development Commands |
|
||||
| Config Change | Setup |
|
||||
|
||||
Keep the README accurate and up-to-date with the actual codebase.
|
||||
|
||||
229
README.md
229
README.md
@ -1,68 +1,207 @@
|
||||
# CodeIgniter 4 Application Starter
|
||||
# TinyQC - Quality Control Management System
|
||||
|
||||
## What is CodeIgniter?
|
||||
A CodeIgniter 4 PHP application for quality control data management in laboratory settings. Built with Tailwind CSS, Alpine.js, and DaisyUI.
|
||||
|
||||
CodeIgniter is a PHP full-stack web framework that is light, fast, flexible and secure.
|
||||
More information can be found at the [official site](https://codeigniter.com).
|
||||
## Features
|
||||
|
||||
This repository holds a composer-installable app starter.
|
||||
It has been built from the
|
||||
[development repository](https://github.com/codeigniter4/CodeIgniter4).
|
||||
- **Dictionary Management**: Maintain departments, tests, and control parameters
|
||||
- **Control Management**: Configure and manage quality control standards
|
||||
- **Daily Entries**: Record daily quality control test results
|
||||
- **Monthly Entries**: Aggregate and track monthly quality control data
|
||||
- **Comments System**: Add notes and comments to results
|
||||
- **Reporting**: Generate quality control reports and analysis
|
||||
|
||||
More information about the plans for version 4 can be found in [CodeIgniter 4](https://forum.codeigniter.com/forumdisplay.php?fid=28) on the forums.
|
||||
## Technology Stack
|
||||
|
||||
You can read the [user guide](https://codeigniter.com/user_guide/)
|
||||
corresponding to the latest version of the framework.
|
||||
| Layer | Technology |
|
||||
|-------|------------|
|
||||
| Backend | CodeIgniter 4 (PHP 8.1+) |
|
||||
| Database | SQL Server |
|
||||
| Frontend | TailwindCSS + Alpine.js + DaisyUI |
|
||||
| Icons | FontAwesome 7 |
|
||||
| Testing | PHPUnit |
|
||||
|
||||
## Installation & updates
|
||||
## Requirements
|
||||
|
||||
`composer create-project codeigniter4/appstarter` then `composer update` whenever
|
||||
there is a new release of the framework.
|
||||
- PHP 8.1 or higher
|
||||
- SQL Server 2016+
|
||||
- Composer
|
||||
- Web server (Apache/Nginx/IIS)
|
||||
|
||||
When updating, check the release notes to see if there are any changes you might need to apply
|
||||
to your `app` folder. The affected files can be copied or merged from
|
||||
`vendor/codeigniter4/framework/app`.
|
||||
## Installation
|
||||
|
||||
## Setup
|
||||
1. **Clone the repository**
|
||||
```bash
|
||||
git clone <repository-url> tinyqc
|
||||
cd tinyqc
|
||||
```
|
||||
|
||||
Copy `env` to `.env` and tailor for your app, specifically the baseURL
|
||||
and any database settings.
|
||||
2. **Install dependencies**
|
||||
```bash
|
||||
composer install
|
||||
```
|
||||
|
||||
## Important Change with index.php
|
||||
3. **Configure environment**
|
||||
```bash
|
||||
copy env .env
|
||||
```
|
||||
Edit `.env` with your database settings:
|
||||
```env
|
||||
database.default.hostname = localhost
|
||||
database.default.port = 1433
|
||||
database.default.database = tinyqc
|
||||
database.default.username = sa
|
||||
database.default.password = your_password
|
||||
database.default.DBDriver = SQLSRV
|
||||
```
|
||||
|
||||
`index.php` is no longer in the root of the project! It has been moved inside the *public* folder,
|
||||
for better security and separation of components.
|
||||
4. **Set up database**
|
||||
- Create a new SQL Server database
|
||||
- Run migrations if applicable
|
||||
- Seed initial data if needed
|
||||
|
||||
This means that you should configure your web server to "point" to your project's *public* folder, and
|
||||
not to the project root. A better practice would be to configure a virtual host to point there. A poor practice would be to point your web server to the project root and expect to enter *public/...*, as the rest of your logic and the
|
||||
framework are exposed.
|
||||
5. **Configure web server**
|
||||
Point your web server to the `public` directory:
|
||||
```apache
|
||||
<VirtualHost *:80>
|
||||
ServerName tinyqc.local
|
||||
DocumentRoot "D:/data/www/tinyqc/public"
|
||||
<Directory "D:/data/www/tinyqc">
|
||||
AllowOverride All
|
||||
Require all granted
|
||||
</Directory>
|
||||
</VirtualHost>
|
||||
```
|
||||
|
||||
**Please** read the user guide for a better explanation of how CI4 works!
|
||||
6. **Access the application**
|
||||
Open http://localhost in your browser
|
||||
|
||||
## Repository Management
|
||||
## Project Structure
|
||||
|
||||
We use GitHub issues, in our main repository, to track **BUGS** and to track approved **DEVELOPMENT** work packages.
|
||||
We use our [forum](http://forum.codeigniter.com) to provide SUPPORT and to discuss
|
||||
FEATURE REQUESTS.
|
||||
```
|
||||
tinyqc/
|
||||
├── app/
|
||||
│ ├── Config/ # Configuration files
|
||||
│ │ ├── Database.php # Database settings
|
||||
│ │ └── Routes.php # Route definitions
|
||||
│ ├── Controllers/ # Application controllers
|
||||
│ │ ├── Api/ # API controllers
|
||||
│ │ ├── Dashboard.php
|
||||
│ │ ├── Dept.php
|
||||
│ │ ├── Test.php
|
||||
│ │ ├── Control.php
|
||||
│ │ ├── Entry.php
|
||||
│ │ ├── PageController.php
|
||||
│ │ └── Report.php
|
||||
│ ├── Models/ # Database models
|
||||
│ │ ├── DictDeptModel.php
|
||||
│ │ ├── DictTestModel.php
|
||||
│ │ ├── DictControlModel.php
|
||||
│ │ ├── ControlModel.php
|
||||
│ │ ├── ControlTestModel.php
|
||||
│ │ ├── DailyResultModel.php
|
||||
│ │ └── ...
|
||||
│ └── Views/ # View templates
|
||||
│ ├── layout/ # Layout templates
|
||||
│ ├── dashboard.php
|
||||
│ ├── dept/ # Department views
|
||||
│ ├── test/ # Test views
|
||||
│ ├── control/ # Control views
|
||||
│ ├── entry/ # Entry views
|
||||
│ └── report/ # Report views
|
||||
├── public/ # Web root
|
||||
├── tests/ # Unit tests
|
||||
├── writable/ # Writable directory
|
||||
├── env # Environment template
|
||||
├── composer.json
|
||||
└── phpunit.xml.dist
|
||||
```
|
||||
|
||||
This repository is a "distribution" one, built by our release preparation script.
|
||||
Problems with it can be raised on our forum, or as issues in the main repository.
|
||||
## Usage
|
||||
|
||||
## Server Requirements
|
||||
### Dashboard
|
||||
The main dashboard provides an overview of quality control status and quick access to all modules.
|
||||
|
||||
PHP version 8.1 or higher is required, with the following extensions installed:
|
||||
### Dictionary Management
|
||||
|
||||
- [intl](http://php.net/manual/en/intl.requirements.php)
|
||||
- [mbstring](http://php.net/manual/en/mbstring.installation.php)
|
||||
- **Departments**: Manage department/category entries
|
||||
- **Tests**: Maintain test parameters and specifications
|
||||
- **Controls**: Configure control standards and limits
|
||||
|
||||
> [!WARNING]
|
||||
> - The end of life date for PHP 7.4 was November 28, 2022.
|
||||
> - The end of life date for PHP 8.0 was November 26, 2023.
|
||||
> - If you are still using PHP 7.4 or 8.0, you should upgrade immediately.
|
||||
> - The end of life date for PHP 8.1 will be December 31, 2025.
|
||||
### Data Entry
|
||||
|
||||
Additionally, make sure that the following extensions are enabled in your PHP:
|
||||
- **Daily Entry**: Record daily QC test results
|
||||
- **Monthly Entry**: Aggregate monthly data and comments
|
||||
|
||||
- json (enabled by default - don't turn it off)
|
||||
- [mysqlnd](http://php.net/manual/en/mysqlnd.install.php) if you plan to use MySQL
|
||||
- [libcurl](http://php.net/manual/en/curl.requirements.php) if you plan to use the HTTP\CURLRequest library
|
||||
### Reports
|
||||
|
||||
Generate quality control reports based on:
|
||||
- Date ranges
|
||||
- Test types
|
||||
- Control parameters
|
||||
|
||||
## API Endpoints
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| GET | /api/dept | List departments |
|
||||
| GET | /api/dept/:id | Get department details |
|
||||
| POST | /api/dept | Create department |
|
||||
| PUT | /api/dept/:id | Update department |
|
||||
| DELETE | /api/dept/:id | Delete department |
|
||||
| GET | /api/test | List tests |
|
||||
| GET | /api/test/:id | Get test details |
|
||||
| POST | /api/test | Create test |
|
||||
| PUT | /api/test/:id | Update test |
|
||||
| DELETE | /api/test/:id | Delete test |
|
||||
| GET | /api/control | List controls |
|
||||
| GET | /api/control/:id | Get control details |
|
||||
| POST | /api/control | Create control |
|
||||
| PUT | /api/control/:id | Update control |
|
||||
| DELETE | /api/control/:id | Delete control |
|
||||
| GET | /api/entry/controls | Get controls for entry |
|
||||
| GET | /api/entry/tests | Get tests for entry |
|
||||
| POST | /api/entry/daily | Save daily result |
|
||||
| POST | /api/entry/monthly | Save monthly entry |
|
||||
| POST | /api/entry/comment | Save comment |
|
||||
|
||||
## Development
|
||||
|
||||
### Running Tests
|
||||
|
||||
```bash
|
||||
# Run all tests
|
||||
./vendor/bin/phpunit
|
||||
|
||||
# Run with coverage
|
||||
./vendor/bin/phpunit --coverage-html coverage/
|
||||
```
|
||||
|
||||
### Code Style
|
||||
|
||||
Follow these guidelines:
|
||||
- PSR-12 coding standards
|
||||
- CamelCase for variables/functions
|
||||
- PascalCase for classes
|
||||
- snake_case for database tables/columns
|
||||
|
||||
### Adding New Features
|
||||
|
||||
1. Create model in `app/Models/`
|
||||
2. Create API controller in `app/Controllers/Api/`
|
||||
3. Add routes in `app/Config/Routes.php`
|
||||
4. Create views in `app/Views/[module]/`
|
||||
5. Add menu item in layout if needed
|
||||
|
||||
## Documentation
|
||||
|
||||
- [agent1.md](agent1.md) - Complete development guide
|
||||
- [VIEWS_RULES.md](VIEWS_RULES.md) - View patterns and conventions
|
||||
|
||||
## License
|
||||
|
||||
This project is proprietary software.
|
||||
|
||||
## Support
|
||||
|
||||
For support, please contact the development team.
|
||||
|
||||
531
VIEWS_RULES.md
531
VIEWS_RULES.md
@ -1,531 +0,0 @@
|
||||
# TinyLab View Rules
|
||||
|
||||
This document defines the view patterns and conventions used in TinyLab. Follow these rules when creating new views or modifying existing ones.
|
||||
|
||||
## 1. Directory Structure
|
||||
|
||||
```
|
||||
app/Views/
|
||||
├── layout/
|
||||
│ ├── main_layout.php # Primary app layout (sidebar, navbar, dark mode)
|
||||
│ └── form_layout.php # Lightweight layout for standalone forms
|
||||
├── [module_name]/ # Feature module (e.g., patients, requests)
|
||||
│ ├── index.php # Main list page
|
||||
│ ├── dialog_form.php # Modal form (Create/Edit)
|
||||
│ └── drawer_filter.php # Filter drawer (optional)
|
||||
├── master/
|
||||
│ └── [entity]/ # Master data entity (e.g., doctors, samples)
|
||||
│ ├── index.php
|
||||
│ └── dialog_form.php
|
||||
└── errors/
|
||||
└── html/
|
||||
├── error_404.php
|
||||
└── error_exception.php
|
||||
```
|
||||
|
||||
## 2. Layout Extension
|
||||
|
||||
All pages must extend the appropriate layout:
|
||||
|
||||
```php
|
||||
<?= $this->extend("layout/main_layout"); ?>
|
||||
<?= $this->section("content") ?>
|
||||
<!-- Page content here -->
|
||||
<?= $this->endSection(); ?>
|
||||
<?= $this->section("script") ?>
|
||||
<!-- Alpine.js scripts here -->
|
||||
<?= $this->endSection(); ?>
|
||||
```
|
||||
|
||||
Use `form_layout.php` for standalone pages like login:
|
||||
```php
|
||||
<?= $this->extend("layout/form_layout"); ?>
|
||||
```
|
||||
|
||||
## 3. Alpine.js Integration
|
||||
|
||||
### 3.1 Component Definition
|
||||
|
||||
Always use `alpine:init` event listener:
|
||||
|
||||
```php
|
||||
<?= $this->section("script") ?>
|
||||
<script type="module">
|
||||
import Alpine from '<?= base_url('/assets/js/app.js'); ?>';
|
||||
|
||||
document.addEventListener('alpine:init', () => {
|
||||
Alpine.data("componentName", () => ({
|
||||
// State
|
||||
loading: false,
|
||||
showModal: false,
|
||||
list: [],
|
||||
item: null,
|
||||
form: {},
|
||||
errors: {},
|
||||
keyword: '',
|
||||
|
||||
// Lifecycle
|
||||
init() {
|
||||
this.fetchList();
|
||||
},
|
||||
|
||||
// Methods
|
||||
async fetchList() {
|
||||
this.loading = true;
|
||||
try {
|
||||
const res = await fetch(`${window.BASEURL}/api/resource`);
|
||||
const data = await res.json();
|
||||
this.list = data.data || [];
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
|
||||
showForm(id = null) {
|
||||
this.form = id ? this.list.find(x => x.id === id) : {};
|
||||
this.showModal = true;
|
||||
},
|
||||
|
||||
closeModal() {
|
||||
this.showModal = false;
|
||||
this.errors = {};
|
||||
},
|
||||
|
||||
validate() {
|
||||
this.errors = {};
|
||||
if (!this.form.field) this.errors.field = 'Field is required';
|
||||
return Object.keys(this.errors).length === 0;
|
||||
},
|
||||
|
||||
async save() {
|
||||
if (!this.validate()) return;
|
||||
this.loading = true;
|
||||
try {
|
||||
const method = this.form.id ? 'PATCH' : 'POST';
|
||||
const res = await fetch(`${window.BASEURL}/api/resource`, {
|
||||
method,
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(this.form)
|
||||
});
|
||||
const data = await res.json();
|
||||
if (data.status === 'success') {
|
||||
this.closeModal();
|
||||
this.fetchList();
|
||||
}
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
}
|
||||
}));
|
||||
});
|
||||
|
||||
Alpine.start();
|
||||
</script>
|
||||
<?= $this->endSection(); ?>
|
||||
```
|
||||
|
||||
### 3.2 Alpine Data Attribute
|
||||
|
||||
Wrap page content in the component:
|
||||
|
||||
```php
|
||||
<main x-data="componentName()">
|
||||
<!-- Page content -->
|
||||
</main>
|
||||
```
|
||||
|
||||
## 4. Modal/Dialog Pattern
|
||||
|
||||
### 4.1 Standard Modal Structure
|
||||
|
||||
```php
|
||||
<!-- Backdrop -->
|
||||
<div x-show="showModal"
|
||||
x-transition:enter="transition ease-out duration-200"
|
||||
x-transition:enter-start="opacity-0"
|
||||
x-transition:enter-end="opacity-100"
|
||||
x-transition:leave="transition ease-in duration-150"
|
||||
x-transition:leave-start="opacity-100"
|
||||
x-transition:leave-end="opacity-0"
|
||||
class="fixed inset-0 bg-slate-900/50 backdrop-blur-sm z-40"
|
||||
@click="closeModal()">
|
||||
</div>
|
||||
|
||||
<!-- Modal Panel -->
|
||||
<div x-show="showModal"
|
||||
x-cloak
|
||||
x-transition:enter="transition ease-out duration-200"
|
||||
x-transition:enter-start="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
||||
x-transition:enter-end="opacity-100 translate-y-0 sm:scale-100"
|
||||
x-transition:leave="transition ease-in duration-150"
|
||||
x-transition:leave-start="opacity-100 translate-y-0 sm:scale-100"
|
||||
x-transition:leave-end="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
||||
class="fixed inset-0 z-50 flex items-center justify-center p-4">
|
||||
<div class="bg-white rounded-2xl shadow-2xl w-full max-w-2xl" @click.stop>
|
||||
<!-- Header -->
|
||||
<div class="px-6 py-4 border-b border-slate-100 flex items-center justify-between">
|
||||
<h3 class="text-lg font-semibold text-slate-800" x-text="form.id ? 'Edit' : 'New'"></h3>
|
||||
<button @click="closeModal()" class="text-slate-400 hover:text-slate-600">
|
||||
<i class="fa-solid fa-xmark text-xl"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Form -->
|
||||
<form @submit.prevent="save()">
|
||||
<div class="p-6">
|
||||
<!-- Form fields -->
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-slate-700 mb-1">Field <span class="text-red-500">*</span></label>
|
||||
<input type="text" x-model="form.field"
|
||||
class="w-full px-4 py-2.5 text-sm bg-slate-50 border border-slate-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition-all"
|
||||
:class="{'border-red-300 bg-red-50': errors.field}" />
|
||||
<p x-show="errors.field" x-text="errors.field" class="text-red-500 text-xs mt-1"></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Footer -->
|
||||
<div class="flex items-center justify-end gap-3 px-6 py-4 border-t border-slate-100 bg-slate-50/50 rounded-b-2xl">
|
||||
<button type="button" @click="closeModal()" class="px-4 py-2 text-sm font-medium text-slate-600 hover:text-slate-800 transition-colors">Cancel</button>
|
||||
<button type="submit" :disabled="loading" class="px-4 py-2 text-sm font-medium text-white bg-blue-600 rounded-lg hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors">
|
||||
<template x-if="!loading"><span><i class="fa-solid fa-check mr-1"></i> Save</span></template>
|
||||
<template x-if="loading"><span><svg class="animate-spin h-4 w-4 mr-1 inline" viewBox="0 0 24 24"><!-- SVG --></svg> Saving...</span></template>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
## 5. Page Structure Pattern
|
||||
|
||||
### 5.1 Standard CRUD Page
|
||||
|
||||
```php
|
||||
<?= $this->extend("layout/main_layout"); ?>
|
||||
<?= $this->section("content") ?>
|
||||
<main x-data="componentName()">
|
||||
<!-- Page Header -->
|
||||
<div class="flex items-center justify-between mb-6">
|
||||
<div>
|
||||
<h1 class="text-2xl font-bold text-slate-800">Module Title</h1>
|
||||
<p class="text-sm text-slate-500 mt-1">Module description</p>
|
||||
</div>
|
||||
<button @click="showForm()" class="btn btn-primary">
|
||||
<i class="fa-solid fa-plus mr-2"></i>New Item
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Search Card -->
|
||||
<div class="bg-white rounded-xl border border-slate-100 shadow-sm p-4 mb-6">
|
||||
<div class="flex gap-3">
|
||||
<div class="flex-1 relative">
|
||||
<i class="fa-solid fa-search absolute left-3 top-1/2 -translate-y-1/2 text-slate-400 text-sm"></i>
|
||||
<input type="text" x-model="keyword" @keyup.enter="fetchList()"
|
||||
class="w-full pl-10 pr-4 py-2.5 text-sm bg-slate-50 border border-slate-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500"
|
||||
placeholder="Search..." />
|
||||
</div>
|
||||
<button @click="fetchList()" class="btn btn-primary">
|
||||
<i class="fa-solid fa-search mr-2"></i>Search
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Error Alert -->
|
||||
<div x-show="error" x-transition class="bg-red-50 border border-red-200 text-red-700 px-4 py-3 rounded-lg mb-6">
|
||||
<div class="flex items-center gap-2">
|
||||
<i class="fa-solid fa-circle-exclamation"></i>
|
||||
<span x-text="error"></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Data Table Card -->
|
||||
<div class="bg-white rounded-xl border border-slate-100 shadow-sm overflow-hidden">
|
||||
<!-- Loading State -->
|
||||
<template x-if="loading">
|
||||
<div class="p-12 text-center">
|
||||
<div class="w-16 h-16 rounded-full bg-blue-50 flex items-center justify-center mx-auto mb-4">
|
||||
<i class="fa-solid fa-spinner fa-spin text-blue-500 text-xl"></i>
|
||||
</div>
|
||||
<p class="text-slate-500 text-sm">Loading...</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- Empty State -->
|
||||
<template x-if="!loading && (!list || list.length === 0)">
|
||||
<div class="flex-1 flex items-center justify-center p-8">
|
||||
<div class="text-center">
|
||||
<div class="w-12 h-12 rounded-full bg-slate-100 flex items-center justify-center mx-auto mb-3">
|
||||
<i class="fa-solid fa-inbox text-slate-400"></i>
|
||||
</div>
|
||||
<p class="text-slate-500 text-sm">No data found</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- Data Table -->
|
||||
<template x-if="!loading && list && list.length > 0">
|
||||
<table class="w-full text-sm text-left">
|
||||
<thead class="bg-slate-50 text-slate-500 text-xs uppercase tracking-wider">
|
||||
<tr>
|
||||
<th class="py-3 px-5 font-semibold">#</th>
|
||||
<th class="py-3 px-5 font-semibold">Code</th>
|
||||
<th class="py-3 px-5 font-semibold">Name</th>
|
||||
<th class="py-3 px-5 font-semibold text-right">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-slate-100">
|
||||
<template x-for="(item, index) in list" :key="item.id">
|
||||
<tr class="hover:bg-slate-50/50 transition-colors">
|
||||
<td class="py-3 px-5" x-text="index + 1"></td>
|
||||
<td class="py-3 px-5">
|
||||
<span class="font-mono text-xs bg-slate-100 text-slate-600 px-2 py-1 rounded" x-text="item.code"></span>
|
||||
</td>
|
||||
<td class="py-3 px-5 font-medium text-slate-800" x-text="item.name"></td>
|
||||
<td class="py-3 px-5 text-right">
|
||||
<button @click="showForm(item.id)" class="text-blue-600 hover:text-blue-800 mr-3">
|
||||
<i class="fa-solid fa-pen-to-square"></i>
|
||||
</button>
|
||||
<button @click="delete(item.id)" class="text-red-600 hover:text-red-800">
|
||||
<i class="fa-solid fa-trash"></i>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
</tbody>
|
||||
</table>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<!-- Dialog Include -->
|
||||
<?= $this->include('module/dialog_form'); ?>
|
||||
</main>
|
||||
<?= $this->endSection(); ?>
|
||||
```
|
||||
|
||||
### 5.2 Master-Detail Pattern
|
||||
|
||||
```php
|
||||
<!-- Master-Detail Layout -->
|
||||
<div class="flex-1 grid grid-cols-1 lg:grid-cols-3 gap-6 min-h-0">
|
||||
<!-- List Panel -->
|
||||
<div class="bg-white rounded-xl border border-slate-100 shadow-sm overflow-hidden flex flex-col">
|
||||
<div class="p-4 border-b border-slate-100">
|
||||
<input type="text" x-model="keyword" @keyup.enter="fetchList()" placeholder="Search..." class="w-full px-3 py-2 text-sm bg-slate-50 border border-slate-200 rounded-lg" />
|
||||
</div>
|
||||
<div class="flex-1 overflow-y-auto">
|
||||
<template x-for="item in list" :key="item.id">
|
||||
<div class="px-4 py-3 hover:bg-blue-50/50 cursor-pointer border-b border-slate-50"
|
||||
:class="{'bg-blue-50': selectedId === item.id}"
|
||||
@click="fetchDetail(item.id)">
|
||||
<p class="font-medium text-slate-800" x-text="item.name"></p>
|
||||
<p class="text-xs text-slate-500" x-text="item.code"></p>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Detail Panel -->
|
||||
<div class="lg:col-span-2 bg-white rounded-xl border border-slate-100 shadow-sm">
|
||||
<template x-if="!detail">
|
||||
<div class="flex items-center justify-center h-full min-h-[400px] text-slate-400">
|
||||
<div class="text-center">
|
||||
<i class="fa-solid fa-folder-open text-4xl mb-3"></i>
|
||||
<p>Select an item to view details</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template x-if="detail">
|
||||
<div class="p-6">
|
||||
<!-- Detail content -->
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
## 6. Form Field Patterns
|
||||
|
||||
### 6.1 Input with Icon
|
||||
```php
|
||||
<div class="relative">
|
||||
<i class="fa-solid fa-icon absolute left-3 top-1/2 -translate-y-1/2 text-slate-400 text-sm"></i>
|
||||
<input type="text" x-model="form.field"
|
||||
class="w-full pl-10 pr-4 py-2.5 text-sm bg-slate-50 border border-slate-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition-all"
|
||||
placeholder="Placeholder text" />
|
||||
</div>
|
||||
```
|
||||
|
||||
### 6.2 Select Dropdown
|
||||
```php
|
||||
<select x-model="form.field" class="w-full px-4 py-2.5 text-sm bg-slate-50 border border-slate-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500">
|
||||
<option value="">-- Select --</option>
|
||||
<template x-for="option in options" :key="option.value">
|
||||
<option :value="option.value" x-text="option.label"></option>
|
||||
</template>
|
||||
</select>
|
||||
```
|
||||
|
||||
### 6.3 Checkbox
|
||||
```php
|
||||
<label class="flex items-center gap-2 cursor-pointer">
|
||||
<input type="checkbox" x-model="form.field" class="checkbox checkbox-sm checkbox-primary" />
|
||||
<span class="text-sm text-slate-700">Checkbox label</span>
|
||||
</label>
|
||||
```
|
||||
|
||||
### 6.4 Radio Group
|
||||
```php
|
||||
<div class="flex gap-4">
|
||||
<template x-for="option in options" :key="option.value">
|
||||
<label class="flex items-center gap-2 cursor-pointer">
|
||||
<input type="radio" :name="'fieldName'" :value="option.value" x-model="form.field" class="radio radio-sm radio-primary" />
|
||||
<span class="text-sm text-slate-700" x-text="option.label"></span>
|
||||
</label>
|
||||
</template>
|
||||
</div>
|
||||
```
|
||||
|
||||
## 7. Status Badges
|
||||
|
||||
```php
|
||||
<span class="px-2 py-0.5 rounded-full text-xs font-medium"
|
||||
:class="{
|
||||
'bg-amber-100 text-amber-700': status === 'P',
|
||||
'bg-blue-100 text-blue-700': status === 'I',
|
||||
'bg-emerald-100 text-emerald-700': status === 'C',
|
||||
'bg-red-100 text-red-700': status === 'X'
|
||||
}"
|
||||
x-text="getStatusLabel(status)">
|
||||
</span>
|
||||
```
|
||||
|
||||
## 8. CSS Classes Reference
|
||||
|
||||
### Layout
|
||||
- `flex`, `flex-col`, `grid`, `grid-cols-2`, `gap-4`
|
||||
- `w-full`, `max-w-2xl`, `min-h-0`
|
||||
- `overflow-hidden`, `overflow-y-auto`
|
||||
|
||||
### Spacing
|
||||
- `p-4`, `px-6`, `py-3`, `m-4`, `mb-6`
|
||||
- `space-x-4`, `gap-3`
|
||||
|
||||
### Typography
|
||||
- `text-sm`, `text-xs`, `text-lg`, `text-2xl`
|
||||
- `font-medium`, `font-semibold`, `font-bold`
|
||||
- `text-slate-500`, `text-slate-800`
|
||||
|
||||
### Borders & Backgrounds
|
||||
- `bg-white`, `bg-slate-50`, `bg-blue-50`
|
||||
- `border`, `border-slate-100`, `border-red-300`
|
||||
- `rounded-lg`, `rounded-xl`, `rounded-2xl`
|
||||
|
||||
### Components
|
||||
- `btn btn-primary`, `btn btn-ghost`
|
||||
- `checkbox checkbox-sm`
|
||||
- `radio radio-primary`
|
||||
- `input`, `select`, `textarea`
|
||||
|
||||
### Icons
|
||||
FontAwesome 7 via CDN: `<i class="fa-solid fa-icon-name"></i>`
|
||||
|
||||
## 9. API Response Format
|
||||
|
||||
Views expect API responses in this format:
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "success",
|
||||
"message": "Operation successful",
|
||||
"data": [...]
|
||||
}
|
||||
```
|
||||
|
||||
## 10. Validation Pattern
|
||||
|
||||
```javascript
|
||||
validate() {
|
||||
this.errors = {};
|
||||
|
||||
if (!this.form.field1) {
|
||||
this.errors.field1 = 'Field 1 is required';
|
||||
}
|
||||
if (!this.form.field2) {
|
||||
this.errors.field2 = 'Field 2 is required';
|
||||
}
|
||||
if (this.form.field3 && !/^\d+$/.test(this.form.field3)) {
|
||||
this.errors.field3 = 'Must be numeric';
|
||||
}
|
||||
|
||||
return Object.keys(this.errors).length === 0;
|
||||
}
|
||||
```
|
||||
|
||||
## 11. Error Handling
|
||||
|
||||
```javascript
|
||||
async save() {
|
||||
this.loading = true;
|
||||
try {
|
||||
const res = await fetch(url, { ... });
|
||||
const data = await res.json();
|
||||
if (data.status === 'success') {
|
||||
this.showToast('Saved successfully');
|
||||
this.fetchList();
|
||||
} else {
|
||||
this.error = data.message || 'An error occurred';
|
||||
}
|
||||
} catch (err) {
|
||||
this.error = 'Network error. Please try again.';
|
||||
console.error(err);
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 12. Quick Reference: File Templates
|
||||
|
||||
### Standard List Page Template
|
||||
See: `app/Views/master/doctors/doctors_index.php`
|
||||
|
||||
### Modal Form Template
|
||||
See: `app/Views/master/doctors/dialog_doctors_form.php`
|
||||
|
||||
### Master-Detail Page Template
|
||||
See: `app/Views/patients/patients_index.php`
|
||||
|
||||
### Result Entry Table Template
|
||||
See: `app/Views/requests/dialog_result_entry.php`
|
||||
|
||||
## 13. Checklist for New Views
|
||||
|
||||
- [ ] Create view file in correct directory
|
||||
- [ ] Extend appropriate layout (`main_layout` or `form_layout`)
|
||||
- [ ] Define `content` and `script` sections
|
||||
- [ ] Wrap content in `x-data` component
|
||||
- [ ] Include modal form if needed
|
||||
- [ ] Use DaisyUI components for buttons, inputs, selects
|
||||
- [ ] Add loading and empty states
|
||||
- [ ] Implement proper error handling
|
||||
- [ ] Use FontAwesome icons consistently
|
||||
- [ ] Follow naming conventions (snake_case for PHP, camelCase for JS)
|
||||
|
||||
## 14. Conventions Summary
|
||||
|
||||
| Aspect | Convention |
|
||||
|--------|------------|
|
||||
| File naming | snake_case (e.g., `patients_index.php`) |
|
||||
| PHP variables | snake_case |
|
||||
| JavaScript variables | camelCase |
|
||||
| HTML classes | kebab-case (Tailwind) |
|
||||
| Icons | FontAwesome 7 |
|
||||
| UI Framework | TailwindCSS + DaisyUI |
|
||||
| State management | Alpine.js |
|
||||
| API format | JSON with `status`, `message`, `data` |
|
||||
| Primary key | `{table}_id` (e.g., `pat_id`) |
|
||||
| Soft deletes | All tables use `deleted_at` |
|
||||
@ -19,20 +19,20 @@ $routes->group('api', function ($routes) {
|
||||
$routes->get('dept', 'Api\DeptApiController::index');
|
||||
$routes->get('dept/(:num)', 'Api\DeptApiController::show/$1');
|
||||
$routes->post('dept', 'Api\DeptApiController::store');
|
||||
$routes->put('dept/(:num)', 'Api\DeptApiController::update/$1');
|
||||
$routes->patch('dept/(:num)', 'Api\DeptApiController::update/$1');
|
||||
$routes->delete('dept/(:num)', 'Api\DeptApiController::delete/$1');
|
||||
|
||||
$routes->get('test', 'Api\TestApiController::index');
|
||||
$routes->get('test/(:num)', 'Api\TestApiController::show/$1');
|
||||
$routes->post('test', 'Api\TestApiController::store');
|
||||
$routes->put('test/(:num)', 'Api\TestApiController::update/$1');
|
||||
$routes->patch('test/(:num)', 'Api\TestApiController::update/$1');
|
||||
$routes->delete('test/(:num)', 'Api\TestApiController::delete/$1');
|
||||
|
||||
$routes->get('control', 'Api\ControlApiController::index');
|
||||
$routes->get('control/(:num)', 'Api\ControlApiController::show/$1');
|
||||
$routes->get('control/(:num)/tests', 'Api\ControlApiController::getTests/$1');
|
||||
$routes->post('control', 'Api\ControlApiController::store');
|
||||
$routes->put('control/(:num)', 'Api\ControlApiController::update/$1');
|
||||
$routes->patch('control/(:num)', 'Api\ControlApiController::update/$1');
|
||||
$routes->delete('control/(:num)', 'Api\ControlApiController::delete/$1');
|
||||
|
||||
$routes->get('entry/controls', 'Api\EntryApiController::getControls');
|
||||
|
||||
@ -10,65 +10,77 @@ class ControlApiController extends BaseController
|
||||
{
|
||||
protected $dictControlModel;
|
||||
protected $controlTestModel;
|
||||
protected $rules;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->dictControlModel = new DictControlModel();
|
||||
$this->controlTestModel = new ControlTestModel();
|
||||
$this->rules = [
|
||||
'name' => 'required|min_length[1]',
|
||||
'dept_ref_id' => 'required',
|
||||
];
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
$controls = $this->dictControlModel->getWithDept();
|
||||
return $this->response->setJSON([
|
||||
try {
|
||||
$rows = $this->dictControlModel->getWithDept();
|
||||
return $this->respond([
|
||||
'status' => 'success',
|
||||
'message' => 'Controls fetched successfully',
|
||||
'data' => $controls
|
||||
]);
|
||||
'message' => 'fetch success',
|
||||
'data' => $rows
|
||||
], 200);
|
||||
} catch (\Exception $e) {
|
||||
return $this->failServerError('Exception: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function show($id)
|
||||
public function show($id = null)
|
||||
{
|
||||
$control = $this->dictControlModel->find($id);
|
||||
if (!$control) {
|
||||
return $this->response->setJSON([
|
||||
'status' => 'error',
|
||||
'message' => 'Control not found'
|
||||
])->setStatusCode(404);
|
||||
}
|
||||
return $this->response->setJSON([
|
||||
try {
|
||||
$rows = $this->dictControlModel->where('control_id', $id)->findAll();
|
||||
if (empty($rows)) {
|
||||
return $this->respond([
|
||||
'status' => 'success',
|
||||
'data' => $control
|
||||
]);
|
||||
'message' => 'data not found.'
|
||||
], 200);
|
||||
}
|
||||
|
||||
public function getTests($id)
|
||||
{
|
||||
$tests = $this->controlTestModel->where('control_ref_id', $id)->findAll();
|
||||
$testIds = array_column($tests, 'test_ref_id');
|
||||
|
||||
return $this->response->setJSON([
|
||||
return $this->respond([
|
||||
'status' => 'success',
|
||||
'data' => $testIds
|
||||
]);
|
||||
'message' => 'fetch success',
|
||||
'data' => $rows
|
||||
], 200);
|
||||
} catch (\Exception $e) {
|
||||
return $this->failServerError('Something went wrong: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function store()
|
||||
public function getTests($id = null)
|
||||
{
|
||||
$post = $this->request->getJSON(true);
|
||||
try {
|
||||
$rows = $this->controlTestModel->where('control_ref_id', $id)->findAll();
|
||||
return $this->respond([
|
||||
'status' => 'success',
|
||||
'message' => 'fetch success',
|
||||
'data' => $rows
|
||||
], 200);
|
||||
} catch (\Exception $e) {
|
||||
return $this->failServerError('Something went wrong: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
$controlData = [
|
||||
'dept_ref_id' => $post['dept_ref_id'] ?? null,
|
||||
'name' => $post['name'] ?? '',
|
||||
'lot' => $post['lot'] ?? '',
|
||||
'producer' => $post['producer'] ?? '',
|
||||
'expdate' => $post['expdate'] ?? null,
|
||||
];
|
||||
public function create()
|
||||
{
|
||||
$input = $this->request->getJSON(true);
|
||||
if (!$this->validate($this->rules)) {
|
||||
return $this->failValidationErrors($this->validator->getErrors());
|
||||
}
|
||||
try {
|
||||
$controlId = $this->dictControlModel->insert($input, true);
|
||||
|
||||
$controlId = $this->dictControlModel->insert($controlData, true);
|
||||
|
||||
if (!empty($post['test_ids'])) {
|
||||
foreach ($post['test_ids'] as $testId) {
|
||||
if (!empty($input['test_ids'])) {
|
||||
foreach ($input['test_ids'] as $testId) {
|
||||
$this->controlTestModel->insert([
|
||||
'control_ref_id' => $controlId,
|
||||
'test_ref_id' => $testId,
|
||||
@ -78,37 +90,27 @@ class ControlApiController extends BaseController
|
||||
}
|
||||
}
|
||||
|
||||
if ($controlId) {
|
||||
return $this->response->setJSON([
|
||||
return $this->respondCreated([
|
||||
'status' => 'success',
|
||||
'message' => 'Control saved successfully',
|
||||
'data' => ['control_id' => $controlId]
|
||||
'message' => $controlId
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return $this->failServerError('Something went wrong: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
return $this->response->setJSON([
|
||||
'status' => 'error',
|
||||
'message' => 'Failed to save control'
|
||||
])->setStatusCode(500);
|
||||
}
|
||||
|
||||
public function update($id)
|
||||
public function update($id = null)
|
||||
{
|
||||
$post = $this->request->getJSON(true);
|
||||
$input = $this->request->getJSON(true);
|
||||
if (!$this->validate($this->rules)) {
|
||||
return $this->failValidationErrors($this->validator->getErrors());
|
||||
}
|
||||
try {
|
||||
$this->dictControlModel->update($id, $input);
|
||||
|
||||
$controlData = [
|
||||
'dept_ref_id' => $post['dept_ref_id'] ?? null,
|
||||
'name' => $post['name'] ?? '',
|
||||
'lot' => $post['lot'] ?? '',
|
||||
'producer' => $post['producer'] ?? '',
|
||||
'expdate' => $post['expdate'] ?? null,
|
||||
];
|
||||
|
||||
$success = $this->dictControlModel->update($id, $controlData);
|
||||
|
||||
if (!empty($post['test_ids'])) {
|
||||
if (!empty($input['test_ids'])) {
|
||||
$this->controlTestModel->where('control_ref_id', $id)->delete();
|
||||
foreach ($post['test_ids'] as $testId) {
|
||||
foreach ($input['test_ids'] as $testId) {
|
||||
$this->controlTestModel->insert([
|
||||
'control_ref_id' => $id,
|
||||
'test_ref_id' => $testId,
|
||||
@ -118,34 +120,27 @@ class ControlApiController extends BaseController
|
||||
}
|
||||
}
|
||||
|
||||
if ($success) {
|
||||
return $this->response->setJSON([
|
||||
return $this->respond([
|
||||
'status' => 'success',
|
||||
'message' => 'Control updated successfully'
|
||||
'message' => 'update success',
|
||||
'data' => $id
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return $this->failServerError('Something went wrong: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
return $this->response->setJSON([
|
||||
'status' => 'error',
|
||||
'message' => 'Failed to update control'
|
||||
])->setStatusCode(500);
|
||||
}
|
||||
|
||||
public function delete($id)
|
||||
public function delete($id = null)
|
||||
{
|
||||
try {
|
||||
$this->controlTestModel->where('control_ref_id', $id)->delete();
|
||||
$success = $this->dictControlModel->delete($id);
|
||||
|
||||
if ($success) {
|
||||
return $this->response->setJSON([
|
||||
$this->dictControlModel->delete($id);
|
||||
return $this->respond([
|
||||
'status' => 'success',
|
||||
'message' => 'Control deleted successfully'
|
||||
'message' => 'delete success'
|
||||
]);
|
||||
}
|
||||
|
||||
return $this->response->setJSON([
|
||||
'status' => 'error',
|
||||
'message' => 'Failed to delete control'
|
||||
])->setStatusCode(500);
|
||||
} catch (\Exception $e) {
|
||||
return $this->failServerError('Something went wrong: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,98 +8,95 @@ use App\Models\DictDeptModel;
|
||||
class DeptApiController extends BaseController
|
||||
{
|
||||
protected $dictDeptModel;
|
||||
protected $rules;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->dictDeptModel = new DictDeptModel();
|
||||
$this->rules = [
|
||||
'name' => 'required|min_length[1]',
|
||||
];
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
$depts = $this->dictDeptModel->findAll();
|
||||
return $this->response->setJSON([
|
||||
try {
|
||||
$rows = $this->dictDeptModel->findAll();
|
||||
return $this->respond([
|
||||
'status' => 'success',
|
||||
'message' => 'Departments fetched successfully',
|
||||
'data' => $depts
|
||||
]);
|
||||
'message' => 'fetch success',
|
||||
'data' => $rows
|
||||
], 200);
|
||||
} catch (\Exception $e) {
|
||||
return $this->failServerError('Exception: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function show($id)
|
||||
public function show($id = null)
|
||||
{
|
||||
$dept = $this->dictDeptModel->find($id);
|
||||
if (!$dept) {
|
||||
return $this->response->setJSON([
|
||||
'status' => 'error',
|
||||
'message' => 'Department not found'
|
||||
])->setStatusCode(404);
|
||||
}
|
||||
return $this->response->setJSON([
|
||||
try {
|
||||
$rows = $this->dictDeptModel->where('dept_id', $id)->findAll();
|
||||
if (empty($rows)) {
|
||||
return $this->respond([
|
||||
'status' => 'success',
|
||||
'data' => $dept
|
||||
]);
|
||||
'message' => 'data not found.'
|
||||
], 200);
|
||||
}
|
||||
return $this->respond([
|
||||
'status' => 'success',
|
||||
'message' => 'fetch success',
|
||||
'data' => $rows
|
||||
], 200);
|
||||
} catch (\Exception $e) {
|
||||
return $this->failServerError('Something went wrong: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function store()
|
||||
public function create()
|
||||
{
|
||||
$post = $this->request->getJSON(true);
|
||||
|
||||
$data = [
|
||||
'name' => $post['name'] ?? '',
|
||||
];
|
||||
|
||||
$id = $this->dictDeptModel->insert($data);
|
||||
|
||||
if ($id) {
|
||||
return $this->response->setJSON([
|
||||
$input = $this->request->getJSON(true);
|
||||
if (!$this->validate($this->rules)) {
|
||||
return $this->failValidationErrors($this->validator->getErrors());
|
||||
}
|
||||
try {
|
||||
$id = $this->dictDeptModel->insert($input, true);
|
||||
return $this->respondCreated([
|
||||
'status' => 'success',
|
||||
'message' => 'Department saved successfully',
|
||||
'data' => ['dept_id' => $id]
|
||||
'message' => $id
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return $this->failServerError('Something went wrong: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
return $this->response->setJSON([
|
||||
'status' => 'error',
|
||||
'message' => 'Failed to save department'
|
||||
])->setStatusCode(500);
|
||||
}
|
||||
|
||||
public function update($id)
|
||||
public function update($id = null)
|
||||
{
|
||||
$post = $this->request->getJSON(true);
|
||||
|
||||
$data = [
|
||||
'name' => $post['name'] ?? '',
|
||||
];
|
||||
|
||||
$success = $this->dictDeptModel->update($id, $data);
|
||||
|
||||
if ($success) {
|
||||
return $this->response->setJSON([
|
||||
$input = $this->request->getJSON(true);
|
||||
if (!$this->validate($this->rules)) {
|
||||
return $this->failValidationErrors($this->validator->getErrors());
|
||||
}
|
||||
try {
|
||||
$this->dictDeptModel->update($id, $input);
|
||||
return $this->respond([
|
||||
'status' => 'success',
|
||||
'message' => 'Department updated successfully'
|
||||
'message' => 'update success',
|
||||
'data' => $id
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return $this->failServerError('Something went wrong: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
return $this->response->setJSON([
|
||||
'status' => 'error',
|
||||
'message' => 'Failed to update department'
|
||||
])->setStatusCode(500);
|
||||
}
|
||||
|
||||
public function delete($id)
|
||||
public function delete($id = null)
|
||||
{
|
||||
$success = $this->dictDeptModel->delete($id);
|
||||
|
||||
if ($success) {
|
||||
return $this->response->setJSON([
|
||||
try {
|
||||
$this->dictDeptModel->delete($id);
|
||||
return $this->respond([
|
||||
'status' => 'success',
|
||||
'message' => 'Department deleted successfully'
|
||||
'message' => 'delete success'
|
||||
]);
|
||||
}
|
||||
|
||||
return $this->response->setJSON([
|
||||
'status' => 'error',
|
||||
'message' => 'Failed to delete department'
|
||||
])->setStatusCode(500);
|
||||
} catch (\Exception $e) {
|
||||
return $this->failServerError('Something went wrong: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -25,119 +25,111 @@ class EntryApiController extends BaseController
|
||||
|
||||
public function getControls()
|
||||
{
|
||||
try {
|
||||
$date = $this->request->getGet('date');
|
||||
$deptid = $this->request->getGet('deptid');
|
||||
$deptId = $this->request->getGet('deptId');
|
||||
|
||||
$controls = $this->dictControlModel->getActiveByDate($date, $deptid);
|
||||
|
||||
return $this->response->setJSON([
|
||||
$rows = $this->dictControlModel->getActiveByDate($date, $deptId);
|
||||
return $this->respond([
|
||||
'status' => 'success',
|
||||
'message' => 'Controls fetched successfully',
|
||||
'data' => $controls
|
||||
]);
|
||||
'message' => 'fetch success',
|
||||
'data' => $rows
|
||||
], 200);
|
||||
} catch (\Exception $e) {
|
||||
return $this->failServerError('Something went wrong: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function getTests()
|
||||
{
|
||||
$controlid = $this->request->getGet('controlid');
|
||||
try {
|
||||
$controlId = $this->request->getGet('controlId');
|
||||
|
||||
$tests = $this->controlTestModel->getByControl($controlid);
|
||||
|
||||
return $this->response->setJSON([
|
||||
$rows = $this->controlTestModel->getByControl($controlId);
|
||||
return $this->respond([
|
||||
'status' => 'success',
|
||||
'message' => 'Tests fetched successfully',
|
||||
'data' => $tests
|
||||
]);
|
||||
'message' => 'fetch success',
|
||||
'data' => $rows
|
||||
], 200);
|
||||
} catch (\Exception $e) {
|
||||
return $this->failServerError('Something went wrong: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function saveDaily()
|
||||
{
|
||||
$post = $this->request->getPost();
|
||||
$input = $this->request->getJSON(true);
|
||||
|
||||
try {
|
||||
$resultData = [
|
||||
'control_ref_id' => $post['controlid'] ?? 0,
|
||||
'test_ref_id' => $post['testid'] ?? 0,
|
||||
'resdate' => $post['resdate'] ?? date('Y-m-d'),
|
||||
'resvalue' => $post['resvalue'] ?? '',
|
||||
'rescomment' => $post['rescomment'] ?? '',
|
||||
'control_ref_id' => $input['controlId'] ?? 0,
|
||||
'test_ref_id' => $input['testId'] ?? 0,
|
||||
'resdate' => $input['resdate'] ?? date('Y-m-d'),
|
||||
'resvalue' => $input['resvalue'] ?? '',
|
||||
'rescomment' => $input['rescomment'] ?? '',
|
||||
];
|
||||
|
||||
$success = $this->resultModel->saveResult($resultData);
|
||||
|
||||
if ($success) {
|
||||
return $this->response->setJSON([
|
||||
$this->resultModel->saveResult($resultData);
|
||||
return $this->respond([
|
||||
'status' => 'success',
|
||||
'message' => 'Result saved successfully'
|
||||
'message' => 'save success'
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return $this->failServerError('Something went wrong: ' . $e->getMessage());
|
||||
}
|
||||
|
||||
return $this->response->setJSON([
|
||||
'status' => 'error',
|
||||
'message' => 'Failed to save result'
|
||||
])->setStatusCode(500);
|
||||
}
|
||||
|
||||
public function saveMonthly()
|
||||
{
|
||||
$post = $this->request->getPost();
|
||||
$input = $this->request->getJSON(true);
|
||||
|
||||
$controlid = $post['controlid'] ?? 0;
|
||||
$testid = $post['testid'] ?? 0;
|
||||
$dates = $post['dates'] ?? '';
|
||||
$resvalues = $post['resvalue'] ?? [];
|
||||
try {
|
||||
$controlId = $input['controlId'] ?? 0;
|
||||
$testId = $input['testId'] ?? 0;
|
||||
$dates = $input['dates'] ?? '';
|
||||
$resvalues = $input['resvalue'] ?? [];
|
||||
|
||||
$success = true;
|
||||
foreach ($resvalues as $day => $value) {
|
||||
if (!empty($value)) {
|
||||
$resultData = [
|
||||
'control_ref_id' => $controlid,
|
||||
'test_ref_id' => $testid,
|
||||
'control_ref_id' => $controlId,
|
||||
'test_ref_id' => $testId,
|
||||
'resdate' => $dates . '-' . str_pad($day, 2, '0', STR_PAD_LEFT),
|
||||
'resvalue' => $value,
|
||||
'rescomment' => '',
|
||||
];
|
||||
if (!$this->resultModel->saveResult($resultData)) {
|
||||
$success = false;
|
||||
}
|
||||
$this->resultModel->saveResult($resultData);
|
||||
}
|
||||
}
|
||||
|
||||
if ($success) {
|
||||
return $this->response->setJSON([
|
||||
return $this->respond([
|
||||
'status' => 'success',
|
||||
'message' => 'Monthly data saved successfully'
|
||||
'message' => 'save success'
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return $this->failServerError('Something went wrong: ' . $e->getMessage());
|
||||
}
|
||||
|
||||
return $this->response->setJSON([
|
||||
'status' => 'error',
|
||||
'message' => 'Failed to save some entries'
|
||||
])->setStatusCode(500);
|
||||
}
|
||||
|
||||
public function saveComment()
|
||||
{
|
||||
$post = $this->request->getPost();
|
||||
$input = $this->request->getJSON(true);
|
||||
|
||||
try {
|
||||
$commentData = [
|
||||
'control_ref_id' => $post['controlid'] ?? 0,
|
||||
'test_ref_id' => $post['testid'] ?? 0,
|
||||
'commonth' => $post['commonth'] ?? '',
|
||||
'comtext' => $post['comtext'] ?? '',
|
||||
'control_ref_id' => $input['controlId'] ?? 0,
|
||||
'test_ref_id' => $input['testId'] ?? 0,
|
||||
'commonth' => $input['commonth'] ?? '',
|
||||
'comtext' => $input['comtext'] ?? '',
|
||||
];
|
||||
|
||||
$success = $this->commentModel->saveComment($commentData);
|
||||
|
||||
if ($success) {
|
||||
return $this->response->setJSON([
|
||||
$this->commentModel->saveComment($commentData);
|
||||
return $this->respond([
|
||||
'status' => 'success',
|
||||
'message' => 'Comment saved successfully'
|
||||
'message' => 'save success'
|
||||
]);
|
||||
}
|
||||
|
||||
return $this->response->setJSON([
|
||||
'status' => 'error',
|
||||
'message' => 'Failed to save comment'
|
||||
])->setStatusCode(500);
|
||||
} catch (\Exception $e) {
|
||||
return $this->failServerError('Something went wrong: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,111 +10,97 @@ class TestApiController extends BaseController
|
||||
{
|
||||
protected $dictTestModel;
|
||||
protected $dictDeptModel;
|
||||
protected $rules;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->dictTestModel = new DictTestModel();
|
||||
$this->dictDeptModel = new DictDeptModel();
|
||||
$this->rules = [
|
||||
'name' => 'required|min_length[1]',
|
||||
'dept_ref_id' => 'required',
|
||||
];
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
$tests = $this->dictTestModel->getWithDept();
|
||||
return $this->response->setJSON([
|
||||
try {
|
||||
$rows = $this->dictTestModel->getWithDept();
|
||||
return $this->respond([
|
||||
'status' => 'success',
|
||||
'message' => 'Tests fetched successfully',
|
||||
'data' => $tests
|
||||
]);
|
||||
'message' => 'fetch success',
|
||||
'data' => $rows
|
||||
], 200);
|
||||
} catch (\Exception $e) {
|
||||
return $this->failServerError('Exception: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function show($id)
|
||||
public function show($id = null)
|
||||
{
|
||||
$test = $this->dictTestModel->find($id);
|
||||
if (!$test) {
|
||||
return $this->response->setJSON([
|
||||
'status' => 'error',
|
||||
'message' => 'Test not found'
|
||||
])->setStatusCode(404);
|
||||
}
|
||||
return $this->response->setJSON([
|
||||
try {
|
||||
$rows = $this->dictTestModel->where('test_id', $id)->findAll();
|
||||
if (empty($rows)) {
|
||||
return $this->respond([
|
||||
'status' => 'success',
|
||||
'data' => $test
|
||||
]);
|
||||
'message' => 'data not found.'
|
||||
], 200);
|
||||
}
|
||||
return $this->respond([
|
||||
'status' => 'success',
|
||||
'message' => 'fetch success',
|
||||
'data' => $rows
|
||||
], 200);
|
||||
} catch (\Exception $e) {
|
||||
return $this->failServerError('Something went wrong: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function store()
|
||||
public function create()
|
||||
{
|
||||
$post = $this->request->getJSON(true);
|
||||
|
||||
$testData = [
|
||||
'dept_ref_id' => $post['dept_ref_id'] ?? null,
|
||||
'name' => $post['name'] ?? '',
|
||||
'unit' => $post['unit'] ?? '',
|
||||
'method' => $post['method'] ?? '',
|
||||
'cva' => $post['cva'] ?? '',
|
||||
'ba' => $post['ba'] ?? '',
|
||||
'tea' => $post['tea'] ?? '',
|
||||
];
|
||||
|
||||
$id = $this->dictTestModel->insert($testData);
|
||||
|
||||
if ($id) {
|
||||
return $this->response->setJSON([
|
||||
$input = $this->request->getJSON(true);
|
||||
if (!$this->validate($this->rules)) {
|
||||
return $this->failValidationErrors($this->validator->getErrors());
|
||||
}
|
||||
try {
|
||||
$id = $this->dictTestModel->insert($input, true);
|
||||
return $this->respondCreated([
|
||||
'status' => 'success',
|
||||
'message' => 'Test saved successfully',
|
||||
'data' => ['test_id' => $id]
|
||||
'message' => $id
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return $this->failServerError('Something went wrong: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
return $this->response->setJSON([
|
||||
'status' => 'error',
|
||||
'message' => 'Failed to save test'
|
||||
])->setStatusCode(500);
|
||||
}
|
||||
|
||||
public function update($id)
|
||||
public function update($id = null)
|
||||
{
|
||||
$post = $this->request->getJSON(true);
|
||||
|
||||
$testData = [
|
||||
'dept_ref_id' => $post['dept_ref_id'] ?? null,
|
||||
'name' => $post['name'] ?? '',
|
||||
'unit' => $post['unit'] ?? '',
|
||||
'method' => $post['method'] ?? '',
|
||||
'cva' => $post['cva'] ?? '',
|
||||
'ba' => $post['ba'] ?? '',
|
||||
'tea' => $post['tea'] ?? '',
|
||||
];
|
||||
|
||||
$success = $this->dictTestModel->update($id, $testData);
|
||||
|
||||
if ($success) {
|
||||
return $this->response->setJSON([
|
||||
$input = $this->request->getJSON(true);
|
||||
if (!$this->validate($this->rules)) {
|
||||
return $this->failValidationErrors($this->validator->getErrors());
|
||||
}
|
||||
try {
|
||||
$this->dictTestModel->update($id, $input);
|
||||
return $this->respond([
|
||||
'status' => 'success',
|
||||
'message' => 'Test updated successfully'
|
||||
'message' => 'update success',
|
||||
'data' => $id
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return $this->failServerError('Something went wrong: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
return $this->response->setJSON([
|
||||
'status' => 'error',
|
||||
'message' => 'Failed to update test'
|
||||
])->setStatusCode(500);
|
||||
}
|
||||
|
||||
public function delete($id)
|
||||
public function delete($id = null)
|
||||
{
|
||||
$success = $this->dictTestModel->delete($id);
|
||||
|
||||
if ($success) {
|
||||
return $this->response->setJSON([
|
||||
try {
|
||||
$this->dictTestModel->delete($id);
|
||||
return $this->respond([
|
||||
'status' => 'success',
|
||||
'message' => 'Test deleted successfully'
|
||||
'message' => 'delete success'
|
||||
]);
|
||||
}
|
||||
|
||||
return $this->response->setJSON([
|
||||
'status' => 'error',
|
||||
'message' => 'Failed to delete test'
|
||||
])->setStatusCode(500);
|
||||
} catch (\Exception $e) {
|
||||
return $this->failServerError('Something went wrong: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,18 +3,21 @@
|
||||
namespace App\Controllers;
|
||||
|
||||
use CodeIgniter\Controller;
|
||||
use CodeIgniter\API\ResponseTrait;
|
||||
use CodeIgniter\HTTP\RequestInterface;
|
||||
use CodeIgniter\HTTP\ResponseInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
abstract class BaseController extends Controller
|
||||
{
|
||||
use ResponseTrait;
|
||||
|
||||
protected $session;
|
||||
|
||||
public function initController(RequestInterface $request, ResponseInterface $response, LoggerInterface $logger)
|
||||
{
|
||||
parent::initController($request, $response, $logger);
|
||||
$this->session = \Config\Services::session();
|
||||
$this->helpers = ['form', 'url'];
|
||||
$this->helpers = ['form', 'url', 'json'];
|
||||
}
|
||||
}
|
||||
|
||||
@ -33,6 +33,18 @@ class CreateCmodQcTables extends Migration
|
||||
'type' => 'FLOAT',
|
||||
'null' => true,
|
||||
],
|
||||
'created_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => true,
|
||||
],
|
||||
'updated_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => true,
|
||||
],
|
||||
'deleted_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => true,
|
||||
],
|
||||
]);
|
||||
$this->forge->addKey('control_test_id', true);
|
||||
$this->forge->createTable('control_tests');
|
||||
@ -67,6 +79,18 @@ class CreateCmodQcTables extends Migration
|
||||
'type' => 'TEXT',
|
||||
'null' => true,
|
||||
],
|
||||
'created_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => true,
|
||||
],
|
||||
'updated_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => true,
|
||||
],
|
||||
'deleted_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => true,
|
||||
],
|
||||
]);
|
||||
$this->forge->addKey('result_id', true);
|
||||
$this->forge->createTable('results');
|
||||
@ -101,6 +125,18 @@ class CreateCmodQcTables extends Migration
|
||||
'type' => 'DATE',
|
||||
'null' => true,
|
||||
],
|
||||
'created_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => true,
|
||||
],
|
||||
'updated_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => true,
|
||||
],
|
||||
'deleted_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => true,
|
||||
],
|
||||
]);
|
||||
$this->forge->addKey('control_id', true);
|
||||
$this->forge->createTable('dict_controls');
|
||||
@ -117,6 +153,18 @@ class CreateCmodQcTables extends Migration
|
||||
'constraint' => 50,
|
||||
'null' => true,
|
||||
],
|
||||
'created_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => true,
|
||||
],
|
||||
'updated_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => true,
|
||||
],
|
||||
'deleted_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => true,
|
||||
],
|
||||
]);
|
||||
$this->forge->addKey('dept_id', true);
|
||||
$this->forge->createTable('dict_depts');
|
||||
@ -163,6 +211,18 @@ class CreateCmodQcTables extends Migration
|
||||
'constraint' => 50,
|
||||
'null' => true,
|
||||
],
|
||||
'created_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => true,
|
||||
],
|
||||
'updated_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => true,
|
||||
],
|
||||
'deleted_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => true,
|
||||
],
|
||||
]);
|
||||
$this->forge->addKey('test_id', true);
|
||||
$this->forge->createTable('dict_tests');
|
||||
@ -193,6 +253,18 @@ class CreateCmodQcTables extends Migration
|
||||
'type' => 'TEXT',
|
||||
'null' => true,
|
||||
],
|
||||
'created_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => true,
|
||||
],
|
||||
'updated_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => true,
|
||||
],
|
||||
'deleted_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => true,
|
||||
],
|
||||
]);
|
||||
$this->forge->addKey('result_comment_id', true);
|
||||
$this->forge->createTable('result_comments');
|
||||
|
||||
47
app/Helpers/stringcase_helper.php
Normal file
47
app/Helpers/stringcase_helper.php
Normal file
@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
if (!function_exists('camel_to_snake')) {
|
||||
function camel_to_snake(string $string): string
|
||||
{
|
||||
$pattern = '/([a-z])([A-Z])/';
|
||||
return strtolower(preg_replace($pattern, '$1_$2', $string));
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('camel_to_snake_array')) {
|
||||
function camel_to_snake_array(array $data): array
|
||||
{
|
||||
$converted = [];
|
||||
foreach ($data as $key => $value) {
|
||||
$snakeKey = camel_to_snake($key);
|
||||
$converted[$snakeKey] = $value;
|
||||
}
|
||||
return $converted;
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('snake_to_camel')) {
|
||||
function snake_to_camel(string $string): string
|
||||
{
|
||||
$parts = explode('_', $string);
|
||||
$camel = array_map(function ($part, $index) {
|
||||
if ($index === 0) {
|
||||
return $part;
|
||||
}
|
||||
return ucfirst($part);
|
||||
}, $parts, array_keys($parts));
|
||||
return implode('', $camel);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('snake_to_camel_array')) {
|
||||
function snake_to_camel_array(array $data): array
|
||||
{
|
||||
$converted = [];
|
||||
foreach ($data as $key => $value) {
|
||||
$camelKey = snake_to_camel($key);
|
||||
$converted[$camelKey] = $value;
|
||||
}
|
||||
return $converted;
|
||||
}
|
||||
}
|
||||
113
app/Models/BaseModel.php
Normal file
113
app/Models/BaseModel.php
Normal file
@ -0,0 +1,113 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use CodeIgniter\Model;
|
||||
|
||||
class BaseModel extends Model
|
||||
{
|
||||
protected $returnType = 'array';
|
||||
protected $useSoftDeletes = true;
|
||||
protected $useTimestamps = true;
|
||||
protected $createdField = 'created_at';
|
||||
protected $updatedField = 'updated_at';
|
||||
protected $deletedField = 'deleted_at';
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function initialize()
|
||||
{
|
||||
if (empty($this->returnType)) {
|
||||
$this->returnType = 'array';
|
||||
}
|
||||
}
|
||||
|
||||
public function findAll(?int $limit = null, int $offset = 0)
|
||||
{
|
||||
$rows = parent::findAll($limit, $offset);
|
||||
return $this->snakeToCamelRecursive($rows);
|
||||
}
|
||||
|
||||
public function find($id = null)
|
||||
{
|
||||
$row = parent::find($id);
|
||||
if ($row) {
|
||||
return $this->snakeToCamel($row);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public function first()
|
||||
{
|
||||
$row = parent::first();
|
||||
if ($row) {
|
||||
return $this->snakeToCamel($row);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected function snakeToCamel(array $row): array
|
||||
{
|
||||
$converted = [];
|
||||
foreach ($row as $key => $value) {
|
||||
$camelKey = $this->snakeToCamelKey($key);
|
||||
$converted[$camelKey] = $value;
|
||||
}
|
||||
return $converted;
|
||||
}
|
||||
|
||||
protected function snakeToCamelRecursive($data)
|
||||
{
|
||||
if (is_array($data)) {
|
||||
if (isset($data[0]) || empty($data)) {
|
||||
return array_map([$this, 'snakeToCamelRecursive'], $data);
|
||||
}
|
||||
return $this->snakeToCamel($data);
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
protected function snakeToCamelKey(string $key): string
|
||||
{
|
||||
$parts = explode('_', $key);
|
||||
$camel = array_map(function ($part, $index) {
|
||||
if ($index === 0) {
|
||||
return $part;
|
||||
}
|
||||
return ucfirst($part);
|
||||
}, $parts, array_keys($parts));
|
||||
return implode('', $camel);
|
||||
}
|
||||
|
||||
public function insert($data = null, bool $returnID = true)
|
||||
{
|
||||
$snakeData = $this->camelToSnakeArray($data);
|
||||
return parent::insert($snakeData, $returnID);
|
||||
}
|
||||
|
||||
public function update($id = null, $row = null): bool
|
||||
{
|
||||
$snakeData = $this->camelToSnakeArray($row);
|
||||
return parent::update($id, $snakeData);
|
||||
}
|
||||
|
||||
protected function camelToSnakeArray(array $data): array
|
||||
{
|
||||
$converted = [];
|
||||
foreach ($data as $key => $value) {
|
||||
$snakeKey = $this->camelToSnakeKey($key);
|
||||
$converted[$snakeKey] = $value;
|
||||
}
|
||||
return $converted;
|
||||
}
|
||||
|
||||
protected function camelToSnakeKey(string $key): string
|
||||
{
|
||||
$pattern = '/([a-z])([A-Z])/';
|
||||
$snake = preg_replace($pattern, '$1_$2', $key);
|
||||
return strtolower($snake);
|
||||
}
|
||||
}
|
||||
@ -2,38 +2,38 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use CodeIgniter\Model;
|
||||
use App\Models\BaseModel;
|
||||
|
||||
class ControlModel extends Model
|
||||
class ControlModel extends BaseModel
|
||||
{
|
||||
protected $table = 'dict_control';
|
||||
protected $primaryKey = 'id';
|
||||
protected $table = 'dict_controls';
|
||||
protected $primaryKey = 'control_id';
|
||||
protected $useAutoIncrement = true;
|
||||
protected $returnType = 'array';
|
||||
protected $useSoftDeletes = false;
|
||||
protected $allowedFields = ['deptid', 'name', 'lot', 'producer', 'expdate'];
|
||||
protected $useTimestamps = false;
|
||||
protected $useSoftDeletes = true;
|
||||
protected $useTimestamps = true;
|
||||
protected $allowedFields = ['dept_ref_id', 'name', 'lot', 'producer', 'expdate'];
|
||||
|
||||
public function getByDept($deptid)
|
||||
public function getByDept($deptId)
|
||||
{
|
||||
return $this->where('deptid', $deptid)->findAll();
|
||||
return $this->where('dept_ref_id', $deptId)->findAll();
|
||||
}
|
||||
|
||||
public function getWithDept()
|
||||
{
|
||||
$builder = $this->db->table('dict_control c');
|
||||
$builder = $this->db->table('dict_controls c');
|
||||
$builder->select('c.*, d.name as dept_name');
|
||||
$builder->join('dict_dept d', 'd.id = c.deptid', 'left');
|
||||
$builder->join('dict_depts d', 'd.dept_id = c.dept_ref_id', 'left');
|
||||
return $builder->get()->getResultArray();
|
||||
}
|
||||
|
||||
public function getActiveByDate($date, $deptid = null)
|
||||
public function getActiveByDate($date, $deptId = null)
|
||||
{
|
||||
$builder = $this->db->table('dict_control c');
|
||||
$builder = $this->db->table('dict_controls c');
|
||||
$builder->select('c.*');
|
||||
$builder->where('c.expdate >=', $date);
|
||||
if ($deptid) {
|
||||
$builder->where('c.deptid', $deptid);
|
||||
if ($deptId) {
|
||||
$builder->where('c.dept_ref_id', $deptId);
|
||||
}
|
||||
$builder->orderBy('c.name', 'ASC');
|
||||
return $builder->get()->getResultArray();
|
||||
|
||||
@ -2,17 +2,17 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use CodeIgniter\Model;
|
||||
use App\Models\BaseModel;
|
||||
|
||||
class ControlTestModel extends Model
|
||||
class ControlTestModel extends BaseModel
|
||||
{
|
||||
protected $table = 'control_tests';
|
||||
protected $primaryKey = 'control_test_id';
|
||||
protected $useAutoIncrement = true;
|
||||
protected $returnType = 'array';
|
||||
protected $useSoftDeletes = false;
|
||||
protected $allowedFields = ['control_test_id', 'control_ref_id', 'test_ref_id', 'mean', 'sd'];
|
||||
protected $useTimestamps = false;
|
||||
protected $useSoftDeletes = true;
|
||||
protected $useTimestamps = true;
|
||||
protected $allowedFields = ['control_ref_id', 'test_ref_id', 'mean', 'sd'];
|
||||
|
||||
public function getByControl($controlId)
|
||||
{
|
||||
|
||||
@ -2,41 +2,41 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use CodeIgniter\Model;
|
||||
use App\Models\BaseModel;
|
||||
|
||||
class DailyResultModel extends Model
|
||||
class DailyResultModel extends BaseModel
|
||||
{
|
||||
protected $table = 'daily_result';
|
||||
protected $primaryKey = 'id';
|
||||
protected $primaryKey = 'daily_result_id';
|
||||
protected $useAutoIncrement = true;
|
||||
protected $returnType = 'array';
|
||||
protected $useSoftDeletes = false;
|
||||
protected $allowedFields = ['controlid', 'testid', 'resdate', 'resvalue', 'rescomment'];
|
||||
protected $useTimestamps = false;
|
||||
protected $useSoftDeletes = true;
|
||||
protected $useTimestamps = true;
|
||||
protected $allowedFields = ['control_ref_id', 'test_ref_id', 'resdate', 'resvalue', 'rescomment'];
|
||||
|
||||
public function getByMonth($controlid, $testid, $yearMonth)
|
||||
public function getByMonth($controlId, $testId, $yearMonth)
|
||||
{
|
||||
$startDate = $yearMonth . '-01';
|
||||
$endDate = $yearMonth . '-31';
|
||||
|
||||
$builder = $this->db->table('daily_result');
|
||||
$builder->select('*');
|
||||
$builder->where('controlid', $controlid);
|
||||
$builder->where('testid', $testid);
|
||||
$builder->where('control_ref_id', $controlId);
|
||||
$builder->where('test_ref_id', $testId);
|
||||
$builder->where('resdate >=', $startDate);
|
||||
$builder->where('resdate <=', $endDate);
|
||||
$builder->orderBy('resdate', 'ASC');
|
||||
return $builder->get()->getResultArray();
|
||||
}
|
||||
|
||||
public function getByControlMonth($controlid, $yearMonth)
|
||||
public function getByControlMonth($controlId, $yearMonth)
|
||||
{
|
||||
$startDate = $yearMonth . '-01';
|
||||
$endDate = $yearMonth . '-31';
|
||||
|
||||
$builder = $this->db->table('daily_result');
|
||||
$builder->select('*');
|
||||
$builder->where('controlid', $controlid);
|
||||
$builder->where('control_ref_id', $controlId);
|
||||
$builder->where('resdate >=', $startDate);
|
||||
$builder->where('resdate <=', $endDate);
|
||||
return $builder->get()->getResultArray();
|
||||
@ -46,14 +46,14 @@ class DailyResultModel extends Model
|
||||
{
|
||||
$builder = $this->db->table('daily_result');
|
||||
$existing = $builder->select('*')
|
||||
->where('controlid', $data['controlid'])
|
||||
->where('testid', $data['testid'])
|
||||
->where('control_ref_id', $data['control_ref_id'])
|
||||
->where('test_ref_id', $data['test_ref_id'])
|
||||
->where('resdate', $data['resdate'])
|
||||
->get()
|
||||
->getRowArray();
|
||||
|
||||
if ($existing) {
|
||||
return $builder->where('id', $existing['id'])->update($data);
|
||||
return $builder->where('daily_result_id', $existing['daily_result_id'])->update($data);
|
||||
} else {
|
||||
return $builder->insert($data);
|
||||
}
|
||||
|
||||
@ -2,15 +2,15 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use CodeIgniter\Model;
|
||||
use App\Models\BaseModel;
|
||||
|
||||
class DeptModel extends Model
|
||||
class DeptModel extends BaseModel
|
||||
{
|
||||
protected $table = 'dict_dept';
|
||||
protected $primaryKey = 'id';
|
||||
protected $table = 'dict_depts';
|
||||
protected $primaryKey = 'dept_id';
|
||||
protected $useAutoIncrement = true;
|
||||
protected $returnType = 'array';
|
||||
protected $useSoftDeletes = false;
|
||||
protected $useSoftDeletes = true;
|
||||
protected $useTimestamps = true;
|
||||
protected $allowedFields = ['name'];
|
||||
protected $useTimestamps = false;
|
||||
}
|
||||
|
||||
@ -2,17 +2,17 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use CodeIgniter\Model;
|
||||
use App\Models\BaseModel;
|
||||
|
||||
class DictControlModel extends Model
|
||||
class DictControlModel extends BaseModel
|
||||
{
|
||||
protected $table = 'dict_controls';
|
||||
protected $primaryKey = 'control_id';
|
||||
protected $useAutoIncrement = true;
|
||||
protected $returnType = 'array';
|
||||
protected $useSoftDeletes = false;
|
||||
protected $allowedFields = ['control_id', 'dept_ref_id', 'name', 'lot', 'producer', 'expdate'];
|
||||
protected $useTimestamps = false;
|
||||
protected $useSoftDeletes = true;
|
||||
protected $useTimestamps = true;
|
||||
protected $allowedFields = ['dept_ref_id', 'name', 'lot', 'producer', 'expdate'];
|
||||
|
||||
public function getByDept($deptId)
|
||||
{
|
||||
|
||||
@ -2,15 +2,15 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use CodeIgniter\Model;
|
||||
use App\Models\BaseModel;
|
||||
|
||||
class DictDeptModel extends Model
|
||||
class DictDeptModel extends BaseModel
|
||||
{
|
||||
protected $table = 'dict_depts';
|
||||
protected $primaryKey = 'dept_id';
|
||||
protected $useAutoIncrement = true;
|
||||
protected $returnType = 'array';
|
||||
protected $useSoftDeletes = false;
|
||||
protected $allowedFields = ['dept_id', 'name'];
|
||||
protected $useTimestamps = false;
|
||||
protected $useSoftDeletes = true;
|
||||
protected $useTimestamps = true;
|
||||
protected $allowedFields = ['name'];
|
||||
}
|
||||
|
||||
@ -2,17 +2,17 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use CodeIgniter\Model;
|
||||
use App\Models\BaseModel;
|
||||
|
||||
class DictTestModel extends Model
|
||||
class DictTestModel extends BaseModel
|
||||
{
|
||||
protected $table = 'dict_tests';
|
||||
protected $primaryKey = 'test_id';
|
||||
protected $useAutoIncrement = true;
|
||||
protected $returnType = 'array';
|
||||
protected $useSoftDeletes = false;
|
||||
protected $allowedFields = ['test_id', 'dept_ref_id', 'name', 'unit', 'method', 'cva', 'ba', 'tea'];
|
||||
protected $useTimestamps = false;
|
||||
protected $useSoftDeletes = true;
|
||||
protected $useTimestamps = true;
|
||||
protected $allowedFields = ['dept_ref_id', 'name', 'unit', 'method', 'cva', 'ba', 'tea'];
|
||||
|
||||
public function getByDept($deptId)
|
||||
{
|
||||
|
||||
@ -2,35 +2,35 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use CodeIgniter\Model;
|
||||
use App\Models\BaseModel;
|
||||
|
||||
class MonthlyCommentModel extends Model
|
||||
class MonthlyCommentModel extends BaseModel
|
||||
{
|
||||
protected $table = 'monthly_comment';
|
||||
protected $primaryKey = 'id';
|
||||
protected $primaryKey = 'monthly_comment_id';
|
||||
protected $useAutoIncrement = true;
|
||||
protected $returnType = 'array';
|
||||
protected $useSoftDeletes = false;
|
||||
protected $allowedFields = ['controlid', 'testid', 'commonth', 'comtext'];
|
||||
protected $useTimestamps = false;
|
||||
protected $useSoftDeletes = true;
|
||||
protected $useTimestamps = true;
|
||||
protected $allowedFields = ['control_ref_id', 'test_ref_id', 'commonth', 'comtext'];
|
||||
|
||||
public function getByControlTestMonth($controlid, $testid, $yearMonth)
|
||||
public function getByControlTestMonth($controlId, $testId, $yearMonth)
|
||||
{
|
||||
return $this->where('controlid', $controlid)
|
||||
->where('testid', $testid)
|
||||
return $this->where('control_ref_id', $controlId)
|
||||
->where('test_ref_id', $testId)
|
||||
->where('commonth', $yearMonth)
|
||||
->first();
|
||||
}
|
||||
|
||||
public function saveComment($data)
|
||||
{
|
||||
$existing = $this->where('controlid', $data['controlid'])
|
||||
->where('testid', $data['testid'])
|
||||
$existing = $this->where('control_ref_id', $data['control_ref_id'])
|
||||
->where('test_ref_id', $data['test_ref_id'])
|
||||
->where('commonth', $data['commonth'])
|
||||
->first();
|
||||
|
||||
if ($existing) {
|
||||
return $this->update($existing['id'], $data);
|
||||
return $this->update($existing['monthly_comment_id'], $data);
|
||||
} else {
|
||||
return $this->insert($data);
|
||||
}
|
||||
|
||||
@ -2,17 +2,17 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use CodeIgniter\Model;
|
||||
use App\Models\BaseModel;
|
||||
|
||||
class ResultCommentModel extends Model
|
||||
class ResultCommentModel extends BaseModel
|
||||
{
|
||||
protected $table = 'result_comments';
|
||||
protected $primaryKey = 'result_comment_id';
|
||||
protected $useAutoIncrement = true;
|
||||
protected $returnType = 'array';
|
||||
protected $useSoftDeletes = false;
|
||||
protected $allowedFields = ['result_comment_id', 'control_ref_id', 'test_ref_id', 'commonth', 'comtext'];
|
||||
protected $useTimestamps = false;
|
||||
protected $useSoftDeletes = true;
|
||||
protected $useTimestamps = true;
|
||||
protected $allowedFields = ['control_ref_id', 'test_ref_id', 'commonth', 'comtext'];
|
||||
|
||||
public function getByControlTestMonth($controlId, $testId, $yearMonth)
|
||||
{
|
||||
|
||||
@ -2,17 +2,17 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use CodeIgniter\Model;
|
||||
use App\Models\BaseModel;
|
||||
|
||||
class ResultModel extends Model
|
||||
class ResultModel extends BaseModel
|
||||
{
|
||||
protected $table = 'results';
|
||||
protected $primaryKey = 'result_id';
|
||||
protected $useAutoIncrement = true;
|
||||
protected $returnType = 'array';
|
||||
protected $useSoftDeletes = false;
|
||||
protected $allowedFields = ['result_id', 'control_ref_id', 'test_ref_id', 'resdate', 'resvalue', 'rescomment'];
|
||||
protected $useTimestamps = false;
|
||||
protected $useSoftDeletes = true;
|
||||
protected $useTimestamps = true;
|
||||
protected $allowedFields = ['control_ref_id', 'test_ref_id', 'resdate', 'resvalue', 'rescomment'];
|
||||
|
||||
public function getByMonth($controlId, $testId, $yearMonth)
|
||||
{
|
||||
|
||||
@ -2,28 +2,28 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use CodeIgniter\Model;
|
||||
use App\Models\BaseModel;
|
||||
|
||||
class TestModel extends Model
|
||||
class TestModel extends BaseModel
|
||||
{
|
||||
protected $table = 'dict_test';
|
||||
protected $primaryKey = 'id';
|
||||
protected $table = 'dict_tests';
|
||||
protected $primaryKey = 'test_id';
|
||||
protected $useAutoIncrement = true;
|
||||
protected $returnType = 'array';
|
||||
protected $useSoftDeletes = false;
|
||||
protected $allowedFields = ['deptid', 'name', 'unit', 'method', 'cva', 'ba', 'tea'];
|
||||
protected $useTimestamps = false;
|
||||
protected $useSoftDeletes = true;
|
||||
protected $useTimestamps = true;
|
||||
protected $allowedFields = ['dept_ref_id', 'name', 'unit', 'method', 'cva', 'ba', 'tea'];
|
||||
|
||||
public function getByDept($deptid)
|
||||
public function getByDept($deptId)
|
||||
{
|
||||
return $this->where('deptid', $deptid)->findAll();
|
||||
return $this->where('dept_ref_id', $deptId)->findAll();
|
||||
}
|
||||
|
||||
public function getWithDept()
|
||||
{
|
||||
$builder = $this->db->table('dict_test t');
|
||||
$builder = $this->db->table('dict_tests t');
|
||||
$builder->select('t.*, d.name as dept_name');
|
||||
$builder->join('dict_dept d', 'd.id = t.deptid', 'left');
|
||||
$builder->join('dict_depts d', 'd.dept_id = t.dept_ref_id', 'left');
|
||||
return $builder->get()->getResultArray();
|
||||
}
|
||||
}
|
||||
|
||||
@ -197,7 +197,7 @@ document.addEventListener('alpine:init', () => {
|
||||
: `${window.BASEURL}/api/control`;
|
||||
|
||||
const res = await fetch(url, {
|
||||
method: this.form.control_id ? 'PUT' : 'POST',
|
||||
method: this.form.control_id ? 'PATCH' : 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(this.form)
|
||||
});
|
||||
|
||||
@ -142,7 +142,7 @@ document.addEventListener('alpine:init', () => {
|
||||
: `${window.BASEURL}/api/dept`;
|
||||
|
||||
const res = await fetch(url, {
|
||||
method: this.form.dept_id ? 'PUT' : 'POST',
|
||||
method: this.form.dept_id ? 'PATCH' : 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ name: this.form.name })
|
||||
});
|
||||
|
||||
@ -94,7 +94,7 @@
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body class="bg-gray-50 h-full overflow-hidden text-slate-800 antialiased">
|
||||
<body x-data="layoutManager()" :class="{ 'overflow-hidden': $store.appState.sidebarOpen && isMobile() }" class="bg-gray-50 h-full text-slate-800 antialiased">
|
||||
<div x-cloak x-show="App.loading" x-transition.opacity
|
||||
class="fixed inset-0 z-[100] flex items-center justify-center bg-white/80 backdrop-blur-sm">
|
||||
<div class="bg-white shadow-xl rounded-2xl p-6 flex items-center space-x-4 border border-slate-100">
|
||||
@ -104,7 +104,7 @@
|
||||
</div>
|
||||
|
||||
<div class="flex h-screen bg-slate-50">
|
||||
<div id="sidebar-backdrop" x-show="App.sidebarOpen" @click="App.sidebarOpen = false" x-transition.opacity aria-hidden="true"
|
||||
<div id="sidebar-backdrop" x-show="$store.appState.sidebarOpen" @click="$store.appState.sidebarOpen = false" x-transition.opacity aria-hidden="true"
|
||||
class="fixed inset-0 z-40 bg-slate-900/50 backdrop-blur-sm lg:hidden"></div>
|
||||
|
||||
<aside id="sidebar"
|
||||
@ -112,8 +112,8 @@
|
||||
resultsOpen: <?= in_array($active_menu, ['entry', 'entry_daily']) ? 'true' : 'false' ?>,
|
||||
masterOpen: <?= in_array($active_menu, ['test', 'control', 'dept']) ? 'true' : 'false' ?>
|
||||
}"
|
||||
:class="App.sidebarOpen ? 'translate-x-0' : '-translate-x-full'"
|
||||
class="fixed inset-y-0 left-0 z-50 w-72 bg-white border-r border-slate-200 transition-transform duration-300 ease-in-out lg:static lg:translate-x-0 flex flex-col shadow-lg lg:shadow-none">
|
||||
:class="$store.appState.sidebarOpen ? 'translate-x-0' : '-translate-x-full lg:-translate-x-full'"
|
||||
class="fixed inset-y-0 left-0 z-50 w-64 transition-transform duration-300 ease-in-out flex flex-col shadow-lg">
|
||||
<div class="flex h-16 items-center px-6 border-b border-slate-100 bg-white/50">
|
||||
<div class="flex items-center space-x-3">
|
||||
<div class="h-8 w-8 rounded-lg bg-gradient-to-br from-primary-600 to-primary-700 flex items-center justify-center shadow-lg shadow-primary-500/30">
|
||||
@ -203,11 +203,12 @@
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<div class="flex-1 flex flex-col overflow-hidden bg-slate-50/50">
|
||||
<div class="flex-1 flex flex-col overflow-hidden bg-slate-50/50 transition-all duration-300"
|
||||
:class="$store.appState.sidebarOpen ? 'lg:ml-64' : 'lg:ml-0'">
|
||||
<header class="bg-white/80 backdrop-blur-md sticky top-0 z-30 border-b border-slate-200/60 supports-backdrop-blur:bg-white/60">
|
||||
<div class="flex items-center justify-between h-16 px-8">
|
||||
<div class="flex items-center">
|
||||
<button id="sidebar-toggle" @click="App.sidebarOpen = !App.sidebarOpen" class="lg:hidden p-2 -ml-2 text-slate-500 hover:text-slate-700 hover:bg-slate-100 rounded-lg">
|
||||
<button id="sidebar-toggle" @click="$store.appState.sidebarOpen = !$store.appState.sidebarOpen" class="p-2 -ml-2 text-slate-500 hover:text-slate-700 hover:bg-slate-100 rounded-lg">
|
||||
<i class="fa-solid fa-bars h-6 w-6 flex items-center justify-center"></i>
|
||||
</button>
|
||||
<h2 class="ml-2 lg:ml-0 text-xl font-bold text-slate-800 tracking-tight"><?= $page_title ?? 'Dashboard' ?></h2>
|
||||
@ -236,6 +237,15 @@
|
||||
<script src="<?= base_url('js/app.js') ?>"></script>
|
||||
<script src="<?= base_url('js/tables.js') ?>"></script>
|
||||
<script src="<?= base_url('js/charts.js') ?>"></script>
|
||||
<script>
|
||||
document.addEventListener('alpine:init', () => {
|
||||
Alpine.data('layoutManager', () => ({
|
||||
isMobile() {
|
||||
return window.innerWidth < 1024;
|
||||
}
|
||||
}));
|
||||
});
|
||||
</script>
|
||||
<?= $this->renderSection("script"); ?>
|
||||
</body>
|
||||
|
||||
|
||||
@ -186,7 +186,7 @@ document.addEventListener('alpine:init', () => {
|
||||
: `${window.BASEURL}/api/test`;
|
||||
|
||||
const res = await fetch(url, {
|
||||
method: this.form.test_id ? 'PUT' : 'POST',
|
||||
method: this.form.test_id ? 'PATCH' : 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(this.form)
|
||||
});
|
||||
|
||||
File diff suppressed because one or more lines are too long
@ -1,3 +1,10 @@
|
||||
document.addEventListener('alpine:init', () => {
|
||||
Alpine.store('appState', {
|
||||
loading: false,
|
||||
sidebarOpen: false
|
||||
});
|
||||
});
|
||||
|
||||
window.App = {
|
||||
loading: false,
|
||||
sidebarOpen: false,
|
||||
@ -15,12 +22,18 @@ window.App = {
|
||||
if (toggleBtn) {
|
||||
toggleBtn.addEventListener('click', () => {
|
||||
this.sidebarOpen = !this.sidebarOpen;
|
||||
if (window.Alpine) {
|
||||
Alpine.store('appState').sidebarOpen = this.sidebarOpen;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (backdrop) {
|
||||
backdrop.addEventListener('click', () => {
|
||||
this.sidebarOpen = false;
|
||||
if (window.Alpine) {
|
||||
Alpine.store('appState').sidebarOpen = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
13
v1/assets/Chart.min.js
vendored
13
v1/assets/Chart.min.js
vendored
File diff suppressed because one or more lines are too long
4
v1/assets/jquery.js
vendored
4
v1/assets/jquery.js
vendored
File diff suppressed because one or more lines are too long
349
v1/assets/normalize.min.css
vendored
349
v1/assets/normalize.min.css
vendored
@ -1,349 +0,0 @@
|
||||
/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */
|
||||
|
||||
/* Document
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* 1. Correct the line height in all browsers.
|
||||
* 2. Prevent adjustments of font size after orientation changes in iOS.
|
||||
*/
|
||||
|
||||
html {
|
||||
line-height: 1.15; /* 1 */
|
||||
-webkit-text-size-adjust: 100%; /* 2 */
|
||||
}
|
||||
|
||||
/* Sections
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Remove the margin in all browsers.
|
||||
*/
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the `main` element consistently in IE.
|
||||
*/
|
||||
|
||||
main {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/**
|
||||
* Correct the font size and margin on `h1` elements within `section` and
|
||||
* `article` contexts in Chrome, Firefox, and Safari.
|
||||
*/
|
||||
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
margin: 0.67em 0;
|
||||
}
|
||||
|
||||
/* Grouping content
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* 1. Add the correct box sizing in Firefox.
|
||||
* 2. Show the overflow in Edge and IE.
|
||||
*/
|
||||
|
||||
hr {
|
||||
box-sizing: content-box; /* 1 */
|
||||
height: 0; /* 1 */
|
||||
overflow: visible; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Correct the inheritance and scaling of font size in all browsers.
|
||||
* 2. Correct the odd `em` font sizing in all browsers.
|
||||
*/
|
||||
|
||||
pre {
|
||||
font-family: monospace, monospace; /* 1 */
|
||||
font-size: 1em; /* 2 */
|
||||
}
|
||||
|
||||
/* Text-level semantics
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Remove the gray background on active links in IE 10.
|
||||
*/
|
||||
|
||||
a {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Remove the bottom border in Chrome 57-
|
||||
* 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
|
||||
*/
|
||||
|
||||
abbr[title] {
|
||||
border-bottom: none; /* 1 */
|
||||
text-decoration: underline; /* 2 */
|
||||
text-decoration: underline dotted; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the correct font weight in Chrome, Edge, and Safari.
|
||||
*/
|
||||
|
||||
b,
|
||||
strong {
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Correct the inheritance and scaling of font size in all browsers.
|
||||
* 2. Correct the odd `em` font sizing in all browsers.
|
||||
*/
|
||||
|
||||
code,
|
||||
kbd,
|
||||
samp {
|
||||
font-family: monospace, monospace; /* 1 */
|
||||
font-size: 1em; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the correct font size in all browsers.
|
||||
*/
|
||||
|
||||
small {
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevent `sub` and `sup` elements from affecting the line height in
|
||||
* all browsers.
|
||||
*/
|
||||
|
||||
sub,
|
||||
sup {
|
||||
font-size: 75%;
|
||||
line-height: 0;
|
||||
position: relative;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
sub {
|
||||
bottom: -0.25em;
|
||||
}
|
||||
|
||||
sup {
|
||||
top: -0.5em;
|
||||
}
|
||||
|
||||
/* Embedded content
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Remove the border on images inside links in IE 10.
|
||||
*/
|
||||
|
||||
img {
|
||||
border-style: none;
|
||||
}
|
||||
|
||||
/* Forms
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* 1. Change the font styles in all browsers.
|
||||
* 2. Remove the margin in Firefox and Safari.
|
||||
*/
|
||||
|
||||
button,
|
||||
input,
|
||||
optgroup,
|
||||
select,
|
||||
textarea {
|
||||
font-family: inherit; /* 1 */
|
||||
font-size: 100%; /* 1 */
|
||||
line-height: 1.15; /* 1 */
|
||||
margin: 0; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the overflow in IE.
|
||||
* 1. Show the overflow in Edge.
|
||||
*/
|
||||
|
||||
button,
|
||||
input { /* 1 */
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the inheritance of text transform in Edge, Firefox, and IE.
|
||||
* 1. Remove the inheritance of text transform in Firefox.
|
||||
*/
|
||||
|
||||
button,
|
||||
select { /* 1 */
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* Correct the inability to style clickable types in iOS and Safari.
|
||||
*/
|
||||
|
||||
button,
|
||||
[type="button"],
|
||||
[type="reset"],
|
||||
[type="submit"] {
|
||||
-webkit-appearance: button;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the inner border and padding in Firefox.
|
||||
*/
|
||||
|
||||
button::-moz-focus-inner,
|
||||
[type="button"]::-moz-focus-inner,
|
||||
[type="reset"]::-moz-focus-inner,
|
||||
[type="submit"]::-moz-focus-inner {
|
||||
border-style: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore the focus styles unset by the previous rule.
|
||||
*/
|
||||
|
||||
button:-moz-focusring,
|
||||
[type="button"]:-moz-focusring,
|
||||
[type="reset"]:-moz-focusring,
|
||||
[type="submit"]:-moz-focusring {
|
||||
outline: 1px dotted ButtonText;
|
||||
}
|
||||
|
||||
/**
|
||||
* Correct the padding in Firefox.
|
||||
*/
|
||||
|
||||
fieldset {
|
||||
padding: 0.35em 0.75em 0.625em;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Correct the text wrapping in Edge and IE.
|
||||
* 2. Correct the color inheritance from `fieldset` elements in IE.
|
||||
* 3. Remove the padding so developers are not caught out when they zero out
|
||||
* `fieldset` elements in all browsers.
|
||||
*/
|
||||
|
||||
legend {
|
||||
box-sizing: border-box; /* 1 */
|
||||
color: inherit; /* 2 */
|
||||
display: table; /* 1 */
|
||||
max-width: 100%; /* 1 */
|
||||
padding: 0; /* 3 */
|
||||
white-space: normal; /* 1 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the correct vertical alignment in Chrome, Firefox, and Opera.
|
||||
*/
|
||||
|
||||
progress {
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the default vertical scrollbar in IE 10+.
|
||||
*/
|
||||
|
||||
textarea {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Add the correct box sizing in IE 10.
|
||||
* 2. Remove the padding in IE 10.
|
||||
*/
|
||||
|
||||
[type="checkbox"],
|
||||
[type="radio"] {
|
||||
box-sizing: border-box; /* 1 */
|
||||
padding: 0; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Correct the cursor style of increment and decrement buttons in Chrome.
|
||||
*/
|
||||
|
||||
[type="number"]::-webkit-inner-spin-button,
|
||||
[type="number"]::-webkit-outer-spin-button {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Correct the odd appearance in Chrome and Safari.
|
||||
* 2. Correct the outline style in Safari.
|
||||
*/
|
||||
|
||||
[type="search"] {
|
||||
-webkit-appearance: textfield; /* 1 */
|
||||
outline-offset: -2px; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the inner padding in Chrome and Safari on macOS.
|
||||
*/
|
||||
|
||||
[type="search"]::-webkit-search-decoration {
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Correct the inability to style clickable types in iOS and Safari.
|
||||
* 2. Change font properties to `inherit` in Safari.
|
||||
*/
|
||||
|
||||
::-webkit-file-upload-button {
|
||||
-webkit-appearance: button; /* 1 */
|
||||
font: inherit; /* 2 */
|
||||
}
|
||||
|
||||
/* Interactive
|
||||
========================================================================== */
|
||||
|
||||
/*
|
||||
* Add the correct display in Edge, IE 10+, and Firefox.
|
||||
*/
|
||||
|
||||
details {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add the correct display in all browsers.
|
||||
*/
|
||||
|
||||
summary {
|
||||
display: list-item;
|
||||
}
|
||||
|
||||
/* Misc
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Add the correct display in IE 10+.
|
||||
*/
|
||||
|
||||
template {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the correct display in IE 10.
|
||||
*/
|
||||
|
||||
[hidden] {
|
||||
display: none;
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@ -1,16 +0,0 @@
|
||||
/*html,pre,th,table { font-family:'Courier New', Courier, monospace; font-size:7.8pt; margin:0;}*/
|
||||
html,pre,th,table { font-family:'Lucida Console', Monaco, monospace; font-size:9pt; margin:0;}
|
||||
#page {
|
||||
z-index:1; background: white; display: block; margin: 0; page-break-after:always;
|
||||
width: 210mm; height: 280mm;
|
||||
}
|
||||
#page { padding:0.5cm 0.5cm 0cm 0.5cm; }
|
||||
table {border-collapse:collapse; }
|
||||
th,td { line-height:1.3; padding:3px; }
|
||||
td { vertical-align:top; border:solid 1px black; }
|
||||
th { border:solid 1.5px black; }
|
||||
|
||||
h1,h2,h3,h4,h5 { padding:0; margin:0; }
|
||||
#resultdata { float:left; width:6cm; }
|
||||
#resultimg { float: left; width:7cm; }
|
||||
#footer { float:left; margin:0cm auto; }
|
||||
@ -1,26 +0,0 @@
|
||||
html, body { margin: 0; padding: 0; font-size: 100%; font: inherit; vertical-align: baseline; }
|
||||
/* HTML5 display-role reset for older browsers */
|
||||
article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section { display: block; }
|
||||
body {line-height: 1;}
|
||||
ol, ul {list-style: none; padding:0;}
|
||||
blockquote, q { quotes: none;}
|
||||
blockquote:before, blockquote:after,
|
||||
q:before, q:after { content: ''; content: none; }
|
||||
|
||||
table { border-collapse: collapse; border-spacing: 0; }
|
||||
ul { list-style-type: none; margin: 0; overflow: hidden; background-color: #595959; }
|
||||
li { float: left; color: white; text-align: center; padding: 5px 0; }
|
||||
li a { display: block; padding:5px 10px; color: white; text-align: center; text-decoration: none; }
|
||||
li a:hover { background-color: #7FDBFF; }
|
||||
table tr td { padding: 5px 5px; }
|
||||
table tr th { padding: 5px 5px; }
|
||||
|
||||
tr:nth-child(even) {background-color: #e6e6ff;}
|
||||
|
||||
#container { width:100%; font-size: 10px; font-weight: bold;}
|
||||
#content { width:98%;margin:0 auto; }
|
||||
#nav{
|
||||
font-family: "Courier New";
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
}
|
||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@ -1,19 +0,0 @@
|
||||
<?php
|
||||
$serverName = "localhost";
|
||||
$db1 = "cmod_qc";
|
||||
//$db2 = "summitmod";
|
||||
$connectionInfo = array( "Database"=>$db1, "UID"=>"sa", "PWD"=>"Summittso4516728");
|
||||
$conn1 = sqlsrv_connect( $serverName, $connectionInfo);
|
||||
if( !$conn1 ) {
|
||||
echo "Connection 1 could not be established.<br />";
|
||||
die( print_r( sqlsrv_errors(), true));
|
||||
}
|
||||
/*
|
||||
$connectionInfo = array( "Database"=>$db2, "UID"=>"td", "PWD"=>"td");
|
||||
$conn2 = sqlsrv_connect( $serverName, $connectionInfo);
|
||||
if( !$conn2 ) {
|
||||
echo "Connection 2 could not be established.<br />";
|
||||
die( print_r( sqlsrv_errors(), true));
|
||||
}
|
||||
*/
|
||||
?>
|
||||
@ -1,26 +0,0 @@
|
||||
<?php
|
||||
if(!isset($_POST['submit'])) {
|
||||
?>
|
||||
<form method='POST'>
|
||||
control name<br/>
|
||||
<input type='text' name='cname' /><br/>
|
||||
lot<br/>
|
||||
<input type='text' name='lot' /><br/>
|
||||
producer<br/>
|
||||
<input type='text' name='producer' /><br/>
|
||||
expdate<br/>
|
||||
<input type='date' name='expdate' /><br/>
|
||||
<input type='submit' name='submit' value='add' />
|
||||
</form>
|
||||
<?php
|
||||
} else {
|
||||
$cname=stripslashes($_POST['cname']);
|
||||
$lot=$_POST['lot'];
|
||||
$expdate=$_POST['expdate'];
|
||||
$producer=$_POST['producer'];
|
||||
$sql="INSERT INTO DICT_CONTROL(name,lot,producer,expdate) values ('$cname','$lot','$producer','$expdate')";
|
||||
$stmt = sqlsrv_query( $conn1, $sql );
|
||||
if( $stmt == false) { die( print_r( sqlsrv_errors(), true) ); }
|
||||
echo "<meta http-equiv='refresh' content='0;url=?p=dict' />";
|
||||
}
|
||||
?>
|
||||
@ -1,13 +0,0 @@
|
||||
<?php
|
||||
$cid = $_GET['cid'];
|
||||
|
||||
$sql="DELETE DICT_CONTROL WHERE id='$cid'";
|
||||
$stmt = sqlsrv_query( $conn1, $sql );
|
||||
if( $stmt == false) { die( print_r( sqlsrv_errors(), true) ); }
|
||||
|
||||
$sql="DELETE CONTROL_TEST WHERE controlid='$cid'";
|
||||
$stmt = sqlsrv_query( $conn1, $sql );
|
||||
if( $stmt == false) { die( print_r( sqlsrv_errors(), true) ); }
|
||||
|
||||
echo "<meta http-equiv='refresh' content='0;url=?p=dict' />";
|
||||
?>
|
||||
@ -1,45 +0,0 @@
|
||||
<?php
|
||||
if(!isset($_POST['submit'])) {
|
||||
$cid = $_GET['cid'];
|
||||
$sql = "select name,lot,producer,expdate, deptid from DICT_CONTROL where id='$cid'";
|
||||
$stmt = sqlsrv_query( $conn1, $sql );
|
||||
if( $stmt == false) { die( print_r( sqlsrv_errors(), true) ); }
|
||||
$row = sqlsrv_fetch_array( $stmt, SQLSRV_FETCH_NUMERIC);
|
||||
$cname = $row[0];
|
||||
$lot = $row[1];
|
||||
$producer = $row[2];
|
||||
if($row[3] != '') { $expdate = date_format($row[3],"Y-m-d"); }
|
||||
else { $expdate = ''; }
|
||||
$deptid = $row[4];
|
||||
?>
|
||||
<form method='POST'>
|
||||
dept.<br />
|
||||
<select id='dept' name="deptid">
|
||||
<option value='1' <?php if($deptid==1) {echo "selected"; }?>>Kimia</option>
|
||||
<option value='2' <?php if($deptid==2) {echo "selected"; }?>>Imun</option>
|
||||
</select><br />
|
||||
control name<br/>
|
||||
<input type='text' name='cname' value='<?php echo $cname;?>' /><br/>
|
||||
lot<br/>
|
||||
<input type='text' name='lot' value='<?php echo $lot;?>' /><br/>
|
||||
producer<br/>
|
||||
<input type='text' name='producer' value='<?php echo $producer;?>' /><br/>
|
||||
expdate<br/>
|
||||
<input type='date' name='expdate' value='<?php echo $expdate;?>'/><br/>
|
||||
<input type='submit' name='submit' value='update' />
|
||||
<input type='hidden' name='cid' value='<?php echo $cid;?>' /><br/>
|
||||
</form>
|
||||
<?php
|
||||
} else {
|
||||
$cid=$_POST['cid'];
|
||||
$deptid = $_POST['deptid'];
|
||||
$cname=stripslashes($_POST['cname']);
|
||||
$lot=$_POST['lot'];
|
||||
$producer=$_POST['producer'];
|
||||
$expdate=$_POST['expdate'];
|
||||
$sql="UPDATE DICT_CONTROL SET deptid='$deptid', name='$cname', lot='$lot', expdate='$expdate', producer='$producer' WHERE id='$cid'";
|
||||
$stmt=sqlsrv_query( $conn1, $sql );
|
||||
if($stmt==false) { die( print_r( sqlsrv_errors(), true) ); }
|
||||
echo "<meta http-equiv='refresh' content='0;url=?p=dict' />";
|
||||
}
|
||||
?>
|
||||
@ -1,26 +0,0 @@
|
||||
<h2>Control</h2>
|
||||
<a href='?p=control&d=add'>New Control</a>
|
||||
<table border='1'>
|
||||
<tr> <th>ID</th> <th>Name</th> <th>Lot#</th> <th>Producer</th> <th>EXPdate</th> </tr>
|
||||
<?php
|
||||
$sql = "select id,name,lot,producer,expdate from DICT_CONTROL order by expdate DESC";
|
||||
$stmt = sqlsrv_query( $conn1, $sql );
|
||||
if( $stmt == false) { die( print_r( sqlsrv_errors(), true) ); }
|
||||
$i=1;
|
||||
while( $row = sqlsrv_fetch_array( $stmt, SQLSRV_FETCH_NUMERIC) ) {
|
||||
$cid = $row[0];
|
||||
$cname = $row[1];
|
||||
$lot = $row[2];
|
||||
$producer = $row[3];
|
||||
if($row[4] != '') {
|
||||
$expdate = date_format($row[4],"d-m-Y");
|
||||
} else { $expdate = ''; }
|
||||
echo "<tr><td>$i</td> <td>$cname</td> <td>$lot</td> <td>$producer</td> <td>$expdate</td>
|
||||
<td><a href='?p=control&d=lot_add'>add lot</a></td>
|
||||
<td><a href='?p=ct&cid=$cid'>detail</a> - <a href='?p=control&d=edit&cid=$cid'>edit</a> -
|
||||
<a href='?p=control&d=del&cid=$cid'>del</a>
|
||||
</td></tr>";
|
||||
$i++;
|
||||
}
|
||||
?>
|
||||
</table>
|
||||
@ -1,27 +0,0 @@
|
||||
<?php
|
||||
$cid = $_GET['cid'];
|
||||
$sql = "select name from DICT_CONTROL where id='$cid'";
|
||||
$stmt = sqlsrv_query( $conn1, $sql );
|
||||
if( $stmt == false) { die( print_r( sqlsrv_errors(), true) ); }
|
||||
$row = sqlsrv_fetch_array( $stmt, SQLSRV_FETCH_NUMERIC);
|
||||
$cname = $row[0];
|
||||
if(!isset($_POST['submit'])) {
|
||||
?>
|
||||
<form method='POST'>
|
||||
control : <?=$cname;?><br/>
|
||||
lot<br/>
|
||||
<input type='text' name='lot' /><br/>
|
||||
expdate<br/>
|
||||
<input type='date' name='expdate' /><br/>
|
||||
<input type='submit' name='submit' value='add' />
|
||||
</form>
|
||||
<?php
|
||||
} else {
|
||||
$lot=$_POST['lot'];
|
||||
$expdate=$_POST['expdate'];
|
||||
$sql="INSERT INTO DICT_CONTROL( name,lot,expdate) values ('$cname','$lot','$expdate')";
|
||||
$stmt = sqlsrv_query( $conn1, $sql );
|
||||
if( $stmt == false) { die( print_r( sqlsrv_errors(), true) ); }
|
||||
echo "<meta http-equiv='refresh' content='0;url=?p=dict' />";
|
||||
}
|
||||
?>
|
||||
@ -1,8 +0,0 @@
|
||||
<?php
|
||||
$ctid = $_GET['ctid'];
|
||||
$cid = $_GET['cid'];
|
||||
$sql="DELETE CONTROL_TEST WHERE id='$ctid'";
|
||||
$stmt = sqlsrv_query( $conn1, $sql );
|
||||
if( $stmt == false) { die( print_r( sqlsrv_errors(), true) ); }
|
||||
echo "<meta http-equiv='refresh' content='0;url=?p=ct&cid=$cid' />";
|
||||
?>
|
||||
@ -1,29 +0,0 @@
|
||||
<?php
|
||||
$cid = $_GET['cid'];
|
||||
$ctid = $_GET['ctid'];
|
||||
if(!isset($_POST['submit'])) {
|
||||
$sql = "select dt.name, ct.mean, ct.sd from DICT_TEST dt, CONTROL_TEST ct
|
||||
where ct.testid=dt.id and ct.id='$ctid'";
|
||||
$stmt = sqlsrv_query( $conn1, $sql );
|
||||
if( $stmt == false) { die( print_r( sqlsrv_errors(), true) ); }
|
||||
$row = sqlsrv_fetch_array( $stmt, SQLSRV_FETCH_NUMERIC );
|
||||
$tname = $row[0];
|
||||
$mean = $row[1];
|
||||
$sd = $row[2];
|
||||
?>
|
||||
<form method='POST'>
|
||||
<h2><?php echo "$tname ";?></h2>
|
||||
mean<br/><input type='text' name='mean' value='<?php echo $mean;?>' /><br/>
|
||||
sd<br/><input type='text' name='sd' value='<?php echo $sd;?>' /><br/>
|
||||
<input type='submit' name='submit' value='update' />
|
||||
<?php
|
||||
} else {
|
||||
$ctid = $_GET['ctid'];
|
||||
$mean = $_POST['mean'];
|
||||
$sd = $_POST['sd'];
|
||||
$sql = "UPDATE CONTROL_TEST SET mean='$mean', sd='$sd' WHERE id='$ctid'";
|
||||
$stmt = sqlsrv_query( $conn1, $sql );
|
||||
if( $stmt == false) { die( print_r( sqlsrv_errors(), true) ); }
|
||||
echo "<META http-equiv='refresh' content='0;url=?p=ct&cid=$cid'>";
|
||||
}
|
||||
?>
|
||||
@ -1,64 +0,0 @@
|
||||
<?php
|
||||
$cid = $_GET['cid'];
|
||||
$sql = "select name, lot, expdate from DICT_CONTROL where id='$cid'";
|
||||
$stmt = sqlsrv_query( $conn1, $sql );
|
||||
if( $stmt == false) { die( print_r( sqlsrv_errors(), true) ); }
|
||||
$row = sqlsrv_fetch_array( $stmt, SQLSRV_FETCH_NUMERIC );
|
||||
$cname = $row[0];
|
||||
$lot = $row[1];
|
||||
if($row[2]!='') { $expdate = date_format($row[2],"d-m-Y"); }
|
||||
else { $expdate = ''; }
|
||||
if(isset($_POST['add'])) {
|
||||
if(isset($_POST['test'])) {
|
||||
$testid = $_POST['test'];
|
||||
$mean = $_POST['mean'];
|
||||
$sd = $_POST['sd'];
|
||||
$sql = "INSERT INTO CONTROL_TEST (testid,controlid,mean,sd) VALUES ('$testid','$cid','$mean','$sd')";
|
||||
$stmt = sqlsrv_query( $conn1, $sql );
|
||||
if( $stmt == false) { die( print_r( sqlsrv_errors(), true) ); }
|
||||
}
|
||||
}
|
||||
?>
|
||||
Control <?php echo $cname; ?><br/>
|
||||
Lot <?php echo $lot; ?><br/>
|
||||
Exp date <?php echo $expdate; ?><br/>
|
||||
<table border='1'>
|
||||
<tr><th>no</th><th>test</th><th>mean</th><th>sd</th></tr>
|
||||
<tr>
|
||||
<form method='POST'>
|
||||
<td></td>
|
||||
<td><select name='test'>
|
||||
<?php
|
||||
$sql = "select id, name from DICT_TEST
|
||||
where id not in (select testid from CONTROL_TEST where controlid='$cid')";
|
||||
$stmt = sqlsrv_query( $conn1, $sql );
|
||||
if( $stmt == false) { die( print_r( sqlsrv_errors(), true) ); }
|
||||
while( $row = sqlsrv_fetch_array( $stmt, SQLSRV_FETCH_NUMERIC) ) {
|
||||
$tid = $row[0];
|
||||
$tname = $row[1];
|
||||
echo "<option value='$tid'>$tname</option>";
|
||||
}
|
||||
?>
|
||||
</select></td>
|
||||
<td><input type='text' name='mean' /></td>
|
||||
<td><input type='text' name='sd' /></td>
|
||||
<td><input type='submit' value='+' name='add' /></td>
|
||||
</form>
|
||||
</tr>
|
||||
<?php
|
||||
$sql = "select ct.id, dt.name, ct.mean, ct.sd from DICT_TEST dt, CONTROL_TEST ct
|
||||
where ct.testid=dt.id and ct.controlid='$cid'";
|
||||
$stmt = sqlsrv_query( $conn1, $sql );
|
||||
if( $stmt == false) { die( print_r( sqlsrv_errors(), true) ); }
|
||||
$i=1;
|
||||
while( $row = sqlsrv_fetch_array( $stmt, SQLSRV_FETCH_NUMERIC) ) {
|
||||
$ctid = $row[0];
|
||||
$tname = $row[1];
|
||||
$tmean = $row[2];
|
||||
$tsd = $row[3];
|
||||
echo "<tr> <td>$i</td> <td>$tname</td> <td>$tmean</td> <td>$tsd</td>
|
||||
<td> <a href='?p=ct&d=edit&ctid=$ctid&cid=$cid'>edit</a> - <a href='?p=ct&d=del&ctid=$ctid&cid=$cid'>delete</a> </td> </tr>";
|
||||
$i++;
|
||||
}
|
||||
?>
|
||||
</table>
|
||||
@ -1,99 +0,0 @@
|
||||
<?php
|
||||
$date=date("Y-m");
|
||||
/*
|
||||
$sql = "select id, name, lot from DICT_CONTROL order by expdate desc";
|
||||
$stmt = sqlsrv_query( $conn1, $sql );
|
||||
if( $stmt == false) { die( print_r( sqlsrv_errors(), true) ); }
|
||||
*/
|
||||
?>
|
||||
<form method='GET' target='_blank'>
|
||||
<input type='hidden' name='p' value='entry_monthly'>
|
||||
<table>
|
||||
<tr> <td>Dept.</td> <td>:</td>
|
||||
<td>
|
||||
<select id='dept'>
|
||||
<option value='1'>Kimia</option>
|
||||
<option value='2'>Imun</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr> <td>Date</td> <td>:</td> <td><input type='date' id='dates' name='dates' onInput='getControl(this.value);' /></td> </tr>
|
||||
<tr> <td>Control</td> <td>:</td> <td><select id='control' name='control' onchange='getTest(this.value);'><option> -- Select Control -- </option></select></td> </tr>
|
||||
<tr> <td>Test</td> <td>:</td> <td><select id='test' name='test'><option> -- Select Test -- </option></select></td> </tr>
|
||||
<tr> <td><input type='submit' value='go'></td> </tr>
|
||||
</table>
|
||||
</form>
|
||||
<script src="assets/jquery.js"></script>
|
||||
<script type="text/javascript">
|
||||
function getTest(){
|
||||
// Empty the dropdown
|
||||
var testel = document.getElementById('test');
|
||||
test.innerHTML = "";
|
||||
|
||||
var testopt = document.createElement('option');
|
||||
testopt.value = 0;
|
||||
testopt.innerHTML = '-- Select Test --';
|
||||
testel.appendChild(testopt);
|
||||
|
||||
var control = $("#control").val();
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
contentType: "application/json; charset=utf-8",
|
||||
url: "inc/entry_ajax.php",
|
||||
datatype : 'JSON',
|
||||
data: JSON.stringify( {request:'getTest', control: control} ),
|
||||
success: function(response){
|
||||
var result = JSON.parse(response);
|
||||
var len = result.length;
|
||||
|
||||
for(var i=0; i<len; i++){
|
||||
var id = result[i].id;
|
||||
var name = result[i].name;
|
||||
//console.log(result[i]);
|
||||
// Add option to state dropdown
|
||||
var opt = document.createElement('option');
|
||||
opt.value = id;
|
||||
opt.innerHTML = name;
|
||||
testel.appendChild(opt);
|
||||
}
|
||||
},
|
||||
error:function(exception){alert('Exeption:'+exception);}
|
||||
});
|
||||
}
|
||||
function getControl(){
|
||||
// Empty the dropdown
|
||||
var controlel = document.getElementById('control');
|
||||
control.innerHTML = "";
|
||||
|
||||
var controlopt = document.createElement('option');
|
||||
controlopt.value = 0;
|
||||
controlopt.innerHTML = '-- Select Control --';
|
||||
controlel.appendChild(controlopt);
|
||||
|
||||
var dates = $("#dates").val();
|
||||
var dept = $("#dept").val();
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
contentType: "application/json; charset=utf-8",
|
||||
url: "inc/entry_ajax.php",
|
||||
datatype : 'JSON',
|
||||
data: JSON.stringify( {request:'getControl', dates: dates, dept:dept} ),
|
||||
success: function(response){
|
||||
var result = JSON.parse(response);
|
||||
var len = result.length;
|
||||
|
||||
for(var i=0; i<len; i++){
|
||||
var id = result[i].id;
|
||||
var name = result[i].name;
|
||||
//console.log(result[i]);
|
||||
// Add option to state dropdown
|
||||
var opt = document.createElement('option');
|
||||
opt.value = id;
|
||||
opt.innerHTML = name;
|
||||
controlel.appendChild(opt);
|
||||
}
|
||||
},
|
||||
error:function(exception){alert('Exeption:'+exception);}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
@ -1,51 +0,0 @@
|
||||
<?php
|
||||
include '../config.php';
|
||||
|
||||
// Read POST data
|
||||
$postData = json_decode(file_get_contents("php://input"));
|
||||
$request = "";
|
||||
if(isset($postData->request)){
|
||||
$request = $postData->request;
|
||||
}
|
||||
|
||||
// Get Test
|
||||
if($request == 'getTest'){
|
||||
$result = array();$data = array();
|
||||
|
||||
if(isset($postData->control)){
|
||||
$control = $postData->control;
|
||||
$sql = "select dt.id, dt.name from CONTROL_TEST ct left join DICT_TEST dt on dt.id=ct.testid where ct.controlid='$control'";
|
||||
$stmt = sqlsrv_query( $conn1, $sql );
|
||||
if( $stmt == false) { die( print_r( sqlsrv_errors(), true) ); }
|
||||
while ( $row = sqlsrv_fetch_array( $stmt, SQLSRV_FETCH_NUMERIC ) ) {
|
||||
$id = $row[0];
|
||||
$name = $row[1];
|
||||
$data[] = array( "id" => $id, "name" => $name );
|
||||
}
|
||||
}
|
||||
|
||||
echo json_encode($data);
|
||||
die;
|
||||
}
|
||||
|
||||
// Get Control
|
||||
elseif($request == 'getControl'){
|
||||
$result = array();$data = array();
|
||||
|
||||
if(isset($postData->dates)){
|
||||
$dates = $postData->dates;
|
||||
$dept = $postData->dept;
|
||||
$sql = "select id, name, lot from DICT_CONTROL where expdate > '$dates' and deptID='$dept'";
|
||||
$stmt = sqlsrv_query( $conn1, $sql );
|
||||
if( $stmt == false) { die( print_r( sqlsrv_errors(), true) ); }
|
||||
while ( $row = sqlsrv_fetch_array( $stmt, SQLSRV_FETCH_NUMERIC ) ) {
|
||||
$id = $row[0];
|
||||
$name = $row[1];
|
||||
$lot = $row[2];
|
||||
$data[] = array( "id" => $id, "name" => "$name - $lot" );
|
||||
}
|
||||
}
|
||||
|
||||
echo json_encode($data);
|
||||
die;
|
||||
}
|
||||
@ -1,74 +0,0 @@
|
||||
<?php
|
||||
if(isset($_POST['date'])) { $date = $_POST['date']; }
|
||||
else { $date=date("Y-m-d"); }
|
||||
$sql = "select id, name, lot from DICT_CONTROL where expdate > '$date' ";
|
||||
$stmt = sqlsrv_query( $conn1, $sql );
|
||||
if( $stmt == false) { die( print_r( sqlsrv_errors(), true) ); }
|
||||
?>
|
||||
<form method='POST' action='inc/entry_daily_1.php' target='_blank' />
|
||||
<table>
|
||||
<tr> <td>Dept.</td> <td>:</td>
|
||||
<td>
|
||||
<select id='dept'>
|
||||
<option value='1'>Kimia</option>
|
||||
<option value='2'>Imun</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr> <td>Date</td> <td>:</td>
|
||||
<td><input type='date' id='date' name='date' value='<?=$date;?>' onInput='getControl();' /></td>
|
||||
</tr>
|
||||
<tr> <td>Control</td> <td>:</td>
|
||||
<td><select id='control' name='control'>
|
||||
<option value=''> -- Select Control -- </option>
|
||||
<?php
|
||||
while ( $row = sqlsrv_fetch_array( $stmt, SQLSRV_FETCH_NUMERIC ) ) {
|
||||
$id = $row[0];
|
||||
$name = "$row[1] - $row[2]";
|
||||
echo "<option value='$id'>$name</option>";
|
||||
}?>
|
||||
</select></td>
|
||||
</tr>
|
||||
<tr> <td><input type='submit' value='go'></td> </tr>
|
||||
</table>
|
||||
</form>
|
||||
<script src="assets/jquery.js"></script>
|
||||
<script type="text/javascript">
|
||||
function getControl(){
|
||||
// Empty the dropdown
|
||||
var controlel = document.getElementById('control');
|
||||
control.innerHTML = "";
|
||||
|
||||
var controlopt = document.createElement('option');
|
||||
controlopt.value = 0;
|
||||
controlopt.innerHTML = '-- Select Control --';
|
||||
controlel.appendChild(controlopt);
|
||||
|
||||
var dates = $("#date").val();
|
||||
var dept = $("#dept").val();
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
contentType: "application/json; charset=utf-8",
|
||||
url: "inc/entry_ajax.php",
|
||||
datatype : 'JSON',
|
||||
data: JSON.stringify( {request:'getControl', dates: dates, dept:dept} ),
|
||||
success: function(response){
|
||||
var result = JSON.parse(response);
|
||||
var len = result.length;
|
||||
|
||||
for(var i=0; i<len; i++){
|
||||
var id = result[i].id;
|
||||
var name = result[i].name;
|
||||
var lot = result[i].lot;
|
||||
console.log(result[i]);
|
||||
// Add option to state dropdown
|
||||
var opt = document.createElement('option');
|
||||
opt.value = id;
|
||||
opt.innerHTML = name+' ('+lot+')';
|
||||
controlel.appendChild(opt);
|
||||
}
|
||||
},
|
||||
error:function(exception){alert('Exeption:'+exception);}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
@ -1,85 +0,0 @@
|
||||
<?php
|
||||
include("../config.php");
|
||||
if(!isset($_POST['submit'])) {
|
||||
$controlid = $_POST['control'];
|
||||
$date = $_POST['date'];
|
||||
/*
|
||||
$sql = "select dr.testid, dt.name, drx.resvalue, drx.resdate as latestVal, ct.mean, ct.sd
|
||||
from CONTROL_TEST ct
|
||||
left join DICT_TEST dt on ct.testid=dt.id
|
||||
left join (
|
||||
select controlid, testid, max(resdate) as resdate from DAILY_RESULT
|
||||
group by controlid, testid
|
||||
) as dr on dr.controlid=ct.controlid and dr.testid=ct.testid
|
||||
left join DAILY_RESULT drx on drx.controlid=dr.controlid and drx.testid=dr.testid and drx.resdate=dr.resdate
|
||||
where ct.controlid='$controlid'";
|
||||
*/
|
||||
$sql = "select ct.testid, dt.name, ct.mean, ct.sd, dr.resvalue
|
||||
from CONTROL_TEST ct
|
||||
left join DICT_TEST dt on ct.testid=dt.id
|
||||
full join DAILY_RESULT dr on dr.controlid=ct.controlid and dr.testid=ct.testid
|
||||
and dr.resdate between '$date 00:00' and '$date 23:59'
|
||||
where ct.controlid='$controlid'";
|
||||
$stmt = sqlsrv_query( $conn1, $sql );
|
||||
if( $stmt == false) { die( print_r( sqlsrv_errors(), true) ); }
|
||||
|
||||
?>
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>QC APP</title>
|
||||
<link rel="stylesheet" href="../assets/styles.css?v=<?php echo time(); ?>">
|
||||
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
|
||||
</head>
|
||||
<body>
|
||||
<div id='container'>
|
||||
<div id='content'>
|
||||
<h3><b>Tanggal</b> <?=$date;?></h3>
|
||||
<table border='1'>
|
||||
<form method='POST'>
|
||||
<tr> <th>Test</th> <th>Value</th> <th>Mean (SD)</th>
|
||||
<?php
|
||||
while( $row = sqlsrv_fetch_array( $stmt, SQLSRV_FETCH_NUMERIC ) ) {
|
||||
$tid = $row[0];
|
||||
$tname = $row[1];
|
||||
$tmean = $row[2];
|
||||
$tsd = $row[3];
|
||||
$tvalue = $row[4];
|
||||
echo "<tr> <td>$tname</td>
|
||||
<td><input type='text' name='value[$tid]' value='$tvalue' /></td>
|
||||
<td>$tmean ($tsd)</td>
|
||||
</tr>";
|
||||
}
|
||||
?>
|
||||
<tr> <td colspan='3' style='text-align:right;'> <input type='submit' name='submit' value='save' /> </td></tr>
|
||||
</table>
|
||||
<br/>
|
||||
<input type='hidden' name='controlid' value='<?=$controlid;?>' />
|
||||
<input type='hidden' name='date' value='<?=$date;?>' />
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
<?php
|
||||
} else {
|
||||
$controlid = $_POST['controlid'];
|
||||
$date = $_POST['date'];
|
||||
$data = $_POST['value'];
|
||||
foreach($data as $testid => $value) {
|
||||
if($value != '') {
|
||||
$sql = "if exists (select * from DAILY_RESULT where controlid='$controlid' and testid='$testid' and resdate='$date 00:00')
|
||||
update DAILY_RESULT set resvalue='$value' where controlid='$controlid' and testid='$testid' and resdate='$date 00:00'
|
||||
else
|
||||
insert into DAILY_RESULT(controlid, testid, resvalue, resdate) values ('$controlid', '$testid', '$value', '$date 00:00')";
|
||||
} else {
|
||||
$sql = "if exists (select * from DAILY_RESULT where controlid='$controlid' and testid='$testid' and resdate='$date 00:00')
|
||||
delete from DAILY_RESULT where controlid='$controlid' and testid='$testid' and resdate='$date 00:00'";
|
||||
}
|
||||
//echo "<pre>$sql</pre><br/>";
|
||||
$stmt = sqlsrv_query( $conn1, $sql );
|
||||
if( $stmt == false) { die( print_r( sqlsrv_errors(), true) ); }
|
||||
}
|
||||
echo "Data updated...";
|
||||
}
|
||||
?>
|
||||
@ -1,192 +0,0 @@
|
||||
<?php
|
||||
include("config.php");
|
||||
if(!isset($_POST['submit'])) {
|
||||
if(isset($_GET['control'])) { $control = $_GET['control']; }
|
||||
else { $control = $_POST['control']; }
|
||||
if(isset($_GET['dates'])) { $date = $_GET['dates']; }
|
||||
else { $date = $_POST['dates']; }
|
||||
$date = substr($date,0,7);
|
||||
if(isset($_GET['test'])) { $testid = $_GET['test']; }
|
||||
else { $testid = $_POST['test']; }
|
||||
// control data
|
||||
$sql = "select name, lot from DICT_CONTROL where id='$control'";
|
||||
$stmt = sqlsrv_query( $conn1, $sql );
|
||||
if( $stmt == false) { die( print_r( sqlsrv_errors(), true) ); }
|
||||
$row = sqlsrv_fetch_array( $stmt, SQLSRV_FETCH_NUMERIC );
|
||||
$cname = $row[0];
|
||||
$lot = $row[1];
|
||||
|
||||
// test data
|
||||
$sql = "select name from DICT_TEST where id='$testid'";
|
||||
$stmt = sqlsrv_query( $conn1, $sql );
|
||||
if( $stmt == false) { die( print_r( sqlsrv_errors(), true) ); }
|
||||
$row = sqlsrv_fetch_array( $stmt, SQLSRV_FETCH_NUMERIC );
|
||||
$tname = $row[0];
|
||||
|
||||
// test result
|
||||
$sql = "select resdate, resvalue, rescomment from DAILY_RESULT where controlid='$control' and testid='$testid' and convert( varchar(7), resdate, 126) ='$date' ";
|
||||
$stmt = sqlsrv_query( $conn1, $sql );
|
||||
if( $stmt == false) { die( print_r( sqlsrv_errors(), true) ); }
|
||||
while( $row = sqlsrv_fetch_array( $stmt, SQLSRV_FETCH_NUMERIC ) ) {
|
||||
$day = date_format($row[0],'j');
|
||||
$res = $row[1];
|
||||
$rescom = $row[2];
|
||||
$data [$day] = $res;
|
||||
$comment [$day] = $rescom;
|
||||
}
|
||||
|
||||
#mean sd
|
||||
$sql = "select mean, sd from CONTROL_TEST where controlid='$control' and testid='$testid'";
|
||||
$stmt = sqlsrv_query( $conn1, $sql );
|
||||
if( $stmt == false) { die( print_r( sqlsrv_errors(), true) ); }
|
||||
$row = sqlsrv_fetch_array( $stmt, SQLSRV_FETCH_NUMERIC );
|
||||
$mean = $row[0];
|
||||
$sd = $row[1];
|
||||
$max = $mean + ($sd*2);
|
||||
$min = $mean - ($sd*2);
|
||||
|
||||
#comtext
|
||||
$sql = "select comtext from MONTHLY_COMMENT where controlid='$control' and testid='$testid' and commonth='$date'";
|
||||
$stmt = sqlsrv_query( $conn1, $sql );
|
||||
if( $stmt == false) { die( print_r( sqlsrv_errors(), true) ); }
|
||||
$row = sqlsrv_fetch_array( $stmt, SQLSRV_FETCH_NUMERIC );
|
||||
$comtext = '';
|
||||
if(isset($row[0])) { $comtext = $row[0]; }
|
||||
|
||||
$hari = date("t",strtotime("$date-1"));
|
||||
?>
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>QC APP</title>
|
||||
<link rel="stylesheet" href="../assets/styles.css?v=<?php echo time(); ?>">
|
||||
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
|
||||
</head>
|
||||
<body>
|
||||
<div id='container'>
|
||||
<div id='content'>
|
||||
<b>Periode</b> <?=$date;?><br/>
|
||||
<table border='1'>
|
||||
<tr> <th colspan='2'><?php echo "$cname ($lot) - $tname";?></th> </tr>
|
||||
<tr> <td>Mean</td> <td><?=$mean;?></td></tr>
|
||||
<tr> <td>SD</td> <td><?=$sd;?></td></tr>
|
||||
<tr> <td>Range</td> <td><?=$min;?> - <?=$max;?></td></tr>
|
||||
</table>
|
||||
<br/>
|
||||
<form method='POST'>
|
||||
<table border='1'>
|
||||
<tr> <th>Day</th> <th>Result</th> <th>Comment</th> </tr>
|
||||
<?php
|
||||
for($i=1;$i<=$hari;$i++) {
|
||||
echo "<tr> <td>$i</td>";
|
||||
if(isset($data[$i])) { echo "<td><input type='text' name='data[$i]' value='$data[$i]' size='25' /></td>"; }
|
||||
else { echo "<td><input type='text' name='data[$i]' size='25' /></td>"; }
|
||||
if(isset($comment[$i])) { echo "<td><input type='text' name='comment[$i]' value='$comment[$i]' size='50' /></td>"; }
|
||||
else { echo "<td><input type='text' name='comment[$i]' size='50' /></td>"; }
|
||||
}
|
||||
?>
|
||||
<tr> <td colspan='2' valign='top'>Comment:</td> <td><textarea name='monthlycomment' cols='40'><?=$comtext;?></textarea> </td> </tr>
|
||||
<tr> <td colspan='3' align='right'><input type='submit' name='submit' value='update' /></td> </tr>
|
||||
</table>
|
||||
<input type='hidden' name='control' value='<?=$control;?>' />
|
||||
<input type='hidden' name='dates' value='<?=$date;?>' />
|
||||
<input type='hidden' name='test' value='<?=$testid;?>' />
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
<?php
|
||||
} else {
|
||||
$control = $_POST['control'];
|
||||
$date = $_POST['dates'];
|
||||
$testid = $_POST['test'];
|
||||
$data = $_POST['data'];
|
||||
$comment = $_POST['comment'];
|
||||
$i = 1;
|
||||
foreach($data as $data1) {
|
||||
if($data1>0) {$rdata[$i]=$data1;}
|
||||
$i++;
|
||||
}
|
||||
$data = $rdata;
|
||||
$hari = date("t",strtotime("$date-1"));
|
||||
$sql = "SELECT id,resdate FROM DAILY_RESULT WHERE convert(varchar(7),resdate,126) ='$date' and controlid='$control' and testid='$testid'";
|
||||
//echo $sql;
|
||||
$stmt = sqlsrv_query( $conn1, $sql);
|
||||
while( $row = sqlsrv_fetch_array( $stmt, SQLSRV_FETCH_NUMERIC ) ) {
|
||||
$id = $row[0];
|
||||
$cday = date_format($row[1],"j");
|
||||
$resid[$cday] = $id;
|
||||
}
|
||||
///*
|
||||
for($i=1;$i<=$hari;$i++) {
|
||||
if( isset($data[$i]) ) {
|
||||
if( isset($resid[$i]) ) { $dataUpdate[$resid[$i]] = $data[$i]; $commentUpdate[$resid[$i]]= $comment[$i]; } // data update
|
||||
else { $dataInsert[$i] = $data[$i]; } // data insert
|
||||
}
|
||||
elseif( isset($resid[$i]) ) { $dataDelete[] = $resid[$i]; } // data delete
|
||||
}
|
||||
|
||||
//INSERT
|
||||
if(isset($dataInsert)) {
|
||||
$sql = "INSERT INTO DAILY_RESULT (controlid, testid, resdate, resvalue, rescomment ) VALUES ";
|
||||
foreach($dataInsert as $day => $data1) {
|
||||
if($day < 10) { $day="0$day"; }
|
||||
$sql.= "('$control', '$testid', '$date-$day', '$data1','$comment[$day]'),";
|
||||
}
|
||||
$sql = substr($sql,0,-1);
|
||||
$stmt = sqlsrv_query( $conn1, $sql);
|
||||
if( $stmt === false ) { die( print_r( sqlsrv_errors(), true)); }
|
||||
echo "inserting new control result done... <br/>";
|
||||
}
|
||||
|
||||
//UPDATE
|
||||
if(isset($dataUpdate)) {
|
||||
foreach($dataUpdate as $drid => $data1) {
|
||||
$sql = "update DAILY_RESULT set resvalue='$data1', rescomment='$commentUpdate[$drid]' where id='$drid'";
|
||||
$stmt = sqlsrv_query( $conn1, $sql);
|
||||
if( $stmt === false ) { die( print_r( sqlsrv_errors(), true)); }
|
||||
//echo "update $drid <br/>";
|
||||
}
|
||||
echo "updating control result done... <br/>";
|
||||
}
|
||||
|
||||
//DELETE
|
||||
if(isset($dataDelete)) {
|
||||
foreach($dataDelete as $drid ) {
|
||||
$sql = "delete from DAILY_RESULT where id='$drid'";
|
||||
$stmt = sqlsrv_query( $conn1, $sql);
|
||||
if( $stmt === false ) { die( print_r( sqlsrv_errors(), true)); }
|
||||
//echo "delete $drid $sql<br/>";
|
||||
}
|
||||
echo "deleting control result done... <br/>";
|
||||
}
|
||||
|
||||
$comtext = $_POST['monthlycomment'];
|
||||
if( $comtext != '' ) {
|
||||
$sql = "if exists (select * from MONTHLY_COMMENT with (updlock,serializable) where commonth='$date' and controlid='$control' and testid='$testid')
|
||||
begin
|
||||
update MONTHLY_COMMENT set comtext='$comtext'
|
||||
where commonth='$date' and controlid='$control' and testid='$testid'
|
||||
end
|
||||
else
|
||||
begin
|
||||
insert into MONTHLY_COMMENT (controlid, testid, commonth, comtext )
|
||||
values ('$control', '$testid', '$date', '$comtext')
|
||||
end";
|
||||
echo $sql;
|
||||
$stmt = sqlsrv_query( $conn1, $sql);
|
||||
if( $stmt === false ) { die( print_r( sqlsrv_errors(), true)); }
|
||||
echo "updating comment done<br/>";
|
||||
} else {
|
||||
$sql = "delete from MONTHLY_COMMENT where commonth='$date' and controlid='$control' and testid='$testid'";
|
||||
$stmt = sqlsrv_query( $conn1, $sql);
|
||||
if( $stmt === false ) { die( print_r( sqlsrv_errors(), true)); }
|
||||
echo "deleting comment done<br/>";
|
||||
}
|
||||
|
||||
//echo "<br/>redirecting ....<META http-equiv='refresh' content='2;url=./index.php?p=entry_1&control=$control&dates=$date&test=$testid'>";
|
||||
echo "<br/>redirecting ....<META http-equiv='refresh' content='2;url=./index.php?p=entry'>";
|
||||
//*/
|
||||
}
|
||||
?>
|
||||
326
v1/inc/qc.php
326
v1/inc/qc.php
@ -1,326 +0,0 @@
|
||||
<?php
|
||||
$date = $_POST['qcdate'];
|
||||
$testcode = $_POST['testcode'];
|
||||
include("config.php");
|
||||
#$date = "2016-06";
|
||||
#$testcode = "BUN";
|
||||
$year = substr($date,0,4);
|
||||
$month = substr($date,5,2);
|
||||
$monthName1 = date('F', mktime(0, 0, 0, $month, 10));
|
||||
$monthName = substr($monthName1,0,3);
|
||||
$days = cal_days_in_month(CAL_GREGORIAN, $month, $year);
|
||||
|
||||
$sql = "select distinct controlcode from DAILY_RUNS
|
||||
where TESTCODE = '$testcode' AND convert( varchar(7), RESCTRLDATETIMEASP, 126) = '$date'";
|
||||
$stmt = sqlsrv_query( $conn1, $sql );
|
||||
if( $stmt == false) { die( print_r( sqlsrv_errors(), true) ); }
|
||||
while( $row = sqlsrv_fetch_array( $stmt, SQLSRV_FETCH_NUMERIC) ) {
|
||||
$qccode[] = $row[0];
|
||||
}
|
||||
|
||||
foreach($qccode as $ccode) {
|
||||
// getting mean,sd on each control
|
||||
$sql = "select distinct REFASSAYVALUE, REFSTANDARDDEVIATION
|
||||
from DAILY_RUNS
|
||||
where TESTCODE = '$testcode' AND CONTROLCODE = '$ccode'
|
||||
AND convert( varchar(7), RESCTRLDATETIMEASP, 126) = '$date'";
|
||||
$stmt = sqlsrv_query( $conn1, $sql );
|
||||
if( $stmt == false) { die( print_r( sqlsrv_errors(), true) ); }
|
||||
$row = sqlsrv_fetch_array( $stmt, SQLSRV_FETCH_NUMERIC );
|
||||
$mean[$ccode] = round($row[0],2);
|
||||
$sd[$ccode] = round($row[1],2);
|
||||
$min[$ccode] = $mean[$ccode] - (3*$sd[$ccode]);
|
||||
$max[$ccode] = $mean[$ccode] + (3*$sd[$ccode]);
|
||||
|
||||
$total = 0;
|
||||
$total2 = 0;
|
||||
$sql = "select day(RESCTRLDATETIMEASP), RESULTCTRL
|
||||
from daily_runs
|
||||
where TESTCODE = '$testcode' AND CONTROLCODE = '$ccode'
|
||||
AND convert( varchar(7), RESCTRLDATETIMEASP, 126) = '$date'";
|
||||
#AND DISPOSITION NOT IN ('3','4') AND VAL_USERID is not NULL
|
||||
$stmt = sqlsrv_query( $conn1, $sql );
|
||||
if( $stmt == false) { die( print_r( sqlsrv_errors(), true) ); }
|
||||
$i=0;
|
||||
while( $row = sqlsrv_fetch_array( $stmt, SQLSRV_FETCH_NUMERIC) ) {
|
||||
$d = $row[0];
|
||||
$value = $row[1];
|
||||
$val[$ccode][$d][] = $value;
|
||||
$total += $value;
|
||||
$total2 += $value*$value;
|
||||
$i++;
|
||||
}
|
||||
$n[$ccode] = $i;
|
||||
if($n[$ccode]>1) {
|
||||
// meanMVA = total/n
|
||||
$meanMVA[$ccode] = round($total/$n[$ccode],3);
|
||||
// CV = sqrt ( ( E(x^2) - (total^2 / n) ) / n - 1 )
|
||||
$cv[$ccode] = round(sqrt(($total2 - ($total*$total)/$n[$ccode]) / ($n[$ccode] - 1)),3);
|
||||
// %CV = CV / (total/n)
|
||||
$pcv[$ccode] = round( $cv[$ccode] * 100 / $n[$ccode] ,3);
|
||||
} else {
|
||||
// meanMVA = total/n
|
||||
$meanMVA[$ccode] = 0;
|
||||
// CV = sqrt ( ( E(x^2) - (total^2 / n) ) / n - 1 )
|
||||
$cv[$ccode] = 0;
|
||||
// %CV = CV / (total/n)
|
||||
$pcv[$ccode] = 0;
|
||||
}
|
||||
}
|
||||
?>
|
||||
<script src="plotly-latest.min.js"></script>
|
||||
<style>
|
||||
#container {width:1100px; margin:0 auto;}
|
||||
#header {text-align:center;}
|
||||
#col1 {float:left;margin:20px 40px 0 0;width:300px}
|
||||
#col2 {float:left;0 width:350px}
|
||||
#col3 {float:right;margin : 25px 190px 0 0;width:350px}
|
||||
table { border-collapse: collapse; }
|
||||
th,td { padding-left: 15px; padding-right: 15px }
|
||||
#graph_C7 { text-align:center; }
|
||||
#html{font-size:20px;}
|
||||
</style>
|
||||
<div id='container'>
|
||||
<div id='header'>
|
||||
<b>Laporan QC - Lab RS Sumber Waras</b> <br/>
|
||||
<b>TMS 24i PREMIUM </b> <br/>
|
||||
<?php foreach ($qccode as $ccode) { echo "<div id='graph_$ccode' style='width:1000px;float:left;'></div> "; }?>
|
||||
</div>
|
||||
|
||||
<div id='col1'>
|
||||
<b>Periode : </b> <?php echo "$monthName1 $year";?> <br/>
|
||||
<b>Test : </b> <?php echo "$testcode ";?> <br/>
|
||||
<table border='1'>
|
||||
<tr> <th>QC Code</th> <?php foreach($qccode as $ccode) echo "<th>$ccode</th>"; ?> </tr>
|
||||
<tr> <td>Mean</td> <?php foreach($mean as $mean1) echo "<td>$mean1</td>"; ?> </tr>
|
||||
<tr> <td>1SD</td> <?php foreach($sd as $sd1)echo "<td>$sd1</td>"; ?> </tr>
|
||||
<tr> <td>Range</td> <?php foreach($qccode as $ccode) echo "<td>$min[$ccode] - $max[$ccode]</td>"; ?> </tr>
|
||||
<tr> <td></td> </tr>
|
||||
<tr> <td>Mean MVA</td> <?php foreach($qccode as $ccode) echo "<td>".$meanMVA[$ccode]."</td>"; ?> </tr>
|
||||
<tr> <td>SD</td> <?php foreach($qccode as $ccode) echo "<td>".$cv[$ccode]."</td>"; ?> </tr>
|
||||
<tr> <td>%CV</td> <?php foreach($qccode as $ccode) echo "<td>".$pcv[$ccode]."</td>"; ?> </tr>
|
||||
</table>
|
||||
</div>
|
||||
<div id='col2'>
|
||||
<table border='1'>
|
||||
<tr> <th>No</th> <th>Datetime</th> <?php foreach($qccode as $ccode) echo "<th>$ccode</th>"; ?> </tr>
|
||||
<?php
|
||||
// getting value count per day
|
||||
for($i=1;$i<=$days;$i++) {
|
||||
foreach($qccode as $ccode) {
|
||||
if(isset($val[$ccode][$i])) { $cnt[$i][$ccode] = count($val[$ccode][$i]); }
|
||||
else { $cnt[$i][$ccode] = 1; }
|
||||
}
|
||||
$count[$i] = max($cnt[$i]);
|
||||
}
|
||||
|
||||
//show the value on table
|
||||
$k = 1;
|
||||
for($i=1;$i<=16;$i++) { // 1-16
|
||||
for($j=0;$j<$count[$i];$j++) { // value per day
|
||||
echo "<tr> <td>$k</td> <td>$i - $monthName</td>";
|
||||
foreach($qccode as $ccode){
|
||||
if(isset($val[$ccode][$i][$j])) echo "<td>".$val[$ccode][$i][$j]."</td>";
|
||||
else echo "<td></td>";
|
||||
}
|
||||
$k++;
|
||||
echo "</tr>";
|
||||
}
|
||||
}
|
||||
?>
|
||||
</table>
|
||||
</div>
|
||||
<div id='col3'>
|
||||
<table border='1'>
|
||||
<?php
|
||||
for($i=17;$i<=$days;$i++) { // 17-end
|
||||
for($j=0;$j<$count[$i];$j++) { // value per day
|
||||
echo "<tr> <td>$k</td> <td>$i - $monthName</td>";
|
||||
foreach($qccode as $ccode){
|
||||
if(isset($val[$ccode][$i][$j])) echo "<td>".$val[$ccode][$i][$j]."</td>";
|
||||
else echo "<td></td>";
|
||||
}
|
||||
$k++;
|
||||
echo "</tr>";
|
||||
}
|
||||
}
|
||||
?>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<script>
|
||||
<?php
|
||||
foreach ($qccode as $ccode) {
|
||||
echo "var val_$ccode = {
|
||||
connectgaps: false,mode: 'lines+markers',
|
||||
line: { color: 'rgb(0, 0, 0)', width: 1 },
|
||||
x:[";
|
||||
// x days
|
||||
for($i=1;$i<=$days;$i++) { echo $i,","; }
|
||||
echo "],
|
||||
";
|
||||
|
||||
//y values
|
||||
echo "y:[";
|
||||
for($i=1;$i<=$days;$i++) {
|
||||
if(isset($val[$ccode][$i])) { $count = count($val[$ccode][$i]); }
|
||||
else { $count = 1; }
|
||||
for($j=0;$j<$count;$j++) {
|
||||
if(isset($val[$ccode][$i][$j])) {
|
||||
if($j==($count-1)) {// separate multi value
|
||||
echo $val[$ccode][$i][$j].",";
|
||||
$val1[$ccode][$i] = $val[$ccode][$i][$j];
|
||||
} else {
|
||||
$mulx[$ccode][] = $i;
|
||||
$muly[$ccode][] = $val[$ccode][$i][$j];
|
||||
}
|
||||
} else {
|
||||
echo "null,";
|
||||
}
|
||||
}
|
||||
}
|
||||
echo "]};
|
||||
";
|
||||
|
||||
//scatter for multi val on one y axis
|
||||
if(isset($mulx[$ccode])) {
|
||||
echo "var mul_$ccode = {
|
||||
mode: 'markers', type: 'scatter',
|
||||
line: { color: 'rgb(0, 0, 0)', width: 1 },
|
||||
x:[";
|
||||
foreach ($mulx[$ccode] as $mulx1) { echo $mulx1,","; }
|
||||
echo "],
|
||||
";
|
||||
|
||||
//y values
|
||||
echo "y:[";
|
||||
foreach ($muly[$ccode] as $muly1) { echo $muly1,","; }
|
||||
echo "]};
|
||||
";
|
||||
}
|
||||
//mean and sd
|
||||
echo "var layout_$ccode = {
|
||||
title: '$ccode',
|
||||
showlegend : false,
|
||||
shapes: [";
|
||||
//mean
|
||||
echo" {
|
||||
type: 'line', x0: 0, x1: 32,
|
||||
y0: $mean[$ccode], y1:$mean[$ccode],
|
||||
line: { color: 'rgb(0, 0, 0)', width: 2 }
|
||||
},";
|
||||
//1sd
|
||||
$p1sd = $mean[$ccode]+$sd[$ccode];
|
||||
$p2sd = $mean[$ccode]+(2*$sd[$ccode]);
|
||||
$p3sd = $mean[$ccode]+(3*$sd[$ccode]);
|
||||
$p4sd = $mean[$ccode]+(4*$sd[$ccode]);
|
||||
$m1sd = $mean[$ccode]-$sd[$ccode];
|
||||
$m2sd = $mean[$ccode]-(2*$sd[$ccode]);
|
||||
$m3sd = $mean[$ccode]-(3*$sd[$ccode]);
|
||||
$m4sd = $mean[$ccode]-(4*$sd[$ccode]);
|
||||
echo" {
|
||||
type: 'line', x0: 0, x1: 32,
|
||||
y0:$p1sd, y1:$p1sd,
|
||||
line: { color: 'rgb(0,255,0)', width: 2 }
|
||||
},{
|
||||
type: 'line', x0: 0, x1: 32,
|
||||
y0:$m1sd, y1:$m1sd,
|
||||
line: { color: 'rgb(0,255,0)', width: 2 }
|
||||
},";
|
||||
//2sd
|
||||
echo" {
|
||||
type: 'line', x0: 0, x1: 32,
|
||||
y0:$p2sd, y1:$p2sd,
|
||||
line: { color: 'rgb(255, 255, 0)', width: 2 }
|
||||
},{
|
||||
type: 'line', x0: 0, x1: 32,
|
||||
y0:$m2sd, y1:$m2sd,
|
||||
line: { color: 'rgb(255, 255, 0)', width: 2 }
|
||||
},";
|
||||
//3sd
|
||||
echo" {
|
||||
type: 'line', x0: 0, x1: 32,
|
||||
y0:$p3sd, y1:$p3sd,
|
||||
line: { color: 'rgb(255, 0, 0)', width: 2 }
|
||||
},{
|
||||
type: 'line', x0: 0, x1: 32,
|
||||
y0:$m3sd, y1:$m3sd,
|
||||
line: { color: 'rgb(255, 0, 0)', width: 2 }
|
||||
},";
|
||||
|
||||
//jumping value LOL
|
||||
//2,5,9 - 3,5,6
|
||||
//2,5 - 3,5 ; 5,9 - 5,6
|
||||
/*
|
||||
foreach($val1[$ccode] as $i => $value) {
|
||||
|
||||
}
|
||||
|
||||
//single jump
|
||||
if(isset($nullx[$ccode])) {
|
||||
foreach($nullx[$ccode] as $null) {
|
||||
if($null != 1) {
|
||||
$y0 = $val1[$ccode][$null-1];
|
||||
$y1 = $val1[$ccode][$null+1];
|
||||
echo "{
|
||||
type: 'line', x0: $null-1, x1: $null+1,
|
||||
y0:$y0, y1:$y1,
|
||||
line: { color: 'rgb( 0, 0, 0)', dash:'dot' }
|
||||
},";
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
$n = 0;
|
||||
$i = 1;
|
||||
while( $i <= $days) {
|
||||
if(!isset($val1[$ccode][$i])) {
|
||||
if(isset($val1[$ccode][$i-1])){
|
||||
$x0 = $i-1;
|
||||
$y0 = $val1[$ccode][$i-1];
|
||||
$n=1;
|
||||
}
|
||||
} else {
|
||||
if($n==1) {
|
||||
$x1 = $i;
|
||||
$y1 = $val1[$ccode][$i];
|
||||
echo "{
|
||||
type: 'line', x0: $x0, x1: $x1,
|
||||
y0:$y0, y1:$y1,
|
||||
line: { color: 'rgb( 0, 0, 0)', dash:'dot' }
|
||||
},";
|
||||
$n=0;
|
||||
}
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
echo "]
|
||||
};
|
||||
";
|
||||
|
||||
echo "
|
||||
var txt_$ccode = {
|
||||
x: [ 33, 33, 33, 33, 33, 33, 33],
|
||||
y: [ $p3sd, $p2sd, $p1sd, $mean[$ccode], $m1sd, $m2sd, $m3sd],
|
||||
text: [ '+3SD', '+2SD', '+1SD', 'mean', '-1SD', '-2SD', '-3SD' ],
|
||||
mode: 'text'
|
||||
}
|
||||
";
|
||||
if(isset($mulx[$ccode])) {
|
||||
echo "
|
||||
var data_$ccode = [val_$ccode, txt_$ccode, mul_$ccode];
|
||||
";
|
||||
}else {
|
||||
echo "
|
||||
var data_$ccode = [val_$ccode, txt_$ccode];
|
||||
";
|
||||
}
|
||||
|
||||
|
||||
//end of layout
|
||||
echo "
|
||||
Plotly.newPlot('graph_$ccode', data_$ccode, layout_$ccode);";
|
||||
}
|
||||
?>
|
||||
</script>
|
||||
@ -1,74 +0,0 @@
|
||||
<?php
|
||||
function getData($control, $dates, $testid, $lastday) {
|
||||
require('../config.php');
|
||||
$cont = explode("|",$control);
|
||||
$control = $cont[0];
|
||||
$lot = $cont[1];
|
||||
$sql = "select name, ct.mean, ct.sd from DICT_CONTROL dc left join CONTROL_TEST ct on dc.id=ct.controlid where dc.id='$control' and ct.testid='$testid'";
|
||||
$stmt = sqlsrv_query( $conn1, $sql );
|
||||
if( $stmt == false) { die( print_r( sqlsrv_errors(), true) ); }
|
||||
$row = sqlsrv_fetch_array( $stmt, SQLSRV_FETCH_NUMERIC );
|
||||
$data['name'] = $row[0];
|
||||
$data['mean'] = $row[1];
|
||||
$data['sd'] = $row[2];
|
||||
$sql = "select dr.resdate, dr.resvalue, dr.rescomment from DAILY_RESULT dr
|
||||
left join CONTROL_TEST ct on ct.testid=dr.testid and ct.controlid=dr.controlid
|
||||
where dr.testid='$testid' and dr.controlid='$control' and convert(varchar(7), dr.resdate, 126)='$dates'
|
||||
order by resdate asc";
|
||||
//echo "$sql";
|
||||
//echo "$testid - $control <br/>";
|
||||
$data['control'] = $control;
|
||||
$data['lot'] = $lot;
|
||||
$stmt = sqlsrv_query( $conn1, $sql );
|
||||
if( $stmt == false) { die( print_r( sqlsrv_errors(), true) ); }
|
||||
while ( $row = sqlsrv_fetch_array( $stmt, SQLSRV_FETCH_NUMERIC ) ) {
|
||||
$day = date_format($row[0],"j");
|
||||
$data['result'] [$day] = $row[1];
|
||||
if(is_numeric($row[1])) {
|
||||
$data['resultx'] [$day] = ( $row[1] - $data['mean'] ) / $data['sd'];
|
||||
} else { $data['resultx'] [$day] = 0; }
|
||||
}
|
||||
|
||||
// mean and sd
|
||||
$data['+2s'] = $data['mean'] + (2*$data['sd']);
|
||||
$data['-2s'] = $data['mean'] - (2*$data['sd']);
|
||||
$data['cv'] = number_format($data['sd'] / $data['mean'] * 100,3);
|
||||
|
||||
// sample mean and sd
|
||||
$num_of_elements = count($data['result']);
|
||||
$variance = 0.0;
|
||||
$data['means'] = array_sum($data['result'])/$num_of_elements;
|
||||
foreach($data['result'] as $i) {
|
||||
if(is_numeric($i)) { $variance += pow(($i - $data['mean']), 2); }
|
||||
}
|
||||
$data['sds'] = (float)sqrt($variance/$num_of_elements);
|
||||
|
||||
$data['means'] = number_format($data['means'],3);
|
||||
$data['sds'] = number_format($data['sds'],3);
|
||||
|
||||
if($data['means'] != 0) {
|
||||
$data['cvs'] = number_format($data['sds'] / $data['means'] * 100,3);
|
||||
}else { $data['cvs'] = 0; }
|
||||
|
||||
$data['bias'] = abs($data['mean']- $data['means']);
|
||||
$data['bias'] = number_format($data['bias'] / $data['mean'] * 100,3);
|
||||
|
||||
$data['te'] = $data['bias'] + ( 2 * $data['cvs'] );
|
||||
|
||||
ksort($data['result']); ksort($data['resultx']);
|
||||
return $data;
|
||||
}
|
||||
|
||||
$control1 = $_POST['control1'];
|
||||
if(isset($_POST['control2'])) { $control2 = $_POST['control2']; }
|
||||
else { $control2 = 0; }
|
||||
if(isset($_POST['control3'])) { $control3 = $_POST['control3']; }
|
||||
else { $control3 = 0; }
|
||||
$dates = $_POST['dates'];
|
||||
$lastday = date("t", strtotime($dates));
|
||||
$testid = $_POST['test'];
|
||||
|
||||
if( $control3 != 0) { require("report_3c.php"); }
|
||||
else if( $control2 != 0) { require("report_2c.php"); }
|
||||
else { require("report_1c.php"); }
|
||||
|
||||
@ -1,145 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<?php
|
||||
require("../config.php");
|
||||
$dates = $_POST['dates'];
|
||||
$lastday = date("t", strtotime($dates));
|
||||
$testid = $_POST['test'];
|
||||
$sql = "select cva, ba, tea, name, method, unit from DICT_TEST where id='$testid'";
|
||||
$stmt = sqlsrv_query( $conn1, $sql );
|
||||
if( $stmt == false) { die( print_r( sqlsrv_errors(), true) ); }
|
||||
$row = sqlsrv_fetch_array( $stmt, SQLSRV_FETCH_NUMERIC );
|
||||
$cva = $row[0];
|
||||
$ba = $row[1];
|
||||
$tea = $row[2];
|
||||
$testname = $row[3];
|
||||
$method = $row[4];
|
||||
$unit = $row[5];
|
||||
$data = getData($control1, $dates, $testid, $lastday);
|
||||
$length = count($data['result']);
|
||||
?>
|
||||
<head>
|
||||
<meta http-equiv='Content-Type' content='text/html; charset=utf-8' />
|
||||
<link rel='stylesheet' href='../assets/normalize.min.css' />
|
||||
<link rel='stylesheet' href='../assets/style_report.css' />
|
||||
<script src="../assets/Chart.min.js"></script>
|
||||
<style>
|
||||
#title { text-align:center; }
|
||||
#title, #info, #result, #footer, #resultdata { margin-bottom:0.5cm; }
|
||||
#footer {width : 100%;}
|
||||
</style>
|
||||
</head>
|
||||
<body style='-webkit-print-color-adjust: exact;'>
|
||||
<div id='page'>
|
||||
<div id='title'>
|
||||
<h3><b>QC Internal</b></h3>
|
||||
<h3>Kimia Klinik</h3>
|
||||
<h5>TRISENSA DIAGNOSTIC CENTRE</h5>
|
||||
</div>
|
||||
|
||||
<div id='info'>
|
||||
<table>
|
||||
<tr>
|
||||
<th>INSTITUTION</th> <td>Laboratorium Gleneagles</td>
|
||||
<th>Instrument</th> <td colspan='3'>TMS 50i</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>TEST NAME</th> <td><?=$testname;?></td>
|
||||
<th>Control Name</th> <td colspan='3'><?=$data['name'];?> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>REAGENT</th> <td> </td>
|
||||
<th>Lot No.</th> <td colspan='3'><?=$data['lot'];?> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>METHOD</th> <td><?=$method;?></td>
|
||||
<th>VALUES</th> <td>-2S</td> <td>Target</td> <td>+2S</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>UNIT</th> <td><?=$unit;?></td>
|
||||
<td></td> <td style='text-align:center;'><?=$data['-2s'];?></td> <td style='text-align:center;'><?=$data['mean'];?></td> <td style='text-align:center;'><?=$data['+2s'];?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>PERIODE</th> <td colspan='5'><?=$dates;?></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div id='resultdata'>
|
||||
<table>
|
||||
<tr>
|
||||
<th>Tanggal</th> <th>Hasil</th>
|
||||
</tr>
|
||||
<?php
|
||||
$i = 1;
|
||||
foreach($data['result'] as $day => $res) {
|
||||
if( is_numeric($res) ) { $res = number_format($res,3); }
|
||||
echo "<tr> <td style='text-align:center;'>$day</td> <td>$res</td> </tr>";
|
||||
}
|
||||
?>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div id='resultimg'>
|
||||
<canvas id="myChart"></canvas>
|
||||
</div>
|
||||
|
||||
<div id='footer'>
|
||||
<table>
|
||||
<tr> <th colspan='4'>QC PERFORMANCE</th> </tr>
|
||||
<tr>
|
||||
<td>MEAN</td> <td><?=$data['means'];?></td>
|
||||
<td>SD</td> <td><?=$data['sds'];?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>CV %</td> <td><?=$data['cv'];?></td>
|
||||
<td>CV <sub>A</sub></td> <td><?=$cva;?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>BIAS %</td> <td><?=$data['bias'];?></td>
|
||||
<td>B<sub>A</sub> %</td> <td><?=$ba;?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>TE %</td> <td><?=$data['te'];?></td>
|
||||
<td>TE<sub>A</sub></td> <td><?=$tea;?></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
<script>
|
||||
const ctx = document.getElementById('myChart');
|
||||
ctx.height = 700;
|
||||
const labels = [ <?php for ($i=1; $i<=$length; $i ++) { echo "$i,"; } ?> ];
|
||||
const data = {
|
||||
labels: labels,
|
||||
datasets: [{
|
||||
axis: 'y',
|
||||
label: 'Hasil QC',
|
||||
data: [
|
||||
<?php
|
||||
foreach($data['resultx'] as $res) {
|
||||
if($res != null) { $res = number_format($res,3); }
|
||||
echo "$res, ";
|
||||
}
|
||||
?>
|
||||
],
|
||||
fill: false,
|
||||
backgroundColor: 'rgba(255, 99, 132, 0.2)',
|
||||
borderColor: 'rgb(255, 99, 132)',
|
||||
borderWidth: 1
|
||||
}]
|
||||
};
|
||||
const config = {
|
||||
type: 'line',
|
||||
data: data,
|
||||
options: {
|
||||
indexAxis: 'y',
|
||||
scales: {
|
||||
xAxis : { min:-4, max:4 }
|
||||
},
|
||||
},
|
||||
};
|
||||
const myChart = new Chart(ctx, config);
|
||||
</script>
|
||||
</html>
|
||||
@ -1,190 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<?php
|
||||
require("../config.php");
|
||||
$dates = $_POST['dates'];
|
||||
$lastday = date("t", strtotime($dates));
|
||||
$testid = $_POST['test'];
|
||||
$sql = "select cva, ba, tea, name, method, unit from DICT_TEST where id='$testid'";
|
||||
$stmt = sqlsrv_query( $conn1, $sql );
|
||||
if( $stmt == false) { die( print_r( sqlsrv_errors(), true) ); }
|
||||
$row = sqlsrv_fetch_array( $stmt, SQLSRV_FETCH_NUMERIC );
|
||||
$cva = $row[0];
|
||||
$ba = $row[1];
|
||||
$tea = $row[2];
|
||||
$testname = $row[3];
|
||||
$method = $row[4];
|
||||
$unit = $row[5];
|
||||
## Control 1
|
||||
$data1 = getData($control1, $dates, $testid, $lastday);
|
||||
$data2 = getData($control2, $dates, $testid, $lastday);
|
||||
$length = count($data1['result']);
|
||||
$length_2 = count($data2['result']);
|
||||
if($length_2 > $length) { $length = $length_2; }
|
||||
// repair jumping control
|
||||
$key1 = array_keys($data1['resultx']);
|
||||
$key2 = array_keys($data2['resultx']);
|
||||
$keys = array_merge($key1,$key2);
|
||||
$keys = array_unique($keys);
|
||||
asort($keys);
|
||||
/*
|
||||
echo "<pre>";
|
||||
print_r($data1['resultx']);
|
||||
print_r($data2['resultx']);
|
||||
print_r($keys);
|
||||
echo "</pre>";
|
||||
*/
|
||||
?>
|
||||
<head>
|
||||
<meta http-equiv='Content-Type' content='text/html; charset=utf-8' />
|
||||
<link rel='stylesheet' href='../assets/normalize.min.css' />
|
||||
<link rel='stylesheet' href='../assets/style_report.css' />
|
||||
<script src="../assets/Chart.min.js"></script>
|
||||
<style>
|
||||
#title { text-align:center; }
|
||||
#title, #info, #result, #footer, #resultdata { margin-bottom:0.5cm; }
|
||||
#footer {width : 100%;}
|
||||
</style>
|
||||
</head>
|
||||
<body style='-webkit-print-color-adjust: exact;'>
|
||||
<div id='page'>
|
||||
<div id='title'>
|
||||
<h3><b>QC Internal</b></h3>
|
||||
<h3>Kimia Klinik</h3>
|
||||
<h5>TRISENSA DIAGNOSTIC CENTRE</h5>
|
||||
</div>
|
||||
|
||||
<div id='info'>
|
||||
<table>
|
||||
<tr>
|
||||
<th>INSTITUTION</th> <td>Laboratorium Gleneagles</td>
|
||||
<th>Instrument</th> <td colspan='3'>TMS 50i</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>TEST NAME</th> <td><?=$testname;?></td>
|
||||
<th>Control</th> <td colspan='3'>C 1 :<?=$data1['name'];?> / C 2 : <?=$data2['name'];?> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>REAGENT</th> <td> </td>
|
||||
<th>Lot No.</th> <td colspan='3'>Lot 1 : <?=$data1['lot'];?> / Lot 2 : <?=$data2['lot'];?> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>METHOD</th> <td><?=$method;?></td>
|
||||
<th>VALUES</th> <td>-2S</td> <td>TARGET</td> <td>+2S</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>UNIT</th> <td><?=$unit;?></td>
|
||||
<th>VALUES</th>
|
||||
<td style='text-align:center;'><?=$data1['-2s'];?></td> <td style='text-align:center;'><?=$data1['mean'];?></td> <td style='text-align:center;'><?=$data1['+2s'];?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td> <td></td>
|
||||
<th></th>
|
||||
<td style='text-align:center;'><?=$data2['-2s'];?></td> <td style='text-align:center;'><?=$data2['mean'];?></td> <td style='text-align:center;'><?=$data2['+2s'];?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>PERIODE</th> <td colspan='5'><?=$dates;?></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div id='resultdata'>
|
||||
<table>
|
||||
<tr>
|
||||
<th>Tanggal</th> <th>Hasil 1</th> <th>Hasil 2</th>
|
||||
</tr>
|
||||
<?php
|
||||
for($i = 1 ; $i<=$lastday; $i++) {
|
||||
$res1 = '';
|
||||
$res2 = '';
|
||||
if( isset($data1['result'][$i]) ) {
|
||||
if( is_numeric($data1['result'][$i]) ) { $res1 = number_format($data1['result'][$i],3); }
|
||||
}
|
||||
if( isset($data2['result'][$i]) ) {
|
||||
if( is_numeric($data2['result'][$i]) ) { $res2 = number_format($data2['result'][$i],3); }
|
||||
}
|
||||
if( $res1 != '' || $res2 !='' ) { echo "<tr> <td style='text-align:center'>$i</td> <td>$res1</td> <td>$res2</td> </tr>"; }
|
||||
}
|
||||
?>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div id='resultimg'>
|
||||
<canvas id="myChart"></canvas>
|
||||
</div>
|
||||
|
||||
<div id='footer'>
|
||||
<table>
|
||||
<tr> <th colspan='4'>QC 1 PERFORMANCE</th> <th colspan='4'>QC 2 PERFORMANCE</th> </tr>
|
||||
<tr>
|
||||
<td>MEAN</td> <td><?=$data1['means'];?></td> <td>SD</td> <td><?=$data1['sds'];?></td>
|
||||
<td>MEAN</td> <td><?=$data2['means'];?></td> <td>SD</td> <td><?=$data2['sds'];?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>CV %</td> <td><?=$data1['cv'];?></td> <td>CV <sub>A</sub></td> <td><?=$cva;?></td>
|
||||
<td>CV %</td> <td><?=$data2['cv'];?></td> <td>CV <sub>A</sub></td> <td><?=$cva;?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>BIAS %</td> <td><?=$data1['bias'];?></td> <td>B<sub>A</sub> %</td> <td><?=$ba;?></td>
|
||||
<td>BIAS %</td> <td><?=$data2['bias'];?></td> <td>B<sub>A</sub> %</td> <td><?=$ba;?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>TE %</td> <td><?=$data1['te'];?></td> <td>TE<sub>A</sub></td> <td><?=$tea;?></td>
|
||||
<td>TE %</td> <td><?=$data2['te'];?></td> <td>TE<sub>A</sub></td> <td><?=$tea;?></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
<script>
|
||||
const ctx = document.getElementById('myChart');
|
||||
ctx.height = 700;
|
||||
const labels = [ <?php for ($i=1; $i<=$length; $i ++) { echo "$i,"; } ?> ];
|
||||
const data = {
|
||||
labels: labels,
|
||||
datasets: [{
|
||||
axis: 'y', label: 'QC1', fill: false, backgroundColor: 'rgba(0, 0, 255, 0.5)', borderColor: 'rgb(0, 0, 255)', borderWidth: 1,
|
||||
data: [
|
||||
<?php
|
||||
$res1 = '';
|
||||
//foreach($data1['resultx'] as $res) {
|
||||
foreach($keys as $key) {
|
||||
if(isset($data1['resultx'][$key])) {
|
||||
$res = $data1['resultx'][$key];
|
||||
$res1 .= number_format($res,3).',';
|
||||
} else { $res1 .= 'null,'; }
|
||||
}
|
||||
$res1 = rtrim($res1,',');
|
||||
echo "$res1";
|
||||
?>
|
||||
]}, {
|
||||
axis: 'y', label: 'QC2', fill: false, backgroundColor: 'rgba(0, 0, 0, 0.5)', borderColor: 'rgb(0, 0, 0)', borderWidth: 1,
|
||||
data: [
|
||||
<?php
|
||||
$res1 = '';
|
||||
//foreach($data2['resultx'] as $res) {
|
||||
foreach($keys as $key) {
|
||||
if(isset($data2['resultx'][$key])) {
|
||||
$res = $data2['resultx'][$key];
|
||||
$res1 .= number_format($res,3).',';
|
||||
} else { $res1 .= 'null,'; }
|
||||
}
|
||||
$res1 = rtrim($res1,',');
|
||||
echo "$res1";
|
||||
?>
|
||||
]}
|
||||
]
|
||||
};
|
||||
const config = {
|
||||
type: 'line',
|
||||
data: data,
|
||||
options: {
|
||||
indexAxis: 'y',
|
||||
scales: {
|
||||
xAxis : { min:-4, max:4 }
|
||||
},
|
||||
},
|
||||
};
|
||||
const myChart = new Chart(ctx, config);
|
||||
</script>
|
||||
</html>
|
||||
@ -1,204 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<?php
|
||||
require("../config.php");
|
||||
$dates = $_POST['dates'];
|
||||
$lastday = date("t", strtotime($dates));
|
||||
$testid = $_POST['test'];
|
||||
$sql = "select cva, ba, tea, name, method, unit from DICT_TEST where id='$testid'";
|
||||
$stmt = sqlsrv_query( $conn1, $sql );
|
||||
if( $stmt == false) { die( print_r( sqlsrv_errors(), true) ); }
|
||||
$row = sqlsrv_fetch_array( $stmt, SQLSRV_FETCH_NUMERIC );
|
||||
$cva = $row[0];
|
||||
$ba = $row[1];
|
||||
$tea = $row[2];
|
||||
$testname = $row[3];
|
||||
$method = $row[4];
|
||||
$unit = $row[5];
|
||||
## Control 1
|
||||
$data1 = getData($control1, $dates, $testid, $lastday);
|
||||
$data2 = getData($control2, $dates, $testid, $lastday);
|
||||
$data3 = getData($control3, $dates, $testid, $lastday);
|
||||
$length = count($data1['result']);
|
||||
$length_2 = count($data2['result']);
|
||||
$length_3 = count($data3['result']);
|
||||
if($length_2 > $length) { $length = $length_2; }
|
||||
if($length_3 > $length) { $length = $length_3; }
|
||||
// repair jumping control
|
||||
$key1 = array_keys($data1['resultx']);
|
||||
$key2 = array_keys($data2['resultx']);
|
||||
$key3 = array_keys($data3['resultx']);
|
||||
$keys = array_merge($key1,$key2,$key3);
|
||||
$keys = array_unique($keys);
|
||||
asort($keys);
|
||||
/*
|
||||
echo "<pre>";
|
||||
print_r($data1['resultx']);
|
||||
print_r($data2['resultx']);
|
||||
print_r($keys);
|
||||
echo "</pre>";
|
||||
*/
|
||||
?>
|
||||
<head>
|
||||
<meta http-equiv='Content-Type' content='text/html; charset=utf-8' />
|
||||
<link rel='stylesheet' href='../assets/normalize.min.css' />
|
||||
<link rel='stylesheet' href='../assets/style_report.css' />
|
||||
<script src="../assets/Chart.min.js"></script>
|
||||
<style>
|
||||
#title { text-align:center; }
|
||||
#title, #info, #result, #footer, #resultdata { margin-bottom:0.5cm; }
|
||||
#footer {width : 100%;}
|
||||
</style>
|
||||
</head>
|
||||
<body style='-webkit-print-color-adjust: exact;'>
|
||||
<div id='page'>
|
||||
<div id='title'>
|
||||
<h3><b>QC Internal</b></h3>
|
||||
<h3>Kimia Klinik</h3>
|
||||
<h5>TRISENSA DIAGNOSTIC CENTRE</h5>
|
||||
</div>
|
||||
|
||||
<div id='info'>
|
||||
<table>
|
||||
<tr>
|
||||
<th>INSTITUTION</th> <td>Laboratorium Gleneagles</td>
|
||||
<th>Instrument</th> <td colspan='3'>TMS 50i</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>TEST NAME</th> <td><?=$testname;?></td>
|
||||
<th>Control</th> <td colspan='3'>C 1 :<?=$data1['name'];?> / C 2 : <?=$data2['name'];?> / C 3 : <?=$data3['name'];?> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>REAGENT</th> <td> </td>
|
||||
<th>Lot No.</th> <td colspan='3'>Lot 1 : <?=$data1['lot'];?> / Lot 2 : <?=$data2['lot'];?> / Lot 3 : <?=$data3['lot'];?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>METHOD</th> <td><?=$method;?></td>
|
||||
<th>VALUES</th> <td>-2S</td> <td>TARGET</td> <td>+2S</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>UNIT</th> <td><?=$unit;?></td>
|
||||
<th>VALUES</th>
|
||||
<td style='text-align:center;'><?=$data1['-2s'];?></td> <td style='text-align:center;'><?=$data1['mean'];?></td> <td style='text-align:center;'><?=$data1['+2s'];?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td> <td></td>
|
||||
<th></th>
|
||||
<td style='text-align:center;'><?=$data2['-2s'];?></td> <td style='text-align:center;'><?=$data2['mean'];?></td> <td style='text-align:center;'><?=$data2['+2s'];?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td> <td></td>
|
||||
<th></th>
|
||||
<td style='text-align:center;'><?=$data3['-2s'];?></td> <td style='text-align:center;'><?=$data3['mean'];?></td> <td style='text-align:center;'><?=$data3['+2s'];?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>PERIODE</th> <td colspan='5'><?=$dates;?></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div id='resultdata'>
|
||||
<table>
|
||||
<tr>
|
||||
<th>Tanggal</th> <th>Hasil 1</th> <th>Hasil 2</th> <th>Hasil 3</th>
|
||||
</tr>
|
||||
<?php
|
||||
for($i = 1 ; $i<=$lastday; $i++) {
|
||||
if( isset($data1['result'][$i]) ) {
|
||||
if( is_numeric($data1['result'][$i]) ) { $res1 = number_format($data1['result'][$i],3); }
|
||||
} else { $res1 = ''; }
|
||||
if( isset($data2['result'][$i]) ) {
|
||||
if( is_numeric($data2['result'][$i]) ) { $res2 = number_format($data2['result'][$i],3); }
|
||||
} else { $res2 = ''; }
|
||||
if( isset($data3['result'][$i]) ) {
|
||||
if( is_numeric($data3['result'][$i]) ) { $res3 = number_format($data3['result'][$i],3); }
|
||||
} else { $res3 = ''; }
|
||||
if( $res1 != '' || $res2 !='' || $res3!='' ) { echo "<tr> <td style='text-align:center'>$i</td> <td>$res1</td> <td>$res2</td> <td>$res3</td> </tr>"; }
|
||||
}
|
||||
?>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div id='resultimg'>
|
||||
<canvas id="myChart"></canvas>
|
||||
</div>
|
||||
|
||||
<div id='footer'>
|
||||
<table>
|
||||
<tr> <th colspan='4'>QC 1 PERFORMANCE</th> <th colspan='4'>QC 2 PERFORMANCE</th> </tr>
|
||||
<tr>
|
||||
<td>MEAN</td> <td><?=$data1['means'];?></td> <td>SD</td> <td><?=$data1['sds'];?></td>
|
||||
<td>MEAN</td> <td><?=$data2['means'];?></td> <td>SD</td> <td><?=$data2['sds'];?></td>
|
||||
<td>MEAN</td> <td><?=$data3['means'];?></td> <td>SD</td> <td><?=$data3['sds'];?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>CV %</td> <td><?=$data1['cv'];?></td> <td>CV <sub>A</sub></td> <td><?=$cva;?></td>
|
||||
<td>CV %</td> <td><?=$data2['cv'];?></td> <td>CV <sub>A</sub></td> <td><?=$cva;?></td>
|
||||
<td>CV %</td> <td><?=$data3['cv'];?></td> <td>CV <sub>A</sub></td> <td><?=$cva;?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>BIAS %</td> <td><?=$data1['bias'];?></td> <td>B<sub>A</sub> %</td> <td><?=$ba;?></td>
|
||||
<td>BIAS %</td> <td><?=$data2['bias'];?></td> <td>B<sub>A</sub> %</td> <td><?=$ba;?></td>
|
||||
<td>BIAS %</td> <td><?=$data3['bias'];?></td> <td>B<sub>A</sub> %</td> <td><?=$ba;?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>TE %</td> <td><?=$data1['te'];?></td> <td>TE<sub>A</sub></td> <td><?=$tea;?></td>
|
||||
<td>TE %</td> <td><?=$data2['te'];?></td> <td>TE<sub>A</sub></td> <td><?=$tea;?></td>
|
||||
<td>TE %</td> <td><?=$data3['te'];?></td> <td>TE<sub>A</sub></td> <td><?=$tea;?></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
<script>
|
||||
const ctx = document.getElementById('myChart');
|
||||
ctx.height = 700;
|
||||
const labels = [ <?php for ($i=1; $i<=$length; $i ++) { echo "$i,"; } ?> ];
|
||||
const data = {
|
||||
labels: labels,
|
||||
datasets: [{
|
||||
axis: 'y', label: 'QC1', fill: false, backgroundColor: 'rgba(0, 0, 255, 0.5)', borderColor: 'rgb(0, 0, 255)', borderWidth: 1,
|
||||
data: [
|
||||
<?php
|
||||
$res1 = '';
|
||||
//foreach($data1['resultx'] as $res) {
|
||||
foreach($keys as $key) {
|
||||
if(isset($data1['resultx'][$key])) {
|
||||
$res = $data1['resultx'][$key];
|
||||
$res1 .= number_format($res,3).',';
|
||||
} else { $res1 .= 'null,'; }
|
||||
}
|
||||
$res1 = rtrim($res1,',');
|
||||
echo "$res1";
|
||||
?>
|
||||
]}, {
|
||||
axis: 'y', label: 'QC2', fill: false, backgroundColor: 'rgba(0, 0, 0, 0.5)', borderColor: 'rgb(0, 0, 0)', borderWidth: 1,
|
||||
data: [
|
||||
<?php
|
||||
$res1 = '';
|
||||
//foreach($data2['resultx'] as $res) {
|
||||
foreach($keys as $key) {
|
||||
if(isset($data2['resultx'][$key])) {
|
||||
$res = $data2['resultx'][$key];
|
||||
$res1 .= number_format($res,3).',';
|
||||
} else { $res1 .= 'null,'; }
|
||||
}
|
||||
$res1 = rtrim($res1,',');
|
||||
echo "$res1";
|
||||
?>
|
||||
]}
|
||||
]
|
||||
};
|
||||
const config = {
|
||||
type: 'line',
|
||||
data: data,
|
||||
options: {
|
||||
indexAxis: 'y',
|
||||
scales: {
|
||||
xAxis : { min:-4, max:4 }
|
||||
},
|
||||
},
|
||||
};
|
||||
const myChart = new Chart(ctx, config);
|
||||
</script>
|
||||
</html>
|
||||
@ -1,32 +0,0 @@
|
||||
<?php
|
||||
if(!isset($_POST['submit'])) {
|
||||
?>
|
||||
<form method='POST'>
|
||||
Test Name<br/>
|
||||
<input type='text' name='testname' /><br/>
|
||||
Unit<br/>
|
||||
<input type='text' name='unit' /><br/>
|
||||
Method<br/>
|
||||
<input type='text' name='method' /><br/>
|
||||
CVA<br/>
|
||||
<input type='text' name='cva' /><br/>
|
||||
BA<br/>
|
||||
<input type='text' name='ba' /><br/>
|
||||
TEA<br/>
|
||||
<input type='text' name='tea' /><br/>
|
||||
<input type='submit' name='submit' value='add' />
|
||||
</form>
|
||||
<?php
|
||||
} else {
|
||||
$testname=stripslashes($_POST['testname']);
|
||||
$method = $_POST['method'];
|
||||
$unit = $_POST['unit'];
|
||||
$cva = $_POST['cva'];
|
||||
$ba = $_POST['ba'];
|
||||
$tea = $_POST['tea'];
|
||||
$sql="INSERT INTO DICT_TEST(name, method, unit, cva, ba, tea) values ('$testname', '$method', '$unit', '$cva', '$ba', '$tea')";
|
||||
$stmt = sqlsrv_query( $conn1, $sql );
|
||||
if( $stmt == false) { die( print_r( sqlsrv_errors(), true) ); }
|
||||
echo "<meta http-equiv='refresh' content='0;url=?p=dict' />";
|
||||
}
|
||||
?>
|
||||
@ -1,7 +0,0 @@
|
||||
<?php
|
||||
$tid = $_GET['tid'];
|
||||
$sql="DELETE DICT_TEST WHERE id='$tid'";
|
||||
$stmt = sqlsrv_query( $conn1, $sql );
|
||||
if( $stmt == false) { die( print_r( sqlsrv_errors(), true) ); }
|
||||
echo "<meta http-equiv='refresh' content='0;url=?p=dict' />";
|
||||
?>
|
||||
@ -1,72 +0,0 @@
|
||||
<?php
|
||||
if(!isset($_POST['submit'])) {
|
||||
$tid = $_GET['tid'];
|
||||
$tname = '';
|
||||
$cva = '';
|
||||
$ba = '';
|
||||
$tea = '';
|
||||
$unit = '';
|
||||
$method = '';
|
||||
$deptid = '';
|
||||
if($tid != 0) {
|
||||
$sql = "select name, cva, ba, tea, unit, method, deptid from DICT_TEST where id='$tid'";
|
||||
$stmt = sqlsrv_query( $conn1, $sql );
|
||||
if( $stmt == false) { die( print_r( sqlsrv_errors(), true) ); }
|
||||
$row = sqlsrv_fetch_array( $stmt, SQLSRV_FETCH_NUMERIC);
|
||||
$tname = $row[0];
|
||||
$cva = $row[1];
|
||||
$ba = $row[2];
|
||||
$tea = $row[3];
|
||||
$unit = $row[4];
|
||||
$method = $row[5];
|
||||
$deptid = $row[6];
|
||||
}
|
||||
$sql = "select id, name from DICT_DEPT";
|
||||
$stmt = sqlsrv_query( $conn1, $sql );
|
||||
while($row=sqlsrv_fetch_array( $stmt, SQLSRV_FETCH_NUMERIC)) {
|
||||
$depts[$row[0]] = $row[1];
|
||||
}
|
||||
?>
|
||||
<form method='POST'>
|
||||
Dept.<br/>
|
||||
<select name='deptid'>
|
||||
<option value=''></option>
|
||||
<?php
|
||||
foreach($depts as $qdeptid => $qdeptname) {
|
||||
echo "<option value='$qdeptid'>$qdeptname</option>";
|
||||
}
|
||||
?>
|
||||
</select>
|
||||
<br/>
|
||||
Name<br/>
|
||||
<input type='text' name='tname' value='<?php echo $tname;?>' /><br/>
|
||||
Unit<br/>
|
||||
<input type='text' name='unit' value='<?php echo $unit;?>' /><br/>
|
||||
Method<br/>
|
||||
<input type='text' name='method' value='<?php echo $method;?>' /><br/>
|
||||
CVA<br/>
|
||||
<input type='text' name='cva' value='<?php echo $cva;?>' /><br/>
|
||||
BA<br/>
|
||||
<input type='text' name='ba' value='<?php echo $ba;?>' /><br/>
|
||||
TEA<br/>
|
||||
<input type='text' name='tea' value='<?php echo $tea;?>' /><br/>
|
||||
<input type='hidden' name='tid' value='<?php echo $tid;?>' /><br/>
|
||||
<input type='submit' name='submit' value='update' />
|
||||
</form>
|
||||
<?php
|
||||
} else {
|
||||
$tid=$_POST['tid'];
|
||||
$tname=stripslashes($_POST['tname']);
|
||||
$deptid = $_POST['deptid'];
|
||||
$method = $_POST['method'];
|
||||
$unit = $_POST['unit'];
|
||||
$cva = $_POST['cva'];
|
||||
$ba = $_POST['ba'];
|
||||
$tea = $_POST['tea'];
|
||||
if($tid != 0) { $sql="UPDATE DICT_TEST SET name='$tname', cva='$cva', ba='$ba', tea='$tea', method='$method', unit='$unit', deptid='$deptid' WHERE id='$tid'"; }
|
||||
else { $sql="INSERT INTO DICT_TEST(name, method, unit, cva, ba, tea, deptid) values ('$testname', '$method', '$unit', '$cva', '$ba', '$tea', '$deptid')"; }
|
||||
$stmt=sqlsrv_query( $conn1, $sql );
|
||||
if($stmt==false) { die( print_r( sqlsrv_errors(), true) ); }
|
||||
echo "<meta http-equiv='refresh' content='0;url=?p=test' />";
|
||||
}
|
||||
?>
|
||||
@ -1,28 +0,0 @@
|
||||
<h2>Test</h2>
|
||||
<a href='?p=test&d=edit&tid=0'>New Test</a> <br/>
|
||||
<table border='1'>
|
||||
<tr> <th>ID</th> <th>Dept.</th> <th>Name</th> <th>Method</th> <th>Unit</th> <th>BA</th> <th>CVA</th> <th>TEA</th> </tr>
|
||||
<?php
|
||||
$sql = "select t.id, t.name,ba,cva,tea,method,unit, d.id, d.name from DICT_TEST t
|
||||
left join DICT_DEPT d on d.id=t.deptid";
|
||||
$stmt = sqlsrv_query( $conn1, $sql );
|
||||
if( $stmt == false) { die( print_r( sqlsrv_errors(), true) ); }
|
||||
$i=1;
|
||||
while( $row = sqlsrv_fetch_array( $stmt, SQLSRV_FETCH_NUMERIC) ) {
|
||||
$tid = $row[0];
|
||||
$tname = $row[1];
|
||||
$ba = $row[2];
|
||||
$cva = $row[3];
|
||||
$tea = $row[4];
|
||||
$method = $row[5];
|
||||
$unit = $row[6];
|
||||
$did = $row[7];
|
||||
$dname = $row[8];
|
||||
echo "<tr><td>$i</td> <td>$dname</td> <td>$tname</td> <td>$method</td> <td>$unit</td> <td>$ba</td> <td>$cva</td> <td>$tea</td>
|
||||
<td><a href='?p=test&d=edit&tid=$tid'>edit</a> -
|
||||
<a href='?p=test&d=del&tid=$tid'>del</a>
|
||||
</td></tr>";
|
||||
$i++;
|
||||
}
|
||||
?>
|
||||
</table>
|
||||
113
v1/inc/view.php
113
v1/inc/view.php
@ -1,113 +0,0 @@
|
||||
<?php
|
||||
include("config.php");
|
||||
$date = date("Y-m-d");
|
||||
?>
|
||||
<form method='POST' action='inc/report.php' target='_blank'>
|
||||
<table>
|
||||
<tr> <td>Date</td> <td>:</td> <td><input type='month' id='dates' name='dates' onInput='getTest(this.value);' /></td> </tr>
|
||||
<tr> <td>Test</td> <td>:</td> <td><select id='test' name='test' onchange='getControl(this.value)'><option> -- Select Test -- </option></select></td> </tr>
|
||||
<tr> <td>Control 1</td> <td>:</td> <td><select id='control1' name='control1' onchange='getControl2()'><option> -- Select Control -- </option></select></td> </tr>
|
||||
<tr> <td>Control 2</td> <td>:</td> <td><select id='control2' name='control2'><option> -- Select Control -- </option></select></td> </tr>
|
||||
<tr> <td><input type='submit' value='go'></td> </tr>
|
||||
</table>
|
||||
</form>
|
||||
<script src='assets/jquery.js'></script>
|
||||
<script type="text/javascript">
|
||||
function getTest(){
|
||||
// Empty the dropdown
|
||||
var testel = document.getElementById('test');
|
||||
var control1el = document.getElementById('control1');
|
||||
var control2el = document.getElementById('control2');
|
||||
|
||||
test.innerHTML = "";
|
||||
control1.innerHTML = "";
|
||||
control2.innerHTML = "";
|
||||
|
||||
var testopt = document.createElement('option');
|
||||
testopt.value = 0;
|
||||
testopt.innerHTML = '-- Select Test --';
|
||||
testel.appendChild(testopt);
|
||||
|
||||
var controlopt = document.createElement('option');
|
||||
controlopt.value = 0;
|
||||
controlopt.innerHTML = '-- Select Control --';
|
||||
control1el.appendChild(controlopt);
|
||||
var controlopt = document.createElement('option');
|
||||
controlopt.value = 0;
|
||||
controlopt.innerHTML = '-- Select Control --';
|
||||
control2el.appendChild(controlopt);
|
||||
|
||||
var dates = $("#dates").val();
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
contentType: "application/json; charset=utf-8",
|
||||
url: "inc/view_ajax.php",
|
||||
datatype : 'JSON',
|
||||
data: JSON.stringify( {request:'getTest', dates: dates} ),
|
||||
success: function(response){
|
||||
var result = JSON.parse(response);
|
||||
var len = result.length;
|
||||
|
||||
for(var i=0; i<len; i++){
|
||||
var id = result[i].id;
|
||||
var name = result[i].name;
|
||||
console.log(result[i]);
|
||||
// Add option to state dropdown
|
||||
var opt = document.createElement('option');
|
||||
opt.value = id;
|
||||
opt.innerHTML = name;
|
||||
testel.appendChild(opt);
|
||||
}
|
||||
},
|
||||
error:function(exception){alert('Exeption:'+exception);}
|
||||
});
|
||||
}
|
||||
|
||||
function getControl(){
|
||||
// Empty the dropdown
|
||||
var control1el = document.getElementById('control1');
|
||||
var control2el = document.getElementById('control2');
|
||||
control1el.innerHTML = "";
|
||||
control2el.innerHTML = "";
|
||||
|
||||
var controlopt = document.createElement('option');
|
||||
controlopt.value = 0;
|
||||
controlopt.innerHTML = '-- Select Control --';
|
||||
control1el.appendChild(controlopt);
|
||||
controlopt.value = 0;
|
||||
controlopt.innerHTML = '-- Select Control --';
|
||||
control2el.appendChild(controlopt);
|
||||
|
||||
// AJAX request
|
||||
var test = $("#test").val();
|
||||
var dates = $("#dates").val();
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
contentType: "application/json; charset=utf-8",
|
||||
url: "inc/view_ajax.php",
|
||||
datatype : 'JSON',
|
||||
data: JSON.stringify( {request:'getControl', test: test, dates: dates} ),
|
||||
success: function(response){
|
||||
var result = JSON.parse(response);
|
||||
var len = result.length;
|
||||
|
||||
for(var i=0; i<len; i++){
|
||||
var id = result[i].id;
|
||||
var name = result[i].name;
|
||||
console.log(result[i]);
|
||||
// Add option to state dropdown
|
||||
var opt = document.createElement('option');
|
||||
opt.value = id;
|
||||
opt.innerHTML = name;
|
||||
control1el.appendChild(opt);
|
||||
var opt = document.createElement('option');
|
||||
opt.value = id;
|
||||
opt.innerHTML = name;
|
||||
control2el.appendChild(opt);
|
||||
}
|
||||
|
||||
},
|
||||
error:function(exception){alert('Exeption:'+exception);}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
@ -1,55 +0,0 @@
|
||||
<?php
|
||||
include '../config.php';
|
||||
|
||||
// Read POST data
|
||||
$postData = json_decode(file_get_contents("php://input"));
|
||||
$request = "";
|
||||
if(isset($postData->request)){
|
||||
$request = $postData->request;
|
||||
}
|
||||
|
||||
// Get Test
|
||||
if($request == 'getTest'){
|
||||
$dates = 0;
|
||||
$result = array();$data = array();
|
||||
|
||||
if(isset($postData->dates)){
|
||||
$dates = $postData->dates;
|
||||
$sql = "select distinct testid, dt.name from DAILY_RESULT dr left join DICT_TEST dt on dt.id=dr.testid where convert(varchar(7), resdate, 126)='$dates'";
|
||||
$stmt = sqlsrv_query( $conn1, $sql );
|
||||
if( $stmt == false) { die( print_r( sqlsrv_errors(), true) ); }
|
||||
while ( $row = sqlsrv_fetch_array( $stmt, SQLSRV_FETCH_NUMERIC ) ) {
|
||||
$id = $row[0];
|
||||
$name = $row[1];
|
||||
$data[] = array( "id" => $id, "name" => $name );
|
||||
}
|
||||
}
|
||||
|
||||
echo json_encode($data);
|
||||
die;
|
||||
}
|
||||
|
||||
// Get control
|
||||
if($request == 'getControl'){
|
||||
$test = 0;
|
||||
$result = array();$data = array();
|
||||
|
||||
if(isset($postData->test)){
|
||||
$test = $postData->test;
|
||||
$dates = $postData->dates;
|
||||
|
||||
$sql = "select distinct dr.controlid, dc.name, dc.lot from DAILY_RESULT dr
|
||||
left join DICT_CONTROL dc on dc.id=dr.controlid
|
||||
where convert(varchar(7), dr.resdate, 126)='$dates' and dr.testid='$test'";
|
||||
$stmt = sqlsrv_query( $conn1, $sql );
|
||||
if( $stmt == false) { die( print_r( sqlsrv_errors(), true) ); }
|
||||
while ( $row = sqlsrv_fetch_array( $stmt, SQLSRV_FETCH_NUMERIC ) ) {
|
||||
$id = "$row[0]|$row[2]";
|
||||
$name = "$row[1] - $row[2]";
|
||||
$data[] = array( "id" => $id, "name" => $name );
|
||||
}
|
||||
}
|
||||
|
||||
echo json_encode($data);
|
||||
die;
|
||||
}
|
||||
57
v1/index.php
57
v1/index.php
@ -1,57 +0,0 @@
|
||||
<?php
|
||||
include("config.php");
|
||||
if(isset($_GET['p'])) {$part = $_GET['p'];}
|
||||
if(isset($_GET['d'])) {$d = $_GET['d'];}
|
||||
?>
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>QC APP</title>
|
||||
<link rel="stylesheet" href="assets/styles.css?v=<?php echo time(); ?>">
|
||||
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
|
||||
</head>
|
||||
<body>
|
||||
<div id="container">
|
||||
<div id="nav">
|
||||
<ul>
|
||||
<li><a href='index.php'>View</a></li>
|
||||
<li><a href='?p=entry'>Monthly Entry</a></li>
|
||||
<li><a href='?p=entry_daily'>Daily Entry</a></li>
|
||||
<li style="float:right"><a href='?p=test'>Dictionary Test</a></li>
|
||||
<li style="float:right"><a href='?p=control'>Dictionary Control</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div id="content">
|
||||
<br/>
|
||||
<?php
|
||||
if(isset($part)){
|
||||
if($part=="control") {
|
||||
if(isset($d)){
|
||||
if($d=="add") { include("inc/control_add.php"); }
|
||||
elseif($d=="lot_add") { include("inc/control_lotadd.php"); }
|
||||
elseif($d=="del") { include("inc/control_del.php"); }
|
||||
elseif($d=="edit") { include("inc/control_edit.php"); }
|
||||
} else { include("inc/control_index.php"); }
|
||||
} elseif($part=="ct") {
|
||||
if(isset($d)){
|
||||
if($d=="add") { include("inc/ct_add.php"); }
|
||||
elseif($d=="edit") { include("inc/ct_edit.php"); }
|
||||
elseif($d=="del") { include("inc/ct_del.php"); }
|
||||
} else { include("inc/ct_view.php"); }
|
||||
} elseif($part=="test") {
|
||||
if(isset($d)){
|
||||
if($d=="add") { include("inc/test_add.php"); }
|
||||
elseif($d=="edit") { include("inc/test_edit.php"); }
|
||||
elseif($d=="del") { include("inc/test_del.php"); }
|
||||
} else { include("inc/test_index.php"); }
|
||||
} elseif($part=="entry") {
|
||||
if(isset($_GET['cid'])) { include('inc/entry_1.php'); }
|
||||
else { include('inc/entry.php'); }
|
||||
} elseif($part=="entry_daily") { include('inc/entry_daily.php'); }
|
||||
elseif($part=="entry_monthly") { include('inc/entry_monthly.php'); }
|
||||
} else { include('inc/view.php'); }
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user