adding editor
This commit is contained in:
parent
6ddb4f9f37
commit
627842bf5c
757
inbound.php
757
inbound.php
@ -1,391 +1,301 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/includes/header.php';
|
||||
require_once __DIR__ . '/m_services/MailService.php';
|
||||
|
||||
// Check if user has view permission
|
||||
if (!canView('inbound')) {
|
||||
redirect('index.php');
|
||||
}
|
||||
require_once 'includes/header.php';
|
||||
|
||||
$error = '';
|
||||
$success = '';
|
||||
$user_id = $_SESSION['user_id'];
|
||||
|
||||
// Fetch statuses
|
||||
$statuses_list = db()->query("SELECT * FROM mailbox_statuses ORDER BY id ASC")->fetchAll();
|
||||
$default_status_id = db()->query("SELECT id FROM mailbox_statuses WHERE is_default = 1 LIMIT 1")->fetchColumn() ?: 1;
|
||||
|
||||
// Function to send assignment notification
|
||||
function sendAssignmentNotification($assigned_to_id, $ref_no, $subject) {
|
||||
if (!$assigned_to_id) return;
|
||||
|
||||
$stmt = db()->prepare("SELECT full_name, email FROM users WHERE id = ?");
|
||||
$stmt->execute([$assigned_to_id]);
|
||||
$user = $stmt->fetch();
|
||||
|
||||
if ($user && !empty($user['email'])) {
|
||||
$to = $user['email'];
|
||||
$email_subject = "تنبيه: تم تعيين بريد جديد لك (رقم القيد: $ref_no)";
|
||||
$htmlBody = "
|
||||
<div dir='rtl' style='font-family: Arial, sans-serif;'>
|
||||
<h2>مرحباً " . htmlspecialchars($user['full_name']) . "</h2>
|
||||
<p>لقد تم تعيين مهمة بريد جديد لك في النظام.</p>
|
||||
<table border='1' cellpadding='10' cellspacing='0' style='border-collapse: collapse;'>
|
||||
<tr>
|
||||
<th style='background-color: #f8f9fa;'>رقم القيد</th>
|
||||
<td>" . htmlspecialchars($ref_no) . "</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th style='background-color: #f8f9fa;'>الموضوع</th>
|
||||
<td>" . htmlspecialchars($subject) . "</td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>يرجى الدخول للنظام لمتابعة المهمة.</p>
|
||||
<br>
|
||||
<p>هذا تنبيه تلقائي، يرجى عدم الرد.</p>
|
||||
</div>
|
||||
";
|
||||
MailService::sendMail($to, $email_subject, $htmlBody);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle actions
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$action = $_POST['action'] ?? '';
|
||||
|
||||
// Permission checks for POST actions
|
||||
if (($action === 'add' && !canAdd('inbound')) || ($action === 'edit' && !canEdit('inbound'))) {
|
||||
$error = 'عذراً، ليس لديك الصلاحية للقيام بهذا الإجراء';
|
||||
// Handle CRUD operations
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
|
||||
if (!canEdit('inbound') && !canAdd('inbound')) {
|
||||
$error = 'ليس لديك صلاحية للقيام بهذا الإجراء.';
|
||||
} else {
|
||||
$type = 'inbound';
|
||||
$action = $_POST['action'];
|
||||
$id = $_POST['id'] ?? 0;
|
||||
$ref_no = $_POST['ref_no'] ?? '';
|
||||
$date_registered = $_POST['date_registered'] ?? date('Y-m-d');
|
||||
$due_date = !empty($_POST['due_date']) ? $_POST['due_date'] : null;
|
||||
$due_date = $_POST['due_date'] ?? null;
|
||||
$sender = $_POST['sender'] ?? '';
|
||||
$recipient = $_POST['recipient'] ?? '';
|
||||
$subject = $_POST['subject'] ?? '';
|
||||
$description = $_POST['description'] ?? '';
|
||||
$status_id = $_POST['status_id'] ?? $default_status_id;
|
||||
$assigned_to = !empty($_POST['assigned_to']) ? $_POST['assigned_to'] : null;
|
||||
$id = $_POST['id'] ?? 0;
|
||||
$status_id = $_POST['status_id'] ?? null;
|
||||
$assigned_to = $_POST['assigned_to'] ?? null;
|
||||
|
||||
if ($ref_no && $subject) {
|
||||
$should_notify = false;
|
||||
if ($action === 'add' || $action === 'edit') {
|
||||
try {
|
||||
db()->beginTransaction();
|
||||
|
||||
if ($action === 'add') {
|
||||
if (!canAdd('inbound')) throw new Exception('ليس لديك صلاحية الإضافة.');
|
||||
$stmt = db()->prepare("INSERT INTO inbound_mail (ref_no, date_registered, due_date, sender, recipient, subject, description, status_id, assigned_to, created_by) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
|
||||
$stmt->execute([$ref_no, $date_registered, $due_date, $sender, $recipient, $subject, $description, $status_id, $assigned_to, $user_id]);
|
||||
$mail_id = db()->lastInsertId();
|
||||
|
||||
if ($assigned_to) {
|
||||
$should_notify = true;
|
||||
}
|
||||
|
||||
$_SESSION['success'] = 'تمت إضافة البريد بنجاح';
|
||||
} elseif ($action === 'edit') {
|
||||
$mail_id = $id;
|
||||
// Get previous assigned_to to check if it changed
|
||||
$stmt_old = db()->prepare("SELECT assigned_to FROM inbound_mail WHERE id = ?");
|
||||
$stmt_old->execute([$id]);
|
||||
$old_assigned_to = $stmt_old->fetchColumn();
|
||||
|
||||
$stmt = db()->prepare("UPDATE inbound_mail SET ref_no = ?, date_registered = ?, due_date = ?, sender = ?, recipient = ?, subject = ?, description = ?, status_id = ?, assigned_to = ? WHERE id = ? ");
|
||||
$stmt->execute([$ref_no, $date_registered, $due_date, $sender, $recipient, $subject, $description, $status_id, $assigned_to, $_SESSION['user_id']]);
|
||||
$id = db()->lastInsertId();
|
||||
$success = 'تم إضافة البريد الوارد بنجاح.';
|
||||
} else {
|
||||
if (!canEdit('inbound')) throw new Exception('ليس لديك صلاحية التعديل.');
|
||||
$stmt = db()->prepare("UPDATE inbound_mail SET ref_no = ?, date_registered = ?, due_date = ?, sender = ?, recipient = ?, subject = ?, description = ?, status_id = ?, assigned_to = ? WHERE id = ?");
|
||||
$stmt->execute([$ref_no, $date_registered, $due_date, $sender, $recipient, $subject, $description, $status_id, $assigned_to, $id]);
|
||||
|
||||
if ($assigned_to && $assigned_to != $old_assigned_to) {
|
||||
$should_notify = true;
|
||||
}
|
||||
|
||||
$_SESSION['success'] = 'تم تحديث البيانات بنجاح';
|
||||
$success = 'تم تحديث بيانات البريد الوارد بنجاح.';
|
||||
}
|
||||
|
||||
// Handle Attachments
|
||||
if (!empty($_FILES['attachments']['name'][0])) {
|
||||
// Handle file uploads
|
||||
if (isset($_FILES['attachments']) && !empty($_FILES['attachments']['name'][0])) {
|
||||
$upload_dir = 'uploads/attachments/';
|
||||
if (!is_dir($upload_dir)) mkdir($upload_dir, 0777, true);
|
||||
|
||||
foreach ($_FILES['attachments']['name'] as $key => $name) {
|
||||
if ($_FILES['attachments']['error'][$key] === 0) {
|
||||
$file_name = time() . '_' . basename($name);
|
||||
$target_path = $upload_dir . $file_name;
|
||||
if (move_uploaded_file($_FILES['attachments']['tmp_name'][$key], $target_path)) {
|
||||
for ($i = 0; $i < count($_FILES['attachments']['name']); $i++) {
|
||||
if ($_FILES['attachments']['error'][$i] === 0) {
|
||||
$filename = time() . '_' . $_FILES['attachments']['name'][$i];
|
||||
$filepath = $upload_dir . $filename;
|
||||
if (move_uploaded_file($_FILES['attachments']['tmp_name'][$i], $filepath)) {
|
||||
$stmt = db()->prepare("INSERT INTO inbound_attachments (mail_id, display_name, file_path, file_name, file_size) VALUES (?, ?, ?, ?, ?)");
|
||||
$stmt->execute([$mail_id, $name, $target_path, $name, $_FILES['attachments']['size'][$key]]);
|
||||
$stmt->execute([$id, $_FILES['attachments']['name'][$i], $filepath, $_FILES['attachments']['name'][$i], $_FILES['attachments']['size'][$i]]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
db()->commit();
|
||||
|
||||
// Notify after commit to avoid holding locks during email sending
|
||||
if ($should_notify) {
|
||||
sendAssignmentNotification($assigned_to, $ref_no, $subject);
|
||||
}
|
||||
|
||||
redirect('inbound.php');
|
||||
} catch (PDOException $e) {
|
||||
if (db()->inTransaction()) db()->rollBack();
|
||||
if ($e->getCode() == 23000) {
|
||||
$error = 'رقم القيد مستخدم مسبقاً';
|
||||
} else {
|
||||
$error = 'حدث خطأ: ' . $e->getMessage();
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
db()->rollBack();
|
||||
$error = 'خطأ: ' . $e->getMessage();
|
||||
}
|
||||
} elseif ($action === 'delete') {
|
||||
if (!canDelete('inbound')) {
|
||||
$error = 'ليس لديك صلاحية الحذف.';
|
||||
} else {
|
||||
$stmt = db()->prepare("DELETE FROM inbound_mail WHERE id = ?");
|
||||
$stmt->execute([$id]);
|
||||
$success = 'تم حذف البريد الوارد بنجاح.';
|
||||
}
|
||||
} else {
|
||||
$error = 'يرجى ملء الحقول المطلوبة (رقم القيد، الموضوع)';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Delete action
|
||||
if (isset($_GET['action']) && $_GET['action'] === 'delete' && isset($_GET['id'])) {
|
||||
if (!canDelete('inbound')) {
|
||||
$error = 'عذراً، ليس لديك الصلاحية لحذف السجلات';
|
||||
} else {
|
||||
$id = $_GET['id'];
|
||||
$stmt = db()->prepare("DELETE FROM inbound_mail WHERE id = ? ");
|
||||
$stmt->execute([$id]);
|
||||
$_SESSION['success'] = 'تم حذف البريد بنجاح';
|
||||
redirect('inbound.php');
|
||||
}
|
||||
}
|
||||
// Fetch stats
|
||||
$total_stmt = db()->query("SELECT COUNT(*) FROM inbound_mail");
|
||||
$total_inbound = $total_stmt->fetchColumn();
|
||||
|
||||
// Get session messages
|
||||
if (isset($_SESSION['success'])) {
|
||||
$success = $_SESSION['success'];
|
||||
unset($_SESSION['success']);
|
||||
}
|
||||
if (isset($_SESSION['error'])) {
|
||||
$error = $_SESSION['error'];
|
||||
unset($_SESSION['error']);
|
||||
}
|
||||
$pending_stmt = db()->prepare("SELECT COUNT(*) FROM inbound_mail WHERE status_id IN (SELECT id FROM mailbox_statuses WHERE is_default = 1 OR name LIKE '%قيد%')");
|
||||
$pending_stmt->execute();
|
||||
$pending_inbound = $pending_stmt->fetchColumn();
|
||||
|
||||
$search = $_GET['search'] ?? '';
|
||||
$my_tasks = isset($_GET['my_tasks']) && $_GET['my_tasks'] == 1;
|
||||
|
||||
// Pagination settings
|
||||
$limit = 10; // Items per page
|
||||
$page = isset($_GET['page']) && is_numeric($_GET['page']) ? (int)$_GET['page'] : 1;
|
||||
if ($page < 1) $page = 1;
|
||||
$offset = ($page - 1) * $limit;
|
||||
|
||||
$where_clauses = ["1=1"];
|
||||
// Search and Filter
|
||||
$where = "WHERE 1=1";
|
||||
$params = [];
|
||||
|
||||
if ($search) {
|
||||
$where_clauses[] = "(m.ref_no LIKE ? OR m.sender LIKE ? OR m.subject LIKE ?)";
|
||||
$params[] = "%$search%";
|
||||
$params[] = "%$search%";
|
||||
$params[] = "%$search%";
|
||||
if (isset($_GET['search']) && !empty($_GET['search'])) {
|
||||
$where .= " AND (m.ref_no LIKE ? OR m.subject LIKE ? OR m.sender LIKE ? OR m.recipient LIKE ?)";
|
||||
$search = "%" . $_GET['search'] . "%";
|
||||
$params = array_merge($params, [$search, $search, $search, $search]);
|
||||
}
|
||||
|
||||
if ($my_tasks) {
|
||||
$where_clauses[] = "m.assigned_to = ?";
|
||||
$params[] = $user_id;
|
||||
if (isset($_GET['status_id']) && !empty($_GET['status_id'])) {
|
||||
$where .= " AND m.status_id = ?";
|
||||
$params[] = $_GET['status_id'];
|
||||
}
|
||||
|
||||
$where_sql = implode(" AND ", $where_clauses);
|
||||
if (isset($_GET['my_tasks'])) {
|
||||
$where .= " AND m.assigned_to = ?";
|
||||
$params[] = $_SESSION['user_id'];
|
||||
}
|
||||
|
||||
// Get total records for pagination
|
||||
$count_query = "SELECT COUNT(*) FROM inbound_mail m WHERE $where_sql";
|
||||
$stmt_count = db()->prepare($count_query);
|
||||
$stmt_count->execute($params);
|
||||
$total_records = $stmt_count->fetchColumn();
|
||||
$total_pages = ceil($total_records / $limit);
|
||||
|
||||
// Fetch paginated results
|
||||
$query = "SELECT m.*, s.name as status_name, s.color as status_color, u.full_name as assigned_to_name,
|
||||
(SELECT GROUP_CONCAT(display_name SEPARATOR '|||') FROM inbound_attachments WHERE mail_id = m.id) as attachment_names
|
||||
FROM inbound_mail m
|
||||
LEFT JOIN mailbox_statuses s ON m.status_id = s.id
|
||||
LEFT JOIN users u ON m.assigned_to = u.id
|
||||
WHERE $where_sql
|
||||
ORDER BY m.created_at DESC
|
||||
LIMIT $limit OFFSET $offset";
|
||||
$where
|
||||
ORDER BY m.date_registered DESC, m.id DESC";
|
||||
|
||||
$stmt = db()->prepare($query);
|
||||
$stmt->execute($params);
|
||||
$mails = $stmt->fetchAll();
|
||||
|
||||
$users_list = db()->query("SELECT id, full_name FROM users ORDER BY full_name")->fetchAll();
|
||||
$statuses = db()->query("SELECT * FROM mailbox_statuses ORDER BY id ASC")->fetchAll();
|
||||
$users = db()->query("SELECT id, full_name, username FROM users ORDER BY full_name ASC")->fetchAll();
|
||||
$default_status_id = db()->query("SELECT id FROM mailbox_statuses WHERE is_default = 1 LIMIT 1")->fetchColumn() ?: ($statuses[0]['id'] ?? null);
|
||||
|
||||
// Handle Deep Link for Edit
|
||||
$deepLinkData = null;
|
||||
if (isset($_GET['action']) && $_GET['action'] === 'edit' && isset($_GET['id'])) {
|
||||
if (canEdit('inbound')) {
|
||||
$stmt = db()->prepare("SELECT m.*, (SELECT GROUP_CONCAT(display_name SEPARATOR '|||') FROM inbound_attachments WHERE mail_id = m.id) as attachment_names FROM inbound_mail m WHERE m.id = ? ");
|
||||
$stmt->execute([$_GET['id']]);
|
||||
$deepLinkData = $stmt->fetch();
|
||||
}
|
||||
}
|
||||
|
||||
function getStatusBadgeInList($mail) {
|
||||
$status_name = $mail['status_name'] ?? 'غير معروف';
|
||||
$status_color = $mail['status_color'] ?? '#6c757d';
|
||||
|
||||
// Translation for default statuses
|
||||
$display_name = $status_name;
|
||||
if ($status_name == 'received') $display_name = 'تم الاستلام';
|
||||
if ($status_name == 'in_progress') $display_name = 'قيد المعالجة';
|
||||
if ($status_name == 'closed') $display_name = 'مكتمل';
|
||||
|
||||
return '<span class="badge" style="background-color: ' . $status_color . ';">' . htmlspecialchars($display_name) . '</span>';
|
||||
if (isset($_GET['id'])) {
|
||||
$dlStmt = db()->prepare("SELECT m.*, (SELECT GROUP_CONCAT(display_name SEPARATOR '|||') FROM inbound_attachments WHERE mail_id = m.id) as attachment_names FROM inbound_mail m WHERE m.id = ?");
|
||||
$dlStmt->execute([$_GET['id']]);
|
||||
$deepLinkData = $dlStmt->fetch();
|
||||
}
|
||||
?>
|
||||
|
||||
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
|
||||
<h1 class="h2">البريد الوارد</h1>
|
||||
<?php if (canAdd('inbound')): ?>
|
||||
<button type="button" class="btn btn-primary shadow-sm" onclick="openMailModal('add')">
|
||||
<i class="fas fa-plus-circle me-1"></i> إضافة جديد
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php if ($success): ?>
|
||||
<div class="alert alert-success alert-dismissible fade show" role="alert">
|
||||
<?= $success ?>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($error): ?>
|
||||
<div class="alert alert-danger alert-dismissible fade show" role="alert">
|
||||
<?= $error ?>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="card shadow-sm border-0 mb-4">
|
||||
<div class="card-header bg-white py-3">
|
||||
<form class="row g-3 align-items-center">
|
||||
<div class="col-md-4">
|
||||
<input type="text" name="search" class="form-control" placeholder="بحث برقم القيد أو الموضوع أو المرسل..." value="<?= htmlspecialchars($search) ?>">
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="form-check form-switch mt-1">
|
||||
<input class="form-check-input" type="checkbox" name="my_tasks" id="myTasksSwitch" value="1" <?= $my_tasks ? 'checked' : '' ?> onchange="this.form.submit()">
|
||||
<label class="form-check-label fw-bold" for="myTasksSwitch">مهامي فقط</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<button type="submit" class="btn btn-secondary px-4">بحث</button>
|
||||
</div>
|
||||
<?php if ($search || $my_tasks): ?>
|
||||
<div class="col-auto">
|
||||
<a href="inbound.php" class="btn btn-link text-decoration-none">إلغاء التصفية</a>
|
||||
</div>
|
||||
<div class="container-fluid py-4">
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-8">
|
||||
<h2 class="fw-bold mb-1"><i class="fas fa-download text-primary me-2"></i> البريد الوارد</h2>
|
||||
<p class="text-muted">إدارة جميع المراسلات الواردة والمهام المسندة.</p>
|
||||
</div>
|
||||
<div class="col-md-4 text-md-end d-flex align-items-center justify-content-md-end gap-2">
|
||||
<?php if (canAdd('inbound')): ?>
|
||||
<button class="btn btn-primary px-4 py-2" onclick="openMailModal('add')">
|
||||
<i class="fas fa-plus me-1"></i> إضافة بريد جديد
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body p-0">
|
||||
|
||||
<!-- Stats Cards -->
|
||||
<div class="row g-3 mb-4">
|
||||
<div class="col-md-3">
|
||||
<div class="card border-0 shadow-sm h-100">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-center mb-3">
|
||||
<div class="rounded-circle bg-primary bg-opacity-10 p-3 me-3">
|
||||
<i class="fas fa-inbox text-primary fa-lg"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h6 class="card-subtitle text-muted mb-1 small">إجمالي الوارد</h6>
|
||||
<h3 class="card-title mb-0 fw-bold"><?= $total_inbound ?></h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="card border-0 shadow-sm h-100">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-center mb-3">
|
||||
<div class="rounded-circle bg-warning bg-opacity-10 p-3 me-3">
|
||||
<i class="fas fa-clock text-warning fa-lg"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h6 class="card-subtitle text-muted mb-1 small">قيد المعالجة</h6>
|
||||
<h3 class="card-title mb-0 fw-bold"><?= $pending_inbound ?></h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if ($error): ?>
|
||||
<div class="alert alert-danger shadow-sm border-0 mb-4"><?= $error ?></div>
|
||||
<?php endif; ?>
|
||||
<?php if ($success): ?>
|
||||
<div class="alert alert-success shadow-sm border-0 mb-4"><?= $success ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- Filter Bar -->
|
||||
<div class="card border-0 shadow-sm mb-4">
|
||||
<div class="card-body p-3">
|
||||
<form method="GET" class="row g-2 align-items-center">
|
||||
<div class="col-md-4">
|
||||
<div class="input-group">
|
||||
<span class="input-group-text bg-white border-end-0"><i class="fas fa-search text-muted"></i></span>
|
||||
<input type="text" name="search" class="form-control border-start-0" placeholder="بحث برقم القيد، الموضوع، أو المرسل..." value="<?= htmlspecialchars($_GET['search'] ?? '') ?>">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<select name="status_id" class="form-select" onchange="this.form.submit()">
|
||||
<option value="">جميع الحالات</option>
|
||||
<?php foreach ($statuses as $status): ?>
|
||||
<option value="<?= $status['id'] ?>" <?= (isset($_GET['status_id']) && $_GET['status_id'] == $status['id']) ? 'selected' : '' ?>><?= $status['name'] ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="form-check form-switch mt-1">
|
||||
<input class="form-check-input" type="checkbox" name="my_tasks" id="myTasks" <?= isset($_GET['my_tasks']) ? 'checked' : '' ?> onchange="this.form.submit()">
|
||||
<label class="form-check-label ms-2" for="myTasks">مهامي فقط</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-2 text-end">
|
||||
<button type="submit" class="btn btn-light w-100">تصفية</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Mails Table -->
|
||||
<div class="card border-0 shadow-sm overflow-hidden">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover align-middle mb-0">
|
||||
<thead class="bg-light">
|
||||
<tr>
|
||||
<th class="ps-4">رقم القيد</th>
|
||||
<th>التاريخ</th>
|
||||
<th>الموعد النهائي</th>
|
||||
<th>الموضوع</th>
|
||||
<th>المرسل</th>
|
||||
<th>المرفقات</th>
|
||||
<th>المسؤول</th>
|
||||
<th>الجهة المرسلة</th>
|
||||
<th>الحالة</th>
|
||||
<th class="pe-4 text-center">الإجراءات</th>
|
||||
<th>المسؤول</th>
|
||||
<th class="text-center pe-4">الإجراءات</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php if ($mails): foreach ($mails as $mail): ?>
|
||||
<?php if (empty($mails)): ?>
|
||||
<tr>
|
||||
<td class="ps-4 fw-bold text-primary"><?= $mail['ref_no'] ?></td>
|
||||
<td><?= $mail['date_registered'] ?></td>
|
||||
<td>
|
||||
<?php if ($mail['due_date']): ?>
|
||||
<span class="<?= (strtotime($mail['due_date']) < time() && $mail['status_name'] != 'closed') ? 'text-danger fw-bold' : '' ?>">
|
||||
<?= $mail['due_date'] ?>
|
||||
<?php if (strtotime($mail['due_date']) < time() && $mail['status_name'] != 'closed'): ?>
|
||||
<i class="fas fa-exclamation-triangle ms-1"></i>
|
||||
<?php endif; ?>
|
||||
</span>
|
||||
<?php else: ?>
|
||||
<span class="text-muted">-</span>
|
||||
<?php endif; ?>
|
||||
<td colspan="7" class="text-center py-5 text-muted">
|
||||
<i class="fas fa-inbox fa-3x mb-3 opacity-20"></i>
|
||||
<p>لا يوجد بريد وارد حالياً.</p>
|
||||
</td>
|
||||
<td><?= htmlspecialchars($mail['subject']) ?></td>
|
||||
<td><?= htmlspecialchars($mail['sender']) ?></td>
|
||||
<td>
|
||||
<?php if (!empty($mail['attachment_names'])): ?>
|
||||
<small class="text-muted"><i class="fas fa-paperclip me-1"></i> <?= htmlspecialchars(str_replace('|||', ', ', $mail['attachment_names'])) ?></small>
|
||||
<?php else: ?>
|
||||
<span class="text-muted">-</span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php if ($mail['assigned_to_name']): ?>
|
||||
<span class="text-nowrap"><i class="fas fa-user-tag me-1 text-muted"></i> <?= htmlspecialchars($mail['assigned_to_name']) ?></span>
|
||||
<?php else: ?>
|
||||
<span class="text-muted">غير معين</span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td><?= getStatusBadgeInList($mail) ?></td>
|
||||
<td class="pe-4 text-center">
|
||||
<a href="view_mail.php?id=<?= $mail['id'] ?>" class="btn btn-sm btn-outline-info" title="عرض التفاصيل"><i class="fas fa-eye"></i></a>
|
||||
|
||||
<?php if (canEdit('inbound')): ?>
|
||||
<button type="button" class="btn btn-sm btn-outline-primary"
|
||||
onclick='openMailModal("edit", <?= json_encode($mail) ?>)' title="تعديل">
|
||||
<i class="fas fa-edit"></i>
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (canDelete('inbound')): ?>
|
||||
<a href="javascript:void(0)" onclick="confirmDelete(<?= $mail['id'] ?>)" class="btn btn-sm btn-outline-danger" title="حذف"><i class="fas fa-trash"></i></a>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; else: ?>
|
||||
<tr>
|
||||
<td colspan="9" class="text-center py-4 text-muted">لا يوجد بريد وارد مسجل حالياً</td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
<?php foreach ($mails as $mail): ?>
|
||||
<tr>
|
||||
<td class="ps-4"><span class="fw-bold text-primary"><?= htmlspecialchars($mail['ref_no']) ?></span></td>
|
||||
<td><?= date('Y-m-d', strtotime($mail['date_registered'])) ?></td>
|
||||
<td>
|
||||
<div class="fw-semibold text-truncate" style="max-width: 250px;"><?= htmlspecialchars($mail['subject']) ?></div>
|
||||
<?php if ($mail['attachment_names']): ?>
|
||||
<span class="badge bg-light text-muted fw-normal" style="font-size: 0.65rem;">
|
||||
<i class="fas fa-paperclip me-1"></i> <?= count(explode('|||', $mail['attachment_names'])) ?> مرفقات
|
||||
</span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td><?= htmlspecialchars($mail['sender']) ?></td>
|
||||
<td>
|
||||
<span class="badge rounded-pill" style="background-color: <?= $mail['status_color'] ?>20; color: <?= $mail['status_color'] ?>;">
|
||||
<i class="fas fa-circle me-1 small"></i> <?= htmlspecialchars($mail['status_name']) ?>
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="rounded-circle bg-light d-flex align-items-center justify-content-center me-2" style="width: 24px; height: 24px;">
|
||||
<i class="fas fa-user-circle text-muted small"></i>
|
||||
</div>
|
||||
<span class="small"><?= htmlspecialchars($mail['assigned_to_name'] ?: 'غير محدد') ?></span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="text-center pe-4">
|
||||
<div class="btn-group shadow-sm rounded">
|
||||
<a href="view_mail.php?id=<?= $mail['id'] ?>&type=inbound" class="btn btn-sm btn-white text-primary border" title="عرض">
|
||||
<i class="fas fa-eye"></i>
|
||||
</a>
|
||||
<?php if (canEdit('inbound')): ?>
|
||||
<button class="btn btn-sm btn-white text-warning border" onclick='openMailModal("edit", <?= json_encode($mail) ?>)' title="تعديل">
|
||||
<i class="fas fa-edit"></i>
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
<?php if (canDelete('inbound')): ?>
|
||||
<form method="POST" class="d-inline" onsubmit="return confirm('هل أنت متأكد من حذف هذا البريد؟');">
|
||||
<input type="hidden" name="action" value="delete">
|
||||
<input type="hidden" name="id" value="<?= $mail['id'] ?>">
|
||||
<button type="submit" class="btn btn-sm btn-white text-danger border rounded-0" title="حذف">
|
||||
<i class="fas fa-trash"></i>
|
||||
</button>
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<?php if ($total_pages > 1): ?>
|
||||
<div class="card-footer bg-white border-0 py-3">
|
||||
<nav aria-label="Page navigation">
|
||||
<ul class="pagination justify-content-center mb-0">
|
||||
<li class="page-item <?= ($page <= 1) ? 'disabled' : '' ?>">
|
||||
<a class="page-link" href="?page=<?= $page - 1 ?><?= $search ? '&search='.urlencode($search) : '' ?><?= $my_tasks ? '&my_tasks=1' : '' ?>" aria-label="Previous">
|
||||
<span aria-hidden="true">«</span>
|
||||
</a>
|
||||
</li>
|
||||
<?php for ($i = 1; $i <= $total_pages; $i++): ?>
|
||||
<li class="page-item <?= ($page == $i) ? 'active' : '' ?>">
|
||||
<a class="page-link" href="?page=<?= $i ?><?= $search ? '&search='.urlencode($search) : '' ?><?= $my_tasks ? '&my_tasks=1' : '' ?>"><?= $i ?></a>
|
||||
</li>
|
||||
<?php endfor; ?>
|
||||
<li class="page-item <?= ($page >= $total_pages) ? 'disabled' : '' ?>">
|
||||
<a class="page-link" href="?page=<?= $page + 1 ?><?= $search ? '&search='.urlencode($search) : '' ?><?= $my_tasks ? '&my_tasks=1' : '' ?>" aria-label="Next">
|
||||
<span aria-hidden="true">»</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php if (canAdd('inbound') || canEdit('inbound')): ?>
|
||||
<!-- Mail Modal -->
|
||||
<!-- Add/Edit Modal -->
|
||||
<div class="modal fade" id="mailModal" tabindex="-1" aria-labelledby="mailModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content border-0 shadow">
|
||||
<div class="modal-header bg-primary text-white">
|
||||
<h5 class="modal-title fw-bold" id="mailModalLabel">إضافة بريد وارد جديد</h5>
|
||||
<div class="modal-header bg-primary text-white py-3">
|
||||
<h5 class="modal-title fw-bold" id="mailModalLabel">بريد وارد جديد</h5>
|
||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<form id="mailForm" method="POST" enctype="multipart/form-data">
|
||||
@ -394,66 +304,63 @@ function getStatusBadgeInList($mail) {
|
||||
<input type="hidden" name="id" id="modalId" value="0">
|
||||
|
||||
<div class="row g-3">
|
||||
<div class="col-md-4">
|
||||
<label class="form-label fw-bold">رقم القيد <span class="text-danger">*</span></label>
|
||||
<input type="text" name="ref_no" id="modalRefNo" class="form-control" required readonly>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label small fw-bold">رقم القيد</label>
|
||||
<input type="text" name="ref_no" id="modalRefNo" class="form-control" readonly required>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label class="form-label fw-bold">تاريخ التسجيل</label>
|
||||
<input type="date" name="date_registered" id="modalDateRegistered" class="form-control">
|
||||
<div class="col-md-6">
|
||||
<label class="form-label small fw-bold">تاريخ التسجيل</label>
|
||||
<input type="date" name="date_registered" id="modalDateRegistered" class="form-control" required>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label class="form-label fw-bold">الموعد النهائي</label>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label small fw-bold">الجهة المرسلة</label>
|
||||
<input type="text" name="sender" id="modalSender" class="form-control" required placeholder="مثال: وزارة العدل">
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label small fw-bold">الجهة المستلمة (الداخلية)</label>
|
||||
<input type="text" name="recipient" id="modalRecipient" class="form-control" required placeholder="مثال: مكتب المدير العام">
|
||||
</div>
|
||||
<div class="col-md-12">
|
||||
<label class="form-label small fw-bold">الموضوع</label>
|
||||
<input type="text" name="subject" id="modalSubject" class="form-control" required>
|
||||
</div>
|
||||
<div class="col-md-12">
|
||||
<label class="form-label small fw-bold">الوصف والملاحظات</label>
|
||||
<textarea name="description" id="modalDescription" class="form-control" rows="5"></textarea>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label small fw-bold">تاريخ الاستحقاق (اختياري)</label>
|
||||
<input type="date" name="due_date" id="modalDueDate" class="form-control">
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label fw-bold">المرسل</label>
|
||||
<input type="text" name="sender" id="modalSender" class="form-control">
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label fw-bold">المستلم الداخلي (القسم/الموظف)</label>
|
||||
<input type="text" name="recipient" id="modalRecipient" class="form-control">
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<label class="form-label fw-bold">الموضوع <span class="text-danger">*</span></label>
|
||||
<input type="text" name="subject" id="modalSubject" class="form-control" required>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<label class="form-label fw-bold">الوصف / ملاحظات</label>
|
||||
<textarea name="description" id="modalDescription" class="form-control" rows="5"></textarea>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<label class="form-label fw-bold">المرفقات</label>
|
||||
<input type="file" name="attachments[]" class="form-control" multiple>
|
||||
<div id="modalExistingAttachments" class="mt-2"></div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label fw-bold">الحالة</label>
|
||||
<select name="status_id" id="modalStatusId" class="form-select">
|
||||
<?php foreach ($statuses_list as $s): ?>
|
||||
<?php
|
||||
$d_name = $s['name'];
|
||||
if ($d_name == 'received') $d_name = 'تم الاستلام';
|
||||
if ($d_name == 'in_progress') $d_name = 'قيد المعالجة';
|
||||
if ($d_name == 'closed') $d_name = 'مكتمل / مغلق';
|
||||
?>
|
||||
<option value="<?= $s['id'] ?>"><?= htmlspecialchars($d_name) ?></option>
|
||||
<label class="form-label small fw-bold">الحالة</label>
|
||||
<select name="status_id" id="modalStatusId" class="form-select" required>
|
||||
<?php foreach ($statuses as $status): ?>
|
||||
<option value="<?= $status['id'] ?>"><?= $status['name'] ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label fw-bold">الموظف المسؤول</label>
|
||||
<div class="col-md-12">
|
||||
<label class="form-label small fw-bold">إسناد المهمة إلى</label>
|
||||
<select name="assigned_to" id="modalAssignedTo" class="form-select">
|
||||
<option value="">-- اختر موظف --</option>
|
||||
<?php foreach ($users_list as $u): ?>
|
||||
<option value="<?= $u['id'] ?>"><?= htmlspecialchars($u['full_name']) ?></option>
|
||||
<option value="">--- اختر مستخدم ---</option>
|
||||
<?php foreach ($users as $user): ?>
|
||||
<option value="<?= $user['id'] ?>"><?= htmlspecialchars($user['full_name'] ?: $user['username']) ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-12 mt-4">
|
||||
<div class="bg-light p-3 rounded">
|
||||
<label class="form-label small fw-bold mb-2 d-block">المرفقات</label>
|
||||
<input type="file" name="attachments[]" id="modalAttachmentsInput" class="form-control" multiple>
|
||||
<div id="modalExistingAttachments" class="mt-2"></div>
|
||||
<div id="modalSelectedAttachments" class="mt-1"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer bg-light">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">إلغاء</button>
|
||||
<div class="modal-footer bg-light border-0">
|
||||
<button type="button" class="btn btn-white border px-4" data-bs-dismiss="modal">إلغاء</button>
|
||||
<button type="submit" class="btn btn-primary px-4">حفظ البيانات</button>
|
||||
</div>
|
||||
</form>
|
||||
@ -461,26 +368,53 @@ function getStatusBadgeInList($mail) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
/* Custom Table Styles */
|
||||
.table thead th {
|
||||
font-size: 0.75rem;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05rem;
|
||||
font-weight: 700;
|
||||
color: #6c757d;
|
||||
border-top: none;
|
||||
padding: 1rem 0.5rem;
|
||||
}
|
||||
.btn-white {
|
||||
background-color: #fff;
|
||||
color: #333;
|
||||
}
|
||||
.btn-white:hover {
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
.badge {
|
||||
padding: 0.5em 0.8em;
|
||||
font-weight: 500;
|
||||
}
|
||||
.input-group-text {
|
||||
color: #adb5bd;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
let descriptionEditor;
|
||||
let mailModal;
|
||||
|
||||
function initEditors() {
|
||||
if (typeof ClassicEditor === 'undefined') {
|
||||
console.error('CKEditor not loaded');
|
||||
if (typeof tinymce === 'undefined') {
|
||||
console.error('TinyMCE not loaded');
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
const config = {
|
||||
return tinymce.init({
|
||||
selector: '#modalDescription',
|
||||
language: 'ar',
|
||||
toolbar: ['heading', '|', 'bold', 'italic', 'link', 'bulletedList', 'numberedList', 'undo', 'redo']
|
||||
};
|
||||
|
||||
return ClassicEditor.create(document.querySelector('#modalDescription'), config)
|
||||
.then(editor => { descriptionEditor = editor; })
|
||||
.catch(err => {
|
||||
console.error('CKEditor Init Error:', err);
|
||||
});
|
||||
directionality: 'rtl',
|
||||
height: 300,
|
||||
plugins: 'advlist autolink lists link image charmap preview anchor searchreplace visualblocks code fullscreen insertdatetime media table help wordcount',
|
||||
toolbar: 'undo redo | fontfamily fontsize | bold italic underline strikethrough | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | removeformat | help',
|
||||
font_size_formats: '8pt 10pt 12pt 14pt 18pt 24pt 36pt',
|
||||
promotion: false,
|
||||
branding: false
|
||||
});
|
||||
}
|
||||
|
||||
function openMailModal(action, data = null) {
|
||||
@ -498,6 +432,8 @@ function openMailModal(action, data = null) {
|
||||
const modalAction = document.getElementById('modalAction');
|
||||
const modalId = document.getElementById('modalId');
|
||||
const existingAttachmentsDiv = document.getElementById('modalExistingAttachments');
|
||||
const selectedAttachmentsDiv = document.getElementById('modalSelectedAttachments');
|
||||
const attachmentsInput = document.getElementById('modalAttachmentsInput');
|
||||
|
||||
const fields = {
|
||||
ref_no: document.getElementById('modalRefNo'),
|
||||
@ -512,6 +448,8 @@ function openMailModal(action, data = null) {
|
||||
|
||||
modalAction.value = action;
|
||||
existingAttachmentsDiv.innerHTML = '';
|
||||
selectedAttachmentsDiv.innerHTML = '';
|
||||
if (attachmentsInput) attachmentsInput.value = '';
|
||||
|
||||
if (action === 'add') {
|
||||
label.textContent = 'إضافة بريد وارد جديد';
|
||||
@ -525,8 +463,11 @@ function openMailModal(action, data = null) {
|
||||
}
|
||||
});
|
||||
|
||||
if (descriptionEditor) descriptionEditor.setData('');
|
||||
else document.getElementById('modalDescription').value = '';
|
||||
if (typeof tinymce !== 'undefined' && tinymce.get('modalDescription')) {
|
||||
tinymce.get('modalDescription').setContent('');
|
||||
} else {
|
||||
document.getElementById('modalDescription').value = '';
|
||||
}
|
||||
} else {
|
||||
label.textContent = 'تعديل البريد الوارد';
|
||||
modalId.value = data.id;
|
||||
@ -534,8 +475,11 @@ function openMailModal(action, data = null) {
|
||||
if (fields[key]) fields[key].value = data[key] || '';
|
||||
});
|
||||
|
||||
if (descriptionEditor) descriptionEditor.setData(data.description || '');
|
||||
else document.getElementById('modalDescription').value = data.description || '';
|
||||
if (typeof tinymce !== 'undefined' && tinymce.get('modalDescription')) {
|
||||
tinymce.get('modalDescription').setContent(data.description || '');
|
||||
} else {
|
||||
document.getElementById('modalDescription').value = data.description || '';
|
||||
}
|
||||
|
||||
// Display existing attachments
|
||||
if (data.attachment_names) {
|
||||
@ -557,68 +501,37 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
<?php if ($deepLinkData): ?>
|
||||
openMailModal('edit', <?= json_encode($deepLinkData) ?>);
|
||||
<?php elseif ($error && isset($_POST['action'])): ?>
|
||||
const errorData = <?= json_encode([
|
||||
'id' => $_POST['id'] ?? 0,
|
||||
'ref_no' => $_POST['ref_no'] ?? '',
|
||||
'date_registered' => $_POST['date_registered'] ?? date('Y-m-d'),
|
||||
'due_date' => $_POST['due_date'] ?? '',
|
||||
'sender' => $_POST['sender'] ?? '',
|
||||
'recipient' => $_POST['recipient'] ?? '',
|
||||
'subject' => $_POST['subject'] ?? '',
|
||||
'description' => $_POST['description'] ?? '',
|
||||
'status_id' => $_POST['status_id'] ?? $default_status_id,
|
||||
'assigned_to' => $_POST['assigned_to'] ?? '',
|
||||
'attachment_names' => $_POST['attachment_names'] ?? ''
|
||||
]) ?>;
|
||||
openMailModal('<?= $_POST['action'] ?>', errorData);
|
||||
<?php elseif (isset($_GET['action']) && $_GET['action'] === 'add'): ?>
|
||||
openMailModal('add');
|
||||
const errorData = <?= json_encode($_POST) ?>;
|
||||
openMailModal(errorData.action, errorData);
|
||||
<?php endif; ?>
|
||||
});
|
||||
|
||||
// Handle file selection display
|
||||
const attachmentsInput = document.getElementById('modalAttachmentsInput');
|
||||
if (attachmentsInput) {
|
||||
attachmentsInput.addEventListener('change', function() {
|
||||
const fileList = this.files;
|
||||
const selectedAttachmentsDiv = document.getElementById('modalSelectedAttachments');
|
||||
selectedAttachmentsDiv.innerHTML = '';
|
||||
|
||||
if (fileList.length > 0) {
|
||||
let html = '<div class="mt-2"><p class="mb-1 fw-bold small text-primary">المرفقات المختارة للرفع:</p><ul class="list-unstyled small">';
|
||||
for (let i = 0; i < fileList.length; i++) {
|
||||
const fileSize = (fileList[i].size / 1024).toFixed(1);
|
||||
html += `<li><i class="fas fa-file-upload me-1 text-primary"></i> ${fileList[i].name} <span class="text-muted">(${fileSize} KB)</span></li>`;
|
||||
}
|
||||
html += '</ul></div>';
|
||||
selectedAttachmentsDiv.innerHTML = html;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
document.getElementById('mailForm').addEventListener('submit', function() {
|
||||
if (descriptionEditor) descriptionEditor.updateSourceElement();
|
||||
if (typeof tinymce !== 'undefined') {
|
||||
tinymce.triggerSave();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function confirmDelete(id) {
|
||||
if (typeof Swal === 'undefined') {
|
||||
if (confirm('هل أنت متأكد من الحذف؟')) {
|
||||
window.location.href = 'inbound.php?action=delete&id=' + id;
|
||||
}
|
||||
return;
|
||||
}
|
||||
Swal.fire({
|
||||
title: 'هل أنت متأكد؟',
|
||||
text: "لا يمكن التراجع عن عملية الحذف!",
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonColor: '#d33',
|
||||
cancelButtonColor: '#3085d6',
|
||||
confirmButtonText: 'نعم، احذف!',
|
||||
cancelButtonText: 'إلغاء'
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
window.location.href = 'inbound.php?action=delete&id=' + id;
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
<?php endif; ?>
|
||||
|
||||
<style>
|
||||
.ck-editor__editable_inline {
|
||||
min-height: 250px;
|
||||
direction: rtl;
|
||||
text-align: right;
|
||||
}
|
||||
.modal-content {
|
||||
border-radius: 15px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.modal-header.bg-primary {
|
||||
background-color: #0d6efd !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
<?php require_once __DIR__ . '/includes/footer.php'; ?>
|
||||
<?php require_once 'includes/footer.php'; ?>
|
||||
@ -36,12 +36,16 @@
|
||||
.footer .border-start {
|
||||
border-color: rgba(0,0,0,0.1) !important;
|
||||
}
|
||||
/* TinyMCE Fixes for Bootstrap Modals */
|
||||
.tox-tinymce-aux {
|
||||
z-index: 9999 !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- Bootstrap Bundle -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<!-- CKEditor -->
|
||||
<script src="https://cdn.ckeditor.com/ckeditor5/40.0.0/classic/ckeditor.js"></script>
|
||||
<!-- TinyMCE Rich Text Editor -->
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/tinymce/6.8.2/tinymce.min.js"></script>
|
||||
<!-- SweetAlert2 -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
||||
<!-- Main App JS -->
|
||||
|
||||
@ -305,7 +305,8 @@ function getStatusBadgeInternal($mail) {
|
||||
</div>
|
||||
<div class="col-md-12">
|
||||
<label class="form-label fw-bold">المرفقات</label>
|
||||
<input type="file" name="attachments[]" class="form-control border-2" multiple>
|
||||
<input type="file" name="attachments[]" id="composeAttachmentsInput" class="form-control border-2" multiple>
|
||||
<div id="composeSelectedAttachments" class="mt-2"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -319,30 +320,58 @@ function getStatusBadgeInternal($mail) {
|
||||
</div>
|
||||
|
||||
<script>
|
||||
let composeEditor;
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
if (typeof ClassicEditor !== 'undefined') {
|
||||
ClassicEditor
|
||||
.create(document.querySelector('#composeEditor'), {
|
||||
language: 'ar',
|
||||
toolbar: ['heading', '|', 'bold', 'italic', 'link', 'bulletedList', 'numberedList', 'blockQuote', 'undo', 'redo'],
|
||||
direction: 'rtl'
|
||||
})
|
||||
.then(editor => {
|
||||
composeEditor = editor;
|
||||
// Force RTL style on editable area
|
||||
editor.ui.view.editable.element.style.direction = 'rtl';
|
||||
editor.ui.view.editable.element.style.textAlign = 'right';
|
||||
})
|
||||
.catch(error => {
|
||||
console.error(error);
|
||||
});
|
||||
if (typeof tinymce !== 'undefined') {
|
||||
tinymce.init({
|
||||
selector: '#composeEditor',
|
||||
language: 'ar',
|
||||
directionality: 'rtl',
|
||||
height: 400,
|
||||
plugins: 'advlist autolink lists link image charmap preview anchor searchreplace visualblocks code fullscreen insertdatetime media table help wordcount',
|
||||
toolbar: 'undo redo | fontfamily fontsize | bold italic underline strikethrough | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | removeformat | help',
|
||||
font_size_formats: '8pt 10pt 12pt 14pt 18pt 24pt 36pt',
|
||||
promotion: false,
|
||||
branding: false
|
||||
});
|
||||
}
|
||||
|
||||
document.getElementById('composeForm').addEventListener('submit', function() {
|
||||
if (composeEditor) composeEditor.updateSourceElement();
|
||||
if (typeof tinymce !== 'undefined') {
|
||||
tinymce.triggerSave();
|
||||
}
|
||||
});
|
||||
|
||||
// Handle file selection display
|
||||
const attachmentsInput = document.getElementById('composeAttachmentsInput');
|
||||
if (attachmentsInput) {
|
||||
attachmentsInput.addEventListener('change', function() {
|
||||
const fileList = this.files;
|
||||
const selectedAttachmentsDiv = document.getElementById('composeSelectedAttachments');
|
||||
selectedAttachmentsDiv.innerHTML = '';
|
||||
|
||||
if (fileList.length > 0) {
|
||||
let html = '<div class="mt-2"><p class="mb-1 fw-bold small text-primary">المرفقات المختارة للرفع:</p><ul class="list-unstyled small">';
|
||||
for (let i = 0; i < fileList.length; i++) {
|
||||
const fileSize = (fileList[i].size / 1024).toFixed(1);
|
||||
html += `<li><i class="fas fa-file-upload me-1 text-primary"></i> ${fileList[i].name} <span class="text-muted">(${fileSize} KB)</span></li>`;
|
||||
}
|
||||
html += '</ul></div>';
|
||||
selectedAttachmentsDiv.innerHTML = html;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Reset attachments list when modal is hidden
|
||||
const composeModal = document.getElementById('composeModal');
|
||||
if (composeModal) {
|
||||
composeModal.addEventListener('hidden.bs.modal', function () {
|
||||
const selectedAttachmentsDiv = document.getElementById('composeSelectedAttachments');
|
||||
const attachmentsInput = document.getElementById('composeAttachmentsInput');
|
||||
if (selectedAttachmentsDiv) selectedAttachmentsDiv.innerHTML = '';
|
||||
if (attachmentsInput) attachmentsInput.value = '';
|
||||
});
|
||||
}
|
||||
|
||||
<?php if (isset($_GET['action']) && $_GET['action'] === 'compose'): ?>
|
||||
var myModal = new bootstrap.Modal(document.getElementById('composeModal'));
|
||||
myModal.show();
|
||||
|
||||
745
outbound.php
745
outbound.php
@ -1,404 +1,284 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/includes/header.php';
|
||||
require_once __DIR__ . '/m_services/MailService.php';
|
||||
|
||||
// Check if user has view permission
|
||||
if (!canView('outbound')) {
|
||||
redirect('index.php');
|
||||
}
|
||||
|
||||
// Safe truncation helper
|
||||
if (!function_exists('truncate_text')) {
|
||||
function truncate_text($text, $limit = 100) {
|
||||
$text = strip_tags($text);
|
||||
if (function_exists('mb_strimwidth')) {
|
||||
return mb_strimwidth($text, 0, $limit, "...");
|
||||
}
|
||||
if (strlen($text) <= $limit) return $text;
|
||||
return substr($text, 0, $limit) . "...";
|
||||
}
|
||||
}
|
||||
require_once 'includes/header.php';
|
||||
|
||||
$error = '';
|
||||
$success = '';
|
||||
$user_id = $_SESSION['user_id'];
|
||||
|
||||
// Fetch statuses
|
||||
$statuses_list = db()->query("SELECT * FROM mailbox_statuses ORDER BY id ASC")->fetchAll();
|
||||
$default_status_id = db()->query("SELECT id FROM mailbox_statuses WHERE is_default = 1 LIMIT 1")->fetchColumn() ?: 1;
|
||||
|
||||
// Function to send assignment notification
|
||||
function sendAssignmentNotification($assigned_to_id, $ref_no, $subject) {
|
||||
if (!$assigned_to_id) return;
|
||||
|
||||
$stmt = db()->prepare("SELECT full_name, email FROM users WHERE id = ?");
|
||||
$stmt->execute([$assigned_to_id]);
|
||||
$user = $stmt->fetch();
|
||||
|
||||
if ($user && !empty($user['email'])) {
|
||||
$to = $user['email'];
|
||||
$email_subject = "تنبيه: تم تعيين بريد جديد لك (رقم القيد: $ref_no)";
|
||||
$htmlBody = "
|
||||
<div dir='rtl' style='font-family: Arial, sans-serif;'>
|
||||
<h2>مرحباً " . htmlspecialchars($user['full_name']) . "</h2>
|
||||
<p>لقد تم تعيين مهمة بريد جديد لك في النظام.</p>
|
||||
<table border='1' cellpadding='10' cellspacing='0' style='border-collapse: collapse;'>
|
||||
<tr>
|
||||
<th style='background-color: #f8f9fa;'>رقم القيد</th>
|
||||
<td>" . htmlspecialchars($ref_no) . "</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th style='background-color: #f8f9fa;'>الموضوع</th>
|
||||
<td>" . htmlspecialchars($subject) . "</td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>يرجى الدخول للنظام لمتابعة المهمة.</p>
|
||||
<br>
|
||||
<p>هذا تنبيه تلقائي، يرجى عدم الرد.</p>
|
||||
</div>
|
||||
";
|
||||
MailService::sendMail($to, $email_subject, $htmlBody);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle actions
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$action = $_POST['action'] ?? '';
|
||||
|
||||
// Permission checks for POST actions
|
||||
if (($action === 'add' && !canAdd('outbound')) || ($action === 'edit' && !canEdit('outbound'))) {
|
||||
$error = 'عذراً، ليس لديك الصلاحية للقيام بهذا الإجراء';
|
||||
// Handle CRUD operations
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
|
||||
if (!canEdit('outbound') && !canAdd('outbound')) {
|
||||
$error = 'ليس لديك صلاحية للقيام بهذا الإجراء.';
|
||||
} else {
|
||||
$type = 'outbound';
|
||||
$action = $_POST['action'];
|
||||
$id = $_POST['id'] ?? 0;
|
||||
$ref_no = $_POST['ref_no'] ?? '';
|
||||
$date_registered = $_POST['date_registered'] ?? date('Y-m-d');
|
||||
$due_date = !empty($_POST['due_date']) ? $_POST['due_date'] : null;
|
||||
$due_date = $_POST['due_date'] ?? null;
|
||||
$sender = $_POST['sender'] ?? '';
|
||||
$recipient = $_POST['recipient'] ?? '';
|
||||
$subject = $_POST['subject'] ?? '';
|
||||
$description = $_POST['description'] ?? '';
|
||||
$status_id = $_POST['status_id'] ?? $default_status_id;
|
||||
$assigned_to = !empty($_POST['assigned_to']) ? $_POST['assigned_to'] : null;
|
||||
$id = $_POST['id'] ?? 0;
|
||||
$status_id = $_POST['status_id'] ?? null;
|
||||
$assigned_to = $_POST['assigned_to'] ?? null;
|
||||
|
||||
if ($ref_no && $subject) {
|
||||
$should_notify = false;
|
||||
if ($action === 'add' || $action === 'edit') {
|
||||
try {
|
||||
db()->beginTransaction();
|
||||
|
||||
if ($action === 'add') {
|
||||
if (!canAdd('outbound')) throw new Exception('ليس لديك صلاحية الإضافة.');
|
||||
$stmt = db()->prepare("INSERT INTO outbound_mail (ref_no, date_registered, due_date, sender, recipient, subject, description, status_id, assigned_to, created_by) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
|
||||
$stmt->execute([$ref_no, $date_registered, $due_date, $sender, $recipient, $subject, $description, $status_id, $assigned_to, $user_id]);
|
||||
$mail_id = db()->lastInsertId();
|
||||
|
||||
if ($assigned_to) {
|
||||
$should_notify = true;
|
||||
}
|
||||
|
||||
$_SESSION['success'] = 'تمت إضافة البريد الصادر بنجاح';
|
||||
} elseif ($action === 'edit') {
|
||||
$mail_id = $id;
|
||||
|
||||
// Get previous assigned_to to check if it changed
|
||||
$stmt_old = db()->prepare("SELECT assigned_to FROM outbound_mail WHERE id = ?");
|
||||
$stmt_old->execute([$id]);
|
||||
$old_assigned_to = $stmt_old->fetchColumn();
|
||||
|
||||
$stmt = db()->prepare("UPDATE outbound_mail SET ref_no = ?, date_registered = ?, due_date = ?, sender = ?, recipient = ?, subject = ?, description = ?, status_id = ?, assigned_to = ? WHERE id = ? ");
|
||||
$stmt->execute([$ref_no, $date_registered, $due_date, $sender, $recipient, $subject, $description, $status_id, $assigned_to, $mail_id]);
|
||||
|
||||
if ($assigned_to && $assigned_to != $old_assigned_to) {
|
||||
$should_notify = true;
|
||||
}
|
||||
|
||||
$_SESSION['success'] = 'تم تحديث البيانات بنجاح';
|
||||
$stmt->execute([$ref_no, $date_registered, $due_date, $sender, $recipient, $subject, $description, $status_id, $assigned_to, $_SESSION['user_id']]);
|
||||
$id = db()->lastInsertId();
|
||||
$success = 'تم إضافة البريد الصادر بنجاح.';
|
||||
} else {
|
||||
if (!canEdit('outbound')) throw new Exception('ليس لديك صلاحية التعديل.');
|
||||
$stmt = db()->prepare("UPDATE outbound_mail SET ref_no = ?, date_registered = ?, due_date = ?, sender = ?, recipient = ?, subject = ?, description = ?, status_id = ?, assigned_to = ? WHERE id = ?");
|
||||
$stmt->execute([$ref_no, $date_registered, $due_date, $sender, $recipient, $subject, $description, $status_id, $assigned_to, $id]);
|
||||
$success = 'تم تحديث بيانات البريد الصادر بنجاح.';
|
||||
}
|
||||
|
||||
// Handle Attachments
|
||||
if (!empty($_FILES['attachments']['name'][0])) {
|
||||
// Handle file uploads
|
||||
if (isset($_FILES['attachments']) && !empty($_FILES['attachments']['name'][0])) {
|
||||
$upload_dir = 'uploads/attachments/';
|
||||
if (!is_dir($upload_dir)) mkdir($upload_dir, 0777, true);
|
||||
|
||||
foreach ($_FILES['attachments']['name'] as $key => $name) {
|
||||
if ($_FILES['attachments']['error'][$key] === 0) {
|
||||
$file_name = time() . '_' . basename($name);
|
||||
$target_path = $upload_dir . $file_name;
|
||||
if (move_uploaded_file($_FILES['attachments']['tmp_name'][$key], $target_path)) {
|
||||
for ($i = 0; $i < count($_FILES['attachments']['name']); $i++) {
|
||||
if ($_FILES['attachments']['error'][$i] === 0) {
|
||||
$filename = time() . '_' . $_FILES['attachments']['name'][$i];
|
||||
$filepath = $upload_dir . $filename;
|
||||
if (move_uploaded_file($_FILES['attachments']['tmp_name'][$i], $filepath)) {
|
||||
$stmt = db()->prepare("INSERT INTO outbound_attachments (mail_id, display_name, file_path, file_name, file_size) VALUES (?, ?, ?, ?, ?)");
|
||||
$stmt->execute([$mail_id, $name, $target_path, $name, $_FILES['attachments']['size'][$key]]);
|
||||
$stmt->execute([$id, $_FILES['attachments']['name'][$i], $filepath, $_FILES['attachments']['name'][$i], $_FILES['attachments']['size'][$i]]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
db()->commit();
|
||||
|
||||
// Notify after commit
|
||||
if ($should_notify) {
|
||||
sendAssignmentNotification($assigned_to, $ref_no, $subject);
|
||||
}
|
||||
|
||||
redirect('outbound.php');
|
||||
} catch (PDOException $e) {
|
||||
if (db()->inTransaction()) db()->rollBack();
|
||||
if ($e->getCode() == 23000) {
|
||||
$error = 'رقم القيد مستخدم مسبقاً';
|
||||
} else {
|
||||
$error = 'حدث خطأ: ' . $e->getMessage();
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
db()->rollBack();
|
||||
$error = 'خطأ: ' . $e->getMessage();
|
||||
}
|
||||
} elseif ($action === 'delete') {
|
||||
if (!canDelete('outbound')) {
|
||||
$error = 'ليس لديك صلاحية الحذف.';
|
||||
} else {
|
||||
$stmt = db()->prepare("DELETE FROM outbound_mail WHERE id = ?");
|
||||
$stmt->execute([$id]);
|
||||
$success = 'تم حذف البريد الصادر بنجاح.';
|
||||
}
|
||||
} else {
|
||||
$error = 'يرجى ملء الحقول المطلوبة (رقم القيد، الموضوع)';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Delete action
|
||||
if (isset($_GET['action']) && $_GET['action'] === 'delete' && isset($_GET['id'])) {
|
||||
if (!canDelete('outbound')) {
|
||||
$error = 'عذراً، ليس لديك الصلاحية لحذف السجلات';
|
||||
} else {
|
||||
$id = $_GET['id'];
|
||||
$stmt = db()->prepare("DELETE FROM outbound_mail WHERE id = ? ");
|
||||
$stmt->execute([$id]);
|
||||
$_SESSION['success'] = 'تم حذف البريد بنجاح';
|
||||
redirect('outbound.php');
|
||||
}
|
||||
}
|
||||
// Fetch stats
|
||||
$total_stmt = db()->query("SELECT COUNT(*) FROM outbound_mail");
|
||||
$total_outbound = $total_stmt->fetchColumn();
|
||||
|
||||
// Get session messages
|
||||
if (isset($_SESSION['success'])) {
|
||||
$success = $_SESSION['success'];
|
||||
unset($_SESSION['success']);
|
||||
}
|
||||
if (isset($_SESSION['error'])) {
|
||||
$error = $_SESSION['error'];
|
||||
unset($_SESSION['error']);
|
||||
}
|
||||
$completed_stmt = db()->prepare("SELECT COUNT(*) FROM outbound_mail WHERE status_id IN (SELECT id FROM mailbox_statuses WHERE name LIKE '%مكتمل%' OR name LIKE '%منتهي%')");
|
||||
$completed_stmt->execute();
|
||||
$completed_outbound = $completed_stmt->fetchColumn();
|
||||
|
||||
$search = $_GET['search'] ?? '';
|
||||
$my_tasks = isset($_GET['my_tasks']) && $_GET['my_tasks'] == 1;
|
||||
|
||||
// Pagination settings
|
||||
$limit = 10; // Items per page
|
||||
$page = isset($_GET['page']) && is_numeric($_GET['page']) ? (int)$_GET['page'] : 1;
|
||||
if ($page < 1) $page = 1;
|
||||
$offset = ($page - 1) * $limit;
|
||||
|
||||
$where_clauses = ["1=1"];
|
||||
// Search and Filter
|
||||
$where = "WHERE 1=1";
|
||||
$params = [];
|
||||
|
||||
if ($search) {
|
||||
$where_clauses[] = "(m.ref_no LIKE ? OR m.recipient LIKE ? OR m.subject LIKE ?)";
|
||||
$params[] = "%$search%";
|
||||
$params[] = "%$search%";
|
||||
$params[] = "%$search%";
|
||||
if (isset($_GET['search']) && !empty($_GET['search'])) {
|
||||
$where .= " AND (m.ref_no LIKE ? OR m.subject LIKE ? OR m.sender LIKE ? OR m.recipient LIKE ?)";
|
||||
$search = "%" . $_GET['search'] . "%";
|
||||
$params = array_merge($params, [$search, $search, $search, $search]);
|
||||
}
|
||||
|
||||
if ($my_tasks) {
|
||||
$where_clauses[] = "m.assigned_to = ?";
|
||||
$params[] = $user_id;
|
||||
if (isset($_GET['status_id']) && !empty($_GET['status_id'])) {
|
||||
$where .= " AND m.status_id = ?";
|
||||
$params[] = $_GET['status_id'];
|
||||
}
|
||||
|
||||
$where_sql = implode(" AND ", $where_clauses);
|
||||
|
||||
// Get total records for pagination
|
||||
$count_query = "SELECT COUNT(*) FROM outbound_mail m WHERE $where_sql";
|
||||
$stmt_count = db()->prepare($count_query);
|
||||
$stmt_count->execute($params);
|
||||
$total_records = $stmt_count->fetchColumn();
|
||||
$total_pages = ceil($total_records / $limit);
|
||||
|
||||
// Fetch paginated results
|
||||
$query = "SELECT m.*, s.name as status_name, s.color as status_color, u.full_name as assigned_to_name,
|
||||
(SELECT GROUP_CONCAT(display_name SEPARATOR '|||') FROM outbound_attachments WHERE mail_id = m.id) as attachment_names
|
||||
FROM outbound_mail m
|
||||
LEFT JOIN mailbox_statuses s ON m.status_id = s.id
|
||||
LEFT JOIN users u ON m.assigned_to = u.id
|
||||
WHERE $where_sql
|
||||
ORDER BY m.created_at DESC
|
||||
LIMIT $limit OFFSET $offset";
|
||||
$where
|
||||
ORDER BY m.date_registered DESC, m.id DESC";
|
||||
|
||||
$stmt = db()->prepare($query);
|
||||
$stmt->execute($params);
|
||||
$mails = $stmt->fetchAll();
|
||||
|
||||
$users_list = db()->query("SELECT id, full_name FROM users ORDER BY full_name")->fetchAll();
|
||||
$statuses = db()->query("SELECT * FROM mailbox_statuses ORDER BY id ASC")->fetchAll();
|
||||
$users = db()->query("SELECT id, full_name, username FROM users ORDER BY full_name ASC")->fetchAll();
|
||||
$default_status_id = db()->query("SELECT id FROM mailbox_statuses WHERE is_default = 1 LIMIT 1")->fetchColumn() ?: ($statuses[0]['id'] ?? null);
|
||||
|
||||
// Handle Deep Link for Edit
|
||||
$deepLinkData = null;
|
||||
if (isset($_GET['action']) && $_GET['action'] === 'edit' && isset($_GET['id'])) {
|
||||
if (canEdit('outbound')) {
|
||||
$stmt = db()->prepare("SELECT m.*, (SELECT GROUP_CONCAT(display_name SEPARATOR '|||') FROM outbound_attachments WHERE mail_id = m.id) as attachment_names FROM outbound_mail m WHERE m.id = ? ");
|
||||
$stmt->execute([$_GET['id']]);
|
||||
$deepLinkData = $stmt->fetch();
|
||||
}
|
||||
}
|
||||
|
||||
function getStatusBadgeInList($mail) {
|
||||
$status_name = $mail['status_name'] ?? 'غير معروف';
|
||||
$status_color = $mail['status_color'] ?? '#6c757d';
|
||||
|
||||
// Translation for default statuses
|
||||
$display_name = $status_name;
|
||||
if ($status_name == 'received') $display_name = 'تم الاستلام';
|
||||
if ($status_name == 'in_progress') $display_name = 'قيد المعالجة';
|
||||
if ($status_name == 'closed') $display_name = 'مكتمل';
|
||||
|
||||
return '<span class="badge" style="background-color: ' . $status_color . ';">' . htmlspecialchars($display_name) . '</span>';
|
||||
if (isset($_GET['id'])) {
|
||||
$dlStmt = db()->prepare("SELECT m.*, (SELECT GROUP_CONCAT(display_name SEPARATOR '|||') FROM outbound_attachments WHERE mail_id = m.id) as attachment_names FROM outbound_mail m WHERE m.id = ?");
|
||||
$dlStmt->execute([$_GET['id']]);
|
||||
$deepLinkData = $dlStmt->fetch();
|
||||
}
|
||||
?>
|
||||
|
||||
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
|
||||
<h1 class="h2">البريد الصادر</h1>
|
||||
<?php if (canAdd('outbound')): ?>
|
||||
<button type="button" class="btn btn-primary shadow-sm" onclick="openMailModal('add')">
|
||||
<i class="fas fa-plus-circle me-1"></i> إضافة جديد
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php if ($success): ?>
|
||||
<div class="alert alert-success alert-dismissible fade show" role="alert">
|
||||
<?= $success ?>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($error): ?>
|
||||
<div class="alert alert-danger alert-dismissible fade show" role="alert">
|
||||
<?= $error ?>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="card shadow-sm border-0 mb-4">
|
||||
<div class="card-header bg-white py-3">
|
||||
<form class="row g-3 align-items-center">
|
||||
<div class="col-md-4">
|
||||
<input type="text" name="search" class="form-control" placeholder="بحث برقم القيد أو الموضوع أو المستلم..." value="<?= htmlspecialchars($search) ?>">
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="form-check form-switch mt-1">
|
||||
<input class="form-check-input" type="checkbox" name="my_tasks" id="myTasksSwitch" value="1" <?= $my_tasks ? 'checked' : '' ?> onchange="this.form.submit()">
|
||||
<label class="form-check-label fw-bold" for="myTasksSwitch">مهامي فقط</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<button type="submit" class="btn btn-secondary px-4">بحث</button>
|
||||
</div>
|
||||
<?php if ($search || $my_tasks): ?>
|
||||
<div class="col-auto">
|
||||
<a href="outbound.php" class="btn btn-link text-decoration-none">إلغاء التصفية</a>
|
||||
</div>
|
||||
<div class="container-fluid py-4">
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-8">
|
||||
<h2 class="fw-bold mb-1"><i class="fas fa-upload text-primary me-2"></i> البريد الصادر</h2>
|
||||
<p class="text-muted">إدارة المراسلات الصادرة إلى الجهات الخارجية وتتبع حالاتها.</p>
|
||||
</div>
|
||||
<div class="col-md-4 text-md-end d-flex align-items-center justify-content-md-end gap-2">
|
||||
<?php if (canAdd('outbound')): ?>
|
||||
<button class="btn btn-primary px-4 py-2" onclick="openMailModal('add')">
|
||||
<i class="fas fa-plus me-1"></i> إضافة صادر جديد
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body p-0">
|
||||
|
||||
<!-- Stats Cards -->
|
||||
<div class="row g-3 mb-4">
|
||||
<div class="col-md-3">
|
||||
<div class="card border-0 shadow-sm h-100">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-center mb-3">
|
||||
<div class="rounded-circle bg-primary bg-opacity-10 p-3 me-3">
|
||||
<i class="fas fa-paper-plane text-primary fa-lg"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h6 class="card-subtitle text-muted mb-1 small">إجمالي الصادر</h6>
|
||||
<h3 class="card-title mb-0 fw-bold"><?= $total_outbound ?></h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="card border-0 shadow-sm h-100">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-center mb-3">
|
||||
<div class="rounded-circle bg-success bg-opacity-10 p-3 me-3">
|
||||
<i class="fas fa-check-circle text-success fa-lg"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h6 class="card-subtitle text-muted mb-1 small">مكتمل / مرسل</h6>
|
||||
<h3 class="card-title mb-0 fw-bold"><?= $completed_outbound ?></h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if ($error): ?>
|
||||
<div class="alert alert-danger shadow-sm border-0 mb-4"><?= $error ?></div>
|
||||
<?php endif; ?>
|
||||
<?php if ($success): ?>
|
||||
<div class="alert alert-success shadow-sm border-0 mb-4"><?= $success ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- Filter Bar -->
|
||||
<div class="card border-0 shadow-sm mb-4">
|
||||
<div class="card-body p-3">
|
||||
<form method="GET" class="row g-2 align-items-center">
|
||||
<div class="col-md-5">
|
||||
<div class="input-group">
|
||||
<span class="input-group-text bg-white border-end-0"><i class="fas fa-search text-muted"></i></span>
|
||||
<input type="text" name="search" class="form-control border-start-0" placeholder="بحث برقم القيد، الموضوع، أو الجهة..." value="<?= htmlspecialchars($_GET['search'] ?? '') ?>">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<select name="status_id" class="form-select" onchange="this.form.submit()">
|
||||
<option value="">جميع الحالات</option>
|
||||
<?php foreach ($statuses as $status): ?>
|
||||
<option value="<?= $status['id'] ?>" <?= (isset($_GET['status_id']) && $_GET['status_id'] == $status['id']) ? 'selected' : '' ?>><?= $status['name'] ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-3 text-end">
|
||||
<button type="submit" class="btn btn-light w-100">تصفية</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Mails Table -->
|
||||
<div class="card border-0 shadow-sm overflow-hidden">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover align-middle mb-0">
|
||||
<thead class="bg-light">
|
||||
<tr>
|
||||
<th class="ps-4">رقم القيد</th>
|
||||
<th>التاريخ</th>
|
||||
<th>الموعد النهائي</th>
|
||||
<th>الموضوع</th>
|
||||
<th>المستلم</th>
|
||||
<th>المرفقات</th>
|
||||
<th>المسؤول</th>
|
||||
<th>الجهة المستلمة</th>
|
||||
<th>الحالة</th>
|
||||
<th class="pe-4 text-center">الإجراءات</th>
|
||||
<th class="text-center pe-4">الإجراءات</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php if ($mails): foreach ($mails as $mail): ?>
|
||||
<?php if (empty($mails)): ?>
|
||||
<tr>
|
||||
<td class="ps-4 fw-bold text-primary"><?= $mail['ref_no'] ?></td>
|
||||
<td><?= $mail['date_registered'] ?></td>
|
||||
<td>
|
||||
<?php if ($mail['due_date']): ?>
|
||||
<span class="<?= (strtotime($mail['due_date']) < time() && $mail['status_name'] != 'closed') ? 'text-danger fw-bold' : '' ?>">
|
||||
<?= $mail['due_date'] ?>
|
||||
<?php if (strtotime($mail['due_date']) < time() && $mail['status_name'] != 'closed'): ?>
|
||||
<i class="fas fa-exclamation-triangle ms-1"></i>
|
||||
<?php endif; ?>
|
||||
</span>
|
||||
<?php else: ?>
|
||||
<span class="text-muted">-</span>
|
||||
<?php endif; ?>
|
||||
<td colspan="6" class="text-center py-5 text-muted">
|
||||
<i class="fas fa-paper-plane fa-3x mb-3 opacity-20"></i>
|
||||
<p>لا يوجد بريد صادر حالياً.</p>
|
||||
</td>
|
||||
<td><?= truncate_text($mail['subject'], 80) ?></td>
|
||||
<td><?= htmlspecialchars($mail['recipient']) ?></td>
|
||||
<td>
|
||||
<?php if (!empty($mail['attachment_names'])): ?>
|
||||
<small class="text-muted"><i class="fas fa-paperclip me-1"></i> <?= htmlspecialchars(str_replace('|||', ', ', $mail['attachment_names'])) ?></small>
|
||||
<?php else: ?>
|
||||
<span class="text-muted">-</span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php if ($mail['assigned_to_name']): ?>
|
||||
<span class="text-nowrap"><i class="fas fa-user-tag me-1 text-muted"></i> <?= htmlspecialchars($mail['assigned_to_name']) ?></span>
|
||||
<?php else: ?>
|
||||
<span class="text-muted">غير معين</span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td><?= getStatusBadgeInList($mail) ?></td>
|
||||
<td class="pe-4 text-center">
|
||||
<a href="view_mail.php?id=<?= $mail['id'] ?>" class="btn btn-sm btn-outline-info" title="عرض التفاصيل"><i class="fas fa-eye"></i></a>
|
||||
|
||||
<?php if (canEdit('outbound')): ?>
|
||||
<button type="button" class="btn btn-sm btn-outline-primary"
|
||||
onclick='openMailModal("edit", <?= json_encode($mail) ?>)' title="تعديل">
|
||||
<i class="fas fa-edit"></i>
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (canDelete('outbound')): ?>
|
||||
<a href="javascript:void(0)" onclick="confirmDelete(<?= $mail['id'] ?>)" class="btn btn-sm btn-outline-danger" title="حذف"><i class="fas fa-trash"></i></a>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; else: ?>
|
||||
<tr>
|
||||
<td colspan="9" class="text-center py-4 text-muted">لا يوجد بريد صادر مسجل حالياً</td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
<?php foreach ($mails as $mail): ?>
|
||||
<tr>
|
||||
<td class="ps-4"><span class="fw-bold text-primary"><?= htmlspecialchars($mail['ref_no']) ?></span></td>
|
||||
<td><?= date('Y-m-d', strtotime($mail['date_registered'])) ?></td>
|
||||
<td>
|
||||
<div class="fw-semibold text-truncate" style="max-width: 300px;"><?= htmlspecialchars($mail['subject']) ?></div>
|
||||
<?php if ($mail['attachment_names']): ?>
|
||||
<span class="badge bg-light text-muted fw-normal" style="font-size: 0.65rem;">
|
||||
<i class="fas fa-paperclip me-1"></i> <?= count(explode('|||', $mail['attachment_names'])) ?> مرفقات
|
||||
</span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td><?= htmlspecialchars($mail['recipient']) ?></td>
|
||||
<td>
|
||||
<span class="badge rounded-pill" style="background-color: <?= $mail['status_color'] ?>20; color: <?= $mail['status_color'] ?>;">
|
||||
<i class="fas fa-circle me-1 small"></i> <?= htmlspecialchars($mail['status_name']) ?>
|
||||
</span>
|
||||
</td>
|
||||
<td class="text-center pe-4">
|
||||
<div class="btn-group shadow-sm rounded">
|
||||
<a href="view_mail.php?id=<?= $mail['id'] ?>&type=outbound" class="btn btn-sm btn-white text-primary border" title="عرض">
|
||||
<i class="fas fa-eye"></i>
|
||||
</a>
|
||||
<a href="print_outbound.php?id=<?= $mail['id'] ?>" target="_blank" class="btn btn-sm btn-white text-secondary border" title="طباعة">
|
||||
<i class="fas fa-print"></i>
|
||||
</a>
|
||||
<?php if (canEdit('outbound')): ?>
|
||||
<button class="btn btn-sm btn-white text-warning border" onclick='openMailModal("edit", <?= json_encode($mail) ?>)' title="تعديل">
|
||||
<i class="fas fa-edit"></i>
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
<?php if (canDelete('outbound')): ?>
|
||||
<form method="POST" class="d-inline" onsubmit="return confirm('هل أنت متأكد من حذف هذا البريد؟');">
|
||||
<input type="hidden" name="action" value="delete">
|
||||
<input type="hidden" name="id" value="<?= $mail['id'] ?>">
|
||||
<button type="submit" class="btn btn-sm btn-white text-danger border rounded-0" title="حذف">
|
||||
<i class="fas fa-trash"></i>
|
||||
</button>
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<?php if ($total_pages > 1): ?>
|
||||
<div class="card-footer bg-white border-0 py-3">
|
||||
<nav aria-label="Page navigation">
|
||||
<ul class="pagination justify-content-center mb-0">
|
||||
<li class="page-item <?= ($page <= 1) ? 'disabled' : '' ?>">
|
||||
<a class="page-link" href="?page=<?= $page - 1 ?><?= $search ? '&search='.urlencode($search) : '' ?><?= $my_tasks ? '&my_tasks=1' : '' ?>" aria-label="Previous">
|
||||
<span aria-hidden="true">«</span>
|
||||
</a>
|
||||
</li>
|
||||
<?php for ($i = 1; $i <= $total_pages; $i++): ?>
|
||||
<li class="page-item <?= ($page == $i) ? 'active' : '' ?>">
|
||||
<a class="page-link" href="?page=<?= $i ?><?= $search ? '&search='.urlencode($search) : '' ?><?= $my_tasks ? '&my_tasks=1' : '' ?>"><?= $i ?></a>
|
||||
</li>
|
||||
<?php endfor; ?>
|
||||
<li class="page-item <?= ($page >= $total_pages) ? 'disabled' : '' ?>">
|
||||
<a class="page-link" href="?page=<?= $page + 1 ?><?= $search ? '&search='.urlencode($search) : '' ?><?= $my_tasks ? '&my_tasks=1' : '' ?>" aria-label="Next">
|
||||
<span aria-hidden="true">»</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php if (canAdd('outbound') || canEdit('outbound')): ?>
|
||||
<!-- Mail Modal -->
|
||||
<!-- Add/Edit Modal -->
|
||||
<div class="modal fade" id="mailModal" tabindex="-1" aria-labelledby="mailModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content border-0 shadow">
|
||||
<div class="modal-header bg-success text-white">
|
||||
<h5 class="modal-title fw-bold" id="mailModalLabel">إضافة بريد صادر جديد</h5>
|
||||
<div class="modal-header bg-primary text-white py-3">
|
||||
<h5 class="modal-title fw-bold" id="mailModalLabel">بريد صادر جديد</h5>
|
||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<form id="mailForm" method="POST" enctype="multipart/form-data">
|
||||
@ -407,93 +287,113 @@ function getStatusBadgeInList($mail) {
|
||||
<input type="hidden" name="id" id="modalId" value="0">
|
||||
|
||||
<div class="row g-3">
|
||||
<div class="col-md-4">
|
||||
<label class="form-label fw-bold">رقم القيد <span class="text-danger">*</span></label>
|
||||
<input type="text" name="ref_no" id="modalRefNo" class="form-control" required readonly>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label class="form-label fw-bold">تاريخ التسجيل</label>
|
||||
<input type="date" name="date_registered" id="modalDateRegistered" class="form-control">
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label class="form-label fw-bold">الموعد النهائي</label>
|
||||
<input type="date" name="due_date" id="modalDueDate" class="form-control">
|
||||
<div class="col-md-6">
|
||||
<label class="form-label small fw-bold">رقم القيد</label>
|
||||
<input type="text" name="ref_no" id="modalRefNo" class="form-control" readonly required>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label fw-bold">المستلم الخارجي (الجهة المستلمة)</label>
|
||||
<input type="text" name="recipient" id="modalRecipient" class="form-control">
|
||||
<label class="form-label small fw-bold">تاريخ التسجيل</label>
|
||||
<input type="date" name="date_registered" id="modalDateRegistered" class="form-control" required>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label fw-bold">المرسل الداخلي (القسم/الموظف)</label>
|
||||
<input type="text" name="sender" id="modalSender" class="form-control">
|
||||
<label class="form-label small fw-bold">الجهة الصادر منها (الداخلية)</label>
|
||||
<input type="text" name="sender" id="modalSender" class="form-control" required placeholder="مثال: الشؤون القانونية">
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<label class="form-label fw-bold">الموضوع <span class="text-danger">*</span></label>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label small fw-bold">الجهة المستلمة (الخارجية)</label>
|
||||
<input type="text" name="recipient" id="modalRecipient" class="form-control" required placeholder="مثال: البنك المركزي">
|
||||
</div>
|
||||
<div class="col-md-12">
|
||||
<label class="form-label small fw-bold">الموضوع</label>
|
||||
<input type="text" name="subject" id="modalSubject" class="form-control" required>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<label class="form-label fw-bold">الوصف / ملاحظات</label>
|
||||
<div class="col-md-12">
|
||||
<label class="form-label small fw-bold">محتوى الخطاب / الوصف</label>
|
||||
<textarea name="description" id="description_editor" class="form-control" rows="5"></textarea>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<label class="form-label fw-bold">المرفقات</label>
|
||||
<input type="file" name="attachments[]" class="form-control" multiple>
|
||||
<div id="modalExistingAttachments" class="mt-2"></div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label fw-bold">الحالة</label>
|
||||
<select name="status_id" id="modalStatusId" class="form-select">
|
||||
<?php foreach ($statuses_list as $s): ?>
|
||||
<?php
|
||||
$d_name = $s['name'];
|
||||
if ($d_name == 'received') $d_name = 'تم الاستلام';
|
||||
if ($d_name == 'in_progress') $d_name = 'قيد المعالجة';
|
||||
if ($d_name == 'closed') $d_name = 'مكتمل / مغلق';
|
||||
?>
|
||||
<option value="<?= $s['id'] ?>"><?= htmlspecialchars($d_name) ?></option>
|
||||
<label class="form-label small fw-bold">الحالة</label>
|
||||
<select name="status_id" id="modalStatusId" class="form-select" required>
|
||||
<?php foreach ($statuses as $status): ?>
|
||||
<option value="<?= $status['id'] ?>"><?= $status['name'] ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label fw-bold">الموظف المسؤول</label>
|
||||
<label class="form-label small fw-bold">إسناد للمتابعة (اختياري)</label>
|
||||
<select name="assigned_to" id="modalAssignedTo" class="form-select">
|
||||
<option value="">-- اختر موظف --</option>
|
||||
<?php foreach ($users_list as $u): ?>
|
||||
<option value="<?= $u['id'] ?>"><?= htmlspecialchars($u['full_name']) ?></option>
|
||||
<option value="">--- اختر مستخدم ---</option>
|
||||
<?php foreach ($users as $user): ?>
|
||||
<option value="<?= $user['id'] ?>"><?= htmlspecialchars($user['full_name'] ?: $user['username']) ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-12 mt-4">
|
||||
<div class="bg-light p-3 rounded">
|
||||
<label class="form-label small fw-bold mb-2 d-block">المرفقات</label>
|
||||
<input type="file" name="attachments[]" id="modalAttachmentsInput" class="form-control" multiple>
|
||||
<div id="modalExistingAttachments" class="mt-2"></div>
|
||||
<div id="modalSelectedAttachments" class="mt-1"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer bg-light">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">إلغاء</button>
|
||||
<button type="submit" class="btn btn-primary px-4">حفظ البيانات</button>
|
||||
<div class="modal-footer bg-light border-0">
|
||||
<button type="button" class="btn btn-white border px-4" data-bs-dismiss="modal">إلغاء</button>
|
||||
<button type="submit" class="btn btn-primary px-4">حفظ الصادر</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
/* Custom Table Styles */
|
||||
.table thead th {
|
||||
font-size: 0.75rem;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05rem;
|
||||
font-weight: 700;
|
||||
color: #6c757d;
|
||||
border-top: none;
|
||||
padding: 1rem 0.5rem;
|
||||
}
|
||||
.btn-white {
|
||||
background-color: #fff;
|
||||
color: #333;
|
||||
}
|
||||
.btn-white:hover {
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
.badge {
|
||||
padding: 0.5em 0.8em;
|
||||
font-weight: 500;
|
||||
}
|
||||
.input-group-text {
|
||||
color: #adb5bd;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
let descriptionEditor;
|
||||
let mailModal;
|
||||
|
||||
function initEditors() {
|
||||
if (typeof ClassicEditor === 'undefined') {
|
||||
console.error('CKEditor not loaded');
|
||||
if (typeof tinymce === 'undefined') {
|
||||
console.error('TinyMCE not loaded');
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
const config = {
|
||||
return tinymce.init({
|
||||
selector: '#description_editor',
|
||||
language: 'ar',
|
||||
toolbar: ['heading', '|', 'bold', 'italic', 'link', 'bulletedList', 'numberedList', 'undo', 'redo']
|
||||
};
|
||||
|
||||
return ClassicEditor.create(document.querySelector('#description_editor'), config)
|
||||
.then(editor => { descriptionEditor = editor; })
|
||||
.catch(err => {
|
||||
console.error('CKEditor Init Error:', err);
|
||||
});
|
||||
directionality: 'rtl',
|
||||
height: 300,
|
||||
plugins: 'advlist autolink lists link image charmap preview anchor searchreplace visualblocks code fullscreen insertdatetime media table help wordcount',
|
||||
toolbar: 'undo redo | fontfamily fontsize | bold italic underline strikethrough | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | removeformat | help',
|
||||
font_size_formats: '8pt 10pt 12pt 14pt 18pt 24pt 36pt',
|
||||
promotion: false,
|
||||
branding: false
|
||||
});
|
||||
}
|
||||
|
||||
function openMailModal(action, data = null) {
|
||||
@ -511,6 +411,8 @@ function openMailModal(action, data = null) {
|
||||
const modalAction = document.getElementById('modalAction');
|
||||
const modalId = document.getElementById('modalId');
|
||||
const existingAttachmentsDiv = document.getElementById('modalExistingAttachments');
|
||||
const selectedAttachmentsDiv = document.getElementById('modalSelectedAttachments');
|
||||
const attachmentsInput = document.getElementById('modalAttachmentsInput');
|
||||
|
||||
const fields = {
|
||||
ref_no: document.getElementById('modalRefNo'),
|
||||
@ -525,6 +427,8 @@ function openMailModal(action, data = null) {
|
||||
|
||||
modalAction.value = action;
|
||||
existingAttachmentsDiv.innerHTML = '';
|
||||
selectedAttachmentsDiv.innerHTML = '';
|
||||
if (attachmentsInput) attachmentsInput.value = '';
|
||||
|
||||
if (action === 'add') {
|
||||
label.textContent = 'إضافة بريد صادر جديد';
|
||||
@ -538,17 +442,23 @@ function openMailModal(action, data = null) {
|
||||
}
|
||||
});
|
||||
|
||||
if (descriptionEditor) descriptionEditor.setData('');
|
||||
else document.getElementById('description_editor').value = '';
|
||||
if (typeof tinymce !== 'undefined' && tinymce.get('description_editor')) {
|
||||
tinymce.get('description_editor').setContent('');
|
||||
} else {
|
||||
document.getElementById('description_editor').value = '';
|
||||
}
|
||||
} else {
|
||||
label.textContent = 'تعديل البريد صادر';
|
||||
label.textContent = 'تعديل البريد الصادر';
|
||||
modalId.value = data.id;
|
||||
Object.keys(fields).forEach(key => {
|
||||
if (fields[key]) fields[key].value = data[key] || '';
|
||||
});
|
||||
|
||||
if (descriptionEditor) descriptionEditor.setData(data.description || '');
|
||||
else document.getElementById('description_editor').value = data.description || '';
|
||||
if (typeof tinymce !== 'undefined' && tinymce.get('description_editor')) {
|
||||
tinymce.get('description_editor').setContent(data.description || '');
|
||||
} else {
|
||||
document.getElementById('description_editor').value = data.description || '';
|
||||
}
|
||||
|
||||
// Display existing attachments
|
||||
if (data.attachment_names) {
|
||||
@ -570,68 +480,37 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
<?php if ($deepLinkData): ?>
|
||||
openMailModal('edit', <?= json_encode($deepLinkData) ?>);
|
||||
<?php elseif ($error && isset($_POST['action'])): ?>
|
||||
const errorData = <?= json_encode([
|
||||
'id' => $_POST['id'] ?? 0,
|
||||
'ref_no' => $_POST['ref_no'] ?? '',
|
||||
'date_registered' => $_POST['date_registered'] ?? date('Y-m-d'),
|
||||
'due_date' => $_POST['due_date'] ?? '',
|
||||
'sender' => $_POST['sender'] ?? '',
|
||||
'recipient' => $_POST['recipient'] ?? '',
|
||||
'subject' => $_POST['subject'] ?? '',
|
||||
'description' => $_POST['description'] ?? '',
|
||||
'status_id' => $_POST['status_id'] ?? $default_status_id,
|
||||
'assigned_to' => $_POST['assigned_to'] ?? '',
|
||||
'attachment_names' => $_POST['attachment_names'] ?? ''
|
||||
]) ?>;
|
||||
openMailModal('<?= $_POST['action'] ?>', errorData);
|
||||
<?php elseif (isset($_GET['action']) && $_GET['action'] === 'add'): ?>
|
||||
openMailModal('add');
|
||||
const errorData = <?= json_encode($_POST) ?>;
|
||||
openMailModal(errorData.action, errorData);
|
||||
<?php endif; ?>
|
||||
});
|
||||
|
||||
// Handle file selection display
|
||||
const attachmentsInput = document.getElementById('modalAttachmentsInput');
|
||||
if (attachmentsInput) {
|
||||
attachmentsInput.addEventListener('change', function() {
|
||||
const fileList = this.files;
|
||||
const selectedAttachmentsDiv = document.getElementById('modalSelectedAttachments');
|
||||
selectedAttachmentsDiv.innerHTML = '';
|
||||
|
||||
if (fileList.length > 0) {
|
||||
let html = '<div class="mt-2"><p class="mb-1 fw-bold small text-primary">المرفقات المختارة للرفع:</p><ul class="list-unstyled small">';
|
||||
for (let i = 0; i < fileList.length; i++) {
|
||||
const fileSize = (fileList[i].size / 1024).toFixed(1);
|
||||
html += `<li><i class="fas fa-file-upload me-1 text-primary"></i> ${fileList[i].name} <span class="text-muted">(${fileSize} KB)</span></li>`;
|
||||
}
|
||||
html += '</ul></div>';
|
||||
selectedAttachmentsDiv.innerHTML = html;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
document.getElementById('mailForm').addEventListener('submit', function() {
|
||||
if (descriptionEditor) descriptionEditor.updateSourceElement();
|
||||
if (typeof tinymce !== 'undefined') {
|
||||
tinymce.triggerSave();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function confirmDelete(id) {
|
||||
if (typeof Swal === 'undefined') {
|
||||
if (confirm('هل أنت متأكد من الحذف؟')) {
|
||||
window.location.href = 'outbound.php?action=delete&id=' + id;
|
||||
}
|
||||
return;
|
||||
}
|
||||
Swal.fire({
|
||||
title: 'هل أنت متأكد؟',
|
||||
text: "لا يمكن التراجع عن عملية الحذف!",
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonColor: '#d33',
|
||||
cancelButtonColor: '#3085d6',
|
||||
confirmButtonText: 'نعم، احذف!',
|
||||
cancelButtonText: 'إلغاء'
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
window.location.href = 'outbound.php?action=delete&id=' + id;
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
<?php endif; ?>
|
||||
|
||||
<style>
|
||||
.ck-editor__editable_inline {
|
||||
min-height: 250px;
|
||||
direction: rtl;
|
||||
text-align: right;
|
||||
}
|
||||
.modal-content {
|
||||
border-radius: 15px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.modal-header.bg-success {
|
||||
background-color: #198754 !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
<?php require_once __DIR__ . '/includes/footer.php'; ?>
|
||||
<?php require_once 'includes/footer.php'; ?>
|
||||
277
print_outbound.php
Normal file
277
print_outbound.php
Normal file
@ -0,0 +1,277 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/db/config.php';
|
||||
require_once __DIR__ . '/includes/settings.php';
|
||||
|
||||
// Check if user is logged in
|
||||
session_start();
|
||||
if (!isset($_SESSION['user_id'])) {
|
||||
die('Access Denied');
|
||||
}
|
||||
|
||||
// Basic permission check (matches header.php logic)
|
||||
function isAdmin() {
|
||||
if (isset($_SESSION['is_super_admin']) && $_SESSION['is_super_admin'] == 1) return true;
|
||||
if (isset($_SESSION['user_role']) && strtolower($_SESSION['user_role']) === 'admin') return true;
|
||||
if (isset($_SESSION['role']) && strtolower($_SESSION['role']) === 'admin') return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
function canView($page) {
|
||||
if (isAdmin()) return true;
|
||||
return $_SESSION['permissions'][$page]['view'] ?? false;
|
||||
}
|
||||
|
||||
if (!canView('outbound')) {
|
||||
die('Unauthorized access');
|
||||
}
|
||||
|
||||
$id = isset($_GET['id']) ? (int)$_GET['id'] : 0;
|
||||
if (!$id) {
|
||||
die('Invalid ID');
|
||||
}
|
||||
|
||||
// Fetch outbound mail details
|
||||
$stmt = db()->prepare("SELECT * FROM outbound_mail WHERE id = ?");
|
||||
$stmt->execute([$id]);
|
||||
$mail = $stmt->fetch();
|
||||
|
||||
if (!$mail) {
|
||||
die('Mail not found');
|
||||
}
|
||||
|
||||
$settings = get_settings();
|
||||
$logo = !empty($settings['site_logo']) ? $settings['site_logo'] : '';
|
||||
$site_name = $settings['site_name'];
|
||||
|
||||
/**
|
||||
* Convert Gregorian date to Hijri
|
||||
*/
|
||||
function gregorianToHijri($date) {
|
||||
if (!$date) return '';
|
||||
$time = strtotime($date);
|
||||
$m = date('m', $time);
|
||||
$d = date('d', $time);
|
||||
$y = date('Y', $time);
|
||||
|
||||
if (($y > 1582) || (($y == 1582) && ($m > 10)) || (($y == 1582) && ($m == 10) && ($d > 14))) {
|
||||
$jd = (int)((1461 * ($y + 4800 + (int)(($m - 14) / 12))) / 4) +
|
||||
(int)((367 * ($m - 2 - 12 * ((int)(($m - 14) / 12)))) / 12) -
|
||||
(int)((3 * ((int)(($y + 4900 + (int)(($m - 14) / 12)) / 100))) / 4) +
|
||||
$d - 32075;
|
||||
} else {
|
||||
$jd = 367 * $y - (int)((7 * ($y + 5001 + (int)(($m - 9) / 7))) / 4) + (int)((275 * $m) / 9) + $d + 1729777;
|
||||
}
|
||||
|
||||
$l = $jd - 1948440 + 10632;
|
||||
$n = (int)(($l - 1) / 10631);
|
||||
$l = $l - 10631 * $n + 354;
|
||||
$j = ((int)((10985 - $l) / 5316)) * ((int)((50 * $l) / 17719)) + ((int)($l / 5670)) * ((int)((43 * $l) / 15238));
|
||||
$l = $l - ((int)((30 - $j) / 15)) * ((int)((17719 * $j) / 50)) - ((int)($j / 16)) * ((int)((15238 * $j) / 43)) + 29;
|
||||
|
||||
$month = (int)((24 * $l) / 709);
|
||||
$day = $l - (int)((709 * $month) / 24);
|
||||
$year = 30 * $n + $j - 30;
|
||||
|
||||
$hijriMonths = [
|
||||
1 => "محرم", 2 => "صفر", 3 => "ربيع الأول", 4 => "ربيع الآخر",
|
||||
5 => "جمادى الأولى", 6 => "جمادى الآخرة", 7 => "رجب", 8 => "شعبان",
|
||||
9 => "رمضان", 10 => "شوال", 11 => "ذو القعدة", 12 => "ذو الحجة"
|
||||
];
|
||||
|
||||
return $day . ' ' . $hijriMonths[$month] . ' ' . $year . ' هـ';
|
||||
}
|
||||
|
||||
$hijriDate = gregorianToHijri($mail['date_registered']);
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="ar" dir="rtl">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>طباعة بريد صادر - <?= htmlspecialchars($mail['ref_no']) ?></title>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Cairo:wght@400;700&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
@page {
|
||||
size: A4;
|
||||
margin: 1.5cm;
|
||||
}
|
||||
body {
|
||||
font-family: 'Cairo', 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||
background-color: #fff;
|
||||
color: #333;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
line-height: 1.6;
|
||||
}
|
||||
.print-container {
|
||||
width: 100%;
|
||||
max-width: 21cm;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
}
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
border-bottom: 3px double #333;
|
||||
padding-bottom: 20px;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
.header-logo img {
|
||||
max-height: 100px;
|
||||
max-width: 200px;
|
||||
}
|
||||
.header-info {
|
||||
text-align: left;
|
||||
font-size: 14px;
|
||||
}
|
||||
.header-title {
|
||||
text-align: center;
|
||||
flex-grow: 1;
|
||||
}
|
||||
.header-title h1 {
|
||||
margin: 0;
|
||||
font-size: 28px;
|
||||
color: #000;
|
||||
text-decoration: underline;
|
||||
}
|
||||
.mail-meta {
|
||||
margin-bottom: 30px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 20px;
|
||||
background: #fff;
|
||||
padding: 10px 0;
|
||||
}
|
||||
.meta-item {
|
||||
flex: 1;
|
||||
min-width: 200px;
|
||||
}
|
||||
.meta-label {
|
||||
font-weight: bold;
|
||||
color: #444;
|
||||
font-size: 14px;
|
||||
display: inline-block;
|
||||
width: 100px;
|
||||
}
|
||||
.meta-value {
|
||||
font-size: 16px;
|
||||
color: #000;
|
||||
border-bottom: 1px dotted #ccc;
|
||||
padding-bottom: 2px;
|
||||
}
|
||||
.mail-content-container {
|
||||
border: 1px solid #000;
|
||||
padding: 30px;
|
||||
min-height: 500px;
|
||||
position: relative;
|
||||
margin-top: 20px;
|
||||
}
|
||||
.mail-content {
|
||||
font-size: 16px;
|
||||
text-align: justify;
|
||||
}
|
||||
.footer {
|
||||
margin-top: 50px;
|
||||
padding-top: 20px;
|
||||
border-top: 1px solid #eee;
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
}
|
||||
.no-print {
|
||||
position: fixed;
|
||||
top: 20px;
|
||||
left: 20px;
|
||||
background: #212529;
|
||||
color: #fff;
|
||||
border: none;
|
||||
padding: 10px 25px;
|
||||
border-radius: 30px;
|
||||
cursor: pointer;
|
||||
z-index: 1000;
|
||||
box-shadow: 0 4px 15px rgba(0,0,0,0.3);
|
||||
font-family: 'Cairo', sans-serif;
|
||||
font-weight: bold;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
.no-print:hover {
|
||||
background: #000;
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
@media print {
|
||||
.no-print {
|
||||
display: none;
|
||||
}
|
||||
body {
|
||||
background: none;
|
||||
}
|
||||
.print-container {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
max-width: 100%;
|
||||
}
|
||||
.mail-content-container {
|
||||
border: none;
|
||||
padding: 10px 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<button class="no-print" onclick="window.print()">
|
||||
<i class="fas fa-print me-1"></i> طباعة الوثيقة
|
||||
</button>
|
||||
|
||||
<div class="print-container">
|
||||
<div class="header">
|
||||
<div class="header-logo">
|
||||
<?php if ($logo): ?>
|
||||
<img src="<?= htmlspecialchars($logo) ?>" alt="Logo">
|
||||
<?php else: ?>
|
||||
<div style="font-weight: bold; font-size: 24px; color: #1a73e8;"><?= htmlspecialchars($site_name) ?></div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="header-title">
|
||||
<!-- Title removed as per user request -->
|
||||
</div>
|
||||
<div class="header-info">
|
||||
<!-- Date and time removed as per user request -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mail-meta">
|
||||
<div class="meta-item">
|
||||
<span class="meta-label">رقم القيد:</span>
|
||||
<span class="meta-value"><?= htmlspecialchars($mail['ref_no']) ?></span>
|
||||
</div>
|
||||
<div class="meta-item" style="flex: 2;">
|
||||
<span class="meta-label">التاريخ:</span>
|
||||
<span class="meta-value">
|
||||
<?= htmlspecialchars($hijriDate) ?>
|
||||
الموافق:
|
||||
<?= htmlspecialchars($mail['date_registered']) ?>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mail-content-container">
|
||||
<div class="mail-content">
|
||||
<?= $mail['description'] ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="footer">
|
||||
<p>
|
||||
<?php if(!empty($settings['site_address'])): ?> العنوان: <?= htmlspecialchars($settings['site_address']) ?> | <?php endif; ?>
|
||||
<?php if(!empty($settings['site_phone'])): ?> هاتف: <?= htmlspecialchars($settings['site_phone']) ?> | <?php endif; ?>
|
||||
<?php if(!empty($settings['site_email'])): ?> بريد: <?= htmlspecialchars($settings['site_email']) ?><?php endif; ?>
|
||||
</p>
|
||||
<p>النظام الإلكتروني لإدارة البريد - <?= htmlspecialchars($site_name) ?></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@ -205,6 +205,9 @@ if ($type == 'internal') {
|
||||
<a href="<?= $back_link ?>" class="btn btn-outline-secondary">عودة للقائمة</a>
|
||||
<?php if ($type !== 'internal' && canEdit($type)): ?>
|
||||
<a href="<?= $type ?>.php?action=edit&id=<?= $mail['id'] ?>" class="btn btn-outline-primary">تعديل البيانات</a>
|
||||
<?php if ($type === 'outbound'): ?>
|
||||
<a href="print_outbound.php?id=<?= $mail['id'] ?>" target="_blank" class="btn btn-outline-secondary"><i class="fas fa-print me-1"></i> طباعة</a>
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user