649 lines
16 KiB
Markdown
649 lines
16 KiB
Markdown
# DevQMS Developer Get Started Guide
|
|
|
|
## Table of Contents
|
|
1. [Project Overview](#project-overview)
|
|
2. [Architecture Overview](#architecture-overview)
|
|
3. [Core Components](#core-components)
|
|
4. [Module System](#module-system)
|
|
5. [DevExtreme Integration](#devextreme-integration)
|
|
6. [Admin-AJAX System](#admin-ajax-system)
|
|
7. [Save Trigger System](#save-trigger-system)
|
|
8. [Batch Excel Operations](#batch-excel-operations)
|
|
9. [Development Workflow](#development-workflow)
|
|
10. [Common Patterns](#common-patterns)
|
|
11. [Troubleshooting](#troubleshooting)
|
|
|
|
## Project Overview
|
|
|
|
DevQMS is a Quality Management System (QMS) built on Laravel framework with advanced features including:
|
|
|
|
- **Modular Architecture**: Each module (WeldLog, TestPackage, etc.) has its own Model, Controller, and View
|
|
- **DevExtreme Integration**: Advanced UI components for data grids, forms, and charts
|
|
- **Dynamic Form System**: Forms are generated dynamically based on database schema
|
|
- **Excel Import/Export**: Batch operations for data management
|
|
- **Role-based Access Control**: User permission system with different levels
|
|
- **Real-time Data Processing**: Save triggers for automatic data synchronization
|
|
|
|
## Architecture Overview
|
|
|
|
### Directory Structure
|
|
|
|
```
|
|
app/
|
|
├── Http/Controllers/
|
|
│ ├── AdminController.php # Main CRUD controller
|
|
│ ├── AdminAjaxController.php # AJAX request handler
|
|
│ └── SaveTrigger/ # Automatic data processing
|
|
├── DevExtreme/ # DevExtreme integration classes
|
|
├── Models/ # Eloquent models
|
|
└── Functions/ # Helper functions
|
|
|
|
resources/views/
|
|
├── admin/ # Admin panel views
|
|
│ └── type/ # Module views
|
|
├── admin-ajax/ # AJAX response views
|
|
├── components/ # Reusable components
|
|
│ ├── blocks/ # Module blocks
|
|
│ └── table/ # DataGrid components
|
|
└── guide/ # Documentation
|
|
|
|
routes/
|
|
└── web.php # Route definitions
|
|
```
|
|
|
|
### Core Technologies
|
|
|
|
- **Backend**: Laravel 8+ with PHP 8+
|
|
- **Frontend**: DevExtreme DataGrid, jQuery, Bootstrap
|
|
- **Database**: MySQL with InnoDB
|
|
- **File Storage**: Laravel Storage with local/cloud options
|
|
- **Excel Processing**: Maatwebsite Excel package
|
|
|
|
## Core Components
|
|
|
|
### 1. AdminController.php
|
|
|
|
The central controller handling all CRUD operations for modules. Key methods:
|
|
|
|
```php
|
|
// Read operations
|
|
public function tableToJson(Request $request, string $tableName)
|
|
public function getDetail(Request $request, string $tableName, string $columnName, string $value)
|
|
|
|
// Write operations
|
|
public function insertJson(Request $request, string $tableName)
|
|
public function saveJson(Request $request, string $tableName)
|
|
public function removeJson(Request $request, string $tableName)
|
|
|
|
// Excel operations
|
|
public function importExcel(Request $request, string $tableName)
|
|
public function exportExcel(Request $request, string $tableName, string $fileName)
|
|
```
|
|
|
|
**Important**: All modules use this centralized controller - no need to create individual controllers for basic CRUD operations.
|
|
|
|
### 2. AdminAjaxController.php
|
|
|
|
Handles AJAX requests through view-based routing:
|
|
|
|
```php
|
|
public function index(Request $request, string $var) {
|
|
$url = "admin-ajax.$var";
|
|
return view($url, array("request" => $request));
|
|
}
|
|
```
|
|
|
|
AJAX views are located in `resources/views/admin-ajax/` and follow the naming pattern `{action}.blade.php`.
|
|
|
|
### 3. DevExtreme Integration
|
|
|
|
#### DbSet.php
|
|
Custom query builder for DevExtreme DataGrid:
|
|
|
|
```php
|
|
$dbSet = new DbSet($mySQL, 'table_name');
|
|
$result = $dbSet->Select(['id', 'name'])
|
|
->Filter(['status' => 'active'])
|
|
->OrderBy('name')
|
|
->SkipTake(0, 10)
|
|
->AsArray();
|
|
```
|
|
|
|
#### Utils.php
|
|
Helper functions for data processing and SQL escaping.
|
|
|
|
## Module System
|
|
|
|
### Creating a New Module
|
|
|
|
1. **Create Model and Migration**:
|
|
```php
|
|
// app/Models/NewModule.php
|
|
class NewModule extends Model {
|
|
protected $table = 'new_modules';
|
|
protected $primaryKey = 'id';
|
|
public $timestamps = true;
|
|
}
|
|
```
|
|
|
|
2. **Create View Template**:
|
|
```php
|
|
// resources/views/admin/type/new-module.blade.php
|
|
<?php
|
|
use App\Models\NewModule;
|
|
|
|
$title = "New Module";
|
|
$tableName = "new_modules";
|
|
$listDatas = NewModule::orderBy("id","DESC")->paginate(setting('row_count'));
|
|
|
|
$blockGroup = [
|
|
'General Info' => [
|
|
'name',
|
|
'description',
|
|
],
|
|
'Details' => [
|
|
'status',
|
|
'created_at',
|
|
],
|
|
];
|
|
|
|
$relationDatas = [
|
|
'status' => [
|
|
'type' => 'select',
|
|
'datas' => [
|
|
'active' => 'Active',
|
|
'inactive' => 'Inactive'
|
|
]
|
|
],
|
|
];
|
|
|
|
$firstUploadFolder = 'NewModule/';
|
|
$firstUploadTitle = 'Upload Files';
|
|
?>
|
|
|
|
<div class="content">
|
|
<div class="row">
|
|
@include("admin.type.document.upload")
|
|
@include("components.blocks.module-block")
|
|
</div>
|
|
</div>
|
|
```
|
|
|
|
3. **Add to Types Table**:
|
|
Register the module in the admin panel's Types section with:
|
|
- Title: "New Module"
|
|
- Slug: "new-module"
|
|
- Fields: "name,description,status,created_at"
|
|
|
|
### Module Template Structure
|
|
|
|
#### sablon4.blade.php
|
|
Base template for modules with these key variables:
|
|
|
|
```php
|
|
$title = "Module Title"; // Page title
|
|
$tableName = "table_name"; // Database table name
|
|
$listDatas = Model::paginate(50); // Data source
|
|
$blockGroup = []; // Field grouping
|
|
$relationDatas = []; // Field type definitions
|
|
$firstUploadFolder = 'ModuleName/'; // File upload folder
|
|
$firstUploadTitle = 'Upload Title'; // Upload section title
|
|
```
|
|
|
|
#### module-block.blade.php
|
|
Handles the DataGrid integration and includes:
|
|
- Column selection
|
|
- Excel import/export
|
|
- DataGrid component
|
|
- Field type mapping
|
|
|
|
## DevExtreme Integration
|
|
|
|
### DataGrid Configuration
|
|
|
|
The DataGrid is configured in `resources/views/components/table/datagrid.blade.php` with:
|
|
|
|
```javascript
|
|
var dataGrid = $("#dataGrid").dxDataGrid({
|
|
dataSource: dataSource,
|
|
keyExpr: "{{$tableName}}",
|
|
allowColumnResizing: true,
|
|
allowColumnReordering: true,
|
|
showBorders: true,
|
|
filterRow: {
|
|
visible: true
|
|
},
|
|
searchPanel: {
|
|
visible: true
|
|
},
|
|
paging: {
|
|
pageSize: 20
|
|
},
|
|
pager: {
|
|
showPageSizeSelector: true,
|
|
allowedPageSizes: [10, 20, 50, 100]
|
|
},
|
|
editing: {
|
|
mode: "popup",
|
|
allowUpdating: true,
|
|
allowAdding: true,
|
|
allowDeleting: true
|
|
}
|
|
});
|
|
```
|
|
|
|
### Field Types
|
|
|
|
Supported field types in `relationDatas`:
|
|
|
|
```php
|
|
$relationDatas = [
|
|
'text_field' => ['type' => 'text'],
|
|
'date_field' => ['type' => 'date'],
|
|
'number_field' => ['type' => 'number'],
|
|
'select_field' => [
|
|
'type' => 'select',
|
|
'datas' => ['option1' => 'Label 1', 'option2' => 'Label 2']
|
|
],
|
|
'link_field' => [
|
|
'type' => 'link-search',
|
|
'html' => '<i class="fa fa-link"></i>'
|
|
],
|
|
'decimal_field' => ['type' => 'decimal'],
|
|
'checkbox_field' => ['type' => 'checkbox']
|
|
];
|
|
```
|
|
|
|
### Custom Validation
|
|
|
|
Add custom validation in `components/table/datagrid/validation-callback/{module}/{field}.blade.php`:
|
|
|
|
```javascript
|
|
function validationCallback_fieldName(e) {
|
|
// Custom validation logic
|
|
if (e.value && e.value.length < 3) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
```
|
|
|
|
## Admin-AJAX System
|
|
|
|
### Creating AJAX Endpoints
|
|
|
|
1. **Create AJAX View**:
|
|
```php
|
|
// resources/views/admin-ajax/custom-action.blade.php
|
|
@php
|
|
$data = db('table_name')->where('condition', $request->input('value'))->get();
|
|
echo json_encode([
|
|
'status' => 'success',
|
|
'data' => $data
|
|
]);
|
|
@endphp
|
|
```
|
|
|
|
2. **Call from JavaScript**:
|
|
```javascript
|
|
$.ajax({
|
|
url: '/admin-ajax/custom-action',
|
|
type: 'POST',
|
|
data: {
|
|
value: 'search_value',
|
|
_token: csrf_token
|
|
},
|
|
success: function(response) {
|
|
// Handle response
|
|
}
|
|
});
|
|
```
|
|
|
|
### Common AJAX Patterns
|
|
|
|
#### Batch Operations
|
|
```php
|
|
// admin-ajax/batch-operation.blade.php
|
|
@php
|
|
$ids = $request->input('ids', []);
|
|
$operation = $request->input('operation');
|
|
|
|
foreach($ids as $id) {
|
|
db('table_name')->where('id', $id)->update(['status' => $operation]);
|
|
}
|
|
|
|
echo json_encode(['status' => 'success', 'processed' => count($ids)]);
|
|
@endphp
|
|
```
|
|
|
|
#### Data Export
|
|
```php
|
|
// admin-ajax/export-data.blade.php
|
|
@php
|
|
$query = $request->input('query');
|
|
$data = DB::select($query);
|
|
|
|
$filename = 'export_' . date('Y-m-d_H-i-s') . '.xlsx';
|
|
Excel::store(new ExportExcel($data), $filename);
|
|
|
|
echo json_encode(['status' => 'success', 'file' => $filename]);
|
|
@endphp
|
|
```
|
|
|
|
## Save Trigger System
|
|
|
|
### Overview
|
|
|
|
Save triggers automatically process data changes and maintain data consistency across related tables.
|
|
|
|
### Trigger Structure
|
|
|
|
```php
|
|
// app/Http/Controllers/SaveTrigger/{table_name}.php
|
|
<?php
|
|
use App\Models\RelatedModel;
|
|
|
|
$id = $request['key'];
|
|
$data = db($tableName)->where("id", $id)->first();
|
|
|
|
// Detect changed fields
|
|
$changedFields = [];
|
|
foreach ($data as $key => $value) {
|
|
if (isset($beforeData->$key) && $beforeData->$key != $value) {
|
|
$changedFields[] = $key;
|
|
}
|
|
}
|
|
|
|
// Execute related updates
|
|
if (in_array('status', $changedFields)) {
|
|
// Update related records
|
|
RelatedModel::where('parent_id', $id)
|
|
->update(['status' => $data->status]);
|
|
}
|
|
```
|
|
|
|
### Common Trigger Patterns
|
|
|
|
#### Status Synchronization
|
|
```php
|
|
// Update related records when status changes
|
|
if (in_array('status', $changedFields)) {
|
|
$newStatus = $data->status;
|
|
|
|
// Update child records
|
|
db('child_table')->where('parent_id', $id)
|
|
->update(['status' => $newStatus]);
|
|
|
|
// Update summary tables
|
|
$summary = db('summary_table')->where('parent_id', $id)->first();
|
|
if ($summary) {
|
|
$summary->update(['last_status' => $newStatus]);
|
|
}
|
|
}
|
|
```
|
|
|
|
#### Calculated Fields
|
|
```php
|
|
// Recalculate totals when related fields change
|
|
if (array_intersect(['quantity', 'unit_price'], $changedFields)) {
|
|
$total = $data->quantity * $data->unit_price;
|
|
|
|
db($tableName)->where('id', $id)
|
|
->update(['total' => $total]);
|
|
}
|
|
```
|
|
|
|
#### Cross-Table Updates
|
|
```php
|
|
// Update related tables when key fields change
|
|
if (in_array('project_id', $changedFields)) {
|
|
$newProjectId = $data->project_id;
|
|
|
|
// Update all related records
|
|
db('related_table')->where('parent_id', $id)
|
|
->update(['project_id' => $newProjectId]);
|
|
}
|
|
```
|
|
|
|
## Batch Excel Operations
|
|
|
|
### Import Process
|
|
|
|
1. **File Upload**: Users upload Excel files through the interface
|
|
2. **Validation**: System validates data format and required fields
|
|
3. **Processing**: Data is processed in batches to handle large files
|
|
4. **Save Triggers**: Each row triggers the appropriate save triggers
|
|
5. **Progress Tracking**: Real-time progress updates via AJAX
|
|
|
|
### Export Process
|
|
|
|
1. **Query Building**: Dynamic SQL query based on filters
|
|
2. **Data Retrieval**: Fetch data with pagination for large datasets
|
|
3. **Formatting**: Apply formatting and styling
|
|
4. **File Generation**: Create Excel file with multiple sheets if needed
|
|
5. **Download**: Provide download link to user
|
|
|
|
### Implementation Example
|
|
|
|
```php
|
|
// Batch Excel Import
|
|
public function importExcel(Request $request, string $tableName) {
|
|
$file = $request->file('file');
|
|
$import = new ImportExcel($tableName);
|
|
|
|
Excel::import($import, $file);
|
|
|
|
return response()->json([
|
|
'status' => 'success',
|
|
'imported' => $import->getRowCount()
|
|
]);
|
|
}
|
|
|
|
// Batch Excel Export
|
|
public function exportExcel(Request $request, string $tableName, string $fileName = "") {
|
|
$query = $request->input('query');
|
|
$data = DB::select($query);
|
|
|
|
$fileName = $fileName ?: $tableName . '_' . date('Y-m-d_H-i-s');
|
|
|
|
return Excel::download(new ExportExcel($data), $fileName . '.xlsx');
|
|
}
|
|
```
|
|
|
|
## Development Workflow
|
|
|
|
### 1. Environment Setup
|
|
|
|
```bash
|
|
# Clone repository
|
|
git clone [repository-url]
|
|
cd dev
|
|
|
|
# Install dependencies
|
|
composer install
|
|
npm install
|
|
|
|
# Configure environment
|
|
cp .env.example .env
|
|
php artisan key:generate
|
|
|
|
# Run migrations
|
|
php artisan migrate
|
|
|
|
# Start development server
|
|
php artisan serve
|
|
```
|
|
|
|
### 2. Creating New Features
|
|
|
|
1. **Database Changes**:
|
|
```bash
|
|
php artisan make:migration create_new_table
|
|
php artisan migrate
|
|
```
|
|
|
|
2. **Model Creation**:
|
|
```bash
|
|
php artisan make:model NewModel
|
|
```
|
|
|
|
3. **View Template**:
|
|
- Copy `sablon4.blade.php` as base
|
|
- Customize variables and field groups
|
|
- Add to Types table
|
|
|
|
4. **Save Triggers** (if needed):
|
|
- Create trigger file in `SaveTrigger/`
|
|
- Define change detection logic
|
|
- Implement cross-table updates
|
|
|
|
### 3. Testing
|
|
|
|
```bash
|
|
# Run tests
|
|
php artisan test
|
|
|
|
# Test specific module
|
|
php artisan test --filter=NewModuleTest
|
|
```
|
|
|
|
### 4. Deployment
|
|
|
|
```bash
|
|
# Production deployment
|
|
composer install --optimize-autoloader --no-dev
|
|
php artisan config:cache
|
|
php artisan route:cache
|
|
php artisan view:cache
|
|
```
|
|
|
|
## Common Patterns
|
|
|
|
### 1. Dynamic Field Handling
|
|
|
|
```php
|
|
// Get field types from database
|
|
$fieldTypes = [];
|
|
foreach($columns as $column) {
|
|
$fieldTypes[$column] = table_column_type($tableName, $column);
|
|
}
|
|
|
|
// Apply custom field types
|
|
$relationDatas = [
|
|
'status' => ['type' => 'select', 'datas' => $statusOptions],
|
|
'date_field' => ['type' => 'date'],
|
|
];
|
|
```
|
|
|
|
### 2. Permission Checking
|
|
|
|
```php
|
|
// Check user permissions
|
|
if (!isAuth($tableName, 'write')) {
|
|
return response()->json(['error' => 'Permission denied'], 403);
|
|
}
|
|
|
|
// Role-based access
|
|
if (!isAdmin()) {
|
|
// Limited access logic
|
|
}
|
|
```
|
|
|
|
### 3. Data Validation
|
|
|
|
```php
|
|
// Custom validation in save triggers
|
|
$requiredFields = ['name', 'email', 'status'];
|
|
foreach($requiredFields as $field) {
|
|
if (empty($data->$field)) {
|
|
throw new Exception("Field $field is required");
|
|
}
|
|
}
|
|
```
|
|
|
|
### 4. Error Handling
|
|
|
|
```php
|
|
try {
|
|
// Database operation
|
|
DB::transaction(function() use ($data) {
|
|
// Complex operations
|
|
});
|
|
} catch (Exception $e) {
|
|
Log::error('Operation failed', [
|
|
'error' => $e->getMessage(),
|
|
'data' => $data
|
|
]);
|
|
|
|
return response()->json(['error' => 'Operation failed'], 500);
|
|
}
|
|
```
|
|
|
|
## Troubleshooting
|
|
|
|
### Common Issues
|
|
|
|
1. **DataGrid Not Loading**:
|
|
- Check browser console for JavaScript errors
|
|
- Verify AJAX endpoint returns valid JSON
|
|
- Check network tab for failed requests
|
|
|
|
2. **Save Triggers Not Working**:
|
|
- Verify trigger file exists in `SaveTrigger/`
|
|
- Check database permissions
|
|
- Review error logs
|
|
|
|
3. **Excel Import Failures**:
|
|
- Validate Excel file format
|
|
- Check column mappings
|
|
- Verify required fields are present
|
|
|
|
4. **Permission Errors**:
|
|
- Check user level in database
|
|
- Verify module permissions
|
|
- Review middleware configuration
|
|
|
|
### Debug Tools
|
|
|
|
1. **Laravel Telescope** (if enabled):
|
|
```
|
|
/telescope
|
|
```
|
|
|
|
2. **Database Logging**:
|
|
```php
|
|
DB::enableQueryLog();
|
|
// ... operations
|
|
dd(DB::getQueryLog());
|
|
```
|
|
|
|
3. **DevExtreme Debug**:
|
|
```javascript
|
|
// Enable DevExtreme debug mode
|
|
DevExpress.config({ debug: true });
|
|
```
|
|
|
|
### Performance Optimization
|
|
|
|
1. **Database Indexing**:
|
|
```sql
|
|
CREATE INDEX idx_table_column ON table_name(column_name);
|
|
```
|
|
|
|
2. **Query Optimization**:
|
|
```php
|
|
// Use eager loading for relationships
|
|
$data = Model::with('relation')->get();
|
|
```
|
|
|
|
3. **Caching**:
|
|
```php
|
|
// Cache frequently accessed data
|
|
$data = Cache::remember('key', 3600, function() {
|
|
return Model::all();
|
|
});
|
|
```
|
|
|
|
---
|
|
|
|
This guide provides a comprehensive overview of the DevQMS system. For specific module documentation, refer to the individual guide files in the `guide/` directory. Always test changes in a development environment before deploying to production. |