update entra id
This commit is contained in:
parent
6752d3515f
commit
2a96d24de7
@ -16,7 +16,24 @@ class PasswordResetRequest extends Request
|
||||
return [
|
||||
'token' => 'required',
|
||||
'email' => 'required|email',
|
||||
'password' => 'required|confirmed|min:8'
|
||||
'password' => [
|
||||
'required',
|
||||
'confirmed',
|
||||
'min:8',
|
||||
'regex:/^(?=.*[A-Za-z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/'
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get custom messages for validator errors.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function messages()
|
||||
{
|
||||
return [
|
||||
'password.regex' => __('The password must be at least 8 characters long and contain at least one number and one special character (@$!%*?&).')
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@ -17,7 +17,12 @@ class RegisterRequest extends Request
|
||||
$rules = [
|
||||
'email' => 'required|email|unique:users,email',
|
||||
'username' => 'required|unique:users,username',
|
||||
'password' => 'required|confirmed|min:8',
|
||||
'password' => [
|
||||
'required',
|
||||
'confirmed',
|
||||
'min:8',
|
||||
'regex:/^(?=.*[A-Za-z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/'
|
||||
],
|
||||
];
|
||||
|
||||
if (setting('registration.captcha.enabled')) {
|
||||
@ -36,10 +41,11 @@ class RegisterRequest extends Request
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function messages()
|
||||
public function messages()
|
||||
{
|
||||
return [
|
||||
'tos.accepted' => __('You have to accept Terms of Service.')
|
||||
'tos.accepted' => __('You have to accept Terms of Service.'),
|
||||
'password.regex' => __('The password must be at least 8 characters long and contain at least one number and one special character (@$!%*?&).')
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@ -17,7 +17,12 @@ class CreateUserRequest extends Request
|
||||
$rules = [
|
||||
'email' => 'required|email|unique:users,email',
|
||||
'username' => 'nullable|unique:users,username',
|
||||
'password' => 'required|min:6|confirmed',
|
||||
'password' => [
|
||||
'required',
|
||||
'confirmed',
|
||||
'min:8',
|
||||
'regex:/^(?=.*[A-Za-z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/'
|
||||
],
|
||||
'birthday' => 'nullable|date',
|
||||
'role_id' => 'required|exists:roles,id',
|
||||
'verified' => 'boolean'
|
||||
@ -29,4 +34,16 @@ class CreateUserRequest extends Request
|
||||
|
||||
return $rules;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get custom messages for validator errors.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function messages()
|
||||
{
|
||||
return [
|
||||
'password.regex' => __('The password must be at least 8 characters long and contain at least one number and one special character (@$!%*?&).')
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@ -19,7 +19,24 @@ class UpdateLoginDetailsRequest extends Request
|
||||
return [
|
||||
'email' => 'required|email|unique:users,email,' . $user->id,
|
||||
'username' => 'nullable|unique:users,username,' . $user->id,
|
||||
'password' => 'nullable|min:8|confirmed'
|
||||
'password' => [
|
||||
'nullable',
|
||||
'confirmed',
|
||||
'min:8',
|
||||
'regex:/^(?=.*[A-Za-z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/'
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get custom messages for validator errors.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function messages()
|
||||
{
|
||||
return [
|
||||
'password.regex' => __('The password must be at least 8 characters long and contain at least one number and one special character (@$!%*?&).')
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@ -21,11 +21,28 @@ class UpdateUserRequest extends Request
|
||||
return [
|
||||
'email' => 'email|unique:users,email,' . $user->id,
|
||||
'username' => 'nullable|unique:users,username,' . $user->id,
|
||||
'password' => 'min:6|confirmed',
|
||||
'password' => [
|
||||
'nullable',
|
||||
'confirmed',
|
||||
'min:8',
|
||||
'regex:/^(?=.*[A-Za-z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/'
|
||||
],
|
||||
'birthday' => 'nullable|date',
|
||||
'role_id' => 'exists:roles,id',
|
||||
'country_id' => 'exists:countries,id',
|
||||
'status' => Rule::in(array_keys(UserStatus::lists()))
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get custom messages for validator errors.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function messages()
|
||||
{
|
||||
return [
|
||||
'password.regex' => __('The password must be at least 8 characters long and contain at least one number and one special character (@$!%*?&).')
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@ -33,7 +33,10 @@ class EventServiceProvider extends ServiceProvider
|
||||
],
|
||||
Verified::class => [
|
||||
ActivateUser::class
|
||||
]
|
||||
],
|
||||
\SocialiteProviders\Manager\SocialiteWasCalled::class => [
|
||||
'SocialiteProviders\\Azure\\AzureExtendSocialite@handle', // Usa una stringa con @handle
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
|
||||
@ -42,6 +42,7 @@
|
||||
"laravel/ui": "^4.0",
|
||||
"laravelcollective/html": "^6.3",
|
||||
"proengsoft/laravel-jsvalidation": "^4.0.0",
|
||||
"socialiteproviders/microsoft-azure": "^5.2",
|
||||
"spatie/laravel-query-builder": "^5.0",
|
||||
"vanguardapp/activity-log": "^5.0",
|
||||
"vanguardapp/announcements": "^5.0",
|
||||
|
||||
127
composer.lock
generated
127
composer.lock
generated
@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "0868d0ed54d8695b929de611fc8beeab",
|
||||
"content-hash": "df98df06998bb59ef615306b9f0d421b",
|
||||
"packages": [
|
||||
{
|
||||
"name": "akaunting/laravel-setting",
|
||||
@ -4145,6 +4145,131 @@
|
||||
},
|
||||
"time": "2024-07-01T07:33:21+00:00"
|
||||
},
|
||||
{
|
||||
"name": "socialiteproviders/manager",
|
||||
"version": "v4.8.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/SocialiteProviders/Manager.git",
|
||||
"reference": "8180ec14bef230ec2351cff993d5d2d7ca470ef4"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/SocialiteProviders/Manager/zipball/8180ec14bef230ec2351cff993d5d2d7ca470ef4",
|
||||
"reference": "8180ec14bef230ec2351cff993d5d2d7ca470ef4",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"illuminate/support": "^8.0 || ^9.0 || ^10.0 || ^11.0 || ^12.0",
|
||||
"laravel/socialite": "^5.5",
|
||||
"php": "^8.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"mockery/mockery": "^1.2",
|
||||
"phpunit/phpunit": "^9.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"providers": [
|
||||
"SocialiteProviders\\Manager\\ServiceProvider"
|
||||
]
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"SocialiteProviders\\Manager\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Andy Wendt",
|
||||
"email": "andy@awendt.com"
|
||||
},
|
||||
{
|
||||
"name": "Anton Komarev",
|
||||
"email": "a.komarev@cybercog.su"
|
||||
},
|
||||
{
|
||||
"name": "Miguel Piedrafita",
|
||||
"email": "soy@miguelpiedrafita.com"
|
||||
},
|
||||
{
|
||||
"name": "atymic",
|
||||
"email": "atymicq@gmail.com",
|
||||
"homepage": "https://atymic.dev"
|
||||
}
|
||||
],
|
||||
"description": "Easily add new or override built-in providers in Laravel Socialite.",
|
||||
"homepage": "https://socialiteproviders.com",
|
||||
"keywords": [
|
||||
"laravel",
|
||||
"manager",
|
||||
"oauth",
|
||||
"providers",
|
||||
"socialite"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/socialiteproviders/manager/issues",
|
||||
"source": "https://github.com/socialiteproviders/manager"
|
||||
},
|
||||
"time": "2025-02-24T19:33:30+00:00"
|
||||
},
|
||||
{
|
||||
"name": "socialiteproviders/microsoft-azure",
|
||||
"version": "5.2.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/SocialiteProviders/Microsoft-Azure.git",
|
||||
"reference": "453d62c9d7e3b3b76e94c913fb46e68a33347b16"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/SocialiteProviders/Microsoft-Azure/zipball/453d62c9d7e3b3b76e94c913fb46e68a33347b16",
|
||||
"reference": "453d62c9d7e3b3b76e94c913fb46e68a33347b16",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-json": "*",
|
||||
"php": "^8.0",
|
||||
"socialiteproviders/manager": "^4.4"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"SocialiteProviders\\Azure\\": ""
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Chris Hemmings",
|
||||
"email": "chris@hemmin.gs"
|
||||
}
|
||||
],
|
||||
"description": "Microsoft Azure OAuth2 Provider for Laravel Socialite",
|
||||
"keywords": [
|
||||
"azure",
|
||||
"laravel",
|
||||
"microsoft",
|
||||
"oauth",
|
||||
"provider",
|
||||
"socialite"
|
||||
],
|
||||
"support": {
|
||||
"docs": "https://socialiteproviders.com/microsoft-azure",
|
||||
"issues": "https://github.com/socialiteproviders/providers/issues",
|
||||
"source": "https://github.com/socialiteproviders/providers"
|
||||
},
|
||||
"time": "2024-03-15T03:02:10+00:00"
|
||||
},
|
||||
{
|
||||
"name": "spatie/laravel-package-tools",
|
||||
"version": "1.14.2",
|
||||
|
||||
@ -198,7 +198,7 @@ return [
|
||||
Illuminate\Pagination\PaginationServiceProvider::class,
|
||||
Illuminate\Pipeline\PipelineServiceProvider::class,
|
||||
Illuminate\Queue\QueueServiceProvider::class,
|
||||
// Illuminate\Redis\RedisServiceProvider::class,
|
||||
// Illuminate\Redis\RedisServiceProvider::class,
|
||||
Illuminate\Auth\Passwords\PasswordResetServiceProvider::class,
|
||||
Illuminate\Session\SessionServiceProvider::class,
|
||||
Illuminate\Translation\TranslationServiceProvider::class,
|
||||
@ -227,6 +227,7 @@ return [
|
||||
Vanguard\Providers\RouteServiceProvider::class,
|
||||
Vanguard\Services\Auth\TwoFactor\AuthyServiceProvider::class,
|
||||
Vanguard\Providers\VanguardServiceProvider::class,
|
||||
\SocialiteProviders\Manager\ServiceProvider::class,
|
||||
],
|
||||
|
||||
/*
|
||||
|
||||
@ -12,7 +12,7 @@ return [
|
||||
*/
|
||||
|
||||
'social' => [
|
||||
'providers' => ['facebook', 'twitter', 'google']
|
||||
'providers' => ['azure']
|
||||
],
|
||||
|
||||
/*
|
||||
|
||||
@ -65,5 +65,11 @@ return [
|
||||
|
||||
'authy' => [
|
||||
'key' => env('AUTHY_KEY')
|
||||
],
|
||||
|
||||
'azure' => [
|
||||
'client_id' => env('AZURE_CLIENT_ID'),
|
||||
'client_secret' => env('AZURE_CLIENT_SECRET'),
|
||||
'redirect' => env('AZURE_REDIRECT_URI'),
|
||||
]
|
||||
];
|
||||
|
||||
BIN
public/userarea.zip
Normal file
BIN
public/userarea.zip
Normal file
Binary file not shown.
167
public/userarea/apilogic/api-to-temp - Copia050325.php
Normal file
167
public/userarea/apilogic/api-to-temp - Copia050325.php
Normal file
@ -0,0 +1,167 @@
|
||||
<?php
|
||||
// Database connection
|
||||
include('../../Connections/repnew.php');
|
||||
// Starts the session to handle session variables
|
||||
$conn = new mysqli($servername, $username, $password, $database);
|
||||
|
||||
// Check the connection
|
||||
if ($conn->connect_error) {
|
||||
die("Connection failed: " . $conn->connect_error);
|
||||
}
|
||||
|
||||
// Check if POST request was received
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
// Array to collect messages about file processing
|
||||
$file_messages = [];
|
||||
|
||||
// Receive JSON from the laboratory via a field in the form (e.g., 'json_data')
|
||||
if (isset($_POST['json_data'])) {
|
||||
$json_data = $_POST['json_data'];
|
||||
|
||||
// Decode JSON for optional validation
|
||||
$decoded_data = json_decode($json_data, true);
|
||||
|
||||
// If the JSON is valid
|
||||
if (json_last_error() === JSON_ERROR_NONE) {
|
||||
// Authenticate using key, secret_key, and reflab
|
||||
if (!isset($decoded_data['key']) || !isset($decoded_data['secret_key']) || !isset($decoded_data['reflab'])) {
|
||||
echo json_encode([
|
||||
"status" => "error",
|
||||
"message" => "Missing authentication fields (key, secret_key, reflab)."
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
$api_key = $decoded_data['key'];
|
||||
$secret_key = $decoded_data['secret_key'];
|
||||
$reflab = $decoded_data['reflab'];
|
||||
|
||||
$query = "SELECT * FROM laboratories WHERE reflab = ? AND api_key = ?";
|
||||
$stmt = $conn->prepare($query);
|
||||
$stmt->bind_param("ss", $reflab, $api_key);
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result();
|
||||
|
||||
// Check if a valid laboratory was found with `reflab` and `api_key`
|
||||
if ($result->num_rows > 0) {
|
||||
$row = $result->fetch_assoc();
|
||||
|
||||
// Verify the status of the laboratory
|
||||
if ($row['status'] !== 'active') {
|
||||
echo json_encode([
|
||||
"status" => "error",
|
||||
"message" => "Laboratory is inactive."
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Verify the secret key using `password_verify`
|
||||
if (!password_verify($secret_key, $row['api_secret'])) {
|
||||
echo json_encode([
|
||||
"status" => "error",
|
||||
"message" => "Invalid secret key."
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
} else {
|
||||
// Check if the `reflab` is valid, but the `api_key` doesn't match
|
||||
$query = "SELECT * FROM laboratories WHERE reflab = ?";
|
||||
$stmt = $conn->prepare($query);
|
||||
$stmt->bind_param("s", $reflab);
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result();
|
||||
|
||||
if ($result->num_rows > 0) {
|
||||
echo json_encode([
|
||||
"status" => "error",
|
||||
"message" => "Invalid API key."
|
||||
]);
|
||||
} else {
|
||||
echo json_encode([
|
||||
"status" => "error",
|
||||
"message" => "Invalid reflab."
|
||||
]);
|
||||
}
|
||||
exit;
|
||||
}
|
||||
|
||||
// Generate a UUID to uniquely identify the record
|
||||
$uuid = uniqid(); // Alternatively, use UUID() in MySQL
|
||||
|
||||
// Extract some information from JSON
|
||||
if (!isset($decoded_data['product']['products_refnumber'])) {
|
||||
echo json_encode([
|
||||
"status" => "error",
|
||||
"message" => "Missing product reference number."
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
$product_refnumber = $decoded_data['product']['products_refnumber']; // Product number
|
||||
$report_number = $decoded_data['product']['reports'][0]['reportsNumberLab'] ?? null; // Report number
|
||||
$rating = $decoded_data['product']['reports'][0]['reportsRating'] ?? null; // Report rating (e.g., Pass/Fail)
|
||||
$saved_at = date("Y-m-d H:i:s"); // Save date
|
||||
|
||||
// Query to insert data into the temp_json_queue table
|
||||
$stmt = $conn->prepare("INSERT INTO temp_json_queue (uuid, lab_id, json_data) VALUES (?, ?, ?)");
|
||||
$lab_id = 1; // Set lab_id to a fixed value for testing purposes
|
||||
$stmt->bind_param("sss", $uuid, $lab_id, $json_data);
|
||||
|
||||
if ($stmt->execute()) {
|
||||
// Handle file uploads if they exist
|
||||
if (!empty($_FILES)) {
|
||||
include('process_files.php'); // Include file processing logic here
|
||||
|
||||
// Retrieve any messages added in process_files.php for files
|
||||
if (!empty($GLOBALS['file_messages'])) {
|
||||
$file_messages = $GLOBALS['file_messages'];
|
||||
}
|
||||
}
|
||||
|
||||
// Set a session variable to notify the report import
|
||||
$_SESSION['new_report'] = [
|
||||
'report_number' => $report_number,
|
||||
'rating' => $rating,
|
||||
'timestamp' => time() // You can use a timestamp to manage the expiration of the notification
|
||||
];
|
||||
|
||||
echo json_encode([
|
||||
"status" => "success",
|
||||
"message" => "Data successfully saved.",
|
||||
"uuid" => $uuid,
|
||||
"product_refnumber" => $product_refnumber, // Product number
|
||||
"report_number" => $report_number, // Report number
|
||||
"rating" => $rating, // Report rating
|
||||
"saved_at" => $saved_at, // Save date
|
||||
"file_messages" => $file_messages // Include file messages
|
||||
]);
|
||||
} else {
|
||||
echo json_encode([
|
||||
"status" => "error",
|
||||
"message" => "Failed to save data."
|
||||
]);
|
||||
}
|
||||
|
||||
$stmt->close();
|
||||
} else {
|
||||
// If the JSON is invalid
|
||||
echo json_encode([
|
||||
"status" => "error",
|
||||
"message" => "Invalid JSON format."
|
||||
]);
|
||||
}
|
||||
} else {
|
||||
echo json_encode([
|
||||
"status" => "error",
|
||||
"message" => "Missing JSON data."
|
||||
]);
|
||||
}
|
||||
} else {
|
||||
echo json_encode([
|
||||
"status" => "error",
|
||||
"message" => "Invalid request method."
|
||||
]);
|
||||
}
|
||||
|
||||
// Close the database connection
|
||||
$conn->close();
|
||||
@ -23,73 +23,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
|
||||
// If the JSON is valid
|
||||
if (json_last_error() === JSON_ERROR_NONE) {
|
||||
// Authenticate using key, secret_key, and reflab
|
||||
if (!isset($decoded_data['key']) || !isset($decoded_data['secret_key']) || !isset($decoded_data['reflab'])) {
|
||||
echo json_encode([
|
||||
"status" => "error",
|
||||
"message" => "Missing authentication fields (key, secret_key, reflab)."
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
$api_key = $decoded_data['key'];
|
||||
$secret_key = $decoded_data['secret_key'];
|
||||
$reflab = $decoded_data['reflab'];
|
||||
|
||||
$query = "SELECT * FROM laboratories WHERE reflab = ? AND api_key = ?";
|
||||
$stmt = $conn->prepare($query);
|
||||
$stmt->bind_param("ss", $reflab, $api_key);
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result();
|
||||
|
||||
// Check if a valid laboratory was found with `reflab` and `api_key`
|
||||
if ($result->num_rows > 0) {
|
||||
$row = $result->fetch_assoc();
|
||||
|
||||
// Verify the status of the laboratory
|
||||
if ($row['status'] !== 'active') {
|
||||
echo json_encode([
|
||||
"status" => "error",
|
||||
"message" => "Laboratory is inactive."
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Verify the secret key using `password_verify`
|
||||
if (!password_verify($secret_key, $row['api_secret'])) {
|
||||
echo json_encode([
|
||||
"status" => "error",
|
||||
"message" => "Invalid secret key."
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
} else {
|
||||
// Check if the `reflab` is valid, but the `api_key` doesn't match
|
||||
$query = "SELECT * FROM laboratories WHERE reflab = ?";
|
||||
$stmt = $conn->prepare($query);
|
||||
$stmt->bind_param("s", $reflab);
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result();
|
||||
|
||||
if ($result->num_rows > 0) {
|
||||
echo json_encode([
|
||||
"status" => "error",
|
||||
"message" => "Invalid API key."
|
||||
]);
|
||||
} else {
|
||||
echo json_encode([
|
||||
"status" => "error",
|
||||
"message" => "Invalid reflab."
|
||||
]);
|
||||
}
|
||||
exit;
|
||||
}
|
||||
|
||||
// Generate a UUID to uniquely identify the record
|
||||
$uuid = uniqid(); // Alternatively, use UUID() in MySQL
|
||||
|
||||
// Extract some information from JSON
|
||||
if (!isset($decoded_data['product']['products_refnumber'])) {
|
||||
// Check only for the required product_refnumber
|
||||
if (!isset($decoded_data['product']) || !is_array($decoded_data['product']) || !isset($decoded_data['product'][0]['products_refnumber'])) {
|
||||
echo json_encode([
|
||||
"status" => "error",
|
||||
"message" => "Missing product reference number."
|
||||
@ -97,9 +32,13 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
exit;
|
||||
}
|
||||
|
||||
$product_refnumber = $decoded_data['product']['products_refnumber']; // Product number
|
||||
$report_number = $decoded_data['product']['reports'][0]['reportsNumberLab'] ?? null; // Report number
|
||||
$rating = $decoded_data['product']['reports'][0]['reportsRating'] ?? null; // Report rating (e.g., Pass/Fail)
|
||||
// Generate a UUID to uniquely identify the record
|
||||
$uuid = uniqid(); // Alternatively, use UUID() in MySQL
|
||||
|
||||
// Extract some information from JSON
|
||||
$product_refnumber = $decoded_data['product'][0]['products_refnumber'];
|
||||
$report_number = $decoded_data['product'][0]['reports'][0]['reportsNumberLab'] ?? null;
|
||||
$rating = $decoded_data['product'][0]['reports'][0]['reportsRating'] ?? null;
|
||||
$saved_at = date("Y-m-d H:i:s"); // Save date
|
||||
|
||||
// Query to insert data into the temp_json_queue table
|
||||
|
||||
168
public/userarea/apilogic/api-to-temp110325.php
Normal file
168
public/userarea/apilogic/api-to-temp110325.php
Normal file
@ -0,0 +1,168 @@
|
||||
<?php
|
||||
// Database connection
|
||||
include('../../Connections/repnew.php');
|
||||
// Starts the session to handle session variables
|
||||
$conn = new mysqli($servername, $username, $password, $database);
|
||||
|
||||
// Check the connection
|
||||
if ($conn->connect_error) {
|
||||
die("Connection failed: " . $conn->connect_error);
|
||||
}
|
||||
|
||||
// Check if POST request was received
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
// Array to collect messages about file processing
|
||||
$file_messages = [];
|
||||
|
||||
// Receive JSON from the laboratory via a field in the form (e.g., 'json_data')
|
||||
if (isset($_POST['json_data'])) {
|
||||
$json_data = $_POST['json_data'];
|
||||
|
||||
// Decode JSON for optional validation
|
||||
$decoded_data = json_decode($json_data, true);
|
||||
|
||||
// If the JSON is valid
|
||||
if (json_last_error() === JSON_ERROR_NONE) {
|
||||
// Authenticate using key, secret_key, and reflab
|
||||
if (!isset($decoded_data['key']) || !isset($decoded_data['secret_key']) || !isset($decoded_data['reflab'])) {
|
||||
echo json_encode([
|
||||
"status" => "error",
|
||||
"message" => "Missing authentication fields (key, secret_key, reflab)."
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
$api_key = $decoded_data['key'];
|
||||
$secret_key = $decoded_data['secret_key'];
|
||||
$reflab = $decoded_data['reflab'];
|
||||
|
||||
$query = "SELECT * FROM laboratories WHERE reflab = ? AND api_key = ?";
|
||||
$stmt = $conn->prepare($query);
|
||||
$stmt->bind_param("ss", $reflab, $api_key);
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result();
|
||||
|
||||
// Check if a valid laboratory was found with `reflab` and `api_key`
|
||||
if ($result->num_rows > 0) {
|
||||
$row = $result->fetch_assoc();
|
||||
|
||||
// Verify the status of the laboratory
|
||||
if ($row['status'] !== 'active') {
|
||||
echo json_encode([
|
||||
"status" => "error",
|
||||
"message" => "Laboratory is inactive."
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Verify the secret key using `password_verify`
|
||||
if (!password_verify($secret_key, $row['api_secret'])) {
|
||||
echo json_encode([
|
||||
"status" => "error",
|
||||
"message" => "Invalid secret key."
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
} else {
|
||||
// Check if the `reflab` is valid, but the `api_key` doesn't match
|
||||
$query = "SELECT * FROM laboratories WHERE reflab = ?";
|
||||
$stmt = $conn->prepare($query);
|
||||
$stmt->bind_param("s", $reflab);
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result();
|
||||
|
||||
if ($result->num_rows > 0) {
|
||||
echo json_encode([
|
||||
"status" => "error",
|
||||
"message" => "Invalid API key."
|
||||
]);
|
||||
} else {
|
||||
echo json_encode([
|
||||
"status" => "error",
|
||||
"message" => "Invalid reflab."
|
||||
]);
|
||||
}
|
||||
exit;
|
||||
}
|
||||
|
||||
// Generate a UUID to uniquely identify the record
|
||||
$uuid = uniqid(); // Alternatively, use UUID() in MySQL
|
||||
|
||||
// Extract some information from JSON
|
||||
// Estrai products_refnumber dal primo elemento dell'array product
|
||||
if (!isset($decoded_data['product']) || !is_array($decoded_data['product']) || !isset($decoded_data['product'][0]['products_refnumber'])) {
|
||||
echo json_encode([
|
||||
"status" => "error",
|
||||
"message" => "Missing product reference number."
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
$product_refnumber = $decoded_data['product'][0]['products_refnumber'];
|
||||
$report_number = $decoded_data['product'][0]['reports'][0]['reportsNumberLab'] ?? null;
|
||||
$rating = $decoded_data['product'][0]['reports'][0]['reportsRating'] ?? null;
|
||||
$saved_at = date("Y-m-d H:i:s"); // Save date
|
||||
|
||||
// Query to insert data into the temp_json_queue table
|
||||
$stmt = $conn->prepare("INSERT INTO temp_json_queue (uuid, lab_id, json_data) VALUES (?, ?, ?)");
|
||||
$lab_id = 1; // Set lab_id to a fixed value for testing purposes
|
||||
$stmt->bind_param("sss", $uuid, $lab_id, $json_data);
|
||||
|
||||
if ($stmt->execute()) {
|
||||
// Handle file uploads if they exist
|
||||
if (!empty($_FILES)) {
|
||||
include('process_files.php'); // Include file processing logic here
|
||||
|
||||
// Retrieve any messages added in process_files.php for files
|
||||
if (!empty($GLOBALS['file_messages'])) {
|
||||
$file_messages = $GLOBALS['file_messages'];
|
||||
}
|
||||
}
|
||||
|
||||
// Set a session variable to notify the report import
|
||||
$_SESSION['new_report'] = [
|
||||
'report_number' => $report_number,
|
||||
'rating' => $rating,
|
||||
'timestamp' => time() // You can use a timestamp to manage the expiration of the notification
|
||||
];
|
||||
|
||||
echo json_encode([
|
||||
"status" => "success",
|
||||
"message" => "Data successfully saved.",
|
||||
"uuid" => $uuid,
|
||||
"product_refnumber" => $product_refnumber, // Product number
|
||||
"report_number" => $report_number, // Report number
|
||||
"rating" => $rating, // Report rating
|
||||
"saved_at" => $saved_at, // Save date
|
||||
"file_messages" => $file_messages // Include file messages
|
||||
]);
|
||||
} else {
|
||||
echo json_encode([
|
||||
"status" => "error",
|
||||
"message" => "Failed to save data."
|
||||
]);
|
||||
}
|
||||
|
||||
$stmt->close();
|
||||
} else {
|
||||
// If the JSON is invalid
|
||||
echo json_encode([
|
||||
"status" => "error",
|
||||
"message" => "Invalid JSON format."
|
||||
]);
|
||||
}
|
||||
} else {
|
||||
echo json_encode([
|
||||
"status" => "error",
|
||||
"message" => "Missing JSON data."
|
||||
]);
|
||||
}
|
||||
} else {
|
||||
echo json_encode([
|
||||
"status" => "error",
|
||||
"message" => "Invalid request method."
|
||||
]);
|
||||
}
|
||||
|
||||
// Close the database connection
|
||||
$conn->close();
|
||||
40
public/userarea/class/db-functions.php
Normal file
40
public/userarea/class/db-functions.php
Normal file
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../../../vendor/autoload.php';
|
||||
|
||||
|
||||
use Dotenv\Dotenv;
|
||||
|
||||
class DBHandlerSelect
|
||||
{
|
||||
private $pdo;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$dotenv = Dotenv::createImmutable(dirname(__DIR__, 3));
|
||||
$dotenv->load();
|
||||
|
||||
$host = $_ENV['DB_HOST'];
|
||||
$db = $_ENV['DB_DATABASE'];
|
||||
$user = $_ENV['DB_USERNAME'];
|
||||
$pass = $_ENV['DB_PASSWORD'];
|
||||
$charset = 'utf8mb4';
|
||||
|
||||
$dsn = "mysql:host=$host;dbname=$db;charset=$charset";
|
||||
$options = [
|
||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
||||
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
||||
PDO::ATTR_EMULATE_PREPARES => false,
|
||||
];
|
||||
|
||||
try {
|
||||
$this->pdo = new PDO($dsn, $user, $pass, $options);
|
||||
} catch (PDOException $e) {
|
||||
die("Database connection failed: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function getConnection()
|
||||
{
|
||||
return $this->pdo;
|
||||
}
|
||||
}
|
||||
61
public/userarea/class/mailer.php
Normal file
61
public/userarea/class/mailer.php
Normal file
@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
use PHPMailer\PHPMailer\PHPMailer;
|
||||
use PHPMailer\PHPMailer\Exception;
|
||||
use Dotenv\Dotenv;
|
||||
|
||||
// Carica le variabili di ambiente
|
||||
require_once dirname(__DIR__, 2) . '/vendor/autoload.php'; // Assicurati che PHPMailer e Dotenv siano installati con Composer
|
||||
|
||||
$dotenv = Dotenv::createImmutable(dirname(__DIR__, 2)); // Se la cartella `class` è a 2 livelli sopra la root
|
||||
$dotenv->load();
|
||||
|
||||
function sendEmail($to, $subject, $body, $attachments = [], $cc = [], $bcc = [])
|
||||
{
|
||||
// Configurazione SMTP
|
||||
$mail = new PHPMailer(true);
|
||||
try {
|
||||
// Configurazione server SMTP con dati da .env
|
||||
$mail->isSMTP();
|
||||
$mail->Host = $_ENV['MAIL_HOST'] ?? 'smtp.example.com';
|
||||
$mail->SMTPAuth = true;
|
||||
$mail->Username = $_ENV['MAIL_USERNAME'] ?? 'email@example.com';
|
||||
$mail->Password = $_ENV['MAIL_PASSWORD'] ?? 'password';
|
||||
$mail->SMTPSecure = $_ENV['MAIL_ENCRYPTION'] ?? PHPMailer::ENCRYPTION_STARTTLS;
|
||||
$mail->Port = $_ENV['MAIL_PORT'] ?? 587;
|
||||
|
||||
// Mittente
|
||||
$mail->setFrom($_ENV['MAIL_FROM_ADDRESS'] ?? 'default@example.com', $_ENV['MAIL_FROM_NAME'] ?? 'Default Name');
|
||||
|
||||
// Destinatari principali
|
||||
foreach ((array)$to as $recipient) {
|
||||
$mail->addAddress($recipient);
|
||||
}
|
||||
|
||||
// Destinatari CC
|
||||
foreach ((array)$cc as $recipient) {
|
||||
$mail->addCC($recipient);
|
||||
}
|
||||
|
||||
// Destinatari BCC
|
||||
foreach ((array)$bcc as $recipient) {
|
||||
$mail->addBCC($recipient);
|
||||
}
|
||||
|
||||
// Allegati
|
||||
foreach ((array)$attachments as $file) {
|
||||
$mail->addAttachment($file);
|
||||
}
|
||||
|
||||
// Contenuto dell'email
|
||||
$mail->isHTML(true);
|
||||
$mail->Subject = $subject;
|
||||
$mail->Body = $body;
|
||||
|
||||
// Invia l'email
|
||||
$mail->send();
|
||||
return ['success' => true, 'message' => 'Email inviata con successo.'];
|
||||
} catch (Exception $e) {
|
||||
return ['success' => false, 'message' => "Errore nell'invio dell'email: {$mail->ErrorInfo}"];
|
||||
}
|
||||
}
|
||||
5
public/userarea/cssinclude.php
Normal file
5
public/userarea/cssinclude.php
Normal file
@ -0,0 +1,5 @@
|
||||
<link href="assets/css/bootstrap.min.css" rel="stylesheet" type="text/css">
|
||||
<link href="assets/css/icons.css" rel="stylesheet" type="text/css">
|
||||
<link href="assets/css/style.css" rel="stylesheet" type="text/css">
|
||||
<link href="https://cdn.jsdelivr.net/npm/boxicons@2.0.7/css/boxicons.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/sweetalert2@10/dist/sweetalert2.min.css">
|
||||
@ -4,11 +4,8 @@ ini_set('display_errors', 1);
|
||||
ini_set('display_startup_errors', 1);
|
||||
error_reporting(E_ALL | E_STRICT);
|
||||
|
||||
define('BASE_PATH', realpath(__DIR__ . '/../../..'));
|
||||
define('BASE_URL', '/reportifynew/public/');
|
||||
define('USERAREA_PATH', '/reportifynew/public/userarea/');
|
||||
define('INCLUDE_PATH', BASE_URL . 'userarea/include/');
|
||||
define('ASSETS_PATH', BASE_URL . 'userarea/include/assets/');
|
||||
require_once __DIR__ . '/path_definition.php';
|
||||
|
||||
// This should be equal to: PATH_TO_VANGUARD_FOLDER/extra/auth.php
|
||||
|
||||
require_once(BASE_PATH . '/extra/auth.php');
|
||||
@ -75,11 +72,7 @@ if (isset($_SESSION["infobox"])) {
|
||||
?>
|
||||
<?php
|
||||
|
||||
|
||||
|
||||
require_once(BASE_PATH . '\public\Connections\repnew.php');
|
||||
|
||||
|
||||
require_once(BASE_PATH . '/public/Connections/repnew.php');
|
||||
|
||||
?>
|
||||
<?php require_once(BASE_PATH . '/public/webassist/mysqli/rsobj.php'); ?>
|
||||
|
||||
8
public/userarea/include/path_definition.php
Normal file
8
public/userarea/include/path_definition.php
Normal file
@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
// Define paths that may change based on the server
|
||||
define('BASE_PATH', realpath(__DIR__ . '/../../..'));
|
||||
define('BASE_URL', '/reportifynew/public/');
|
||||
define('USERAREA_PATH', '/reportifynew/public/userarea/');
|
||||
define('INCLUDE_PATH', BASE_URL . 'userarea/include/');
|
||||
define('ASSETS_PATH', BASE_URL . 'userarea/include/assets/');
|
||||
@ -1,20 +1,24 @@
|
||||
<?php include('include/headscript.php'); ?>
|
||||
<?php
|
||||
// Connessione al database
|
||||
$conn = new mysqli($servername, $username, $password, $database);
|
||||
// Includi la classe DBHandlerSelect
|
||||
require_once 'class/db-functions.php';
|
||||
|
||||
// Inizializza la connessione con DBHandlerSelect
|
||||
$dbHandler = new DBHandlerSelect();
|
||||
$pdo = $dbHandler->getConnection();
|
||||
|
||||
// Query 1: Numero totale di prodotti
|
||||
$totalProductsQuery = "SELECT COUNT(DISTINCT p.idproducts) AS totalProducts FROM products p WHERE 1=1";
|
||||
$totalProductsResult = $conn->query($totalProductsQuery);
|
||||
$totalProducts = $totalProductsResult->fetch_assoc()['totalProducts'];
|
||||
$stmt = $pdo->query($totalProductsQuery);
|
||||
$totalProducts = $stmt->fetch(PDO::FETCH_ASSOC)['totalProducts'];
|
||||
|
||||
// Query 2: Numero totale di report
|
||||
$totalReportsQuery = "
|
||||
SELECT COUNT(DISTINCT r.idreports) AS totalReports
|
||||
FROM reports r
|
||||
LEFT JOIN products p ON r.idproducts = p.idproducts";
|
||||
$totalReportsResult = $conn->query($totalReportsQuery);
|
||||
$totalReports = $totalReportsResult->fetch_assoc()['totalReports'];
|
||||
$stmt = $pdo->query($totalReportsQuery);
|
||||
$totalReports = $stmt->fetch(PDO::FETCH_ASSOC)['totalReports'];
|
||||
|
||||
// Query 3: Numero di report "fail"
|
||||
$failedReportsQuery = "
|
||||
@ -22,39 +26,29 @@ $failedReportsQuery = "
|
||||
FROM reports r
|
||||
LEFT JOIN products p ON r.idproducts = p.idproducts
|
||||
WHERE UPPER(r.reportsRating) IN ('FAIL', 'F', 'DOESN\'T COMPLY')";
|
||||
$failedReportsResult = $conn->query($failedReportsQuery);
|
||||
$failedReports = $failedReportsResult->fetch_assoc()['failedReports'];
|
||||
$stmt = $pdo->query($failedReportsQuery);
|
||||
$failedReports = $stmt->fetch(PDO::FETCH_ASSOC)['failedReports'];
|
||||
|
||||
// Query 4: Numero totale di test
|
||||
$totalTestsQuery = "
|
||||
SELECT COUNT(DISTINCT ap.idreports, ap.idPart, ap.result_TestName) AS totalTests
|
||||
FROM analysis_project ap
|
||||
LEFT JOIN result_project rp ON ap.idAnalysis_Project = rp.idanalysis_project
|
||||
LEFT JOIN reports r ON ap.idreports = r.idreports
|
||||
LEFT JOIN products p ON r.idproducts = p.idproducts";
|
||||
$totalTestsResult = $conn->query($totalTestsQuery);
|
||||
$totalTests = $totalTestsResult->fetch_assoc()['totalTests'];
|
||||
// Verifica connessione
|
||||
if ($conn->connect_error) {
|
||||
die("Connessione fallita: " . $conn->connect_error);
|
||||
}
|
||||
?>
|
||||
<?php
|
||||
// Connessione al database
|
||||
$conn = new mysqli($servername, $username, $password, $database);
|
||||
// Query per ottenere i moduli attivi e disattivi
|
||||
$stmt = $pdo->query($totalTestsQuery);
|
||||
$totalTests = $stmt->fetch(PDO::FETCH_ASSOC)['totalTests'];
|
||||
|
||||
// Query per ottenere i moduli attivi e disattivi
|
||||
$query = "
|
||||
SELECT idmodules, activemod
|
||||
FROM activemodules
|
||||
WHERE idcompany = ?
|
||||
WHERE idcompany = :idcompany
|
||||
";
|
||||
$stmt = $conn->prepare($query);
|
||||
$stmt->bind_param("i", $idcompany);
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result();
|
||||
|
||||
$stmt = $pdo->prepare($query);
|
||||
$stmt->execute(['idcompany' => $idcompany]);
|
||||
$modulesStatus = [];
|
||||
while ($row = $result->fetch_assoc()) {
|
||||
while ($row = $stmt->fetch()) {
|
||||
$modulesStatus[$row['idmodules']] = $row['activemod'];
|
||||
}
|
||||
?>
|
||||
@ -72,14 +66,10 @@ while ($row = $result->fetch_assoc()) {
|
||||
|
||||
<link rel="shortcut icon" href="assets/images/favicon.ico">
|
||||
|
||||
<link href="assets/css/bootstrap.min.css" rel="stylesheet" type="text/css">
|
||||
<link href="assets/css/icons.css" rel="stylesheet" type="text/css">
|
||||
<link href="assets/css/style.css" rel="stylesheet" type="text/css">
|
||||
<link href="https://cdn.jsdelivr.net/npm/boxicons@2.0.7/css/boxicons.min.css" rel="stylesheet">
|
||||
|
||||
<?php include('cssinclude.php'); ?>
|
||||
</head>
|
||||
|
||||
|
||||
<body class="fixed-left">
|
||||
|
||||
<!-- Loader -->
|
||||
@ -95,15 +85,13 @@ while ($row = $result->fetch_assoc()) {
|
||||
<?php include('include/navigationbar.php'); ?>
|
||||
|
||||
<!-- Start right Content here -->
|
||||
|
||||
<div class="content-page">
|
||||
<!-- Start content -->
|
||||
<div class="content">
|
||||
|
||||
<?php include('include/topbar.php'); ?>
|
||||
|
||||
<div class="page-content-wrapper ">
|
||||
|
||||
<div class="page-content-wrapper">
|
||||
<div class="container-fluid">
|
||||
|
||||
<div class="row">
|
||||
@ -120,6 +108,8 @@ while ($row = $result->fetch_assoc()) {
|
||||
</div>
|
||||
</div>
|
||||
<!-- end page title end breadcrumb -->
|
||||
|
||||
<!-- Header Stats -->
|
||||
<div class="row">
|
||||
<div class="col-lg-3">
|
||||
<div class="card">
|
||||
@ -194,10 +184,8 @@ while ($row = $result->fetch_assoc()) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<!-- Button Index -->
|
||||
<div class="row">
|
||||
|
||||
<div class="col-lg-3">
|
||||
<div class="card card-body">
|
||||
<a href="<?php echo USERAREA_PATH; ?>products/products.php">
|
||||
@ -205,7 +193,6 @@ while ($row = $result->fetch_assoc()) {
|
||||
<i class="mdi mdi-database-import d-block display-4 mt-2 mb-3 text-warning"></i>
|
||||
<h5 class="text-primary"><?php echo $products; ?></h5>
|
||||
<p class="text-primary"><?php echo $productsslogan; ?></p><br>
|
||||
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
@ -217,7 +204,6 @@ while ($row = $result->fetch_assoc()) {
|
||||
<i class="mdi mdi-cloud-sync d-block display-4 mt-2 mb-3 text-primary"></i>
|
||||
<h5 class="text-primary">Reports</h5>
|
||||
<p class="text-primary"><?php echo $reportsslogan; ?></p>
|
||||
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
@ -229,7 +215,6 @@ while ($row = $result->fetch_assoc()) {
|
||||
<i class="mdi mdi-signal d-block display-4 mt-2 mb-3 text-info"></i>
|
||||
<h5 class="text-primary"><?php echo $statkpi; ?></h5>
|
||||
<p class="text-primary"><?php echo $statkpislogan; ?></p>
|
||||
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
@ -241,15 +226,12 @@ while ($row = $result->fetch_assoc()) {
|
||||
<i class="mdi mdi-database-import d-block display-4 mt-2 mb-3 text-success"></i>
|
||||
<h5 class="text-primary"><?php echo $importify; ?></h5>
|
||||
<p class="text-primary"><?php echo $importifyslogan; ?></p><br>
|
||||
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-3">
|
||||
<div class="card card-body">
|
||||
@ -258,7 +240,6 @@ while ($row = $result->fetch_assoc()) {
|
||||
<i class="mdi mdi-view-list d-block display-4 mt-2 mb-3 text-danger"></i>
|
||||
<h5 class="text-danger"><?php echo $rsl; ?></h5>
|
||||
<p><?php echo $easyspecslogan; ?></p><br>
|
||||
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
@ -271,7 +252,6 @@ while ($row = $result->fetch_assoc()) {
|
||||
<i class="mdi mdi-database-import d-block display-4 mt-2 mb-3 text-danger"></i>
|
||||
<h5 class="text-danger">SayTRL</h5>
|
||||
<p class="text-danger"><?php echo $saytrlslogan; ?></p>
|
||||
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
@ -284,7 +264,6 @@ while ($row = $result->fetch_assoc()) {
|
||||
<i class="mdi mdi-file-document-box d-block display-4 mt-2 mb-3 text-info"></i>
|
||||
<h5 class="text-primary">Rate&Go</h5>
|
||||
<p class="text-primary"><?php echo $rategoslogan; ?></p>
|
||||
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
@ -296,50 +275,22 @@ while ($row = $result->fetch_assoc()) {
|
||||
<i class="fas fa-random display-4 mt-2 mb-3 text-warning"></i>
|
||||
<h5 class="text-primary">ReEvaluate</h5>
|
||||
<p class="text-primary"><?php echo $reevaluateslogan; ?></p>
|
||||
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<!-- end row -->
|
||||
|
||||
</div><!-- container -->
|
||||
|
||||
</div> <!-- Page content Wrapper -->
|
||||
|
||||
</div> <!-- content -->
|
||||
|
||||
<!-- Footer -->
|
||||
<?php include('include/footer.php'); ?>
|
||||
|
||||
</div>
|
||||
<!-- End Right content here -->
|
||||
|
||||
</div>
|
||||
<!-- END wrapper -->
|
||||
|
||||
|
||||
<!-- jQuery -->
|
||||
<script src="assets/js/jquery.min.js"></script>
|
||||
<script src="assets/js/popper.min.js"></script>
|
||||
<script src="assets/js/bootstrap.min.js"></script>
|
||||
<script src="assets/js/modernizr.min.js"></script>
|
||||
<script src="assets/js/detect.js"></script>
|
||||
<script src="assets/js/fastclick.js"></script>
|
||||
<script src="assets/js/jquery.slimscroll.js"></script>
|
||||
<script src="assets/js/jquery.blockUI.js"></script>
|
||||
<script src="assets/js/waves.js"></script>
|
||||
<script src="assets/js/jquery.nicescroll.js"></script>
|
||||
<script src="assets/js/jquery.scrollTo.min.js"></script>
|
||||
|
||||
<script src="assets/plugins/chart.js/chart.min.js"></script>
|
||||
<script src="assets/pages/dashboard.js"></script>
|
||||
|
||||
<!-- App js -->
|
||||
<script src="assets/js/app.js"></script>
|
||||
<?php include('jsinclude.php'); ?>
|
||||
|
||||
|
||||
</body>
|
||||
|
||||
20
public/userarea/jsinclude.php
Normal file
20
public/userarea/jsinclude.php
Normal file
@ -0,0 +1,20 @@
|
||||
<!-- jQuery -->
|
||||
<script src="assets/js/jquery.min.js"></script>
|
||||
<script src="assets/js/popper.min.js"></script>
|
||||
<script src="assets/js/bootstrap.min.js"></script>
|
||||
<script src="assets/js/modernizr.min.js"></script>
|
||||
<script src="assets/js/detect.js"></script>
|
||||
<script src="assets/js/fastclick.js"></script>
|
||||
<script src="assets/js/jquery.slimscroll.js"></script>
|
||||
<script src="assets/js/jquery.blockUI.js"></script>
|
||||
<script src="assets/js/waves.js"></script>
|
||||
<script src="assets/js/jquery.nRole: System Assistant: icescroll.js"></script>
|
||||
<script src="assets/js/jquery.scrollTo.min.js"></script>
|
||||
|
||||
<script src="assets/plugins/chart.js/chart.min.js"></script>
|
||||
<script src="assets/pages/dashboard.js"></script>
|
||||
|
||||
<!-- App js -->
|
||||
<script src="assets/js/app.js"></script>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@10/dist/sweetalert2.min.js"></script>
|
||||
5
public/userarea/products/cssinclude.php
Normal file
5
public/userarea/products/cssinclude.php
Normal file
@ -0,0 +1,5 @@
|
||||
<link href="../assets/css/bootstrap.min.css" rel="stylesheet" type="text/css">
|
||||
<link href="../assets/css/icons.css" rel="stylesheet" type="text/css">
|
||||
<link href="../assets/css/style.css" rel="stylesheet" type="text/css">
|
||||
<link href="https://cdn.jsdelivr.net/npm/boxicons@2.0.7/css/boxicons.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/sweetalert2@10/dist/sweetalert2.min.css">
|
||||
@ -3,27 +3,44 @@ ini_set('display_errors', 1);
|
||||
ini_set('display_startup_errors', 1);
|
||||
error_reporting(E_ALL);
|
||||
|
||||
include('../include/headscript.php'); ?>
|
||||
<?php include("../class/company.php");
|
||||
include('../include/headscript.php');
|
||||
include("../class/company.php");
|
||||
require_once '../class/db-functions.php'; // Includo DBHandlerSelect
|
||||
|
||||
$page = 'products.php';
|
||||
$conn = new mysqli($servername, $username, $password, $database);
|
||||
|
||||
// Inizializzo la connessione con DBHandlerSelect
|
||||
$dbHandler = new DBHandlerSelect();
|
||||
$pdo = $dbHandler->getConnection();
|
||||
|
||||
// Validazione iduserlogin
|
||||
if (!isset($iduserlogin) || !is_numeric($iduserlogin)) {
|
||||
die("Errore: ID utente non valido.");
|
||||
}
|
||||
|
||||
// Recupera le impostazioni delle colonne e dell'ordinamento dal database
|
||||
$query = "SELECT column_visibility, column_order FROM user_table_settings WHERE iduser = ? AND page = ?";
|
||||
$stmt = $conn->prepare($query);
|
||||
$stmt->bind_param("is", $iduserlogin, $page);
|
||||
$stmt->execute();
|
||||
$stmt->bind_result($column_visibility, $column_order);
|
||||
$stmt->fetch();
|
||||
$stmt->close();
|
||||
?>
|
||||
try {
|
||||
$query = "SELECT column_visibility, column_order FROM user_table_settings WHERE iduser = :iduser AND page = :page";
|
||||
$stmt = $pdo->prepare($query);
|
||||
$stmt->execute(['iduser' => $iduserlogin, 'page' => $page]);
|
||||
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
$column_visibility = $row['column_visibility'] ?? null;
|
||||
$column_order = $row['column_order'] ?? null;
|
||||
} catch (PDOException $e) {
|
||||
error_log("Errore query user_table_settings: " . $e->getMessage());
|
||||
die("Errore nel caricamento delle impostazioni.");
|
||||
}
|
||||
|
||||
<?php
|
||||
$conn = new mysqli($servername, $username, $password, $database);
|
||||
|
||||
// Query per ottenere tutti i prodotti
|
||||
$query = "SELECT * FROM products";
|
||||
$result = $conn->query($query);
|
||||
// Query per ottenere i prodotti con colonne specifiche
|
||||
try {
|
||||
// Rimossa la condizione WHERE iduser per compatibilità (potrebbe non esserci il campo iduser nella tabella products)
|
||||
$query = "SELECT idproducts, products_refnumber, products_description, products_style, products_color, products_season, products_market, products_sku, products_order, product_buyer, products_fibercontentresult, namesupplier, iddepartment, dateprod, dateinlab, dateoutlab, labservice, agerange, products_division, products_phase FROM products";
|
||||
$stmt = $pdo->prepare($query);
|
||||
$stmt->execute();
|
||||
} catch (PDOException $e) {
|
||||
error_log("Errore query products: " . $e->getMessage());
|
||||
die("Errore nel caricamento dei prodotti: " . htmlspecialchars($e->getMessage(), ENT_QUOTES, 'UTF-8'));
|
||||
}
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
@ -45,7 +62,6 @@ $result = $conn->query($query);
|
||||
<link rel="stylesheet" href="https://cdn.datatables.net/buttons/2.3.1/css/buttons.dataTables.min.css">
|
||||
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/colreorder/1.5.6/css/colReorder.dataTables.min.css">
|
||||
|
||||
|
||||
<!-- DataTables JS -->
|
||||
<script src="https://cdn.datatables.net/1.13.1/js/jquery.dataTables.min.js"></script>
|
||||
<!-- DataTables Buttons JS -->
|
||||
@ -54,15 +70,8 @@ $result = $conn->query($query);
|
||||
<script src="https://cdn.datatables.net/buttons/2.3.1/js/buttons.colVis.min.js"></script>
|
||||
<script type="text/javascript" src="https://cdn.datatables.net/colreorder/1.5.6/js/dataTables.colReorder.min.js"></script>
|
||||
|
||||
|
||||
|
||||
<!-- Altri riferimenti al CSS e JS -->
|
||||
<link href="../assets/css/bootstrap.min.css" rel="stylesheet" type="text/css">
|
||||
<link href="../assets/css/icons.css" rel="stylesheet" type="text/css">
|
||||
<link href="../assets/css/style.css" rel="stylesheet" type="text/css">
|
||||
<link href="https://cdn.jsdelivr.net/npm/boxicons@2.0.7/css/boxicons.min.css" rel="stylesheet">
|
||||
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@10/dist/sweetalert2.min.js"></script>
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/sweetalert2@10/dist/sweetalert2.min.css">
|
||||
<?php include('cssinclude.php'); ?>
|
||||
</head>
|
||||
|
||||
<style>
|
||||
@ -111,22 +120,18 @@ $result = $conn->query($query);
|
||||
color: white !important;
|
||||
}
|
||||
|
||||
/* Forza il contrasto per i pulsanti del selettore */
|
||||
.dt-button-collection button.active {
|
||||
background-color: #007bff !important;
|
||||
/* Colore per il bottone selezionato */
|
||||
color: #007bff !important;
|
||||
}
|
||||
|
||||
.dt-button-collection button {
|
||||
background-color: #f8f9fa !important;
|
||||
/* Colore per i bottoni non attivi */
|
||||
color: #000 !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
<body class="fixed-left">
|
||||
|
||||
<div id="wrapper">
|
||||
<?php include('../include/navigationbar.php'); ?>
|
||||
<div class="content-page">
|
||||
@ -134,7 +139,6 @@ $result = $conn->query($query);
|
||||
<?php include('../include/topbar.php'); ?>
|
||||
<div class="page-content-wrapper">
|
||||
<div class="container-fluid">
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<div class="page-title-box">
|
||||
@ -142,7 +146,6 @@ $result = $conn->query($query);
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-xl-12">
|
||||
<div class="card">
|
||||
@ -174,27 +177,27 @@ $result = $conn->query($query);
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php while ($row = $result->fetch_assoc()) { ?>
|
||||
<tr data-productid="<?php echo $row['idproducts']; ?>">
|
||||
<td><?php echo $row['products_refnumber']; ?></td>
|
||||
<td><?php echo $row['products_description']; ?></td>
|
||||
<td><?php echo $row['products_style']; ?></td>
|
||||
<td><?php echo $row['products_color']; ?></td>
|
||||
<td><?php echo $row['products_season']; ?></td>
|
||||
<td><?php echo $row['products_market']; ?></td>
|
||||
<td><?php echo $row['products_sku']; ?></td>
|
||||
<td><?php echo $row['products_order']; ?></td>
|
||||
<td><?php echo $row['product_buyer']; ?></td>
|
||||
<td><?php echo $row['products_fibercontentresult']; ?></td>
|
||||
<td><?php echo $row['namesupplier']; ?></td>
|
||||
<td><?php echo $row['iddepartment']; ?></td>
|
||||
<td><?php echo $row['dateprod']; ?></td>
|
||||
<td><?php echo $row['dateinlab']; ?></td>
|
||||
<td><?php echo $row['dateoutlab']; ?></td>
|
||||
<td><?php echo $row['labservice']; ?></td>
|
||||
<td><?php echo $row['agerange']; ?></td>
|
||||
<td><?php echo $row['products_division']; ?></td>
|
||||
<td><?php echo $row['products_phase']; ?></td>
|
||||
<?php while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) { ?>
|
||||
<tr data-productid="<?php echo htmlspecialchars($row['idproducts'], ENT_QUOTES, 'UTF-8'); ?>">
|
||||
<td><?php echo htmlspecialchars($row['products_refnumber'] ?? '', ENT_QUOTES, 'UTF-8'); ?></td>
|
||||
<td><?php echo htmlspecialchars($row['products_description'] ?? '', ENT_QUOTES, 'UTF-8'); ?></td>
|
||||
<td><?php echo htmlspecialchars($row['products_style'] ?? '', ENT_QUOTES, 'UTF-8'); ?></td>
|
||||
<td><?php echo htmlspecialchars($row['products_color'] ?? '', ENT_QUOTES, 'UTF-8'); ?></td>
|
||||
<td><?php echo htmlspecialchars($row['products_season'] ?? '', ENT_QUOTES, 'UTF-8'); ?></td>
|
||||
<td><?php echo htmlspecialchars($row['products_market'] ?? '', ENT_QUOTES, 'UTF-8'); ?></td>
|
||||
<td><?php echo htmlspecialchars($row['products_sku'] ?? '', ENT_QUOTES, 'UTF-8'); ?></td>
|
||||
<td><?php echo htmlspecialchars($row['products_order'] ?? '', ENT_QUOTES, 'UTF-8'); ?></td>
|
||||
<td><?php echo htmlspecialchars($row['product_buyer'] ?? '', ENT_QUOTES, 'UTF-8'); ?></td>
|
||||
<td><?php echo htmlspecialchars($row['products_fibercontentresult'] ?? '', ENT_QUOTES, 'UTF-8'); ?></td>
|
||||
<td><?php echo htmlspecialchars($row['namesupplier'] ?? '', ENT_QUOTES, 'UTF-8'); ?></td>
|
||||
<td><?php echo htmlspecialchars($row['iddepartment'] ?? '', ENT_QUOTES, 'UTF-8'); ?></td>
|
||||
<td><?php echo htmlspecialchars($row['dateprod'] ?? '', ENT_QUOTES, 'UTF-8'); ?></td>
|
||||
<td><?php echo htmlspecialchars($row['dateinlab'] ?? '', ENT_QUOTES, 'UTF-8'); ?></td>
|
||||
<td><?php echo htmlspecialchars($row['dateoutlab'] ?? '', ENT_QUOTES, 'UTF-8'); ?></td>
|
||||
<td><?php echo htmlspecialchars($row['labservice'] ?? '', ENT_QUOTES, 'UTF-8'); ?></td>
|
||||
<td><?php echo htmlspecialchars($row['agerange'] ?? '', ENT_QUOTES, 'UTF-8'); ?></td>
|
||||
<td><?php echo htmlspecialchars($row['products_division'] ?? '', ENT_QUOTES, 'UTF-8'); ?></td>
|
||||
<td><?php echo htmlspecialchars($row['products_phase'] ?? '', ENT_QUOTES, 'UTF-8'); ?></td>
|
||||
<td>
|
||||
<button class="btn btn-info btn-sm show-reports">Reports</button>
|
||||
</td>
|
||||
@ -207,31 +210,27 @@ $result = $conn->query($query);
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div><!-- container -->
|
||||
</div><!-- Page content Wrapper -->
|
||||
</div><!-- content -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php include('../include/footer.php'); ?>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
var hasUserInteracted = false; // Flag per tracciare l'interazione dell'utente
|
||||
var hasUserInteracted = false;
|
||||
|
||||
// Carica le impostazioni salvate dal server prima di inizializzare DataTables
|
||||
var stateLoaded = false;
|
||||
var columnSettings = {}; // Variabile per memorizzare le impostazioni della tabella
|
||||
var columnSettings = {};
|
||||
|
||||
// Recupera le impostazioni salvate dal server
|
||||
$.ajax({
|
||||
url: 'get_user_table_settings.php', // PHP che recupera i settaggi
|
||||
url: 'get_user_table_settings.php',
|
||||
method: 'POST',
|
||||
data: {
|
||||
user: "<?php echo $iduserlogin; ?>", // ID utente
|
||||
table: 'products' // Nome della tabella
|
||||
user: "<?php echo htmlspecialchars($iduserlogin, ENT_QUOTES, 'UTF-8'); ?>",
|
||||
table: 'products'
|
||||
},
|
||||
async: false, // Carica in modo sincrono per garantire che le impostazioni siano pronte prima di DataTables
|
||||
async: false,
|
||||
success: function(response) {
|
||||
columnSettings = JSON.parse(response);
|
||||
console.log("Impostazioni recuperate:", columnSettings);
|
||||
@ -241,42 +240,36 @@ $result = $conn->query($query);
|
||||
}
|
||||
});
|
||||
|
||||
// Inizializza DataTables con ColReorder, filtri e ColVis
|
||||
var table = $('#productsTable').DataTable({
|
||||
responsive: true,
|
||||
pageLength: 50,
|
||||
order: [
|
||||
[1, 'asc']
|
||||
], // Ordina per descrizione
|
||||
],
|
||||
colReorder: {
|
||||
order: columnSettings && columnSettings.ColReorder ? columnSettings.ColReorder : null // Usa le impostazioni di ColReorder se presenti
|
||||
order: columnSettings && columnSettings.ColReorder ? columnSettings.ColReorder : null
|
||||
},
|
||||
dom: 'Bfrtip', // Integra i bottoni
|
||||
dom: 'Bfrtip',
|
||||
buttons: [{
|
||||
extend: 'colvis', // ColVis per mostrare/nascondere colonne
|
||||
collectionLayout: 'fixed four-column', // Layout del dropdown
|
||||
text: 'Select Columns', // Testo del bottone dropdown
|
||||
postfixButtons: ['colvisRestore'], // Pulsante per ripristinare la configurazione iniziale
|
||||
columns: ':not(:last-child)' // Non nascondere l'ultima colonna (Actions)
|
||||
extend: 'colvis',
|
||||
collectionLayout: 'fixed four-column',
|
||||
text: 'Select Columns',
|
||||
postfixButtons: ['colvisRestore'],
|
||||
columns: ':not(:last-child)'
|
||||
}],
|
||||
initComplete: function() {
|
||||
console.log("DataTables initComplete");
|
||||
|
||||
// Se sono state caricate impostazioni di visibilità delle colonne, applicale
|
||||
if (columnSettings && columnSettings.columns) {
|
||||
console.log("Applico visibilità colonne:", columnSettings.columns);
|
||||
this.api().columns().every(function(index) {
|
||||
var column = this;
|
||||
column.visible(columnSettings.columns[index].visible, false); // Non ridisegnare ogni volta
|
||||
column.visible(columnSettings.columns[index].visible, false);
|
||||
});
|
||||
}
|
||||
|
||||
this.api().columns.adjust().draw(false); // Ridisegna la tabella alla fine
|
||||
|
||||
// Aggiungi i filtri per ogni colonna (eccetto la colonna delle azioni)
|
||||
this.api().columns.adjust().draw(false);
|
||||
this.api().columns().every(function() {
|
||||
var column = this;
|
||||
if (column.index() !== 6) { // Escludi la colonna "Action"
|
||||
if (column.index() !== 19) {
|
||||
var input = $('<input class="form-control form-control-sm" type="text" placeholder="Search"/>')
|
||||
.appendTo($(column.header()))
|
||||
.on('keyup change clear', function() {
|
||||
@ -290,16 +283,14 @@ $result = $conn->query($query);
|
||||
stateSave: true,
|
||||
stateSaveCallback: function(settings, data) {
|
||||
console.log("Salvataggio stato tabella");
|
||||
|
||||
// Salva le impostazioni sul server solo se l'utente ha interagito
|
||||
if (hasUserInteracted) {
|
||||
$.ajax({
|
||||
url: 'save_user_table_settings.php', // PHP che salva i settaggi
|
||||
url: 'save_user_table_settings.php',
|
||||
method: 'POST',
|
||||
data: {
|
||||
user: "<?php echo $iduserlogin; ?>", // ID utente
|
||||
table: 'products', // Nome della tabella
|
||||
settings: JSON.stringify(data) // Impostazioni della tabella
|
||||
user: "<?php echo htmlspecialchars($iduserlogin, ENT_QUOTES, 'UTF-8'); ?>",
|
||||
table: 'products',
|
||||
settings: JSON.stringify(data)
|
||||
},
|
||||
success: function(response) {
|
||||
console.log('Impostazioni salvate:', response);
|
||||
@ -312,7 +303,6 @@ $result = $conn->query($query);
|
||||
}
|
||||
});
|
||||
|
||||
// Imposta il flag `hasUserInteracted` quando l'utente modifica qualcosa (colonne o riordina)
|
||||
table.on('column-reorder', function() {
|
||||
hasUserInteracted = true;
|
||||
console.log("Colonne riordinate");
|
||||
@ -323,7 +313,6 @@ $result = $conn->query($query);
|
||||
console.log("Visibilità colonna cambiata");
|
||||
});
|
||||
|
||||
// Gestione del click su "Reports" per visualizzare la tabella child con i report e le analisi
|
||||
$('#productsTable').on('click', '.show-reports', function() {
|
||||
var tr = $(this).closest('tr');
|
||||
var productId = tr.data('productid');
|
||||
@ -333,7 +322,6 @@ $result = $conn->query($query);
|
||||
button.prop('disabled', true);
|
||||
button.html('<i class="fa fa-spinner fa-spin"></i> Loading...');
|
||||
|
||||
// Se la riga child è già visibile, nascondila
|
||||
if (row.child.isShown()) {
|
||||
row.child.hide();
|
||||
tr.removeClass('shown');
|
||||
@ -342,7 +330,6 @@ $result = $conn->query($query);
|
||||
return;
|
||||
}
|
||||
|
||||
// Carica i report e le analisi tramite AJAX
|
||||
$.ajax({
|
||||
url: 'get_reports_and_analysis.php',
|
||||
type: 'POST',
|
||||
@ -357,15 +344,14 @@ $result = $conn->query($query);
|
||||
button.prop('disabled', false);
|
||||
button.html('Reports');
|
||||
},
|
||||
error: function() {
|
||||
Swal.fire('Error!', 'There was an error loading the reports and analysis.', 'error');
|
||||
error: function(xhr) {
|
||||
Swal.fire('Errore!', xhr.status === 404 ? 'Risorsa non trovata.' : 'Errore nel caricamento dei report.', 'error');
|
||||
button.prop('disabled', false);
|
||||
button.html('Reports');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Funzione per formattare i report e le analisi nella stessa tabella
|
||||
function formatReportsAndAnalysis(data) {
|
||||
var parsedData = JSON.parse(data);
|
||||
var reports = parsedData.reports;
|
||||
@ -374,10 +360,8 @@ $result = $conn->query($query);
|
||||
html += '<tbody>';
|
||||
|
||||
$.each(reports, function(index, report) {
|
||||
// Definisci la classe di stile per il rating del report
|
||||
var ratingClass = '';
|
||||
var ratingValue = report.reportsRating.toLowerCase(); // Converte il valore in minuscolo
|
||||
|
||||
var ratingValue = report.reportsRating.toLowerCase();
|
||||
if (ratingValue === 'fail') {
|
||||
ratingClass = 'bg-danger text-white';
|
||||
} else if (ratingValue === 'pass') {
|
||||
@ -389,12 +373,11 @@ $result = $conn->query($query);
|
||||
html += '<tr>';
|
||||
html += '<td>' + report.reportsNumberLab + '</td>';
|
||||
html += '<td>' + report.reportDateIn + '</td>';
|
||||
html += '<td class="' + ratingClass + '">' + report.reportsRating + '</td>'; // Applica la classe alla cella
|
||||
html += '<td colspan="2"></td>'; // Righe vuote per mantenere l'allineamento
|
||||
html += '<td class="' + ratingClass + '">' + report.reportsRating + '</td>';
|
||||
html += '<td colspan="2"></td>';
|
||||
html += '<td><button class="btn btn-primary btn-sm report-details" data-reportid="' + report.idreports + '">Details</button></td>';
|
||||
html += '</tr>';
|
||||
|
||||
// Se ci sono analisi associate, aggiungi le righe per ciascuna analisi
|
||||
if (report.analysis.length > 0) {
|
||||
$.each(report.analysis, function(i, analysis) {
|
||||
var ratingClass = '';
|
||||
@ -420,20 +403,16 @@ $result = $conn->query($query);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
html += '</tbody></table>';
|
||||
return html;
|
||||
}
|
||||
|
||||
// Funzione per la visualizzazione dei dettagli del report
|
||||
$(document).on('click', '.report-details', function() {
|
||||
var reportId = $(this).data('reportid');
|
||||
window.location.href = 'reportdetails.php?idreports=' + reportId;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@ -1,26 +1,48 @@
|
||||
<?php include('../include/headscript.php'); ?>
|
||||
<?php include("../class/company.php");
|
||||
<?php
|
||||
ini_set('display_errors', 1);
|
||||
ini_set('display_startup_errors', 1);
|
||||
error_reporting(E_ALL);
|
||||
|
||||
$conn = new mysqli($servername, $username, $password, $database);
|
||||
include('../include/headscript.php');
|
||||
include("../class/company.php");
|
||||
require_once '../class/db-functions.php'; // Includo DBHandlerSelect
|
||||
|
||||
$page = 'reports'; // Nome della pagina specifica per salvare/ripristinare le impostazioni
|
||||
$conn = new mysqli($servername, $username, $password, $database);
|
||||
$page = 'reports';
|
||||
|
||||
// Inizializzo la connessione con DBHandlerSelect
|
||||
$dbHandler = new DBHandlerSelect();
|
||||
$conn = $dbHandler->getConnection();
|
||||
|
||||
// Validazione iduserlogin
|
||||
if (!isset($iduserlogin) || !is_numeric($iduserlogin)) {
|
||||
die("Errore: ID utente non valido.");
|
||||
}
|
||||
|
||||
// Recupera le impostazioni delle colonne e dell'ordinamento dal database
|
||||
$query = "SELECT column_visibility, column_order FROM user_table_settings WHERE iduser = ? AND page = ?";
|
||||
$stmt = $conn->prepare($query);
|
||||
$stmt->bind_param("is", $iduserlogin, $page);
|
||||
$stmt->execute();
|
||||
$stmt->bind_result($column_visibility, $column_order);
|
||||
$stmt->fetch();
|
||||
$stmt->close();
|
||||
try {
|
||||
$stmt = $conn->prepare("SELECT column_visibility, column_order FROM user_table_settings WHERE iduser = :iduser AND page = :page");
|
||||
$stmt->execute(['iduser' => $iduserlogin, 'page' => $page]);
|
||||
$userSettings = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
$column_visibility = $userSettings['column_visibility'] ?? null;
|
||||
$column_order = $userSettings['column_order'] ?? null;
|
||||
} catch (PDOException $e) {
|
||||
error_log("Errore query user_table_settings: " . $e->getMessage());
|
||||
die("Errore nel caricamento delle impostazioni.");
|
||||
}
|
||||
|
||||
// Query per ottenere tutti i report e i prodotti associati
|
||||
$query = "
|
||||
SELECT r.*, p.products_refnumber, p.products_description
|
||||
try {
|
||||
$stmt = $conn->prepare("
|
||||
SELECT r.idreports, r.reportsNumberLab, r.reportDateIn, r.reportsRating, p.products_refnumber, p.products_description
|
||||
FROM reports r
|
||||
LEFT JOIN products p ON r.idproducts = p.idproducts";
|
||||
$result = $conn->query($query);
|
||||
LEFT JOIN products p ON r.idproducts = p.idproducts
|
||||
");
|
||||
$stmt->execute();
|
||||
$reports = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
} catch (PDOException $e) {
|
||||
error_log("Errore query reports: " . $e->getMessage());
|
||||
die("Errore nel caricamento dei report: " . htmlspecialchars($e->getMessage(), ENT_QUOTES, 'UTF-8'));
|
||||
}
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
@ -31,8 +53,8 @@ $result = $conn->query($query);
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=0, minimal-ui">
|
||||
<title>Reports</title>
|
||||
<link rel="shortcut icon" href="../assets/images/favicon.ico">
|
||||
|
||||
<!-- Includi prima jQuery -->
|
||||
<!-- Includi prima jQuery -->
|
||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
||||
|
||||
@ -52,15 +74,8 @@ $result = $conn->query($query);
|
||||
<!-- ColReorder JS -->
|
||||
<script src="https://cdn.datatables.net/colreorder/1.5.6/js/dataTables.colReorder.min.js"></script>
|
||||
|
||||
|
||||
<!-- Altri riferimenti al CSS e JS -->
|
||||
<link href="../assets/css/bootstrap.min.css" rel="stylesheet" type="text/css">
|
||||
<link href="../assets/css/icons.css" rel="stylesheet" type="text/css">
|
||||
<link href="../assets/css/style.css" rel="stylesheet" type="text/css">
|
||||
<link rel="shortcut icon" href="../assets/images/favicon.ico">
|
||||
<link href="https://cdn.jsdelivr.net/npm/boxicons@2.0.7/css/boxicons.min.css" rel="stylesheet">
|
||||
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@10/dist/sweetalert2.min.js"></script>
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/sweetalert2@10/dist/sweetalert2.min.css">
|
||||
<?php include('../products/cssinclude.php'); ?>
|
||||
</head>
|
||||
|
||||
<style>
|
||||
@ -89,7 +104,6 @@ $result = $conn->query($query);
|
||||
</style>
|
||||
|
||||
<body class="fixed-left">
|
||||
|
||||
<div id="wrapper">
|
||||
<?php include('../include/navigationbar.php'); ?>
|
||||
<div class="content-page">
|
||||
@ -97,7 +111,6 @@ $result = $conn->query($query);
|
||||
<?php include('../include/topbar.php'); ?>
|
||||
<div class="page-content-wrapper">
|
||||
<div class="container-fluid">
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<div class="page-title-box">
|
||||
@ -105,13 +118,12 @@ $result = $conn->query($query);
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-xl-12">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table id="reportsTable" class="table table-striped table-hover" data-user="<?php echo $iduserlogin; ?>" data-table="reports">
|
||||
<table id="reportsTable" class="table table-striped table-hover" data-user="<?php echo htmlspecialchars($iduserlogin, ENT_QUOTES, 'UTF-8'); ?>" data-table="reports">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Report Number</th>
|
||||
@ -123,31 +135,29 @@ $result = $conn->query($query);
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php while ($row = $result->fetch_assoc()) { ?>
|
||||
<tr data-reportid="<?php echo $row['idreports']; ?>">
|
||||
<td><?php echo $row['reportsNumberLab']; ?></td>
|
||||
<td><?php echo $row['reportDateIn']; ?></td>
|
||||
<td><?php echo $row['products_refnumber']; ?></td>
|
||||
<td><?php echo $row['products_description']; ?></td>
|
||||
<td><?php echo $row['reportsRating']; ?></td>
|
||||
<?php foreach ($reports as $row) { ?>
|
||||
<tr data-reportid="<?php echo htmlspecialchars($row['idreports'], ENT_QUOTES, 'UTF-8'); ?>">
|
||||
<td><?php echo htmlspecialchars($row['reportsNumberLab'] ?? '', ENT_QUOTES, 'UTF-8'); ?></td>
|
||||
<td><?php echo htmlspecialchars($row['reportDateIn'] ?? '', ENT_QUOTES, 'UTF-8'); ?></td>
|
||||
<td><?php echo htmlspecialchars($row['products_refnumber'] ?? '', ENT_QUOTES, 'UTF-8'); ?></td>
|
||||
<td><?php echo htmlspecialchars($row['products_description'] ?? '', ENT_QUOTES, 'UTF-8'); ?></td>
|
||||
<td><?php echo htmlspecialchars($row['reportsRating'] ?? '', ENT_QUOTES, 'UTF-8'); ?></td>
|
||||
<td>
|
||||
<button class="btn btn-info btn-sm show-analysis">Analysis</button>
|
||||
<a class="btn btn-primary btn-sm report-details" href="../products/reportdetails.php?idreports=<?php echo $row['idreports']; ?>">Details</a>
|
||||
<a class="btn btn-primary btn-sm report-details" href="../products/reportdetails.php?idreports=<?php echo htmlspecialchars($row['idreports'], ENT_QUOTES, 'UTF-8'); ?>">Details</a>
|
||||
</td>
|
||||
</tr>
|
||||
<?php } ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div><!-- container -->
|
||||
</div><!-- Page content Wrapper -->
|
||||
</div><!-- content -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php include('../include/footer.php'); ?>
|
||||
</div>
|
||||
</div>
|
||||
@ -155,13 +165,10 @@ $result = $conn->query($query);
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
var hasUserInteracted = false;
|
||||
|
||||
// Recupera le impostazioni salvate dal server prima di inizializzare DataTables
|
||||
var columnSettings = {};
|
||||
var userId = $('#reportsTable').data('user');
|
||||
var tableName = $('#reportsTable').data('table');
|
||||
|
||||
// Recupera le impostazioni salvate
|
||||
$.ajax({
|
||||
url: 'get_user_table_settings_reports.php',
|
||||
method: 'POST',
|
||||
@ -179,7 +186,6 @@ $result = $conn->query($query);
|
||||
}
|
||||
});
|
||||
|
||||
// Inizializza DataTables con ColReorder, filtri e ColVis
|
||||
var table = $('#reportsTable').DataTable({
|
||||
responsive: true,
|
||||
pageLength: 50,
|
||||
@ -189,16 +195,15 @@ $result = $conn->query($query);
|
||||
colReorder: {
|
||||
order: columnSettings && columnSettings.ColReorder ? columnSettings.ColReorder : null
|
||||
},
|
||||
dom: 'Bfrtip', // Integra i bottoni
|
||||
dom: 'Bfrtip',
|
||||
buttons: [{
|
||||
extend: 'colvis',
|
||||
text: 'Select Columns',
|
||||
collectionLayout: 'fixed four-column',
|
||||
postfixButtons: ['colvisRestore'],
|
||||
columns: ':not(:last-child)' // Escludi l'ultima colonna (Actions)
|
||||
columns: ':not(:last-child)'
|
||||
}],
|
||||
initComplete: function() {
|
||||
// Applica le impostazioni di visibilità delle colonne, se presenti
|
||||
if (columnSettings && columnSettings.columns) {
|
||||
console.log("Applico visibilità colonne:", columnSettings.columns);
|
||||
this.api().columns().every(function(index) {
|
||||
@ -206,13 +211,10 @@ $result = $conn->query($query);
|
||||
column.visible(columnSettings.columns[index].visible, false);
|
||||
});
|
||||
}
|
||||
|
||||
this.api().columns.adjust().draw(false);
|
||||
|
||||
// Aggiungi i filtri per ogni colonna (eccetto la colonna delle azioni)
|
||||
this.api().columns().every(function() {
|
||||
var column = this;
|
||||
if (column.index() !== 5) { // Escludi la colonna "Action"
|
||||
if (column.index() !== 5) {
|
||||
$('<input class="form-control form-control-sm" type="text" placeholder="Search"/>')
|
||||
.appendTo($(column.header()))
|
||||
.on('keyup change clear', function() {
|
||||
@ -245,7 +247,6 @@ $result = $conn->query($query);
|
||||
}
|
||||
});
|
||||
|
||||
// Imposta il flag `hasUserInteracted` quando l'utente modifica qualcosa (colonne o riordina)
|
||||
table.on('column-reorder', function() {
|
||||
hasUserInteracted = true;
|
||||
console.log("Colonne riordinate");
|
||||
@ -256,7 +257,6 @@ $result = $conn->query($query);
|
||||
console.log("Visibilità colonna cambiata");
|
||||
});
|
||||
|
||||
// Gestione del click su "Analysis" per visualizzare la tabella child con le analisi
|
||||
$('#reportsTable').on('click', '.show-analysis', function() {
|
||||
var tr = $(this).closest('tr');
|
||||
var reportId = tr.data('reportid');
|
||||
@ -288,8 +288,8 @@ $result = $conn->query($query);
|
||||
button.prop('disabled', false);
|
||||
button.html('Analysis');
|
||||
},
|
||||
error: function() {
|
||||
Swal.fire('Error!', 'There was an error loading the analysis.', 'error');
|
||||
error: function(xhr) {
|
||||
Swal.fire('Errore!', xhr.status === 404 ? 'Risorsa non trovata.' : 'Errore nel caricamento delle analisi.', 'error');
|
||||
button.prop('disabled', false);
|
||||
button.html('Analysis');
|
||||
}
|
||||
@ -304,17 +304,18 @@ $result = $conn->query($query);
|
||||
|
||||
$.each(parsedData, function(index, analysis) {
|
||||
var ratingClass = '';
|
||||
if (analysis.finalRating === 'FAIL') {
|
||||
var ratingValue = (analysis.finalRating || '').toUpperCase();
|
||||
if (ratingValue === 'FAIL') {
|
||||
ratingClass = 'bg-danger text-white';
|
||||
} else if (analysis.finalRating === 'PASS') {
|
||||
} else if (ratingValue === 'PASS') {
|
||||
ratingClass = 'bg-success text-white';
|
||||
} else if (analysis.finalRating === '//' || analysis.finalRating === 'N/A' || analysis.finalRating === 'DATA') {
|
||||
} else if (ratingValue === '//' || ratingValue === 'N/A' || ratingValue === 'DATA') {
|
||||
ratingClass = 'bg-warning text-dark';
|
||||
}
|
||||
|
||||
html += '<tr>';
|
||||
html += '<td>' + (analysis.name ? analysis.name : 'N/A') + '</td>';
|
||||
html += '<td class="' + ratingClass + '">' + (analysis.finalRating ? analysis.finalRating : 'N/A') + '</td>';
|
||||
html += '<td class="' + ratingClass + '">' + (ratingValue || 'N/A') + '</td>';
|
||||
html += '</tr>';
|
||||
});
|
||||
|
||||
@ -323,10 +324,6 @@ $result = $conn->query($query);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
226
public/userarea/statkpi/css-statkpi.php
Normal file
226
public/userarea/statkpi/css-statkpi.php
Normal file
@ -0,0 +1,226 @@
|
||||
<style>
|
||||
#activeFilters {
|
||||
display: flex;
|
||||
font-size: 16px;
|
||||
flex-direction: row;
|
||||
background: 0;
|
||||
}
|
||||
|
||||
|
||||
.badge {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.width-100 {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.flex_center {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.mg_none {
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.table-custom tr {
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
}
|
||||
|
||||
#ajax_preloader {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: transparent;
|
||||
z-index: 9999999;
|
||||
}
|
||||
|
||||
.table-custom td,
|
||||
.table-custom th {
|
||||
padding: 4px 8px;
|
||||
}
|
||||
|
||||
.table-custom .btn {
|
||||
padding: 2px 15px;
|
||||
line-height: 1.7;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.form-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
/* Questo allinea verticalmente gli elementi nella riga */
|
||||
gap: 10px;
|
||||
/* Questo crea una piccola distanza tra gli elementi nella riga */
|
||||
}
|
||||
|
||||
.table-custom .form-control,
|
||||
.table-custom .form-select {
|
||||
height: 25px;
|
||||
/* Puoi modificare questo valore per adattarlo al tuo design */
|
||||
padding: 2px 6px;
|
||||
/* riduce la dimensione del padding */
|
||||
font-size: 14px;
|
||||
/* riduce la dimensione del font */
|
||||
}
|
||||
|
||||
.table-custom .form-control-sm.analysis-input {
|
||||
height: 25px;
|
||||
/* Questo modifica la dimensione degli input con classe 'form-control-sm' e 'analysis-input' */
|
||||
padding: 2px 6px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.padding_none {
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.select2-container--open {
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
.card {
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.05);
|
||||
transition: transform 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
.card:hover {
|
||||
transform: translateY(-3px);
|
||||
}
|
||||
|
||||
.card-body {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.card h2 {
|
||||
font-size: 32px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.card h5 {
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.card {
|
||||
min-height: 150px;
|
||||
/* Imposta un'altezza minima per le card */
|
||||
}
|
||||
|
||||
.percentage {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
margin-top: 5px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.bg-light {
|
||||
background-color: #f8f9fa !important;
|
||||
}
|
||||
|
||||
.border-primary {
|
||||
border: 2px solid #007bff !important;
|
||||
}
|
||||
|
||||
.border-info {
|
||||
border: 2px solid #17a2b8 !important;
|
||||
}
|
||||
|
||||
.border-danger {
|
||||
border: 2px solid #dc3545 !important;
|
||||
}
|
||||
|
||||
.border-success {
|
||||
border: 2px solid #28a745 !important;
|
||||
}
|
||||
|
||||
.border-warning {
|
||||
border: 2px solid #ffc107 !important;
|
||||
}
|
||||
|
||||
.row {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.col-md-2 {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
.col-md-2 {
|
||||
flex: 0 0 100%;
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.filters-applied {
|
||||
display: inline-block;
|
||||
color: white;
|
||||
border-radius: 5px;
|
||||
padding: 5px 10px;
|
||||
font-weight: bold;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.chart-container {
|
||||
width: 100%;
|
||||
margin: 20px;
|
||||
}
|
||||
|
||||
.chart-box {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.card-body {
|
||||
background-color: white;
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
.filter-sidebar {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 300px;
|
||||
height: 100%;
|
||||
background: #f8f9fa;
|
||||
box-shadow: -2px 0 5px rgba(0, 0, 0, 0.1);
|
||||
padding: 20px;
|
||||
display: none;
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
.active-filters {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
body {
|
||||
transition: margin-right 0.3s;
|
||||
/* Smooth transition */
|
||||
}
|
||||
|
||||
#main-content {
|
||||
transition: margin-right 0.3s;
|
||||
/* Smooth transition */
|
||||
}
|
||||
|
||||
.collapsed {
|
||||
margin-right: 300px;
|
||||
/* Hide the sidebar */
|
||||
}
|
||||
</style>
|
||||
68
public/userarea/statkpi/js-dragdrop.php
Normal file
68
public/userarea/statkpi/js-dragdrop.php
Normal file
@ -0,0 +1,68 @@
|
||||
<script>
|
||||
// Manages drag-and-drop functionality for charts, saving and restoring their order
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
const chartContainer = document.getElementById('charts');
|
||||
const sortable = new Sortable(chartContainer, {
|
||||
animation: 150,
|
||||
onEnd: function() {
|
||||
saveChartOrder(); // Save chart order after dragging
|
||||
}
|
||||
});
|
||||
|
||||
// Function to save chart order to localStorage
|
||||
function saveChartOrder() {
|
||||
const order = Array.from(chartContainer.children).map(chart => chart.dataset.id);
|
||||
localStorage.setItem('chartOrder', JSON.stringify(order));
|
||||
|
||||
// lets save it for the user
|
||||
$.ajax({
|
||||
url: 'chartorder.php',
|
||||
method: 'POST',
|
||||
data: {
|
||||
method: 'save',
|
||||
order: order
|
||||
},
|
||||
success: function(response) {
|
||||
|
||||
},
|
||||
error: function() {
|
||||
alert('Error saving chart order.');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Function to restore chart order from localStorage
|
||||
function loadChartOrder() {
|
||||
|
||||
// Load the saved order from localStorage
|
||||
|
||||
const savedOrder = JSON.parse(localStorage.getItem('chartOrder'));
|
||||
if (savedOrder) {
|
||||
savedOrder.forEach(id => {
|
||||
const chart = document.querySelector(`[data-id='${id}']`);
|
||||
chartContainer.appendChild(chart); // Append charts in saved order
|
||||
});
|
||||
}
|
||||
|
||||
// Load the saved order from the database
|
||||
$.ajax({
|
||||
url: 'chartorder.php',
|
||||
method: 'POST',
|
||||
data: {
|
||||
method: 'load'
|
||||
},
|
||||
success: function(response) {
|
||||
|
||||
const order = JSON.parse(response);
|
||||
order.forEach(id => {
|
||||
const chart = document.querySelector(`[data-id='${id}']`);
|
||||
chartContainer.appendChild(chart); // Append charts in saved order
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// Load the saved chart order when the page loads
|
||||
loadChartOrder();
|
||||
});
|
||||
</script>
|
||||
1148
public/userarea/statkpi/js-statkpi.php
Normal file
1148
public/userarea/statkpi/js-statkpi.php
Normal file
File diff suppressed because it is too large
Load Diff
117
public/userarea/statkpi/js/charts/analysisDistributionChart.js
Normal file
117
public/userarea/statkpi/js/charts/analysisDistributionChart.js
Normal file
@ -0,0 +1,117 @@
|
||||
import { generatePieTable } from "../utils/tableGenerator.js";
|
||||
|
||||
export function renderAnalysisDistributionChart(
|
||||
chartData,
|
||||
containerId,
|
||||
tableContainerId,
|
||||
) {
|
||||
// Pulizia del contenitore del grafico
|
||||
const chartContainer = document.querySelector(`#${containerId}`);
|
||||
if (chartContainer) {
|
||||
chartContainer.innerHTML = "";
|
||||
} else {
|
||||
console.error(`Contenitore del grafico non trovato: #${containerId}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Estrai i dati per il grafico a torta
|
||||
const analysisDistribution = chartData || [];
|
||||
const labels = analysisDistribution.map((item) => item.analysisName);
|
||||
const series = analysisDistribution.map((item) => {
|
||||
const value = parseInt(item.totalTests);
|
||||
return isNaN(value) || value < 0 ? 0 : value;
|
||||
});
|
||||
|
||||
// Verifica se ci sono dati validi da visualizzare
|
||||
const hasValidData = series.some((value) => value > 0);
|
||||
if (!hasValidData) {
|
||||
chartContainer.innerHTML =
|
||||
'<p class="text-center text-muted">No valid data to display.</p>';
|
||||
return;
|
||||
}
|
||||
|
||||
// Configurazione del grafico a torta
|
||||
const options = {
|
||||
series: series,
|
||||
chart: {
|
||||
type: "pie",
|
||||
height: 350,
|
||||
toolbar: {
|
||||
show: true,
|
||||
tools: {
|
||||
download: true,
|
||||
selection: false,
|
||||
zoom: false,
|
||||
zoomin: false,
|
||||
zoomout: false,
|
||||
pan: false,
|
||||
reset: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
labels: labels,
|
||||
colors: [
|
||||
"#FF4560",
|
||||
"#008FFB",
|
||||
"#00E396",
|
||||
"#FEB019",
|
||||
"#FF66FF",
|
||||
"#775DD0",
|
||||
"#546E7A",
|
||||
"#26A69A",
|
||||
"#D81B60",
|
||||
"#F06292",
|
||||
"#4FC3F7",
|
||||
"#AED581",
|
||||
"#FF8A65",
|
||||
"#A1887F",
|
||||
"#E0E0E0",
|
||||
"#90A4AE",
|
||||
"#FFCA28",
|
||||
"#78909C",
|
||||
"#D4E157",
|
||||
"#F4FF81",
|
||||
],
|
||||
responsive: [
|
||||
{
|
||||
breakpoint: 480,
|
||||
options: {
|
||||
chart: {
|
||||
width: 200,
|
||||
},
|
||||
legend: {
|
||||
position: "bottom",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
tooltip: {
|
||||
y: {
|
||||
formatter: function (val) {
|
||||
return val + " tests";
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// Render del grafico
|
||||
const chart = new ApexCharts(chartContainer, options);
|
||||
chart.render();
|
||||
|
||||
// Forza un aggiornamento del grafico dopo un breve ritardo
|
||||
setTimeout(() => {
|
||||
chart.updateOptions({});
|
||||
}, 100);
|
||||
|
||||
// Genera la tabella usando la funzione esistente
|
||||
const tableHTML = generatePieTable(labels, series);
|
||||
|
||||
const tableContainer = document.querySelector(`#${tableContainerId}`);
|
||||
if (tableContainer) {
|
||||
tableContainer.innerHTML = tableHTML;
|
||||
} else {
|
||||
console.error(
|
||||
`Contenitore della tabella non trovato: #${tableContainerId}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
143
public/userarea/statkpi/js/charts/analytesFailChart.js
Normal file
143
public/userarea/statkpi/js/charts/analytesFailChart.js
Normal file
@ -0,0 +1,143 @@
|
||||
export function renderAnalytesFailChart(
|
||||
analytesData,
|
||||
containerId,
|
||||
tableContainerId,
|
||||
) {
|
||||
// Pulizia del contenitore del grafico
|
||||
const chartContainer = document.querySelector(`#${containerId}`);
|
||||
if (chartContainer) {
|
||||
chartContainer.innerHTML = "";
|
||||
} else {
|
||||
console.error(`Contenitore del grafico non trovato: #${containerId}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Validazione dei dati
|
||||
if (!Array.isArray(analytesData) || analytesData.length === 0) {
|
||||
chartContainer.innerHTML =
|
||||
'<p class="text-center text-muted">No failures to display.</p>';
|
||||
const tableContainer = document.querySelector(`#${tableContainerId}`);
|
||||
if (tableContainer) {
|
||||
tableContainer.innerHTML =
|
||||
'<p class="text-center text-muted">No failures to display.</p>';
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const labels = analytesData.map((item) => item.AnalyteName || "Unknown");
|
||||
const data = analytesData.map((item) => parseInt(item.FailCount, 10) || 0);
|
||||
|
||||
// Verifica se ci sono dati validi da visualizzare
|
||||
const hasValidData = analytesData.some((item) => item.FailCount > 0);
|
||||
if (!hasValidData) {
|
||||
chartContainer.innerHTML =
|
||||
'<p class="text-center text-muted">No failures to display.</p>';
|
||||
const tableContainer = document.querySelector(`#${tableContainerId}`);
|
||||
if (tableContainer) {
|
||||
tableContainer.innerHTML =
|
||||
'<p class="text-center text-muted">No failures to display.</p>';
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Configurazione del grafico a barre orizzontali
|
||||
const options = {
|
||||
series: [
|
||||
{
|
||||
name: "Failures",
|
||||
data: data,
|
||||
},
|
||||
],
|
||||
chart: {
|
||||
type: "bar",
|
||||
height: 400,
|
||||
toolbar: {
|
||||
show: true,
|
||||
tools: {
|
||||
download: true,
|
||||
selection: false,
|
||||
zoom: false,
|
||||
zoomin: false,
|
||||
zoomout: false,
|
||||
pan: false,
|
||||
reset: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
plotOptions: {
|
||||
bar: {
|
||||
horizontal: true,
|
||||
barHeight: "80%",
|
||||
},
|
||||
},
|
||||
dataLabels: {
|
||||
enabled: false,
|
||||
},
|
||||
xaxis: {
|
||||
categories: labels,
|
||||
title: {
|
||||
text: "Number of Failures",
|
||||
},
|
||||
},
|
||||
yaxis: {
|
||||
title: {
|
||||
text: "Analyte",
|
||||
},
|
||||
},
|
||||
colors: ["#FF4D4D"],
|
||||
fill: {
|
||||
opacity: 1,
|
||||
},
|
||||
tooltip: {
|
||||
y: {
|
||||
formatter: function (val) {
|
||||
return val + " failures";
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// Render del grafico
|
||||
const chart = new ApexCharts(chartContainer, options);
|
||||
chart.render();
|
||||
|
||||
// Genera una tabella per i dati
|
||||
const tableHTML = `
|
||||
<table class="table table-striped table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Analyte</th>
|
||||
<th>Failures</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
${analytesData
|
||||
.map(
|
||||
(item) => `
|
||||
<tr>
|
||||
<td>${item.AnalyteName || "Unknown"}</td>
|
||||
<td>${parseInt(item.FailCount, 10) || 0}</td>
|
||||
</tr>
|
||||
`,
|
||||
)
|
||||
.join("")}
|
||||
</tbody>
|
||||
</table>
|
||||
`;
|
||||
|
||||
// Riprova a trovare il contenitore della tabella con un ritardo
|
||||
const renderTable = () => {
|
||||
const tableContainer = document.querySelector(`#${tableContainerId}`);
|
||||
if (tableContainer) {
|
||||
tableContainer.innerHTML = tableHTML;
|
||||
} else {
|
||||
console.error(
|
||||
`Contenitore della tabella non trovato: #${tableContainerId}`,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
// Prova immediatamente e riprova dopo un breve ritardo
|
||||
renderTable();
|
||||
setTimeout(renderTable, 100);
|
||||
}
|
||||
91
public/userarea/statkpi/js/charts/barChart.js
Normal file
91
public/userarea/statkpi/js/charts/barChart.js
Normal file
@ -0,0 +1,91 @@
|
||||
import { generatePieTable } from "../utils/tableGenerator.js";
|
||||
|
||||
export function renderBarChart(data, containerId, tableContainerId) {
|
||||
// Pulizia del contenitore del grafico
|
||||
const chartContainer = document.querySelector(`#${containerId}`);
|
||||
if (chartContainer) {
|
||||
chartContainer.innerHTML = "";
|
||||
} else {
|
||||
console.error(`Contenitore del grafico non trovato: #${containerId}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Dati per il grafico a barre (usa gli stessi dati del grafico a torta)
|
||||
const intFailReports = parseInt(data.failReportsPie) || 0;
|
||||
const intPassReports = parseInt(data.passReportsPie) || 0;
|
||||
const intOtherReports = parseInt(data.otherReportsPie) || 0;
|
||||
|
||||
const barLabels = ["Fail", "Pass", "Others"];
|
||||
const barSeries = [intFailReports, intPassReports, intOtherReports];
|
||||
|
||||
// Configurazione del grafico a barre
|
||||
const options = {
|
||||
series: [
|
||||
{
|
||||
name: "Reports",
|
||||
data: barSeries,
|
||||
},
|
||||
],
|
||||
chart: {
|
||||
height: 350,
|
||||
type: "bar",
|
||||
toolbar: {
|
||||
show: true,
|
||||
tools: {
|
||||
download: true,
|
||||
selection: false,
|
||||
zoom: false,
|
||||
zoomin: false,
|
||||
zoomout: false,
|
||||
pan: false,
|
||||
reset: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
plotOptions: {
|
||||
bar: {
|
||||
horizontal: false,
|
||||
columnWidth: "55%",
|
||||
endingShape: "rounded",
|
||||
},
|
||||
},
|
||||
dataLabels: {
|
||||
enabled: false,
|
||||
},
|
||||
stroke: {
|
||||
show: true,
|
||||
width: 2,
|
||||
colors: ["transparent"],
|
||||
},
|
||||
xaxis: {
|
||||
categories: barLabels,
|
||||
},
|
||||
colors: ["#FF4D4D", "#28A745", "#FFA500"],
|
||||
fill: {
|
||||
opacity: 1,
|
||||
},
|
||||
tooltip: {
|
||||
y: {
|
||||
formatter: function (val) {
|
||||
return val + " reports";
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// Render del grafico
|
||||
const chart = new ApexCharts(chartContainer, options);
|
||||
chart.render();
|
||||
|
||||
// Genera la tabella e aggiungi un log
|
||||
const tableHTML = generatePieTable(barLabels, barSeries);
|
||||
|
||||
const tableContainer = document.querySelector(`#${tableContainerId}`);
|
||||
if (tableContainer) {
|
||||
tableContainer.innerHTML = tableHTML;
|
||||
} else {
|
||||
console.error(
|
||||
`Contenitore della tabella non trovato: #${tableContainerId}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
133
public/userarea/statkpi/js/charts/horizontalBarChart.js
Normal file
133
public/userarea/statkpi/js/charts/horizontalBarChart.js
Normal file
@ -0,0 +1,133 @@
|
||||
export function renderHorizontalBarChart(
|
||||
chartData,
|
||||
containerId,
|
||||
tableContainerId,
|
||||
) {
|
||||
// Pulizia del contenitore del grafico
|
||||
const chartContainer = document.querySelector(`#${containerId}`);
|
||||
if (chartContainer) {
|
||||
chartContainer.innerHTML = "";
|
||||
} else {
|
||||
console.error(`Contenitore del grafico non trovato: #${containerId}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Estrai i dati per il grafico a barre orizzontali
|
||||
const horizontalBarData = chartData || [];
|
||||
const categories = horizontalBarData.map((item) => item.groupingValue);
|
||||
const passData = horizontalBarData.map((item) => item.passCount);
|
||||
const failData = horizontalBarData.map((item) => item.failCount);
|
||||
const otherData = horizontalBarData.map((item) => item.otherCount);
|
||||
|
||||
// Configurazione del grafico a barre orizzontali
|
||||
const options = {
|
||||
series: [
|
||||
{
|
||||
name: "Pass",
|
||||
data: passData,
|
||||
},
|
||||
{
|
||||
name: "Fail",
|
||||
data: failData,
|
||||
},
|
||||
{
|
||||
name: "Others",
|
||||
data: otherData,
|
||||
},
|
||||
],
|
||||
chart: {
|
||||
type: "bar",
|
||||
height: 600,
|
||||
stacked: true,
|
||||
toolbar: {
|
||||
show: true,
|
||||
tools: {
|
||||
download: true,
|
||||
selection: false,
|
||||
zoom: false,
|
||||
zoomin: false,
|
||||
zoomout: false,
|
||||
pan: false,
|
||||
reset: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
plotOptions: {
|
||||
bar: {
|
||||
horizontal: true,
|
||||
barHeight: "80%",
|
||||
},
|
||||
},
|
||||
dataLabels: {
|
||||
enabled: false,
|
||||
},
|
||||
xaxis: {
|
||||
categories: categories,
|
||||
title: {
|
||||
text: "Number of Reports",
|
||||
},
|
||||
},
|
||||
yaxis: {
|
||||
title: {
|
||||
text: "Grouping Value",
|
||||
},
|
||||
},
|
||||
colors: ["#28A745", "#FF4D4D", "#FFA500"],
|
||||
fill: {
|
||||
opacity: 1,
|
||||
},
|
||||
tooltip: {
|
||||
y: {
|
||||
formatter: function (val) {
|
||||
return val + " reports";
|
||||
},
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
position: "top",
|
||||
horizontalAlign: "left",
|
||||
offsetX: 40,
|
||||
},
|
||||
};
|
||||
|
||||
// Render del grafico
|
||||
const chart = new ApexCharts(chartContainer, options);
|
||||
chart.render();
|
||||
|
||||
// Genera una tabella per i dati
|
||||
const tableHTML = `
|
||||
<table class="table table-striped table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Grouping Value</th>
|
||||
<th>Pass</th>
|
||||
<th>Fail</th>
|
||||
<th>Others</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
${horizontalBarData
|
||||
.map(
|
||||
(item) => `
|
||||
<tr>
|
||||
<td>${item.groupingValue}</td>
|
||||
<td>${item.passCount}</td>
|
||||
<td>${item.failCount}</td>
|
||||
<td>${item.otherCount}</td>
|
||||
</tr>
|
||||
`,
|
||||
)
|
||||
.join("")}
|
||||
</tbody>
|
||||
</table>
|
||||
`;
|
||||
|
||||
const tableContainer = document.querySelector(`#${tableContainerId}`);
|
||||
if (tableContainer) {
|
||||
tableContainer.innerHTML = tableHTML;
|
||||
} else {
|
||||
console.error(
|
||||
`Contenitore della tabella non trovato: #${tableContainerId}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
172
public/userarea/statkpi/js/charts/phaseBarChart.js
Normal file
172
public/userarea/statkpi/js/charts/phaseBarChart.js
Normal file
@ -0,0 +1,172 @@
|
||||
export function renderPhaseBarChart(chartData, containerId, tableContainerId) {
|
||||
// Pulizia del contenitore del grafico
|
||||
const chartContainer = document.querySelector(`#${containerId}`);
|
||||
if (chartContainer) {
|
||||
chartContainer.innerHTML = "";
|
||||
} else {
|
||||
console.error(`Contenitore del grafico non trovato: #${containerId}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Estrai i dati per il grafico a barre
|
||||
const phaseRatingsData = chartData || [];
|
||||
|
||||
// Validazione dei dati
|
||||
if (!Array.isArray(phaseRatingsData) || phaseRatingsData.length === 0) {
|
||||
chartContainer.innerHTML =
|
||||
'<p class="text-center text-muted">No data available for Phase Rating Distribution.</p>';
|
||||
const tableContainer = document.querySelector(`#${tableContainerId}`);
|
||||
if (tableContainer) {
|
||||
tableContainer.innerHTML =
|
||||
'<p class="text-center text-muted">No data available.</p>';
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const phases = phaseRatingsData.map((item) => item.phase || "Unknown");
|
||||
const passData = phaseRatingsData.map(
|
||||
(item) => parseInt(item.passCount) || 0,
|
||||
);
|
||||
const failData = phaseRatingsData.map(
|
||||
(item) => parseInt(item.failCount) || 0,
|
||||
);
|
||||
const otherData = phaseRatingsData.map(
|
||||
(item) => parseInt(item.otherCount) || 0,
|
||||
);
|
||||
|
||||
// Verifica se ci sono dati validi da visualizzare
|
||||
const hasValidData =
|
||||
passData.some((value) => value > 0) ||
|
||||
failData.some((value) => value > 0) ||
|
||||
otherData.some((value) => value > 0);
|
||||
if (!hasValidData) {
|
||||
chartContainer.innerHTML =
|
||||
'<p class="text-center text-muted">No ratings to display.</p>';
|
||||
const tableContainer = document.querySelector(`#${tableContainerId}`);
|
||||
if (tableContainer) {
|
||||
tableContainer.innerHTML =
|
||||
'<p class="text-center text-muted">No ratings to display.</p>';
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Configurazione del grafico a barre orizzontali
|
||||
const options = {
|
||||
series: [
|
||||
{
|
||||
name: "Pass",
|
||||
data: passData,
|
||||
},
|
||||
{
|
||||
name: "Fail",
|
||||
data: failData,
|
||||
},
|
||||
{
|
||||
name: "Others",
|
||||
data: otherData,
|
||||
},
|
||||
],
|
||||
chart: {
|
||||
type: "bar",
|
||||
height: 600,
|
||||
stacked: true,
|
||||
toolbar: {
|
||||
show: true,
|
||||
tools: {
|
||||
download: true,
|
||||
selection: false,
|
||||
zoom: false,
|
||||
zoomin: false,
|
||||
zoomout: false,
|
||||
pan: false,
|
||||
reset: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
plotOptions: {
|
||||
bar: {
|
||||
horizontal: true,
|
||||
barHeight: "80%",
|
||||
},
|
||||
},
|
||||
dataLabels: {
|
||||
enabled: false,
|
||||
},
|
||||
xaxis: {
|
||||
categories: phases,
|
||||
title: {
|
||||
text: "Number of Reports",
|
||||
},
|
||||
},
|
||||
yaxis: {
|
||||
title: {
|
||||
text: "Phase",
|
||||
},
|
||||
},
|
||||
colors: ["#28A745", "#FF4D4D", "#FFA500"],
|
||||
fill: {
|
||||
opacity: 1,
|
||||
},
|
||||
tooltip: {
|
||||
y: {
|
||||
formatter: function (val) {
|
||||
return val + " reports";
|
||||
},
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
position: "top",
|
||||
horizontalAlign: "left",
|
||||
offsetX: 40,
|
||||
},
|
||||
};
|
||||
|
||||
// Render del grafico
|
||||
const chart = new ApexCharts(chartContainer, options);
|
||||
chart.render();
|
||||
|
||||
// Genera una tabella per i dati
|
||||
const tableHTML = `
|
||||
<table class="table table-striped table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Phase</th>
|
||||
<th>Pass</th>
|
||||
<th>Fail</th>
|
||||
<th>Others</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
${phaseRatingsData
|
||||
.map(
|
||||
(item) => `
|
||||
<tr>
|
||||
<td>${item.phase || "Unknown"}</td>
|
||||
<td>${parseInt(item.passCount) || 0}</td>
|
||||
<td>${parseInt(item.failCount) || 0}</td>
|
||||
<td>${parseInt(item.otherCount) || 0}</td>
|
||||
</tr>
|
||||
`,
|
||||
)
|
||||
.join("")}
|
||||
</tbody>
|
||||
</table>
|
||||
`;
|
||||
|
||||
// Riprova a trovare il contenitore della tabella con un ritardo
|
||||
const renderTable = () => {
|
||||
const tableContainer = document.querySelector(`#${tableContainerId}`);
|
||||
if (tableContainer) {
|
||||
tableContainer.innerHTML = tableHTML;
|
||||
tableContainer.style.display = "block"; // Forza la visibilità
|
||||
} else {
|
||||
console.error(
|
||||
`Contenitore della tabella non trovato: #${tableContainerId}`,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
// Prova immediatamente e riprova dopo un breve ritardo
|
||||
renderTable();
|
||||
setTimeout(renderTable, 100);
|
||||
}
|
||||
126
public/userarea/statkpi/js/charts/phasePieChart.js
Normal file
126
public/userarea/statkpi/js/charts/phasePieChart.js
Normal file
@ -0,0 +1,126 @@
|
||||
import { generatePieTable } from "../utils/tableGenerator.js";
|
||||
|
||||
export function renderPhasePieChart(chartData, containerId, tableContainerId) {
|
||||
// Pulizia del contenitore del grafico
|
||||
const chartContainer = document.querySelector(`#${containerId}`);
|
||||
if (chartContainer) {
|
||||
chartContainer.innerHTML = "";
|
||||
} else {
|
||||
console.error(`Contenitore del grafico non trovato: #${containerId}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Estrai i dati per il grafico a torta
|
||||
const phaseData = chartData || [];
|
||||
|
||||
// Validazione dei dati
|
||||
if (!Array.isArray(phaseData) || phaseData.length === 0) {
|
||||
chartContainer.innerHTML =
|
||||
'<p class="text-center text-muted">No data available for Products Distribution by Phase.</p>';
|
||||
const tableContainer = document.querySelector(`#${tableContainerId}`);
|
||||
if (tableContainer) {
|
||||
tableContainer.innerHTML =
|
||||
'<p class="text-center text-muted">No data available.</p>';
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const labels = phaseData.map((item) => item.phase || "Unknown");
|
||||
const series = phaseData.map((item) => {
|
||||
const count = parseInt(item.totalProducts, 10);
|
||||
return isNaN(count) ? 0 : count;
|
||||
});
|
||||
|
||||
// Verifica se ci sono dati validi da visualizzare
|
||||
const hasValidData = series.some((value) => value > 0);
|
||||
|
||||
if (!hasValidData) {
|
||||
chartContainer.innerHTML =
|
||||
'<p class="text-center text-muted">No valid data to display.</p>';
|
||||
const tableContainer = document.querySelector(`#${tableContainerId}`);
|
||||
if (tableContainer) {
|
||||
tableContainer.innerHTML =
|
||||
'<p class="text-center text-muted">No valid data to display.</p>';
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Configurazione del grafico a torta
|
||||
const options = {
|
||||
series: series,
|
||||
chart: {
|
||||
type: "pie",
|
||||
height: 350,
|
||||
toolbar: {
|
||||
show: true,
|
||||
tools: {
|
||||
download: true,
|
||||
selection: false,
|
||||
zoom: false,
|
||||
zoomin: false,
|
||||
zoomout: false,
|
||||
pan: false,
|
||||
reset: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
labels: labels,
|
||||
colors: [
|
||||
"#FF4560",
|
||||
"#008FFB",
|
||||
"#00E396",
|
||||
"#FEB019",
|
||||
"#FF66FF",
|
||||
"#775DD0",
|
||||
],
|
||||
responsive: [
|
||||
{
|
||||
breakpoint: 480,
|
||||
options: {
|
||||
chart: {
|
||||
width: 200,
|
||||
},
|
||||
legend: {
|
||||
position: "bottom",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
tooltip: {
|
||||
y: {
|
||||
formatter: function (val) {
|
||||
return val + " products";
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// Render del grafico
|
||||
const chart = new ApexCharts(chartContainer, options);
|
||||
chart.render();
|
||||
|
||||
// Forza un aggiornamento del grafico dopo un breve ritardo
|
||||
setTimeout(() => {
|
||||
chart.updateOptions({});
|
||||
}, 100);
|
||||
|
||||
// Genera la tabella usando la funzione esistente
|
||||
const tableHTML = generatePieTable(labels, series);
|
||||
|
||||
// Riprova a trovare il contenitore della tabella con un ritardo
|
||||
const renderTable = () => {
|
||||
const tableContainer = document.querySelector(`#${tableContainerId}`);
|
||||
if (tableContainer) {
|
||||
tableContainer.innerHTML = tableHTML;
|
||||
tableContainer.style.display = "block"; // Forza la visibilità
|
||||
} else {
|
||||
console.error(
|
||||
`Contenitore della tabella non trovato: #${tableContainerId}`,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
// Prova immediatamente e riprova dopo un breve ritardo
|
||||
renderTable();
|
||||
setTimeout(renderTable, 100);
|
||||
}
|
||||
68
public/userarea/statkpi/js/charts/pieChart.js
Normal file
68
public/userarea/statkpi/js/charts/pieChart.js
Normal file
@ -0,0 +1,68 @@
|
||||
import { generatePieTable } from "../utils/tableGenerator.js";
|
||||
|
||||
export function renderPieChart(data, containerId, tableContainerId) {
|
||||
// Pulizia del contenitore
|
||||
document.querySelector(`#${containerId}`).innerHTML = "";
|
||||
|
||||
// Dati per il grafico a torta
|
||||
const intFailReports = parseInt(data.failReportsPie);
|
||||
const intPassReports = parseInt(data.passReportsPie);
|
||||
const intOtherReports = parseInt(data.otherReportsPie);
|
||||
|
||||
const pieLabels = ["Fail", "Pass", "Others"];
|
||||
const pieSeries = [intFailReports, intPassReports, intOtherReports];
|
||||
|
||||
// Configurazione del grafico
|
||||
const options = {
|
||||
series: pieSeries,
|
||||
chart: {
|
||||
width: "100%",
|
||||
type: "pie",
|
||||
toolbar: {
|
||||
show: true,
|
||||
tools: {
|
||||
download: true,
|
||||
selection: false,
|
||||
zoom: false,
|
||||
zoomin: false,
|
||||
zoomout: false,
|
||||
pan: false,
|
||||
reset: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
labels: pieLabels,
|
||||
colors: ["#FF4D4D", "#28A745", "#FFA500"],
|
||||
responsive: [
|
||||
{
|
||||
breakpoint: 480,
|
||||
options: {
|
||||
chart: {
|
||||
width: 250,
|
||||
},
|
||||
legend: {
|
||||
position: "bottom",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
legend: {
|
||||
position: "bottom",
|
||||
offsetY: 0,
|
||||
height: 50,
|
||||
},
|
||||
};
|
||||
|
||||
// Render del grafico
|
||||
const chart = new ApexCharts(
|
||||
document.querySelector(`#${containerId}`),
|
||||
options,
|
||||
);
|
||||
chart.render();
|
||||
|
||||
// Genera la tabella
|
||||
document.querySelector(`#${tableContainerId}`).innerHTML = generatePieTable(
|
||||
pieLabels,
|
||||
pieSeries,
|
||||
);
|
||||
}
|
||||
113
public/userarea/statkpi/js/charts/productBySupplierChart.js
Normal file
113
public/userarea/statkpi/js/charts/productBySupplierChart.js
Normal file
@ -0,0 +1,113 @@
|
||||
export function renderProductBySupplierChart(
|
||||
chartData,
|
||||
containerId,
|
||||
tableContainerId,
|
||||
) {
|
||||
// Pulizia del contenitore del grafico
|
||||
const chartContainer = document.querySelector(`#${containerId}`);
|
||||
if (chartContainer) {
|
||||
chartContainer.innerHTML = "";
|
||||
} else {
|
||||
console.error(`Contenitore del grafico non trovato: #${containerId}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Estrai i dati per il grafico
|
||||
const productBySupplier = chartData || [];
|
||||
const suppliers = productBySupplier.map((item) => item.supplier);
|
||||
const totalProducts = productBySupplier.map((item) => item.totalProducts);
|
||||
|
||||
// Configurazione del grafico a barre orizzontali
|
||||
const options = {
|
||||
series: [
|
||||
{
|
||||
name: "Total Products",
|
||||
data: totalProducts,
|
||||
},
|
||||
],
|
||||
chart: {
|
||||
type: "bar",
|
||||
height: 600,
|
||||
toolbar: {
|
||||
show: true,
|
||||
tools: {
|
||||
download: true,
|
||||
selection: false,
|
||||
zoom: false,
|
||||
zoomin: false,
|
||||
zoomout: false,
|
||||
pan: false,
|
||||
reset: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
plotOptions: {
|
||||
bar: {
|
||||
horizontal: true,
|
||||
barHeight: "80%",
|
||||
},
|
||||
},
|
||||
dataLabels: {
|
||||
enabled: true,
|
||||
},
|
||||
xaxis: {
|
||||
categories: suppliers,
|
||||
title: {
|
||||
text: "Number of Products",
|
||||
},
|
||||
},
|
||||
yaxis: {
|
||||
title: {
|
||||
text: "Supplier",
|
||||
},
|
||||
},
|
||||
colors: ["#007BFF"],
|
||||
fill: {
|
||||
opacity: 1,
|
||||
},
|
||||
tooltip: {
|
||||
y: {
|
||||
formatter: function (val) {
|
||||
return val + " products";
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// Render del grafico
|
||||
const chart = new ApexCharts(chartContainer, options);
|
||||
chart.render();
|
||||
|
||||
// Genera una tabella per i dati
|
||||
const tableHTML = `
|
||||
<table class="table table-striped table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Supplier</th>
|
||||
<th>Total Products</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
${productBySupplier
|
||||
.map(
|
||||
(item) => `
|
||||
<tr>
|
||||
<td>${item.supplier}</td>
|
||||
<td>${item.totalProducts}</td>
|
||||
</tr>
|
||||
`,
|
||||
)
|
||||
.join("")}
|
||||
</tbody>
|
||||
</table>
|
||||
`;
|
||||
|
||||
const tableContainer = document.querySelector(`#${tableContainerId}`);
|
||||
if (tableContainer) {
|
||||
tableContainer.innerHTML = tableHTML;
|
||||
} else {
|
||||
console.error(
|
||||
`Contenitore della tabella non trovato: #${tableContainerId}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
120
public/userarea/statkpi/js/charts/worstSuppliersChart.js
Normal file
120
public/userarea/statkpi/js/charts/worstSuppliersChart.js
Normal file
@ -0,0 +1,120 @@
|
||||
export function renderWorstSuppliersChart(
|
||||
chartData,
|
||||
containerId,
|
||||
tableContainerId,
|
||||
) {
|
||||
// Pulizia del contenitore del grafico
|
||||
const chartContainer = document.querySelector(`#${containerId}`);
|
||||
if (chartContainer) {
|
||||
chartContainer.innerHTML = "";
|
||||
} else {
|
||||
console.error(`Contenitore del grafico non trovato: #${containerId}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Estrai i dati per il grafico
|
||||
const worstSuppliers = chartData || [];
|
||||
const suppliers = worstSuppliers.map((item) => item.supplier);
|
||||
const failPercentages = worstSuppliers.map((item) => item.failPercentage);
|
||||
|
||||
// Configurazione del grafico a barre orizzontali
|
||||
const options = {
|
||||
series: [
|
||||
{
|
||||
name: "Fail Percentage",
|
||||
data: failPercentages,
|
||||
},
|
||||
],
|
||||
chart: {
|
||||
type: "bar",
|
||||
height: 600,
|
||||
toolbar: {
|
||||
show: true,
|
||||
tools: {
|
||||
download: true,
|
||||
selection: false,
|
||||
zoom: false,
|
||||
zoomin: false,
|
||||
zoomout: false,
|
||||
pan: false,
|
||||
reset: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
plotOptions: {
|
||||
bar: {
|
||||
horizontal: true,
|
||||
barHeight: "80%",
|
||||
},
|
||||
},
|
||||
dataLabels: {
|
||||
enabled: true,
|
||||
formatter: function (val) {
|
||||
return val.toFixed(2) + "%";
|
||||
},
|
||||
},
|
||||
xaxis: {
|
||||
categories: suppliers,
|
||||
title: {
|
||||
text: "Fail Percentage (%)",
|
||||
},
|
||||
},
|
||||
yaxis: {
|
||||
title: {
|
||||
text: "Supplier",
|
||||
},
|
||||
},
|
||||
colors: ["#FF4D4D"],
|
||||
fill: {
|
||||
opacity: 1,
|
||||
},
|
||||
tooltip: {
|
||||
y: {
|
||||
formatter: function (val) {
|
||||
return val.toFixed(2) + "%";
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// Render del grafico
|
||||
const chart = new ApexCharts(chartContainer, options);
|
||||
chart.render();
|
||||
|
||||
// Genera una tabella per i dati
|
||||
const tableHTML = `
|
||||
<table class="table table-striped table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Supplier</th>
|
||||
<th>Fail Percentage</th>
|
||||
<th>Total Reports</th>
|
||||
<th>Failed Reports</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
${worstSuppliers
|
||||
.map(
|
||||
(item) => `
|
||||
<tr>
|
||||
<td>${item.supplier}</td>
|
||||
<td>${item.failPercentage.toFixed(2)}%</td>
|
||||
<td>${item.totalReports}</td>
|
||||
<td>${item.failedReports}</td>
|
||||
</tr>
|
||||
`,
|
||||
)
|
||||
.join("")}
|
||||
</tbody>
|
||||
</table>
|
||||
`;
|
||||
|
||||
const tableContainer = document.querySelector(`#${tableContainerId}`);
|
||||
if (tableContainer) {
|
||||
tableContainer.innerHTML = tableHTML;
|
||||
} else {
|
||||
console.error(
|
||||
`Contenitore della tabella non trovato: #${tableContainerId}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
145
public/userarea/statkpi/js/charts/worsttenanalysis.js
Normal file
145
public/userarea/statkpi/js/charts/worsttenanalysis.js
Normal file
@ -0,0 +1,145 @@
|
||||
export function renderWorstTenAnalysisChart(
|
||||
analysisData,
|
||||
containerId,
|
||||
tableContainerId,
|
||||
) {
|
||||
// Pulizia del contenitore del grafico
|
||||
const chartContainer = document.querySelector(`#${containerId}`);
|
||||
if (chartContainer) {
|
||||
chartContainer.innerHTML = "";
|
||||
} else {
|
||||
console.error(`Contenitore del grafico non trovato: #${containerId}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Validazione dei dati
|
||||
if (!Array.isArray(analysisData) || analysisData.length === 0) {
|
||||
chartContainer.innerHTML =
|
||||
'<p class="text-center text-muted">No failed tests to display.</p>';
|
||||
const tableContainer = document.querySelector(`#${tableContainerId}`);
|
||||
if (tableContainer) {
|
||||
tableContainer.innerHTML =
|
||||
'<p class="text-center text-muted">No failed tests to display.</p>';
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const labels = analysisData.map((item) => item.name || "Unknown");
|
||||
const data = analysisData.map((item) => parseInt(item.failCount, 10) || 0);
|
||||
|
||||
console.log("Dati per il grafico Worst Analysis:", { labels, data });
|
||||
|
||||
// Verifica se ci sono dati validi da visualizzare
|
||||
const hasValidData = analysisData.some((item) => item.failCount > 0);
|
||||
if (!hasValidData) {
|
||||
chartContainer.innerHTML =
|
||||
'<p class="text-center text-muted">No failed tests to display.</p>';
|
||||
const tableContainer = document.querySelector(`#${tableContainerId}`);
|
||||
if (tableContainer) {
|
||||
tableContainer.innerHTML =
|
||||
'<p class="text-center text-muted">No failed tests to display.</p>';
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Configurazione del grafico a barre orizzontali
|
||||
const options = {
|
||||
series: [
|
||||
{
|
||||
name: "Failed Tests",
|
||||
data: data,
|
||||
},
|
||||
],
|
||||
chart: {
|
||||
type: "bar",
|
||||
height: 400,
|
||||
toolbar: {
|
||||
show: true,
|
||||
tools: {
|
||||
download: true,
|
||||
selection: false,
|
||||
zoom: false,
|
||||
zoomin: false,
|
||||
zoomout: false,
|
||||
pan: false,
|
||||
reset: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
plotOptions: {
|
||||
bar: {
|
||||
horizontal: true,
|
||||
barHeight: "80%",
|
||||
},
|
||||
},
|
||||
dataLabels: {
|
||||
enabled: false,
|
||||
},
|
||||
xaxis: {
|
||||
categories: labels,
|
||||
title: {
|
||||
text: "Number of Failed Tests",
|
||||
},
|
||||
},
|
||||
yaxis: {
|
||||
title: {
|
||||
text: "Analysis",
|
||||
},
|
||||
},
|
||||
colors: ["#FF4D4D"],
|
||||
fill: {
|
||||
opacity: 1,
|
||||
},
|
||||
tooltip: {
|
||||
y: {
|
||||
formatter: function (val) {
|
||||
return val + " failed tests";
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// Render del grafico
|
||||
const chart = new ApexCharts(chartContainer, options);
|
||||
chart.render();
|
||||
|
||||
// Genera una tabella per i dati
|
||||
const tableHTML = `
|
||||
<table class="table table-striped table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Analysis</th>
|
||||
<th>Failed Tests</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
${analysisData
|
||||
.map(
|
||||
(item) => `
|
||||
<tr>
|
||||
<td>${item.name || "Unknown"}</td>
|
||||
<td>${parseInt(item.failCount, 10) || 0}</td>
|
||||
</tr>
|
||||
`,
|
||||
)
|
||||
.join("")}
|
||||
</tbody>
|
||||
</table>
|
||||
`;
|
||||
|
||||
// Riprova a trovare il contenitore della tabella con un ritardo
|
||||
const renderTable = () => {
|
||||
const tableContainer = document.querySelector(`#${tableContainerId}`);
|
||||
if (tableContainer) {
|
||||
tableContainer.innerHTML = tableHTML;
|
||||
} else {
|
||||
console.error(
|
||||
`Contenitore della tabella non trovato: #${tableContainerId}`,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
// Prova immediatamente e riprova dopo un breve ritardo
|
||||
renderTable();
|
||||
setTimeout(renderTable, 100);
|
||||
}
|
||||
138
public/userarea/statkpi/js/main.js
Normal file
138
public/userarea/statkpi/js/main.js
Normal file
@ -0,0 +1,138 @@
|
||||
import { fetchData } from "./utils/ajaxUtils.js";
|
||||
import { renderPieChart } from "./charts/pieChart.js";
|
||||
import { renderBarChart } from "./charts/barChart.js";
|
||||
import { renderHorizontalBarChart } from "./charts/horizontalBarChart.js";
|
||||
import { renderWorstSuppliersChart } from "./charts/worstSuppliersChart.js";
|
||||
import { renderProductBySupplierChart } from "./charts/productBySupplierChart.js";
|
||||
import { renderAnalysisDistributionChart } from "./charts/analysisDistributionChart.js";
|
||||
import { renderWorstTenAnalysisChart } from "./charts/worsttenanalysis.js";
|
||||
import { renderAnalytesFailChart } from "./charts/analytesFailChart.js";
|
||||
import { renderPhasePieChart } from "./charts/phasePieChart.js";
|
||||
import { renderPhaseBarChart } from "./charts/phaseBarChart.js";
|
||||
|
||||
$(document).ready(function () {
|
||||
function getFilters() {
|
||||
return {
|
||||
startDate: $("#startDate").val(),
|
||||
endDate: $("#endDate").val(),
|
||||
supplier: $("#supplierFilter").val(),
|
||||
productsRefnumber: $("#productsRefnumber").val(),
|
||||
productsSeason: $("#productsSeason").val(),
|
||||
ageRange: $("#ageRange").val(),
|
||||
reportsLabName: $("#reportsLabName").val(),
|
||||
reportsTestType: $("#reportsTestType").val(),
|
||||
reportsNumberLab: $("#reportsNumberLab").val(),
|
||||
groupingField: $("#groupingField").val(),
|
||||
};
|
||||
}
|
||||
|
||||
function updateCharts() {
|
||||
const filters = getFilters();
|
||||
|
||||
// Aggiorna il titolo dinamicamente
|
||||
const groupingText = $("#groupingField option:selected").text();
|
||||
$("#dynamicChartTitle").text(
|
||||
`Rating Distribution by Group: ${groupingText}`,
|
||||
);
|
||||
|
||||
fetchData("parsedatachart.php", filters).then((data) => {
|
||||
if (data) {
|
||||
console.log("Dati ricevuti dal backend:", data); // Aggiungi log qui
|
||||
console.log("topFailingAnalysis:", data.topFailingAnalysis);
|
||||
console.log("failedAnalytes:", data.failedAnalytes);
|
||||
|
||||
// Aggiorna le card
|
||||
$("#totalProducts").text(data.totalProducts);
|
||||
$("#totalReports").text(data.totalReports);
|
||||
$("#failedReports").text(data.failedReports);
|
||||
$("#failedReportsPercent").text(
|
||||
`(${data.failedReportsPercent.toFixed(2)}%)`,
|
||||
);
|
||||
$("#totalTests").text(data.totalTests);
|
||||
$("#failedTests").text(data.failedTests);
|
||||
$("#failedTestsPercent").text(
|
||||
`(${data.failedTestsPercent.toFixed(2)}%)`,
|
||||
);
|
||||
|
||||
// Renderizza i grafici
|
||||
renderPieChart(data, "reportPieChart", "tableChart2");
|
||||
renderBarChart(data, "reportBarChart", "tableChart3");
|
||||
renderHorizontalBarChart(
|
||||
data.horizontalBarData,
|
||||
"horizontalBarChart",
|
||||
"tableHorizontalBarChart",
|
||||
);
|
||||
renderHorizontalBarChart(
|
||||
data.horizontalBarAnalysisData,
|
||||
"horizontalBarAnalysisChart",
|
||||
"tableHorizontalBarAnalysisChart",
|
||||
);
|
||||
renderWorstSuppliersChart(
|
||||
data.worstSuppliers,
|
||||
"worstSuppliersChart",
|
||||
"tableChartWorstSuppliers",
|
||||
);
|
||||
renderProductBySupplierChart(
|
||||
data.productBySupplier,
|
||||
"productBySupplierChart",
|
||||
"tableChartProductsBySupplier",
|
||||
);
|
||||
renderAnalysisDistributionChart(
|
||||
data.analysisDistribution,
|
||||
"analysisDistributionChart",
|
||||
"tableChartAnalysisDistribution",
|
||||
);
|
||||
renderWorstTenAnalysisChart(
|
||||
data.topFailingAnalysis,
|
||||
"worsttenanalysis",
|
||||
"tableChartWorst",
|
||||
);
|
||||
renderAnalytesFailChart(
|
||||
data.failedAnalytes,
|
||||
"analytesFailChart",
|
||||
"tableChartAnalytesFail",
|
||||
);
|
||||
renderPhasePieChart(
|
||||
data.phaseData,
|
||||
"phasePieChart",
|
||||
"tableChartPhasePie",
|
||||
);
|
||||
renderPhaseBarChart(
|
||||
data.phaseRatingsData,
|
||||
"phaseBarChart",
|
||||
"tableChartPhaseBar",
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function setupEventListeners() {
|
||||
$(
|
||||
"#startDate, #endDate, #supplierFilter, #productsRefnumber, #productsSeason, #ageRange, #reportsLabName, #reportsTestType, #reportsNumberLab, #groupingField",
|
||||
).on("change", updateCharts);
|
||||
$("#clearFilters").on("click", () => {
|
||||
$("#startDate").val("");
|
||||
$("#endDate").val("");
|
||||
$("#supplierFilter").val("").trigger("change");
|
||||
$("#productsRefnumber").val("").trigger("change");
|
||||
$("#productsSeason").val("").trigger("change");
|
||||
$("#ageRange").val("").trigger("change");
|
||||
$("#reportsLabName").val("").trigger("change");
|
||||
$("#reportsTestType").val("").trigger("change");
|
||||
$("#reportsNumberLab").val("").trigger("change");
|
||||
updateCharts();
|
||||
});
|
||||
|
||||
// Evento per togglare la tabella con delegazione
|
||||
$(document).on("click", ".toggle-table", function () {
|
||||
const target = $(this).data("target");
|
||||
console.log("Toggle table clicked, target:", target);
|
||||
setTimeout(() => {
|
||||
$(target).toggleClass("hidden");
|
||||
}, 200);
|
||||
});
|
||||
}
|
||||
|
||||
setupEventListeners();
|
||||
updateCharts(); // Caricamento iniziale
|
||||
});
|
||||
23
public/userarea/statkpi/js/utils/ajaxUtils.js
Normal file
23
public/userarea/statkpi/js/utils/ajaxUtils.js
Normal file
@ -0,0 +1,23 @@
|
||||
export function fetchData(url, filters) {
|
||||
return $.ajax({
|
||||
url: url,
|
||||
method: "POST",
|
||||
data: filters,
|
||||
})
|
||||
.then((response) => {
|
||||
if (!response) {
|
||||
alert("No data found.");
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return JSON.parse(response);
|
||||
} catch (e) {
|
||||
alert("Invalid data format.");
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
alert("Error retrieving data.");
|
||||
return null;
|
||||
});
|
||||
}
|
||||
24
public/userarea/statkpi/js/utils/tableGenerator.js
Normal file
24
public/userarea/statkpi/js/utils/tableGenerator.js
Normal file
@ -0,0 +1,24 @@
|
||||
export function generatePieTable(labels, series) {
|
||||
let tableHTML = `
|
||||
<table class="table table-striped table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Category</th>
|
||||
<th>Count</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
${labels
|
||||
.map(
|
||||
(label, i) => `
|
||||
<tr>
|
||||
<td>${label}</td>
|
||||
<td>${series[i]}</td>
|
||||
</tr>
|
||||
`,
|
||||
)
|
||||
.join("")}
|
||||
</tbody>
|
||||
</table>`;
|
||||
return tableHTML;
|
||||
}
|
||||
18
public/userarea/statkpi/jsinclude-statkpi.php
Normal file
18
public/userarea/statkpi/jsinclude-statkpi.php
Normal file
@ -0,0 +1,18 @@
|
||||
<script src="../assets/js/popper.min.js"></script>
|
||||
<script src="../assets/js/bootstrap.min.js"></script>
|
||||
<script src="../assets/js/modernizr.min.js"></script>
|
||||
<script src="../assets/js/detect.js"></script>
|
||||
<script src="../assets/js/fastclick.js"></script>
|
||||
<script src="../assets/js/jquery.slimscroll.js"></script>
|
||||
<script src="../assets/js/jquery.blockUI.js"></script>
|
||||
<script src="../assets/js/waves.js"></script>
|
||||
<script src="../assets/js/jquery.nicescroll.js"></script>
|
||||
<script src="../assets/js/jquery.scrollTo.min.js"></script>
|
||||
<script src="../assets/js/common_helper.js"></script>
|
||||
|
||||
<script src="../assets/plugins/chart.js/chart.min.js"></script>
|
||||
<script src="../assets/pages/dashboard.js"></script>
|
||||
|
||||
<!-- App js -->
|
||||
<script src="../assets/js/app.js"></script>
|
||||
<script src="../assets/plugins/alertify/js/alertify.js"></script>
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,7 +1,7 @@
|
||||
@if ($socialProviders)
|
||||
<?php $colSize = 12 / count($socialProviders); ?>
|
||||
<?php $colSize = 12 / count($socialProviders); ?>
|
||||
|
||||
<div class="row pb-3 pt-2">
|
||||
<div class="row pb-3 pt-2">
|
||||
@if (in_array('facebook', $socialProviders))
|
||||
<div class="col-{{ $colSize }} d-flex align-items-center justify-content-center">
|
||||
<a href="{{ url('auth/facebook/login') }}" class="btn-facebook">
|
||||
@ -25,6 +25,14 @@
|
||||
</a>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if (in_array('azure', $socialProviders))
|
||||
<div class="col-{{ $colSize }} d-flex align-items-center justify-content-center">
|
||||
<a href="{{ url('auth/azure/login') }}" style="color: #0078d4;">
|
||||
<i class="fab fa-microsoft fa-2x"></i>
|
||||
</a>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
@endif
|
||||
Loading…
x
Reference in New Issue
Block a user