{"id":470108,"date":"2025-08-08T21:01:18","date_gmt":"2025-08-08T21:01:18","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=470108"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=470108","title":{"rendered":"<span>\u041c\u0438\u043d\u0438 \u0441\u0438\u0441\u0442\u0435\u043c\u0430 web \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0433\u0440\u0430\u0444\u0438\u043a\u043e\u043c \u0441\u043c\u0435\u043d \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u043e\u0432<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<blockquote>\n<p>\u041c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c, \u043a\u043e\u043c\u0443-\u0442\u043e \u043f\u0440\u0438\u0433\u043e\u0434\u0438\u0442\u0441\u044f.<\/p>\n<p>\u041a\u0430\u0434\u0440\u043e\u0432\u0438\u043a\u0438 \u0443 \u043d\u0430\u0441 \u043b\u0435\u043d\u0438\u0432\u044b\u0435 (\u0430 \u043c\u043e\u0436\u0435\u0442, \u043f\u0440\u043e\u0441\u0442\u043e \u043d\u0435 \u0443\u043c\u0435\u044e\u0442) \u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u043e \u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0433\u0440\u0430\u0444\u0438\u043a \u0434\u043b\u044f \u0441\u043c\u0435\u043d\u043d\u044b\u0445 \u0434\u0435\u0436\u0443\u0440\u043d\u044b\u0445. \u042f \u043f\u043e\u043d\u0438\u043c\u0430\u044e, \u0447\u0442\u043e \u0432 Excel \u0442\u0430\u043a\u043e\u0439 \u0442\u0430\u0431\u0435\u043b\u044c \u0437\u0430\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u0437\u0430 5 \u043c\u0438\u043d\u0443\u0442, \u043d\u043e \u043c\u043d\u0435 \u0437\u0430\u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u044d\u0442\u043e \u043f\u0440\u043e\u0449\u0435.<\/p>\n<p>\u042f \u0432\u044b\u0431\u0440\u0430\u043b XAMPP \u2014 \u043f\u0440\u043e\u0441\u0442\u043e \u0438 \u0431\u044b\u0441\u0442\u0440\u043e. \u0414\u0443\u043c\u0430\u044e, \u0435\u0433\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u043d\u0435 \u0441\u043e\u0441\u0442\u0430\u0432\u0438\u0442 \u0442\u0440\u0443\u0434\u0430.<\/p>\n<p>\u0412 \u043c\u043e\u0451\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043a\u0430\u0442\u0430\u043b\u043e\u0433 \u0434\u043b\u044f \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043d\u0430\u0437\u0432\u0430\u043b\u00a0<code>schedule<\/code>.<\/p>\n<\/blockquote>\n<h4>\u041d\u0430\u0431\u043e\u0440 \u0441\u043a\u0440\u0438\u043f\u0442\u043e\u0432 \u0438 \u0448\u0430\u0431\u043b\u043e\u043d\u043e\u0432<\/h4>\n<h3>HTML-\u0448\u0430\u0431\u043b\u043e\u043d\u044b<\/h3>\n<p>\u0421\u0434\u0435\u043b\u0430\u043b \u0434\u0432\u0430 \u0448\u0430\u0431\u043b\u043e\u043d\u0430:<\/p>\n<ol>\n<li>\n<p>\u0414\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0433\u0440\u0430\u0444\u0438\u043a\u043e\u043c<\/p>\n<\/li>\n<li>\n<p>\u0414\u043b\u044f \u043f\u0435\u0447\u0430\u0442\u043d\u043e\u0439 \u0444\u043e\u0440\u043c\u044b<\/p>\n<\/li>\n<\/ol>\n<p><strong>\u041f\u0435\u0440\u0432\u044b\u0439 \u0448\u0430\u0431\u043b\u043e\u043d<\/strong>\u00a0(<code>index.php<\/code>, \u043b\u0435\u0436\u0438\u0442 \u0432 \u043a\u043e\u0440\u043d\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430):<\/p>\n<pre><code class=\"php\">&lt;?php include 'includes\/db.php'; ?&gt; &lt;!DOCTYPE html&gt; &lt;html lang=\"ru\"&gt; &lt;head&gt;   &lt;meta charset=\"UTF-8\"&gt;   &lt;title&gt;\u0413\u0440\u0430\u0444\u0438\u043a \u0441\u043c\u0435\u043d&lt;\/title&gt;   &lt;link rel=\"stylesheet\" href=\"css\/style.css\"&gt; &lt;\/head&gt; &lt;body&gt;   &lt;div class=\"container\"&gt;     &lt;div class=\"nav-tabs\"&gt;       &lt;a class=\"active\" onclick=\"showTab('schedule')\"&gt;\u0413\u0440\u0430\u0444\u0438\u043a \u0441\u043c\u0435\u043d&lt;\/a&gt; &lt;a href=\"view_schedule.php\" target=\"_blank\"&gt;\u0412\u0435\u0440\u0441\u0438\u044f \u0434\u043b\u044f \u043f\u0435\u0447\u0430\u0442\u0438&lt;\/a&gt;       &lt;a onclick=\"showTab('employees')\"&gt;\u0421\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u0438&lt;\/a&gt;     &lt;\/div&gt;      &lt;div id=\"schedule-tab\" class=\"tab-content active\"&gt;       &lt;h2&gt;\u0413\u0440\u0430\u0444\u0438\u043a \u0441\u043c\u0435\u043d \u043d\u0430 &lt;span id=\"current-month\"&gt;&lt;\/span&gt;&lt;\/h2&gt;       &lt;div class=\"controls\"&gt;         &lt;button onclick=\"addEmployeeRow()\"&gt;\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u0443&lt;\/button&gt; &lt;button onclick=\"autoGenerateSelectedRow()\"&gt;\u0421\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0433\u0440\u0430\u0444\u0438\u043a 2\/2&lt;\/button&gt;       &lt;\/div&gt;       &lt;div class=\"schedule-wrapper\"&gt;         &lt;table id=\"schedule-table\"&gt;           &lt;thead id=\"schedule-header\"&gt;             &lt;tr&gt;               &lt;th&gt;\u0421\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a&lt;\/th&gt;               &lt;!-- \u0414\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438 \u0434\u0430\u0442 --&gt;             &lt;\/tr&gt;           &lt;\/thead&gt;           &lt;tbody id=\"schedule-body\"&gt;             &lt;!-- \u0421\u0442\u0440\u043e\u043a\u0438 \u0431\u0443\u0434\u0443\u0442 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c\u0441\u044f \u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u0438 --&gt;           &lt;\/tbody&gt;         &lt;\/table&gt;       &lt;\/div&gt;     &lt;\/div&gt;      &lt;div id=\"employees-tab\" class=\"tab-content\"&gt;       &lt;h2&gt;\u0423\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u0430\u043c\u0438&lt;\/h2&gt;       &lt;div class=\"employee-form\"&gt;         &lt;input type=\"text\" id=\"new-fullname\" placeholder=\"\u0424\u0418\u041e \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u0430\"&gt;         &lt;button onclick=\"addEmployee()\"&gt;\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c&lt;\/button&gt;       &lt;\/div&gt;       &lt;div class=\"employee-list\"&gt;         &lt;select id=\"employee-list\" size=\"8\" multiple&gt;&lt;\/select&gt;         &lt;button onclick=\"removeEmployee()\"&gt;\u0423\u0434\u0430\u043b\u0438\u0442\u044c \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0445&lt;\/button&gt;       &lt;\/div&gt;              &lt;div class=\"status-controls\"&gt;         &lt;h3&gt;\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0441\u0442\u0430\u0442\u0443\u0441\u0430&lt;\/h3&gt;         &lt;select id=\"status-employee\"&gt;&lt;\/select&gt;         &lt;label&gt;\u0421: &lt;input type=\"date\" id=\"date-from\"&gt;&lt;\/label&gt;         &lt;label&gt;\u041f\u043e: &lt;input type=\"date\" id=\"date-to\"&gt;&lt;\/label&gt;         &lt;button onclick=\"setStatus('vacation')\"&gt;\u041e\u0442\u043f\u0443\u0441\u043a&lt;\/button&gt;         &lt;button onclick=\"setStatus('sick_leave')\"&gt;\u0411\u043e\u043b\u044c\u043d\u0438\u0447\u043d\u044b\u0439&lt;\/button&gt;       &lt;\/div&gt;     &lt;\/div&gt;   &lt;\/div&gt;    &lt;script src=\"js\/main.js\"&gt;&lt;\/script&gt;   &lt;script src=\"js\/schedule.js\"&gt;&lt;\/script&gt;   &lt;script src=\"js\/employees.js\"&gt;&lt;\/script&gt; &lt;\/body&gt; &lt;\/html&gt;<\/code><\/pre>\n<blockquote>\n<p>\u041d\u0430 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435 \u0434\u0432\u0430 \u0440\u0430\u0437\u0434\u0435\u043b\u0430:<\/p>\n<ul>\n<li>\n<p>\u0421\u0430\u043c \u0433\u0440\u0430\u0444\u0438\u043a<\/p>\n<\/li>\n<li>\n<p>\u0423\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u0430\u043c\u0438 (\u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435, \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0435, \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0441\u0442\u0430\u0442\u0443\u0441\u043e\u0432: \u0431\u043e\u043b\u044c\u043d\u0438\u0447\u043d\u044b\u0439 \u0438 \u043e\u0442\u043f\u0443\u0441\u043a)<\/p>\n<\/li>\n<\/ul>\n<\/blockquote>\n<figure class=\"full-width\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/a03\/100\/d35\/a03100d35c6cc21388e264ac68a5f63f.png\" width=\"1923\" height=\"657\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/a03\/100\/d35\/a03100d35c6cc21388e264ac68a5f63f.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/a03\/100\/d35\/a03100d35c6cc21388e264ac68a5f63f.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/figure>\n<figure class=\"full-width\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/567\/7e0\/eb9\/5677e0eb9bca3db10a095ef128806224.png\" width=\"1152\" height=\"648\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/567\/7e0\/eb9\/5677e0eb9bca3db10a095ef128806224.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/567\/7e0\/eb9\/5677e0eb9bca3db10a095ef128806224.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/figure>\n<h4>\u0421\u043a\u0440\u0438\u043f\u0442\u044b \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u0430\u043c\u0438 \u0438 \u0441\u0442\u0430\u0442\u0443\u0441\u0430\u043c\u0438<\/h4>\n<h3>add_employee.php\u00a0(\u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u043e\u0432, \u043b\u0435\u0436\u0438\u0442 \u0432\u00a0schedule\/api):<\/h3>\n<pre><code class=\"php\">&lt;?php include '..\/includes\/db.php'; header('Content-Type: application\/json');  $data = json_decode(file_get_contents(\"php:\/\/input\"), true); $fullname = trim($data['fullname']);  if (empty($fullname)) {     http_response_code(400);     echo json_encode(['error' =&gt; 'Fullname is required']);     exit; }  $stmt = $conn-&gt;prepare(\"INSERT INTO employees (fullname) VALUES (?)\"); $stmt-&gt;bind_param(\"s\", $fullname);  if ($stmt-&gt;execute()) {     echo json_encode(['success' =&gt; true, 'id' =&gt; $stmt-&gt;insert_id]); } else {     http_response_code(500);     echo json_encode(['error' =&gt; 'Database error']); } ?&gt;<\/code><\/pre>\n<h3>delete_employee.php\u00a0(\u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0435 \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u0430, \u043b\u0435\u0436\u0438\u0442 \u0432\u00a0schedule\/api):<\/h3>\n<pre><code class=\"php\">&lt;?php include '..\/includes\/db.php'; header('Content-Type: application\/json');  $data = json_decode(file_get_contents(\"php:\/\/input\"), true); $id = (int)$data['id'];  $stmt = $conn-&gt;prepare(\"DELETE FROM employees WHERE id = ?\"); $stmt-&gt;bind_param(\"i\", $id);  if ($stmt-&gt;execute()) {     echo json_encode(['success' =&gt; true]); } else {     http_response_code(500);     echo json_encode(['error' =&gt; 'Database error']); } ?&gt;<\/code><\/pre>\n<h3>get_schedule.php\u00a0(\u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0433\u0440\u0430\u0444\u0438\u043a \u0441\u043c\u0435\u043d \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u043e\u0432 \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0440\u0430\u0441\u043f\u0438\u0441\u0430\u043d\u0438\u044f, \u0432\u043a\u043b\u044e\u0447\u0430\u044f \u0441\u0442\u0430\u0442\u0443\u0441\u044b, \u043b\u0435\u0436\u0438\u0442 \u0432\u00a0schedule\/api):<\/h3>\n<pre><code class=\"php\">&lt;?php include '..\/includes\/db.php'; header('Content-Type: application\/json');  try {     $result = [];          \/\/ \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0432\u0441\u0435\u0445 \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u043e\u0432     $employees = $conn-&gt;query(\"SELECT id, fullname FROM employees ORDER BY fullname\");          \/\/ \u041f\u043e\u0434\u0433\u043e\u0442\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u0437\u0430\u0440\u0430\u043d\u0435\u0435     $shiftQuery = $conn-&gt;prepare(\"SELECT shift_date, shift_type FROM shifts WHERE employee_id = ?\");     $statusQuery = $conn-&gt;prepare(\"SELECT start_date, end_date, status_type FROM employee_status WHERE employee_id = ?\");          while ($emp = $employees-&gt;fetch_assoc()) {         $emp_id = $emp['id'];         $schedule = []; \/\/ \u041e\u0431\u044a\u0435\u0434\u0438\u043d\u0435\u043d\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0441\u043c\u0435\u043d \u0438 \u0441\u0442\u0430\u0442\u0443\u0441\u043e\u0432                  \/\/ \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0441\u043c\u0435\u043d\u044b         $shiftQuery-&gt;bind_param(\"i\", $emp_id);         $shiftQuery-&gt;execute();         $shifts = $shiftQuery-&gt;get_result()-&gt;fetch_all(MYSQLI_ASSOC);                  foreach ($shifts as $shift) {             $schedule[$shift['shift_date']] = [                 'type' =&gt; $shift['shift_type'],                 'is_status' =&gt; false             ];         }                  \/\/ \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0441\u0442\u0430\u0442\u0443\u0441\u044b         $statusQuery-&gt;bind_param(\"i\", $emp_id);         $statusQuery-&gt;execute();         $statuses = $statusQuery-&gt;get_result()-&gt;fetch_all(MYSQLI_ASSOC);                  foreach ($statuses as $status) {             $start = new DateTime($status['start_date']);             $end = new DateTime($status['end_date']);                          \/\/ \u041f\u0435\u0440\u0435\u0431\u0438\u0440\u0430\u0435\u043c \u0432\u0441\u0435 \u0434\u0430\u0442\u044b \u043f\u0435\u0440\u0438\u043e\u0434\u0430 \u0441\u0442\u0430\u0442\u0443\u0441\u0430 (\u0432\u043a\u043b\u044e\u0447\u0430\u044f \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0439 \u0434\u0435\u043d\u044c)             for ($date = $start; $date &lt;= $end; $date-&gt;modify('+1 day')) {                 $dateStr = $date-&gt;format('Y-m-d');                 $schedule[$dateStr] = [                     'type' =&gt; $status['status_type'],                     'is_status' =&gt; true                 ];             }         }                  \/\/ \u0424\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u0441 \u0442\u0438\u043f\u0430\u043c\u0438 (\u0441\u0442\u0430\u0442\u0443\u0441\u044b \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u044e\u0442 \u0441\u043c\u0435\u043d\u044b)         $formattedShifts = [];         foreach ($schedule as $date =&gt; $item) {             $formattedShifts[$date] = $item['type'];         }                  $result[] = [             \"id\" =&gt; $emp_id,             \"fullname\" =&gt; $emp['fullname'],             \"shifts\" =&gt; $formattedShifts         ];     }          echo json_encode($result);      } catch (Exception $e) {     http_response_code(500);     echo json_encode(['error' =&gt; 'Database error: ' . $e-&gt;getMessage()]); } ?&gt;<\/code><\/pre>\n<h3>get_employees.php\u00a0(\u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u0441\u043f\u0438\u0441\u043a\u0430 \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u043e\u0432, \u043b\u0435\u0436\u0438\u0442 \u0432\u00a0schedule\/api):<\/h3>\n<pre><code class=\"php\">&lt;?php include '..\/includes\/db.php'; header('Content-Type: application\/json');  $result = $conn-&gt;query(\"SELECT id, fullname FROM employees ORDER BY fullname\"); $employees = [];  while ($row = $result-&gt;fetch_assoc()) {     $employees[] = $row; }  echo json_encode($employees);  ?&gt;<\/code><\/pre>\n<h3>save_auto_schedule.php\u00a0(\u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0435 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u0433\u0440\u0430\u0444\u0438\u043a\u0430 \u043f\u043e\u0441\u043b\u0435 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438, \u043b\u0435\u0436\u0438\u0442 \u0432\u00a0schedule\/api):<\/h3>\n<pre><code class=\"php\">&lt;?php include '..\/includes\/db.php'; header('Content-Type: application\/json');  $data = json_decode(file_get_contents(\"php:\/\/input\"), true); $employeeId = $data['employee_id']; $shifts = $data['shifts'];  try {     $conn-&gt;begin_transaction();          foreach ($shifts as $shift) {         $stmt = $conn-&gt;prepare(\"INSERT INTO shifts (employee_id, shift_date, shift_type)                                VALUES (?, ?, ?)                               ON DUPLICATE KEY UPDATE shift_type = VALUES(shift_type)\");         $stmt-&gt;bind_param(\"iss\", $employeeId, $shift['date'], $shift['shiftType']);         $stmt-&gt;execute();     }          $conn-&gt;commit();     echo json_encode(['success' =&gt; true]); } catch (Exception $e) {     $conn-&gt;rollback();     http_response_code(500);     echo json_encode(['success' =&gt; false, 'message' =&gt; $e-&gt;getMessage()]); } ?&gt;<\/code><\/pre>\n<h3>set_schedule.php\u00a0(\u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0438 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0433\u0440\u0430\u0444\u0438\u043a\u0430 \u0434\u043b\u044f \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u0430, \u043b\u0435\u0436\u0438\u0442 \u0432\u00a0schedule\/api):<\/h3>\n<pre><code class=\"php\">&lt;?php include '..\/includes\/db.php'; include '..\/includes\/functions.php';  header('Content-Type: application\/json');  $data = json_decode(file_get_contents(\"php:\/\/input\"), true); $employeeId = $data['employee_id']; $date = $data['date']; $shiftType = $data['shift_type'];  if (!employeeExists($employeeId)) {     echo json_encode(['success' =&gt; false, 'message' =&gt; '\u0421\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d']);     exit; }  if (!validateDate($date)) {     echo json_encode(['success' =&gt; false, 'message' =&gt; '\u041d\u0435\u0432\u0435\u0440\u043d\u044b\u0439 \u0444\u043e\u0440\u043c\u0430\u0442 \u0434\u0430\u0442\u044b']);     exit; }  if (!in_array($shiftType, ['day', 'night', 'off'])) {     echo json_encode(['success' =&gt; false, 'message' =&gt; '\u041d\u0435\u0432\u0435\u0440\u043d\u044b\u0439 \u0442\u0438\u043f \u0441\u043c\u0435\u043d\u044b']);     exit; }  $stmt = $conn-&gt;prepare(\"SELECT id FROM shifts WHERE employee_id = ? AND shift_date = ?\"); $stmt-&gt;bind_param(\"is\", $employeeId, $date); $stmt-&gt;execute(); $result = $stmt-&gt;get_result();  if ($result-&gt;num_rows &gt; 0) {     $stmt = $conn-&gt;prepare(\"UPDATE shifts SET shift_type = ? WHERE employee_id = ? AND shift_date = ?\");     $stmt-&gt;bind_param(\"sis\", $shiftType, $employeeId, $date); } else {     $stmt = $conn-&gt;prepare(\"INSERT INTO shifts (employee_id, shift_date, shift_type) VALUES (?, ?, ?)\");     $stmt-&gt;bind_param(\"iss\", $employeeId, $date, $shiftType); }  if ($stmt-&gt;execute()) {     echo json_encode(['success' =&gt; true]); } else {     echo json_encode(['success' =&gt; false, 'message' =&gt; '\u041e\u0448\u0438\u0431\u043a\u0430 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445']); } ?&gt;<\/code><\/pre>\n<h3>set_status.php\u00a0(\u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0441\u0442\u0430\u0442\u0443\u0441\u0430 \u0434\u043b\u044f \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u0430 \u0437\u0430 \u043f\u0435\u0440\u0438\u043e\u0434, \u043b\u0435\u0436\u0438\u0442 \u0432\u00a0schedule\/api):<\/h3>\n<pre><code class=\"php\">&lt;?php include '..\/includes\/db.php'; header('Content-Type: application\/json');  $data = json_decode(file_get_contents(\"php:\/\/input\"), true); $employee_id = (int)$data['employee_id']; $start_date = $data['start_date']; $end_date = $data['end_date']; $status_type = $data['status_type'];  if (empty($employee_id) || empty($start_date) || empty($end_date) || empty($status_type)) {     http_response_code(400);     echo json_encode(['error' =&gt; 'All fields are required']);     exit; }  $stmt = $conn-&gt;prepare(\"DELETE FROM shifts WHERE employee_id = ? AND shift_date BETWEEN ? AND ?\"); $stmt-&gt;bind_param(\"iss\", $employee_id, $start_date, $end_date); $stmt-&gt;execute();  $stmt = $conn-&gt;prepare(\"INSERT INTO employee_status (employee_id, start_date, end_date, status_type) VALUES (?, ?, ?, ?)\"); $stmt-&gt;bind_param(\"isss\", $employee_id, $start_date, $end_date, $status_type);  if ($stmt-&gt;execute()) {     echo json_encode(['success' =&gt; true]); } else {     http_response_code(500);     echo json_encode(['error' =&gt; 'Database error']); } ?&gt;<\/code><\/pre>\n<h3>status.php\u00a0(\u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0441 \u0411\u0414, \u043b\u0435\u0436\u0438\u0442 \u0432\u00a0schedule\/api):<\/h3>\n<pre><code class=\"php\">&lt;?php include '..\/includes\/db.php'; include '..\/includes\/functions.php';  header('Content-Type: application\/json');  $method = $_SERVER['REQUEST_METHOD'];  switch ($method) {     case 'GET':         getEmployeeStatus();         break;     case 'POST':         setEmployeeStatus();         break;     case 'DELETE':         removeEmployeeStatus();         break;     default:         http_response_code(405);         echo json_encode(['error' =&gt; 'Method not allowed']); }  function getEmployeeStatus() {     global $conn;          $employeeId = isset($_GET['employee_id']) ? (int)$_GET['employee_id'] : null;     $date = isset($_GET['date']) ? $_GET['date'] : null;          $sql = \"SELECT es.*, e.fullname              FROM employee_status es             JOIN employees e ON es.employee_id = e.id\";          $conditions = [];     $params = [];     $types = '';          if ($employeeId) {         $conditions[] = \"employee_id = ?\";         $params[] = $employeeId;         $types .= 'i';     }          if ($date) {         $conditions[] = \"? BETWEEN start_date AND end_date\";         $params[] = $date;         $types .= 's';     }          if (!empty($conditions)) {         $sql .= \" WHERE \" . implode(\" AND \", $conditions);     }          $stmt = $conn-&gt;prepare($sql);          if (!empty($params)) {         $stmt-&gt;bind_param($types, ...$params);     }          $stmt-&gt;execute();     $result = $stmt-&gt;get_result();     $statuses = [];          while ($row = $result-&gt;fetch_assoc()) {         $statuses[] = $row;     }          echo json_encode($statuses); }  function setEmployeeStatus() {     global $conn;          $data = json_decode(file_get_contents(\"php:\/\/input\"), true);          $errors = [];          if (empty($data['employee_id'])) {         $errors[] = 'Employee ID is required';     }          if (empty($data['start_date']) || !validateDate($data['start_date'])) {         $errors[] = 'Valid start date is required';     }          if (empty($data['end_date']) || !validateDate($data['end_date'])) {         $errors[] = 'Valid end date is required';     }          if (empty($data['status_type']) || !in_array($data['status_type'], ['vacation', 'sick_leave'])) {         $errors[] = 'Valid status type is required (vacation or sick_leave)';     }          if (!empty($errors)) {         http_response_code(400);         echo json_encode(['errors' =&gt; $errors]);         return;     }          if (!employeeExists($data['employee_id'])) {         http_response_code(404);         echo json_encode(['error' =&gt; 'Employee not found']);         return;     }          $deleteStmt = $conn-&gt;prepare(\"DELETE FROM shifts WHERE employee_id = ? AND shift_date BETWEEN ? AND ?\");     $deleteStmt-&gt;bind_param(\"iss\", $data['employee_id'], $data['start_date'], $data['end_date']);     $deleteStmt-&gt;execute();          $insertStmt = $conn-&gt;prepare(\"INSERT INTO employee_status (employee_id, start_date, end_date, status_type) VALUES (?, ?, ?, ?)\");     $insertStmt-&gt;bind_param(\"isss\", $data['employee_id'], $data['start_date'], $data['end_date'], $data['status_type']);          if ($insertStmt-&gt;execute()) {         echo json_encode(['success' =&gt; true, 'id' =&gt; $insertStmt-&gt;insert_id]);     } else {         http_response_code(500);         echo json_encode(['error' =&gt; 'Database error']);     } }  function removeEmployeeStatus() {     global $conn;          $statusId = isset($_GET['id']) ? (int)$_GET['id'] : null;          if (!$statusId) {         http_response_code(400);         echo json_encode(['error' =&gt; 'Status ID is required']);         return;     }          $stmt = $conn-&gt;prepare(\"DELETE FROM employee_status WHERE id = ?\");     $stmt-&gt;bind_param(\"i\", $statusId);          if ($stmt-&gt;execute()) {         echo json_encode(['success' =&gt; true]);     } else {         http_response_code(500);         echo json_encode(['error' =&gt; 'Database error']);     } } ?&gt;<\/code><\/pre>\n<blockquote>\n<p>\u0421\u043a\u0440\u0438\u043f\u0442\u044b \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u044e\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438:<\/p>\n<ol>\n<li>\n<p>\u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u043e\u0432 \u0432 \u0441\u0438\u0441\u0442\u0435\u043c\u0443<\/p>\n<\/li>\n<li>\n<p>\u0413\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044e \u0440\u0430\u0431\u043e\u0447\u0438\u0445 \u0433\u0440\u0430\u0444\u0438\u043a\u043e\u0432<\/p>\n<\/li>\n<li>\n<p>\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0443 \u0441\u0442\u0430\u0442\u0443\u0441\u043e\u0432 \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u043e\u0432 \u043d\u0430 \u0437\u0430\u0434\u0430\u043d\u043d\u044b\u0439 \u043f\u0435\u0440\u0438\u043e\u0434<\/p>\n<\/li>\n<\/ol>\n<p><strong>\u041e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0438 \u0440\u0430\u0431\u043e\u0442\u044b \u0441\u043e \u0441\u0442\u0430\u0442\u0443\u0441\u0430\u043c\u0438:<\/strong><br \/>\u0424\u0443\u043d\u043a\u0446\u0438\u044f\u00a0<code>set_status<\/code>\u00a0\u0438\u043c\u0435\u0435\u0442 \u043f\u0440\u0438\u043e\u0440\u0438\u0442\u0435\u0442 \u043d\u0430\u0434 \u0441\u0442\u0430\u0442\u0443\u0441\u0430\u043c\u0438 \u0441\u043c\u0435\u043d \u0432 \u0433\u0440\u0430\u0444\u0438\u043a\u0435. \u042d\u0442\u043e \u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442, \u0447\u0442\u043e \u0435\u0441\u043b\u0438 \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 \u043e\u0442\u043f\u0443\u0441\u043a\u0435 \u0441 1 \u043f\u043e 10 \u0447\u0438\u0441\u043b\u043e, \u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0442\u044c \u0435\u043c\u0443 \u0440\u0430\u0431\u043e\u0447\u0438\u0435 \u0441\u043c\u0435\u043d\u044b \u043d\u0430 \u044d\u0442\u043e\u0442 \u043f\u0435\u0440\u0438\u043e\u0434.<\/p>\n<\/blockquote>\n<blockquote>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0435\u043c\u043d\u043e\u0433\u043e JavaScript:<\/p>\n<p>employees.js\u00a0(\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f: \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435, \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0435, \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0441\u0442\u0430\u0442\u0443\u0441\u043e\u0432, \u043b\u0435\u0436\u0438\u0442 \u0432\u00a0schedule\/js):<\/p>\n<\/blockquote>\n<pre><code class=\"javascript\">function fetchEmployees() {   fetch('api\/get_employees.php')     .then(response =&gt; response.json())     .then(data =&gt; {       const employeeList = document.getElementById('employee-list');       const statusEmployee = document.getElementById('status-employee');              employeeList.innerHTML = '';       statusEmployee.innerHTML = '';              data.forEach(employee =&gt; {         const option1 = document.createElement('option');         option1.value = employee.id;         option1.textContent = employee.fullname;         employeeList.appendChild(option1);                  const option2 = document.createElement('option');         option2.value = employee.id;         option2.textContent = employee.fullname;         statusEmployee.appendChild(option2);       });     }); }  function addEmployee() {   const fullname = document.getElementById('new-fullname').value.trim();      if (!fullname) {     alert('\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u0424\u0418\u041e \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u0430');     return;   }      fetch('api\/add_employee.php', {     method: 'POST',     headers: { 'Content-Type': 'application\/json' },     body: JSON.stringify({ fullname: fullname })   })   .then(response =&gt; {     if (!response.ok) throw new Error('\u041e\u0448\u0438\u0431\u043a\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0430');     return response.json();   })   .then(() =&gt; {     document.getElementById('new-fullname').value = '';     fetchEmployees();   })   .catch(error =&gt; {     console.error('Error:', error);     alert('\u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0438 \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u0430');   }); }  function removeEmployee() {   const employeeList = document.getElementById('employee-list');   const selectedOptions = Array.from(employeeList.selectedOptions);      if (selectedOptions.length === 0) {     alert('\u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u043e\u0432 \u0434\u043b\u044f \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044f');     return;   }      if (!confirm(`\u0423\u0434\u0430\u043b\u0438\u0442\u044c ${selectedOptions.length} \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u043e\u0432?`)) {     return;   }      const promises = selectedOptions.map(option =&gt; {     return fetch('api\/delete_employee.php', {       method: 'POST',       headers: { 'Content-Type': 'application\/json' },       body: JSON.stringify({ id: option.value })     });   });      Promise.all(promises)     .then(() =&gt; fetchEmployees())     .catch(error =&gt; {       console.error('Error:', error);       alert('\u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u0438 \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0438 \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u043e\u0432');     }); }  function setStatus(statusType) {   const employeeId = document.getElementById('status-employee').value;   const dateFrom = document.getElementById('date-from').value;   const dateTo = document.getElementById('date-to').value;      if (!employeeId || !dateFrom || !dateTo) {     alert('\u0417\u0430\u043f\u043e\u043b\u043d\u0438\u0442\u0435 \u0432\u0441\u0435 \u043f\u043e\u043b\u044f');     return;   }      fetch('api\/set_status.php', {     method: 'POST',     headers: { 'Content-Type': 'application\/json' },     body: JSON.stringify({       employee_id: employeeId,       start_date: dateFrom,       end_date: dateTo,       status_type: statusType     })   })   .then(response =&gt; {     if (!response.ok) throw new Error('\u041e\u0448\u0438\u0431\u043a\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0430');     return response.json();   })   .then(() =&gt; {     alert('\u0421\u0442\u0430\u0442\u0443\u0441 \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d');     loadSchedule();    })   .catch(error =&gt; {     console.error('Error:', error);     alert('\u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u0438 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0435 \u0441\u0442\u0430\u0442\u0443\u0441\u0430');   }); }<\/code><\/pre>\n<h3>main.js\u00a0(\u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 \u0438 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u0434\u0430\u043d\u043d\u044b\u0445, \u043b\u0435\u0436\u0438\u0442 \u0432\u00a0schedule\/js):<\/h3>\n<pre><code class=\"javascript\">document.addEventListener('DOMContentLoaded', function() {   const months = ['\u042f\u043d\u0432\u0430\u0440\u044c', '\u0424\u0435\u0432\u0440\u0430\u043b\u044c', '\u041c\u0430\u0440\u0442', '\u0410\u043f\u0440\u0435\u043b\u044c', '\u041c\u0430\u0439', '\u0418\u044e\u043d\u044c',                   '\u0418\u044e\u043b\u044c', '\u0410\u0432\u0433\u0443\u0441\u0442', '\u0421\u0435\u043d\u0442\u044f\u0431\u0440\u044c', '\u041e\u043a\u0442\u044f\u0431\u0440\u044c', '\u041d\u043e\u044f\u0431\u0440\u044c', '\u0414\u0435\u043a\u0430\u0431\u0440\u044c'];   const currentDate = new Date();   document.getElementById('current-month').textContent =      `${months[currentDate.getMonth()]} ${currentDate.getFullYear()}`;      fetchEmployees();   initSchedule();      const today = new Date();   document.getElementById('date-from').valueAsDate = today;   document.getElementById('date-to').valueAsDate = new Date(today.getTime() + 7 * 24 * 60 * 60 * 1000); });  function showTab(tabId) {   document.querySelectorAll('.tab-content').forEach(tab =&gt; {     tab.classList.remove('active');   });      document.querySelectorAll('.nav-tabs a').forEach(tab =&gt; {     tab.classList.remove('active');   });      document.getElementById(tabId + '-tab').classList.add('active');      event.target.classList.add('active'); }<\/code><\/pre>\n<h3>schedule.js\u00a0(\u043e\u0441\u043d\u043e\u0432\u043d\u0430\u044f \u043b\u043e\u0433\u0438\u043a\u0430 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0433\u0440\u0430\u0444\u0438\u043a\u043e\u043c, \u043b\u0435\u0436\u0438\u0442 \u0432\u00a0schedule\/js):<\/h3>\n<pre><code class=\"javascript\">\\\\\u0418\u043c\u044f \u0444\u0430\u0439\u043b\u0430 schedule.js. \u041e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0437\u0430 \u0412\u0421\u0415, \u0444\u0430\u0438\u043b \u043b\u0435\u0436\u0438\u0442 \u0432 schedule\\js function initSchedule() {   const headerRow = document.querySelector('#schedule-header tr');   const currentDate = new Date();   const daysInMonth = new Date(currentDate.getFullYear(), currentDate.getMonth() + 1, 0).getDate();      headerRow.innerHTML = '&lt;th&gt;\u0421\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a&lt;\/th&gt;';      for (let day = 1; day &lt;= daysInMonth; day++) {     const th = document.createElement('th');     th.textContent = day;     headerRow.appendChild(th);   }      const addTh = document.createElement('th');   addTh.innerHTML = '&lt;button onclick=\"addEmployeeRow()\"&gt;+&lt;\/button&gt;';   headerRow.appendChild(addTh);      loadSchedule(); }  function addEmployeeRow(employeeId = null) {   const tbody = document.getElementById('schedule-body');   const currentDate = new Date();   const daysInMonth = new Date(currentDate.getFullYear(), currentDate.getMonth() + 1, 0).getDate();      const row = document.createElement('tr');      const nameCell = document.createElement('td');   nameCell.className = 'name-cell';      const select = document.createElement('select');   select.innerHTML = '&lt;option value=\"\"&gt;\u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u0430&lt;\/option&gt;';      const employeeList = document.getElementById('employee-list');   if (employeeList) {     Array.from(employeeList.options).forEach(option =&gt; {       select.innerHTML += `&lt;option value=\"${option.value}\"&gt;${option.text}&lt;\/option&gt;`;     });   }      if (employeeId) {     select.value = employeeId;   }      select.addEventListener('change', function() {     updateEmployeeSchedule(this.value);   });      nameCell.appendChild(select);   row.appendChild(nameCell);      for (let day = 1; day &lt;= daysInMonth; day++) {     const cell = document.createElement('td');     cell.className = 'shift-cell';     cell.textContent = '-';     cell.onclick = function() {       setShiftForCell(this, row.rowIndex - 1, day);     };     row.appendChild(cell);   }      const deleteCell = document.createElement('td');   deleteCell.innerHTML = '&lt;button onclick=\"removeScheduleRow(this)\"&gt;\u00d7&lt;\/button&gt;';   row.appendChild(deleteCell);      tbody.appendChild(row);   return row; }  function setShiftForCell(cell, rowIndex, day) {   const shiftType = prompt('\u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u0442\u0438\u043f \u0441\u043c\u0435\u043d\u044b:\\n\u0414 - \u0414\u0435\u043d\u044c\\n\u041d - \u041d\u043e\u0447\u044c\\n\u0412 - \u0412\u044b\u0445\u043e\u0434\u043d\u043e\u0439')?.toUpperCase();      if (shiftType &amp;&amp; ['\u0414', '\u041d', '\u0412'].includes(shiftType)) {     cell.textContent = shiftType;     cell.className = `shift-cell ${       shiftType === '\u0414' ? 'day-shift' :        shiftType === '\u041d' ? 'night-shift' : 'day-off'     }`;          \/\/ \u0415\u0441\u043b\u0438 \u044d\u0442\u043e \u043e\u0434\u043d\u0430 \u0438\u0437 \u043f\u0435\u0440\u0432\u044b\u0445 \u0434\u0432\u0443\u0445 \u044f\u0447\u0435\u0435\u043a, \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0435\u043c \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u043e\u0435     if (day &lt;= 2) {       const row = document.querySelector(`#schedule-body tr:nth-child(${rowIndex + 1})`);       const firstCell = row.querySelector('td:nth-child(2)');       const secondCell = row.querySelector('td:nth-child(3)');              if (firstCell.textContent !== '-' &amp;&amp; secondCell.textContent !== '-' &amp;&amp;           confirm('\u0421\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u0441\u043c\u0435\u043d\u044b \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u043f\u0435\u0440\u0432\u044b\u0445 \u0434\u0432\u0443\u0445 \u0434\u043d\u0435\u0439?')) {         generatePairSchedule(rowIndex, [           firstCell.textContent,           secondCell.textContent         ]);       }     }   } }  \/\/ \u041e\u0441\u043d\u043e\u0432\u043d\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u043f\u0430\u0440\u043d\u043e\u0439 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u0433\u0440\u0430\u0444\u0438\u043a\u0430 function generatePairSchedule(rowIndex, firstPair) {   const row = document.querySelector(`#schedule-body tr:nth-child(${rowIndex + 1})`);   if (!row) return;    const cells = row.querySelectorAll('.shift-cell');   const daysInMonth = cells.length;      \/\/ \u0423\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u043f\u0435\u0440\u0432\u0443\u044e \u043f\u0430\u0440\u0443   if (firstPair &amp;&amp; firstPair.length === 2) {     cells[0].textContent = firstPair[0];     cells[0].className = `shift-cell ${getShiftClass(firstPair[0])}`;     cells[1].textContent = firstPair[1];     cells[1].className = `shift-cell ${getShiftClass(firstPair[1])}`;   }    \/\/ \u0413\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u043c \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u0434\u043d\u0438 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u043f\u0430\u0440   for (let i = 2; i &lt; daysInMonth; i += 2) {     const prevPair = [cells[i-2].textContent, cells[i-1].textContent];     const nextPair = getNextPair(prevPair);          \/\/ \u0423\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u043f\u0430\u0440\u0443     cells[i].textContent = nextPair[0];     cells[i].className = `shift-cell ${getShiftClass(nextPair[0])}`;          if (i+1 &lt; daysInMonth) {       cells[i+1].textContent = nextPair[1];       cells[i+1].className = `shift-cell ${getShiftClass(nextPair[1])}`;     }   }    saveAutoGeneratedSchedule(row); }  \/\/ \u041e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u043f\u0430\u0440\u0443 \u0441\u043c\u0435\u043d \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0439 function getNextPair(prevPair) {   const [a, b] = prevPair;      \/\/ \u041e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u043f\u0440\u0430\u0432\u0438\u043b\u0430 \u0447\u0435\u0440\u0435\u0434\u043e\u0432\u0430\u043d\u0438\u044f   if (a === '\u0414' &amp;&amp; b === '\u041d') return ['\u0412', '\u0412']; \/\/ \u0414\u041d \u2192 \u0412\u0412   if (a === '\u0412' &amp;&amp; b === '\u0412') return ['\u0414', '\u041d']; \/\/ \u0412\u0412 \u2192 \u0414\u041d   if (a === '\u0412' &amp;&amp; b === '\u0414') return ['\u041d', '\u0412']; \/\/ \u0412\u0414 \u2192 \u041d\u0412   if (a === '\u041d' &amp;&amp; b === '\u0412') return ['\u0412', '\u0414']; \/\/ \u041d\u0412 \u2192 \u0412\u0414      \/\/ \u0415\u0441\u043b\u0438 \u043f\u0430\u0442\u0442\u0435\u0440\u043d \u043d\u0435 \u0440\u0430\u0441\u043f\u043e\u0437\u043d\u0430\u043d, \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u0432\u044b\u0445\u043e\u0434\u043d\u044b\u0435   return ['\u0412', '\u0412']; }  \/\/ \u0412\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 CSS-\u043a\u043b\u0430\u0441\u0441 \u0434\u043b\u044f \u0442\u0438\u043f\u0430 \u0441\u043c\u0435\u043d\u044b function getShiftClass(shift) {   return shift === '\u0414' ? 'day-shift' :           shift === '\u041d' ? 'night-shift' : 'day-off'; }  \/\/ \u0413\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044f \u0433\u0440\u0430\u0444\u0438\u043a\u0430 \u0434\u043b\u044f \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0438 function autoGenerateSelectedRow() {   const selectedRow = document.querySelector('#schedule-body tr.selected');   if (!selectedRow) {     alert('\u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u0441\u0442\u0440\u043e\u043a\u0443 \u0441 \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u043e\u043c');     return;   }    const firstPair = prompt('\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u043f\u0435\u0440\u0432\u0443\u044e \u043f\u0430\u0440\u0443 \u0441\u043c\u0435\u043d (2 \u0441\u0438\u043c\u0432\u043e\u043b\u0430: \u0414, \u041d \u0438\u043b\u0438 \u0412)\\n\u041f\u0440\u0438\u043c\u0435\u0440\u044b:\\n\u0414\u041d - \u0414\u0435\u043d\u044c-\u041d\u043e\u0447\u044c\\n\u0412\u0412 - \u0412\u044b\u0445\u043e\u0434\u043d\u044b\u0435\\n\u0412\u0414 - \u0412\u044b\u0445\u043e\u0434\u043d\u043e\u0439-\u0414\u0435\u043d\u044c\\n\u041d\u0412 - \u041d\u043e\u0447\u044c-\u0412\u044b\u0445\u043e\u0434\u043d\u043e\u0439')     ?.toUpperCase()     ?.split('');      if (!firstPair || firstPair.length !== 2 ||        !['\u0414', '\u041d', '\u0412'].includes(firstPair[0]) ||        !['\u0414', '\u041d', '\u0412'].includes(firstPair[1])) {     alert('\u041d\u0435\u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u044b\u0439 \u0432\u0432\u043e\u0434. \u0412\u0432\u0435\u0434\u0438\u0442\u0435 2 \u0441\u0438\u043c\u0432\u043e\u043b\u0430 (\u0414, \u041d \u0438\u043b\u0438 \u0412)');     return;   }    const rowIndex = Array.from(document.querySelectorAll('#schedule-body tr')).indexOf(selectedRow);   generatePairSchedule(rowIndex, firstPair); }  \/\/ \u0411\u044b\u0441\u0442\u0440\u0430\u044f \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044f \u043f\u043e \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u043c \u043f\u0430\u0442\u0442\u0435\u0440\u043d\u0430\u043c function generateWithPattern(pattern) {   const patterns = {     'dayNight': ['\u0414', '\u041d'],     'offOff': ['\u0412', '\u0412'],     'offDay': ['\u0412', '\u0414'],     'nightOff': ['\u041d', '\u0412']   };      const selectedRow = document.querySelector('#schedule-body tr.selected');   if (!selectedRow) {     alert('\u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u0441\u0442\u0440\u043e\u043a\u0443 \u0441 \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u043e\u043c');     return;   }      const rowIndex = Array.from(document.querySelectorAll('#schedule-body tr')).indexOf(selectedRow);   generatePairSchedule(rowIndex, patterns[pattern]); }  \/\/ \u0421\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0433\u043e \u0433\u0440\u0430\u0444\u0438\u043a\u0430 function saveAutoGeneratedSchedule(row) {   const employeeId = row.querySelector('select').value;   if (!employeeId) return;    const currentDate = new Date();   const year = currentDate.getFullYear();   const month = currentDate.getMonth();   const shifts = [];    row.querySelectorAll('.shift-cell').forEach((cell, dayIndex) =&gt; {     const day = dayIndex + 1;     const date = `${year}-${String(month + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}`;          let shiftType;     if (cell.textContent === '\u0414') shiftType = 'day';     else if (cell.textContent === '\u041d') shiftType = 'night';     else shiftType = 'off';      shifts.push({ date, shiftType });   });    fetch('api\/save_auto_schedule.php', {     method: 'POST',     headers: { 'Content-Type': 'application\/json' },     body: JSON.stringify({ employee_id: employeeId, shifts })   })   .then(response =&gt; response.json())   .then(data =&gt; {     if (!data.success) {       console.error('\u041e\u0448\u0438\u0431\u043a\u0430 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0433\u0440\u0430\u0444\u0438\u043a\u0430');     }   }); }  function loadSchedule() {   fetch('api\/get_schedule.php')     .then(response =&gt; response.json())     .then(data =&gt; {       data.forEach(employee =&gt; {         const row = addEmployeeRow(employee.id);                  Object.keys(employee.shifts).forEach(date =&gt; {           const day = new Date(date).getDate();           const cell = row.cells[day];           const shiftType = employee.shifts[date];                      switch(shiftType) {             case 'day':               cell.textContent = '\u0414';               cell.className = 'shift-cell day-shift';               break;             case 'night':               cell.textContent = '\u041d';               cell.className = 'shift-cell night-shift';               break;             case 'off':               cell.textContent = '\u0412';               cell.className = 'shift-cell day-off';               break;           }         });       });     }); }  function saveSchedule() {   \/\/ \u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0432\u0441\u0435\u0433\u043e \u0433\u0440\u0430\u0444\u0438\u043a\u0430   alert('\u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0433\u0440\u0430\u0444\u0438\u043a\u0430 \u0431\u0443\u0434\u0435\u0442 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u0430'); }  function removeScheduleRow(button) {   if (confirm('\u0423\u0434\u0430\u043b\u0438\u0442\u044c \u044d\u0442\u0443 \u0441\u0442\u0440\u043e\u043a\u0443 \u0438\u0437 \u0433\u0440\u0430\u0444\u0438\u043a\u0430?')) {     button.closest('tr').remove();   } }  \/\/ \u0412\u044b\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u0441\u0442\u0440\u043e\u043a\u0438 \u043f\u0440\u0438 \u043a\u043b\u0438\u043a\u0435 document.addEventListener('click', function(e) {   if (e.target.closest('#schedule-body tr')) {     document.querySelectorAll('#schedule-body tr').forEach(row =&gt; {       row.classList.remove('selected');     });     e.target.closest('tr').classList.add('selected');   } });  \/\/ \u0411\u044b\u0441\u0442\u0440\u044b\u0435 \u043a\u043d\u043e\u043f\u043a\u0438 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 document.addEventListener('DOMContentLoaded', function() {   const quickControls = document.createElement('div');   quickControls.className = 'quick-patterns';   quickControls.innerHTML = `     &lt;button onclick=\"generateWithPattern('dayNight')\"&gt;\u0414\u0435\u043d\u044c-\u041d\u043e\u0447\u044c&lt;\/button&gt;     &lt;button onclick=\"generateWithPattern('offOff')\"&gt;\u0412\u044b\u0445\u043e\u0434\u043d\u044b\u0435&lt;\/button&gt;     &lt;button onclick=\"generateWithPattern('offDay')\"&gt;\u0412\u044b\u0445-\u0414\u0435\u043d\u044c&lt;\/button&gt;     &lt;button onclick=\"generateWithPattern('nightOff')\"&gt;\u041d\u043e\u0447\u044c-\u0412\u044b\u0445&lt;\/button&gt;   `;   document.querySelector('.controls').appendChild(quickControls); });  \/\/ \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0432 \u043a\u043e\u043d\u0435\u0446 \u0444\u0430\u0439\u043b\u0430 function setupStatusButtons() {     document.querySelectorAll('.name-cell').forEach(cell =&gt; {         const employeeId = cell.closest('tr').querySelector('select')?.value;         const employeeName = cell.textContent;                  if (employeeId) {             const statusBtn = document.createElement('button');             statusBtn.textContent = '\u0421\u0442\u0430\u0442\u0443\u0441';             statusBtn.style.marginLeft = '10px';             statusBtn.onclick = (e) =&gt; {                 e.stopPropagation();                 showStatusModal(employeeId, employeeName);             };             cell.appendChild(statusBtn);         }     }); }  \/\/ \u0412\u044b\u0437\u044b\u0432\u0430\u0435\u043c \u044d\u0442\u0443 \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u043f\u043e\u0441\u043b\u0435 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0433\u0440\u0430\u0444\u0438\u043a\u0430 \/\/ \u0412 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 loadSchedule() \u043f\u043e\u0441\u043b\u0435 \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043e\u0431\u0430\u0432\u044c\u0442\u0435: setupStatusButtons();<\/code><\/pre>\n<h3>status.js\u00a0(\u0440\u0430\u0431\u043e\u0442\u0430 \u0441\u043e \u0441\u0442\u0430\u0442\u0443\u0441\u0430\u043c\u0438, \u043b\u0435\u0436\u0438\u0442 \u0432\u00a0schedule\/js):<\/h3>\n<pre><code class=\"javascript\">\\\\\u0418\u043c\u044f \u0444\u0430\u0439\u043b\u0430 status.js. \u0412\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0443 \u0441\u043e \u0441\u0442\u0430\u0442\u0443\u0441\u0430\u043c\u0438, \u0444\u0430\u0438\u043b \u043b\u0435\u0436\u0438\u0442 \u0432 schedule\\js function showStatusModal(employeeId, employeeName) {     const modal = document.createElement('div');     modal.className = 'modal';     modal.innerHTML = `         &lt;div class=\"modal-content\"&gt;             &lt;span class=\"close\"&gt;&amp;times;&lt;\/span&gt;             &lt;h3&gt;\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0441\u0442\u0430\u0442\u0443\u0441\u0430 \u0434\u043b\u044f ${employeeName}&lt;\/h3&gt;             &lt;div class=\"form-group\"&gt;                 &lt;label&gt;\u0422\u0438\u043f \u0441\u0442\u0430\u0442\u0443\u0441\u0430:&lt;\/label&gt;                 &lt;select id=\"status-type\"&gt;                     &lt;option value=\"vacation\"&gt;\u041e\u0442\u043f\u0443\u0441\u043a&lt;\/option&gt;                     &lt;option value=\"sick_leave\"&gt;\u0411\u043e\u043b\u044c\u043d\u0438\u0447\u043d\u044b\u0439&lt;\/option&gt;                 &lt;\/select&gt;             &lt;\/div&gt;             &lt;div class=\"form-group\"&gt;                 &lt;label&gt;\u0421:&lt;\/label&gt;                 &lt;input type=\"date\" id=\"status-start-date\"&gt;             &lt;\/div&gt;             &lt;div class=\"form-group\"&gt;                 &lt;label&gt;\u041f\u043e:&lt;\/label&gt;                 &lt;input type=\"date\" id=\"status-end-date\"&gt;             &lt;\/div&gt;             &lt;button onclick=\"saveStatus(${employeeId})\"&gt;\u0421\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c&lt;\/button&gt;             &lt;div id=\"status-list\"&gt;&lt;\/div&gt;         &lt;\/div&gt;     `;          document.body.appendChild(modal);          const today = new Date();     document.getElementById('status-start-date').valueAsDate = today;     document.getElementById('status-end-date').valueAsDate = new Date(today.getTime() + 7 * 24 * 60 * 60 * 1000);          modal.querySelector('.close').onclick = () =&gt; modal.remove();          loadEmployeeStatuses(employeeId); }  function loadEmployeeStatuses(employeeId) {     fetch(`api\/status.php?employee_id=${employeeId}`)         .then(response =&gt; response.json())         .then(statuses =&gt; {             const statusList = document.getElementById('status-list');             statusList.innerHTML = '&lt;h4&gt;\u0422\u0435\u043a\u0443\u0449\u0438\u0435 \u0441\u0442\u0430\u0442\u0443\u0441\u044b:&lt;\/h4&gt;';                          if (statuses.length === 0) {                 statusList.innerHTML += '&lt;p&gt;\u041d\u0435\u0442 \u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0445 \u0441\u0442\u0430\u0442\u0443\u0441\u043e\u0432&lt;\/p&gt;';                 return;             }                          statuses.forEach(status =&gt; {                 const statusDiv = document.createElement('div');                 statusDiv.className = 'status-item';                 statusDiv.innerHTML = `                     &lt;p&gt;                         ${status.status_type === 'vacation' ? '\u041e\u0442\u043f\u0443\u0441\u043a' : '\u0411\u043e\u043b\u044c\u043d\u0438\u0447\u043d\u044b\u0439'}                          \u0441 ${status.start_date} \u043f\u043e ${status.end_date}                         &lt;button onclick=\"deleteStatus(${status.id})\"&gt;\u0423\u0434\u0430\u043b\u0438\u0442\u044c&lt;\/button&gt;                     &lt;\/p&gt;                 `;                 statusList.appendChild(statusDiv);             });         }); }  function saveStatus(employeeId) {     const statusType = document.getElementById('status-type').value;     const startDate = document.getElementById('status-start-date').value;     const endDate = document.getElementById('status-end-date').value;          fetch('api\/status.php', {         method: 'POST',         headers: { 'Content-Type': 'application\/json' },         body: JSON.stringify({             employee_id: employeeId,             start_date: startDate,             end_date: endDate,             status_type: statusType         })     })     .then(response =&gt; response.json())     .then(() =&gt; {         alert('\u0421\u0442\u0430\u0442\u0443\u0441 \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d');         loadEmployeeStatuses(employeeId);         loadSchedule();     })     .catch(error =&gt; {         console.error('Error:', error);         alert('\u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u0438 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0435 \u0441\u0442\u0430\u0442\u0443\u0441\u0430');     }); }  function deleteStatus(statusId) {     if (!confirm('\u0423\u0434\u0430\u043b\u0438\u0442\u044c \u044d\u0442\u043e\u0442 \u0441\u0442\u0430\u0442\u0443\u0441?')) return;          fetch(`api\/status.php?id=${statusId}`, {         method: 'DELETE'     })     .then(response =&gt; response.json())     .then(() =&gt; {         alert('\u0421\u0442\u0430\u0442\u0443\u0441 \u0443\u0434\u0430\u043b\u0435\u043d');         loadSchedule();     })     .catch(error =&gt; {         console.error('Error:', error);         alert('\u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u0438 \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0438 \u0441\u0442\u0430\u0442\u0443\u0441\u0430');     }); }  function addStatusStyles() {     const style = document.createElement('style');     style.textContent = `         .modal {             display: block;             position: fixed;             z-index: 1;             left: 0;             top: 0;             width: 100%;             height: 100%;             background-color: rgba(0,0,0,0.4);         }                  .modal-content {             background-color: #fefefe;             margin: 15% auto;             padding: 20px;             border: 1px solid #888;             width: 50%;         }                  .close {             color: #aaa;             float: right;             font-size: 28px;             font-weight: bold;             cursor: pointer;         }                  .form-group {             margin-bottom: 15px;         }                  .status-item {             padding: 10px;             border-bottom: 1px solid #eee;         }     `;     document.head.appendChild(style); }  document.addEventListener('DOMContentLoaded', addStatusStyles);<\/code><\/pre>\n<blockquote>\n<p>PHP \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0411\u0414<\/p>\n<p>db.php\u00a0(\u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043a \u0411\u0414, \u043b\u0435\u0436\u0438\u0442 \u0432\u00a0schedule\/includes):<\/p>\n<\/blockquote>\n<pre><code class=\"php\">&lt;?php $host = 'localhost'; $user = 'root'; $pass = ''; $dbname = 'schedule_db'; $conn = new mysqli($host, $user, $pass, $dbname); if ($conn-&gt;connect_error) {     die('\u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f: ' . $conn-&gt;connect_error); } ?&gt;<\/code><\/pre>\n<h3>functions.php\u00a0(\u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432, \u043b\u0435\u0436\u0438\u0442 \u0432\u00a0schedule\/includes):<\/h3>\n<pre><code class=\"php\">&lt;?php function employeeExists($employeeId) {     global $conn;     $stmt = $conn-&gt;prepare(\"SELECT id FROM employees WHERE id = ?\");     $stmt-&gt;bind_param(\"i\", $employeeId);     $stmt-&gt;execute();     $result = $stmt-&gt;get_result();     return $result-&gt;num_rows &gt; 0; }  function validateDate($date, $format = 'Y-m-d') {     $d = DateTime::createFromFormat($format, $date);     return $d &amp;&amp; $d-&gt;format($format) == $date; }  function getEmployeeStatuses($employeeId, $date = null) {     global $conn;          $sql = \"SELECT * FROM employee_status WHERE employee_id = ?\";     $params = [$employeeId];     $types = \"i\";          if ($date) {         $sql .= \" AND ? BETWEEN start_date AND end_date\";         $params[] = $date;         $types .= \"s\";     }          $stmt = $conn-&gt;prepare($sql);     $stmt-&gt;bind_param($types, ...$params);     $stmt-&gt;execute();     $result = $stmt-&gt;get_result();     $statuses = [];          while ($row = $result-&gt;fetch_assoc()) {         $statuses[] = $row;     }          return $statuses; }  function hasActiveStatus($employeeId, $date) {     global $conn;          $stmt = $conn-&gt;prepare(\"SELECT id FROM employee_status                            WHERE employee_id = ? AND ? BETWEEN start_date AND end_date\");     $stmt-&gt;bind_param(\"is\", $employeeId, $date);     $stmt-&gt;execute();     $result = $stmt-&gt;get_result();     return $result-&gt;num_rows &gt; 0; }<\/code><\/pre>\n<h3>employees.php\u00a0(\u0432\u0435\u0431-\u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u0430\u043c\u0438, \u043b\u0435\u0436\u0438\u0442 \u0432\u00a0schedule):<\/h3>\n<pre><code class=\"php\">&lt;?php include 'includes\/db.php'; ?&gt; &lt;!DOCTYPE html&gt; &lt;html lang=\"ru\"&gt; &lt;head&gt;   &lt;meta charset=\"UTF-8\"&gt;   &lt;title&gt;\u0421\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u0438&lt;\/title&gt;   &lt;link rel=\"stylesheet\" href=\"css\/style.css\"&gt; &lt;\/head&gt; &lt;body&gt;   &lt;nav&gt;     &lt;a href=\"index.php\"&gt;\u0413\u0440\u0430\u0444\u0438\u043a&lt;\/a&gt; |     &lt;a href=\"employees.php\"&gt;\u0421\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u0438&lt;\/a&gt;   &lt;\/nav&gt;   &lt;div class=\"container\"&gt;     &lt;h2&gt;\u0423\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u0430\u043c\u0438&lt;\/h2&gt;     &lt;input type=\"text\" id=\"new-name\" placeholder=\"\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u0424\u0418\u041e\"&gt;     &lt;button onclick=\"addEmployee()\"&gt;\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c&lt;\/button&gt;     &lt;br&gt;&lt;br&gt;     &lt;select id=\"employee-list\"&gt;&lt;\/select&gt;     &lt;button onclick=\"deleteEmployee()\"&gt;\u0423\u0434\u0430\u043b\u0438\u0442\u044c&lt;\/button&gt;   &lt;\/div&gt;   &lt;script src=\"js\/script.js\"&gt;&lt;\/script&gt; &lt;\/body&gt; &lt;\/html&gt;<\/code><\/pre>\n<blockquote>\n<p>\u0412\u0442\u043e\u0440\u043e\u0439 HTML-\u0448\u0430\u0431\u043b\u043e\u043d<\/p>\n<p>\u041a\u0430\u043a \u044f \u043f\u0438\u0441\u0430\u043b \u0432 \u043d\u0430\u0447\u0430\u043b\u0435, \u0443 \u043c\u0435\u043d\u044f \u0434\u0432\u0430 HTML-\u0448\u0430\u0431\u043b\u043e\u043d\u0430. \u0412\u0442\u043e\u0440\u043e\u0439 \u044f \u0441\u0434\u0435\u043b\u0430\u043b \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u043d\u0435 \u043f\u043e\u043b\u0443\u0447\u0430\u043b\u043e\u0441\u044c \u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0431\u043e\u043b\u044c\u043d\u0438\u0447\u043d\u043e\u0433\u043e \u0438 \u043e\u0442\u043f\u0443\u0441\u043a\u0430 (\u043a\u0430\u043a \u043f\u043e\u043a\u0430\u0437\u0430\u043d\u043e \u043d\u0430 \u043f\u0435\u0440\u0432\u043e\u043c \u0441\u043a\u0440\u0438\u043d\u0448\u043e\u0442\u0435: \u0443 \u043f\u0435\u0440\u0432\u043e\u0433\u043e \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u0430 \u0441 1 \u043f\u043e 7 \u0447\u0438\u0441\u043b\u043e \u0441\u0442\u043e\u044f\u0442 \u043f\u0440\u043e\u0447\u0435\u0440\u043a\u0438, \u043d\u043e \u0432 &#171;\u0412\u0435\u0440\u0441\u0438\u0438 \u0434\u043b\u044f \u043f\u0435\u0447\u0430\u0442\u0438&#187; \u0443 \u043d\u0435\u0433\u043e \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0435\u0442\u0441\u044f &#171;\u041e\u0442\u043f\u0443\u0441\u043a&#187;). \u0422\u0430\u043a\u0436\u0435 \u0442\u0430\u043c \u0432\u044b\u0432\u043e\u0434\u0438\u0442\u0441\u044f \u043e\u0431\u0449\u0435\u0435 \u0447\u0438\u0441\u043b\u043e \u043e\u0442\u0440\u0430\u0431\u043e\u0442\u0430\u043d\u043d\u044b\u0445 \u0447\u0430\u0441\u043e\u0432 \u0437\u0430 \u043c\u0435\u0441\u044f\u0446 (\u0438\u0437 \u0440\u0430\u0441\u0447\u0451\u0442\u0430: 1 \u0441\u043c\u0435\u043d\u0430 = 11 \u0447\u0430\u0441\u043e\u0432).  <\/p>\n<\/blockquote>\n<figure class=\"full-width\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/248\/b5d\/9e2\/248b5d9e20d1beb518b29b90a3ab5542.png\" width=\"1901\" height=\"757\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/248\/b5d\/9e2\/248b5d9e20d1beb518b29b90a3ab5542.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/248\/b5d\/9e2\/248b5d9e20d1beb518b29b90a3ab5542.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/figure>\n<h3>view_schedule.php\u00a0(\u0432\u0435\u0440\u0441\u0438\u044f \u0434\u043b\u044f \u043f\u0435\u0447\u0430\u0442\u0438, \u0440\u0430\u0441\u0447\u0451\u0442 \u0432\u0440\u0435\u043c\u0435\u043d\u0438, \u043b\u0435\u0436\u0438\u0442 \u0432\u00a0schedule):<\/h3>\n<pre><code class=\"php\">&lt;?php include 'includes\/db.php'; ?&gt; &lt;!DOCTYPE html&gt; &lt;html lang=\"ru\"&gt; &lt;head&gt;   &lt;meta charset=\"UTF-8\"&gt;   &lt;title&gt;\u041f\u0440\u043e\u0441\u043c\u043e\u0442\u0440 \u0433\u0440\u0430\u0444\u0438\u043a\u0430 \u0441\u043c\u0435\u043d&lt;\/title&gt;   &lt;link rel=\"stylesheet\" href=\"css\/style.css\"&gt;   &lt;style&gt;     \/* \u041e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u0441\u0442\u0438\u043b\u0438 *\/     body {       font-family: Arial, sans-serif;       margin: 0;       padding: 0;     }          .container {       width: 100%;       padding: 20px;       box-sizing: border-box;     }          \/* \u0428\u0430\u043f\u043a\u0430 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430 *\/     .document-header {       text-align: center;       margin-bottom: 20px;     }          .department-name {       font-size: 14pt;       font-weight: bold;       margin-bottom: 5px;     }          .document-title {       font-size: 16pt;       font-weight: bold;       margin: 15px 0;     }          .document-date {       font-size: 12pt;       margin-bottom: 15px;     }          .approval-block {       text-align: right;       margin: 30px 0;     }          \/* \u0422\u0430\u0431\u043b\u0438\u0446\u0430 \u0441 \u0433\u0440\u0430\u0444\u0438\u043a\u043e\u043c *\/     .schedule-wrapper {       width: 100%;       overflow-x: auto;       margin-bottom: 30px;     }          #schedule-table {       border-collapse: collapse;       width: 100%;       font-size: 10pt;     }          #schedule-table th, #schedule-table td {       border: 1px solid #000;       padding: 2px;       text-align: center;       min-width: 22px;     }          #schedule-table th {       background-color: #f2f2f2;       font-weight: bold;     }          .name-cell {       min-width: 150px;       background-color: #f9f9f9;       position: sticky;       left: 0;     }          .hours-cell {       font-weight: bold;       background-color: #f2f2f2;     }          \/* \u041f\u043e\u0434\u043f\u0438\u0441\u044c *\/     .signature-block {       margin-top: 50px;       width: 100%;     }          .signature-line {       border-top: 1px solid #000;       width: 200px;       display: inline-block;       margin: 0 20px;     }          \/* \u0421\u0442\u0438\u043b\u0438 \u0434\u043b\u044f \u043f\u0435\u0447\u0430\u0442\u0438 *\/     @media print {       @page {         size: A4 landscape;         margin: 10mm;       }              body {         padding: 0;         margin: 0;         font-size: 10pt;       }              .no-print {         display: none;       }              #schedule-table {         width: 100%;         font-size: 8pt;       }              #schedule-table th, #schedule-table td {         padding: 3px;       }              .hours-cell {         font-weight: bold;         background-color: #f2f2f2 !important;       }       #employee-signatures div {         font-family: monospace;         white-space: pre;         margin-bottom: 10px;         line-height: 1.3;       }     }          \/* \u0426\u0432\u0435\u0442\u0430 \u0441\u043c\u0435\u043d *\/     .day-shift { background-color: #d4edda; }     .night-shift { background-color: #cce5ff; }     .day-off { background-color: #fff3cd; }     .vacation { background-color: #ffcccc; }     .sick-leave { background-color: #ff9999; }   &lt;\/style&gt; &lt;\/head&gt; &lt;body&gt;   &lt;div class=\"container\"&gt;     &lt;!-- \u0428\u0430\u043f\u043a\u0430 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430 --&gt;     &lt;div class=\"document-header\"&gt;       &lt;div class=\"department-name\"&gt;\u0417\u0410\u041f\u0418\u0421\u0410\u0422\u042c \u0421\u0412\u041e\u0418 \u0414\u0410\u041d\u041d\u042b\u0415&lt;\/div&gt;       &lt;div class=\"document-date\"&gt;\u0414\u0430\u0442\u0430 \u0441\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0433\u0440\u0430\u0444\u0438\u043a\u0430: &lt;?= date('d.m.Y') ?&gt;&lt;\/div&gt;       &lt;?php         $months = [           1 =&gt; '\u042f\u043d\u0432\u0430\u0440\u044c',           2 =&gt; '\u0424\u0435\u0432\u0440\u0430\u043b\u044c',           3 =&gt; '\u041c\u0430\u0440\u0442',           4 =&gt; '\u0410\u043f\u0440\u0435\u043b\u044c',           5 =&gt; '\u041c\u0430\u0439',           6 =&gt; '\u0418\u044e\u043d\u044c',           7 =&gt; '\u0418\u044e\u043b\u044c',           8 =&gt; '\u0410\u0432\u0433\u0443\u0441\u0442',           9 =&gt; '\u0421\u0435\u043d\u0442\u044f\u0431\u0440\u044c',           10 =&gt; '\u041e\u043a\u0442\u044f\u0431\u0440\u044c',           11 =&gt; '\u041d\u043e\u044f\u0431\u0440\u044c',           12 =&gt; '\u0414\u0435\u043a\u0430\u0431\u0440\u044c'         ];         $currentMonth = $months[date('n')];       ?&gt;       &lt;div class=\"document-title\"&gt;\u0413\u0440\u0430\u0444\u0438\u043a \u0440\u0430\u0431\u043e\u0442\u044b \u043d\u0430 &lt;?= $currentMonth . ' ' . date('Y') ?&gt; \u0433.&lt;\/div&gt;     &lt;\/div&gt;          &lt;div class=\"approval-block\"&gt;       \u0423\u0422\u0412\u0415\u0420\u0416\u0414\u0410\u042e&lt;br&gt;       \u0417\u0410\u041f\u0418\u0421\u0410\u0422\u042c \u0421\u0412\u041e\u0418 \u0414\u0410\u041d\u041d\u042b\u0415 (\u0414\u041e\u041b\u0416\u041d\u041e\u0421\u0422\u042c, \u0415\u0421\u041b\u0418 \u041d\u0423\u0416\u041d\u041e)&lt;br&gt;       ___________________ (\u043f\u043e\u0434\u043f\u0438\u0441\u044c)     &lt;\/div&gt;          &lt;!-- \u041e\u0441\u043d\u043e\u0432\u043d\u0430\u044f \u0442\u0430\u0431\u043b\u0438\u0446\u0430 \u0441 \u0433\u0440\u0430\u0444\u0438\u043a\u043e\u043c --&gt;     &lt;div class=\"schedule-wrapper\"&gt;       &lt;table id=\"schedule-table\"&gt;         &lt;thead id=\"schedule-header\"&gt;           &lt;tr&gt;             &lt;th&gt;\u0421\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a&lt;\/th&gt;             &lt;!-- \u0414\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438 \u0434\u0430\u0442 --&gt;           &lt;\/tr&gt;         &lt;\/thead&gt;         &lt;tbody id=\"schedule-body\"&gt;           &lt;!-- \u0421\u0442\u0440\u043e\u043a\u0438 \u0431\u0443\u0434\u0443\u0442 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c\u0441\u044f \u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u0438 --&gt;         &lt;\/tbody&gt;       &lt;\/table&gt;     &lt;\/div&gt;          &lt;!-- \u0411\u043b\u043e\u043a \u043f\u043e\u0434\u043f\u0438\u0441\u0438 --&gt;     &lt;div class=\"signature-block\"&gt;       &lt;div style=\"float: left; width: 50%;\"&gt;         \u041e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0435 \u043b\u0438\u0446\u043e:&lt;br&gt;         \u0417\u0410\u041f\u0418\u0421\u0410\u0422\u042c \u0421\u0412\u041e\u0418 \u0414\u0410\u041d\u041d\u042b\u0415 (\u0414\u041e\u041b\u0416\u041d\u041e\u0421\u0422\u042c)&lt;br&gt;         ___________________ (\u043f\u043e\u0434\u043f\u0438\u0441\u044c)       &lt;\/div&gt;              &lt;div style=\"float: right; width: 35%; text-align: left;\"&gt;         \u0421 \u0433\u0440\u0430\u0444\u0438\u043a\u043e\u043c \u0440\u0430\u0431\u043e\u0442\u044b \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u043b\u0435\u043d\u044b:&lt;br&gt;         &lt;div id=\"employee-signatures\"&gt;&lt;\/div&gt;       &lt;\/div&gt;       &lt;div style=\"clear: both;\"&gt;&lt;\/div&gt;     &lt;\/div&gt;          &lt;button class=\"no-print\" onclick=\"window.print()\" style=\"padding: 10px 20px; margin-top: 20px; cursor: pointer;\"&gt;\u041f\u0435\u0447\u0430\u0442\u044c&lt;\/button&gt;   &lt;\/div&gt;    &lt;script&gt;     document.addEventListener('DOMContentLoaded', function() {       loadSchedule();     });      function loadSchedule() {       fetch('api\/get_schedule.php')         .then(response =&gt; response.json())         .then(data =&gt; {           const currentDate = new Date();           const year = currentDate.getFullYear();           const month = currentDate.getMonth();           const daysInMonth = new Date(year, month + 1, 0).getDate();                      \/\/ \u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a \u0441 \u0434\u0430\u0442\u0430\u043c\u0438           const headerRow = document.querySelector('#schedule-header tr');           headerRow.innerHTML = '&lt;th&gt;\u0421\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a&lt;\/th&gt;';                      for (let day = 1; day &lt;= daysInMonth; day++) {             const th = document.createElement('th');             th.textContent = day;             headerRow.appendChild(th);           }                      \/\/ \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a \u0434\u043b\u044f \u0447\u0430\u0441\u043e\u0432           headerRow.innerHTML += '&lt;th&gt;\u0427\u0430\u0441\u044b&lt;\/th&gt;';                      \/\/ \u0417\u0430\u043f\u043e\u043b\u043d\u044f\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u0435 \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u043e\u0432           const tbody = document.getElementById('schedule-body');           const signatures = document.getElementById('employee-signatures');           tbody.innerHTML = '';                      data.forEach(employee =&gt; {             let totalHours = 0;                          \/\/ \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0441\u0442\u0440\u043e\u043a\u0443 \u0432 \u0442\u0430\u0431\u043b\u0438\u0446\u0443             const row = document.createElement('tr');                          \/\/ \u042f\u0447\u0435\u0439\u043a\u0430 \u0441 \u0438\u043c\u0435\u043d\u0435\u043c             const nameCell = document.createElement('td');             nameCell.className = 'name-cell';             nameCell.textContent = employee.fullname;             row.appendChild(nameCell);                          \/\/ \u042f\u0447\u0435\u0439\u043a\u0438 \u0441\u043c\u0435\u043d             for (let day = 1; day &lt;= daysInMonth; day++) {               const date = `${year}-${String(month + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}`;               const shiftType = employee.shifts[date] || '';               const cell = document.createElement('td');                              switch(shiftType) {                 case 'day':                   cell.textContent = '\u0414';                   cell.className = 'day-shift';                   totalHours += 11;                   break;                 case 'night':                   cell.textContent = '\u041d';                   cell.className = 'night-shift';                   totalHours += 11;                   break;                 case 'off':                   cell.textContent = '\u0412';                   cell.className = 'day-off';                   break;                 case 'vacation':                   cell.textContent = '\u041e\u0442\u043f';                   cell.className = 'vacation';                   break;                 case 'sick_leave':                   cell.textContent = '\u0411';                   cell.className = 'sick-leave';                   break;                 default:                   cell.textContent = '-';               }                              row.appendChild(cell);             }                          \/\/ \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u044f\u0447\u0435\u0439\u043a\u0443 \u0441 \u043e\u0431\u0449\u0438\u043c \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e\u043c \u0447\u0430\u0441\u043e\u0432             const hoursCell = document.createElement('td');             hoursCell.textContent = totalHours &gt; 0 ? totalHours : '';             hoursCell.className = 'hours-cell';             row.appendChild(hoursCell);                          tbody.appendChild(row);                          \/\/ \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u043f\u043e\u0434\u043f\u0438\u0441\u044c \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u0430             const signature = document.createElement('div');             signature.style.fontFamily = 'monospace';             signature.style.whiteSpace = 'pre';              \/\/ \u0412\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u043c \u0434\u043b\u0438\u043d\u0443 \u0424\u0418\u041e \u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u043f\u043e\u0434\u0447\u0435\u0440\u043a\u0438\u0432\u0430\u043d\u0438\u044f             const nameLength = employee.fullname.length;             const totalLength = 40; \/\/ \u041e\u0431\u0449\u0430\u044f \u0434\u043b\u0438\u043d\u0430 \u0441\u0442\u0440\u043e\u043a\u0438             const underlineLength = totalLength - nameLength - 10; \/\/ 10 - \u043c\u0435\u0441\u0442\u043e \u0434\u043b\u044f \"(\u043f\u043e\u0434\u043f\u0438\u0441\u044c)\"              signature.innerHTML = `   ${employee.fullname} ${'_'.repeat(underlineLength)} (\u043f\u043e\u0434\u043f\u0438\u0441\u044c) `;             signatures.appendChild(signature);           });         })         .catch(error =&gt; {           console.error('\u041e\u0448\u0438\u0431\u043a\u0430 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0433\u0440\u0430\u0444\u0438\u043a\u0430:', error);           alert('\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c \u0433\u0440\u0430\u0444\u0438\u043a');         });     }   &lt;\/script&gt; &lt;\/body&gt; &lt;\/html&gt;<\/code><\/pre>\n<h3>view_schedule.js\u00a0(\u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u0433\u0440\u0430\u0444\u0438\u043a\u0430 \u0434\u043b\u044f \u043f\u0435\u0447\u0430\u0442\u0438, \u043b\u0435\u0436\u0438\u0442 \u0432\u00a0schedule\/js):<\/h3>\n<pre><code class=\"php\">document.addEventListener('DOMContentLoaded', function() {   loadSchedule(); });  function loadSchedule() {   fetch('api\/get_schedule.php')     .then(response =&gt; response.json())     .then(data =&gt; {       const currentDate = new Date();       const year = currentDate.getFullYear();       const month = currentDate.getMonth();       const daysInMonth = new Date(year, month + 1, 0).getDate();              const headerRow = document.querySelector('#schedule-header tr');       headerRow.innerHTML = '&lt;th&gt;\u0421\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a&lt;\/th&gt;';              for (let day = 1; day &lt;= daysInMonth; day++) {         const th = document.createElement('th');         th.textContent = day;         headerRow.appendChild(th);       }              headerRow.innerHTML += '&lt;th&gt;\u0427\u0430\u0441\u044b&lt;\/th&gt;';              const tbody = document.getElementById('schedule-body');       const signatures = document.getElementById('employee-signatures');       tbody.innerHTML = '';              data.forEach(employee =&gt; {         let totalHours = 0;                  const row = document.createElement('tr');                  const nameCell = document.createElement('td');         nameCell.className = 'name-cell';         nameCell.textContent = employee.fullname;         row.appendChild(nameCell);                  for (let day = 1; day &lt;= daysInMonth; day++) {           const date = `${year}-${String(month + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}`;           const shiftType = employee.shifts[date] || '';           const cell = document.createElement('td');                      switch(shiftType) {             case 'day':               cell.textContent = '\u0414';               cell.className = 'day-shift';               totalHours += 11;               break;             case 'night':               cell.textContent = '\u041d';               cell.className = 'night-shift';               totalHours += 11;               break;             case 'off':               cell.textContent = '\u0412';               cell.className = 'day-off';               break;             case 'vacation':               cell.textContent = '\u041e\u0442\u043f';               cell.className = 'vacation';               break;             case 'sick_leave':               cell.textContent = '\u0411';               cell.className = 'sick-leave';               break;             default:               cell.textContent = '-';           }                      row.appendChild(cell);         }                  const totalCell = document.createElement('td');         totalCell.textContent = totalHours &gt; 0 ? totalHours : '';         totalCell.className = 'employee-total';         row.appendChild(totalCell);                  tbody.appendChild(row);                  const signature = document.createElement('div');         signature.innerHTML = `           ${employee.fullname} ___________________            &lt;span style=\"font-size: 0.8em;\"&gt;(\u043f\u043e\u0434\u043f\u0438\u0441\u044c)&lt;\/span&gt;&lt;br&gt;&lt;br&gt;         `;         signatures.appendChild(signature);       });     })     .catch(error =&gt; {       console.error('\u041e\u0448\u0438\u0431\u043a\u0430 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0433\u0440\u0430\u0444\u0438\u043a\u0430:', error);       alert('\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c \u0433\u0440\u0430\u0444\u0438\u043a');     }); }<\/code><\/pre>\n<blockquote>\n<p>\u0418\u0442\u043e\u0433\u043e\u0432\u0430\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/p>\n<p>schedule\/<br \/> \u251c\u2500\u2500 api\/                  # \u0421\u043a\u0440\u0438\u043f\u0442\u044b API \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0411\u0414<br \/> \u2502   \u251c\u2500\u2500 add_employee.php<br \/> \u2502   \u251c\u2500\u2500 delete_employee.php<br \/> \u2502   \u251c\u2500\u2500 get_employees.php<br \/> \u2502   \u251c\u2500\u2500 get_schedule.php<br \/> \u2502   \u251c\u2500\u2500 save_auto_schedule.php<br \/> \u2502   \u251c\u2500\u2500 set_schedule.php<br \/> \u2502   \u251c\u2500\u2500 set_status.php<br \/> \u2502   \u2514\u2500\u2500 status.php<br \/> \u251c\u2500\u2500 includes\/             # \u0412\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0444\u0430\u0439\u043b\u044b<br \/> \u2502   \u251c\u2500\u2500 db.php            # \u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043a \u0411\u0414<br \/> \u2502   \u2514\u2500\u2500 functions.php     # \u041e\u0431\u0449\u0438\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438<br \/> \u251c\u2500\u2500 js\/                   # \u041a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u0438\u0435 \u0441\u043a\u0440\u0438\u043f\u0442\u044b<br \/> \u2502   \u251c\u2500\u2500 employees.js      # \u0423\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u0430\u043c\u0438<br \/> \u2502   \u251c\u2500\u2500 main.js           # \u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0441\u0438\u0441\u0442\u0435\u043c\u044b<br \/> \u2502   \u251c\u2500\u2500 schedule.js       # \u041b\u043e\u0433\u0438\u043a\u0430 \u0433\u0440\u0430\u0444\u0438\u043a\u0430 \u0441\u043c\u0435\u043d<br \/> \u2502   \u251c\u2500\u2500 status.js         # \u0423\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0441\u0442\u0430\u0442\u0443\u0441\u0430\u043c\u0438<br \/> \u2502   \u2514\u2500\u2500 view_schedule.js  # \u041f\u0435\u0447\u0430\u0442\u043d\u0430\u044f \u0432\u0435\u0440\u0441\u0438\u044f \u0433\u0440\u0430\u0444\u0438\u043a\u0430<br \/> \u251c\u2500\u2500 css\/<br \/> \u2502   \u2514\u2500\u2500 style.css         # \u0421\u0442\u0438\u043b\u0438 \u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u0441\u0442\u0440\u0430\u043d\u0438\u0446<br \/> \u2514\u2500\u2500 views\/                # HTML-\u0448\u0430\u0431\u043b\u043e\u043d\u044b<br \/> \u251c\u2500\u2500 index.php         # \u0413\u043b\u0430\u0432\u043d\u0430\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430<br \/> \u251c\u2500\u2500 employees.php     # \u0418\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u043e\u0432<br \/> \u2514\u2500\u2500 view_schedule.php # \u0421\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u043f\u0435\u0447\u0430\u0442\u0438<\/p>\n<p>\u0441\u0441\u044b\u043b\u043a\u0438 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b <\/p>\n<p><a href=\"http:\/\/localhost\/schedule\/\" rel=\"noopener noreferrer nofollow\">http:\/\/localhost\/schedule\/<\/a> <\/p>\n<p> <a href=\"http:\/\/localhost\/schedule\/view_schedule.php\" rel=\"noopener noreferrer nofollow\">http:\/\/localhost\/schedule\/view_schedule.php<\/a><\/p>\n<\/blockquote>\n<h4>\u0421\u0442\u0438\u043b\u0438 (style.css)<\/h4>\n<pre><code class=\"css\">body {   font-family: Arial, sans-serif;   margin: 0;   padding: 20px; }  .nav-tabs {   display: flex;   margin-bottom: 20px;   border-bottom: 1px solid #ddd; }  .nav-tabs a {   padding: 10px 15px;   cursor: pointer;   border: 1px solid transparent;   border-radius: 4px 4px 0 0;   margin-right: 5px; }  .nav-tabs a.active {   border-color: #ddd #ddd #fff;   background: #fff;   color: #555;   font-weight: bold; }  .tab-content {   display: none; }  .tab-content.active {   display: block; }  .schedule-wrapper {   overflow-x: auto; }  #schedule-table {   border-collapse: collapse;   width: 100%; }  #schedule-table th, #schedule-table td {   border: 1px solid #ddd;   padding: 8px;   text-align: center; }  #schedule-table th {   background-color: #f2f2f2; }  .name-cell {   min-width: 150px;   background-color: #f9f9f9; }  .shift-cell {   cursor: pointer; }  .shift-cell:hover {   background-color: #f0f0f0; }  .day-shift {   background-color: #d4edda; }  .night-shift {   background-color: #cce5ff; }  .day-off {   background-color: #fff3cd; }  .controls {   margin-bottom: 15px; }  .employee-form, .employee-list, .status-controls {   margin-bottom: 20px; }  #schedule-body tr.selected {   background-color: #e6f7ff;   outline: 2px solid #1890ff; }  .day-shift {   background-color: #d4edda; }  .night-shift {   background-color: #cce5ff; }  .day-off {   background-color: #fff3cd; }  \/* \u0421\u0442\u0438\u043b\u0438 \u0434\u043b\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0430 *\/ .view-mode {   background: #fff;   padding: 20px; }  .view-mode #schedule-table {   width: auto;   margin: 0 auto; }  .view-mode .name-cell {   min-width: 200px;   position: sticky;   left: 0;   background: #f9f9f9;   z-index: 1; }  .print-button {   background: #4CAF50;   color: white;   border: none;   padding: 10px 15px;   border-radius: 4px;   cursor: pointer;   font-size: 16px; }  .print-button:hover {   background: #45a049; }  @media print {   body {     padding: 0;     margin: 0;   }   .print-button {     display: none;   }   #schedule-table {     width: 100%;     font-size: 12pt;   } }  .vacation {     background-color: #ffcccc;     position: relative; }  .sick-leave {     background-color: #ff9999;     position: relative; }<\/code><\/pre>\n<blockquote>\n<p>\u041d\u0430\u0434\u0435\u044e\u0441\u044c, \u043a\u043e\u043c\u0443-\u0442\u043e \u044d\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043b\u0435\u0437\u043d\u043e!<\/p>\n<\/blockquote>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/935510\/\"> https:\/\/habr.com\/ru\/articles\/935510\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<blockquote>\n<p>\u041c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c, \u043a\u043e\u043c\u0443-\u0442\u043e \u043f\u0440\u0438\u0433\u043e\u0434\u0438\u0442\u0441\u044f.<\/p>\n<p>\u041a\u0430\u0434\u0440\u043e\u0432\u0438\u043a\u0438 \u0443 \u043d\u0430\u0441 \u043b\u0435\u043d\u0438\u0432\u044b\u0435 (\u0430 \u043c\u043e\u0436\u0435\u0442, \u043f\u0440\u043e\u0441\u0442\u043e \u043d\u0435 \u0443\u043c\u0435\u044e\u0442) \u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u043e \u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0433\u0440\u0430\u0444\u0438\u043a \u0434\u043b\u044f \u0441\u043c\u0435\u043d\u043d\u044b\u0445 \u0434\u0435\u0436\u0443\u0440\u043d\u044b\u0445. \u042f \u043f\u043e\u043d\u0438\u043c\u0430\u044e, \u0447\u0442\u043e \u0432 Excel \u0442\u0430\u043a\u043e\u0439 \u0442\u0430\u0431\u0435\u043b\u044c \u0437\u0430\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u0437\u0430 5 \u043c\u0438\u043d\u0443\u0442, \u043d\u043e \u043c\u043d\u0435 \u0437\u0430\u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u044d\u0442\u043e \u043f\u0440\u043e\u0449\u0435.<\/p>\n<p>\u042f \u0432\u044b\u0431\u0440\u0430\u043b XAMPP \u2014 \u043f\u0440\u043e\u0441\u0442\u043e \u0438 \u0431\u044b\u0441\u0442\u0440\u043e. \u0414\u0443\u043c\u0430\u044e, \u0435\u0433\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u043d\u0435 \u0441\u043e\u0441\u0442\u0430\u0432\u0438\u0442 \u0442\u0440\u0443\u0434\u0430.<\/p>\n<p>\u0412 \u043c\u043e\u0451\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043a\u0430\u0442\u0430\u043b\u043e\u0433 \u0434\u043b\u044f \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043d\u0430\u0437\u0432\u0430\u043b\u00a0<code>schedule<\/code>.<\/p>\n<\/blockquote>\n<h4>\u041d\u0430\u0431\u043e\u0440 \u0441\u043a\u0440\u0438\u043f\u0442\u043e\u0432 \u0438 \u0448\u0430\u0431\u043b\u043e\u043d\u043e\u0432<\/h4>\n<h3>HTML-\u0448\u0430\u0431\u043b\u043e\u043d\u044b<\/h3>\n<p>\u0421\u0434\u0435\u043b\u0430\u043b \u0434\u0432\u0430 \u0448\u0430\u0431\u043b\u043e\u043d\u0430:<\/p>\n<ol>\n<li>\n<p>\u0414\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0433\u0440\u0430\u0444\u0438\u043a\u043e\u043c<\/p>\n<\/li>\n<li>\n<p>\u0414\u043b\u044f \u043f\u0435\u0447\u0430\u0442\u043d\u043e\u0439 \u0444\u043e\u0440\u043c\u044b<\/p>\n<\/li>\n<\/ol>\n<p><strong>\u041f\u0435\u0440\u0432\u044b\u0439 \u0448\u0430\u0431\u043b\u043e\u043d<\/strong>\u00a0(<code>index.php<\/code>, \u043b\u0435\u0436\u0438\u0442 \u0432 \u043a\u043e\u0440\u043d\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430):<\/p>\n<pre><code class=\"php\">&lt;?php include 'includes\/db.php'; ?&gt; &lt;!DOCTYPE html&gt; &lt;html lang=\"ru\"&gt; &lt;head&gt;   &lt;meta charset=\"UTF-8\"&gt;   &lt;title&gt;\u0413\u0440\u0430\u0444\u0438\u043a \u0441\u043c\u0435\u043d&lt;\/title&gt;   &lt;link rel=\"stylesheet\" href=\"css\/style.css\"&gt; &lt;\/head&gt; &lt;body&gt;   &lt;div class=\"container\"&gt;     &lt;div class=\"nav-tabs\"&gt;       &lt;a class=\"active\" onclick=\"showTab('schedule')\"&gt;\u0413\u0440\u0430\u0444\u0438\u043a \u0441\u043c\u0435\u043d&lt;\/a&gt; &lt;a href=\"view_schedule.php\" target=\"_blank\"&gt;\u0412\u0435\u0440\u0441\u0438\u044f \u0434\u043b\u044f \u043f\u0435\u0447\u0430\u0442\u0438&lt;\/a&gt;       &lt;a onclick=\"showTab('employees')\"&gt;\u0421\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u0438&lt;\/a&gt;     &lt;\/div&gt;      &lt;div id=\"schedule-tab\" class=\"tab-content active\"&gt;       &lt;h2&gt;\u0413\u0440\u0430\u0444\u0438\u043a \u0441\u043c\u0435\u043d \u043d\u0430 &lt;span id=\"current-month\"&gt;&lt;\/span&gt;&lt;\/h2&gt;       &lt;div class=\"controls\"&gt;         &lt;button onclick=\"addEmployeeRow()\"&gt;\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u0443&lt;\/button&gt; &lt;button onclick=\"autoGenerateSelectedRow()\"&gt;\u0421\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0433\u0440\u0430\u0444\u0438\u043a 2\/2&lt;\/button&gt;       &lt;\/div&gt;       &lt;div class=\"schedule-wrapper\"&gt;         &lt;table id=\"schedule-table\"&gt;           &lt;thead id=\"schedule-header\"&gt;             &lt;tr&gt;               &lt;th&gt;\u0421\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a&lt;\/th&gt;               &lt;!-- \u0414\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438 \u0434\u0430\u0442 --&gt;             &lt;\/tr&gt;           &lt;\/thead&gt;           &lt;tbody id=\"schedule-body\"&gt;             &lt;!-- \u0421\u0442\u0440\u043e\u043a\u0438 \u0431\u0443\u0434\u0443\u0442 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c\u0441\u044f \u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u0438 --&gt;           &lt;\/tbody&gt;         &lt;\/table&gt;       &lt;\/div&gt;     &lt;\/div&gt;      &lt;div id=\"employees-tab\" class=\"tab-content\"&gt;       &lt;h2&gt;\u0423\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u0430\u043c\u0438&lt;\/h2&gt;       &lt;div class=\"employee-form\"&gt;         &lt;input type=\"text\" id=\"new-fullname\" placeholder=\"\u0424\u0418\u041e \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u0430\"&gt;         &lt;button onclick=\"addEmployee()\"&gt;\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c&lt;\/button&gt;       &lt;\/div&gt;       &lt;div class=\"employee-list\"&gt;         &lt;select id=\"employee-list\" size=\"8\" multiple&gt;&lt;\/select&gt;         &lt;button onclick=\"removeEmployee()\"&gt;\u0423\u0434\u0430\u043b\u0438\u0442\u044c \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0445&lt;\/button&gt;       &lt;\/div&gt;              &lt;div class=\"status-controls\"&gt;         &lt;h3&gt;\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0441\u0442\u0430\u0442\u0443\u0441\u0430&lt;\/h3&gt;         &lt;select id=\"status-employee\"&gt;&lt;\/select&gt;         &lt;label&gt;\u0421: &lt;input type=\"date\" id=\"date-from\"&gt;&lt;\/label&gt;         &lt;label&gt;\u041f\u043e: &lt;input type=\"date\" id=\"date-to\"&gt;&lt;\/label&gt;         &lt;button onclick=\"setStatus('vacation')\"&gt;\u041e\u0442\u043f\u0443\u0441\u043a&lt;\/button&gt;         &lt;button onclick=\"setStatus('sick_leave')\"&gt;\u0411\u043e\u043b\u044c\u043d\u0438\u0447\u043d\u044b\u0439&lt;\/button&gt;       &lt;\/div&gt;     &lt;\/div&gt;   &lt;\/div&gt;    &lt;script src=\"js\/main.js\"&gt;&lt;\/script&gt;   &lt;script src=\"js\/schedule.js\"&gt;&lt;\/script&gt;   &lt;script src=\"js\/employees.js\"&gt;&lt;\/script&gt; &lt;\/body&gt; &lt;\/html&gt;<\/code><\/pre>\n<blockquote>\n<p>\u041d\u0430 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435 \u0434\u0432\u0430 \u0440\u0430\u0437\u0434\u0435\u043b\u0430:<\/p>\n<ul>\n<li>\n<p>\u0421\u0430\u043c \u0433\u0440\u0430\u0444\u0438\u043a<\/p>\n<\/li>\n<li>\n<p>\u0423\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u0430\u043c\u0438 (\u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435, \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0435, \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0441\u0442\u0430\u0442\u0443\u0441\u043e\u0432: \u0431\u043e\u043b\u044c\u043d\u0438\u0447\u043d\u044b\u0439 \u0438 \u043e\u0442\u043f\u0443\u0441\u043a)<\/p>\n<\/li>\n<\/ul>\n<\/blockquote>\n<figure class=\"full-width\"><\/figure>\n<figure class=\"full-width\"><\/figure>\n<h4>\u0421\u043a\u0440\u0438\u043f\u0442\u044b \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u0430\u043c\u0438 \u0438 \u0441\u0442\u0430\u0442\u0443\u0441\u0430\u043c\u0438<\/h4>\n<h3>add_employee.php\u00a0(\u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u043e\u0432, \u043b\u0435\u0436\u0438\u0442 \u0432\u00a0schedule\/api):<\/h3>\n<pre><code class=\"php\">&lt;?php include '..\/includes\/db.php'; header('Content-Type: application\/json');  $data = json_decode(file_get_contents(\"php:\/\/input\"), true); $fullname = trim($data['fullname']);  if (empty($fullname)) {     http_response_code(400);     echo json_encode(['error' =&gt; 'Fullname is required']);     exit; }  $stmt = $conn-&gt;prepare(\"INSERT INTO employees (fullname) VALUES (?)\"); $stmt-&gt;bind_param(\"s\", $fullname);  if ($stmt-&gt;execute()) {     echo json_encode(['success' =&gt; true, 'id' =&gt; $stmt-&gt;insert_id]); } else {     http_response_code(500);     echo json_encode(['error' =&gt; 'Database error']); } ?&gt;<\/code><\/pre>\n<h3>delete_employee.php\u00a0(\u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0435 \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u0430, \u043b\u0435\u0436\u0438\u0442 \u0432\u00a0schedule\/api):<\/h3>\n<pre><code class=\"php\">&lt;?php include '..\/includes\/db.php'; header('Content-Type: application\/json');  $data = json_decode(file_get_contents(\"php:\/\/input\"), true); $id = (int)$data['id'];  $stmt = $conn-&gt;prepare(\"DELETE FROM employees WHERE id = ?\"); $stmt-&gt;bind_param(\"i\", $id);  if ($stmt-&gt;execute()) {     echo json_encode(['success' =&gt; true]); } else {     http_response_code(500);     echo json_encode(['error' =&gt; 'Database error']); } ?&gt;<\/code><\/pre>\n<h3>get_schedule.php\u00a0(\u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0433\u0440\u0430\u0444\u0438\u043a \u0441\u043c\u0435\u043d \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u043e\u0432 \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0440\u0430\u0441\u043f\u0438\u0441\u0430\u043d\u0438\u044f, \u0432\u043a\u043b\u044e\u0447\u0430\u044f \u0441\u0442\u0430\u0442\u0443\u0441\u044b, \u043b\u0435\u0436\u0438\u0442 \u0432\u00a0schedule\/api):<\/h3>\n<pre><code class=\"php\">&lt;?php include '..\/includes\/db.php'; header('Content-Type: application\/json');  try {     $result = [];          \/\/ \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0432\u0441\u0435\u0445 \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u043e\u0432     $employees = $conn-&gt;query(\"SELECT id, fullname FROM employees ORDER BY fullname\");          \/\/ \u041f\u043e\u0434\u0433\u043e\u0442\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u0437\u0430\u0440\u0430\u043d\u0435\u0435     $shiftQuery = $conn-&gt;prepare(\"SELECT shift_date, shift_type FROM shifts WHERE employee_id = ?\");     $statusQuery = $conn-&gt;prepare(\"SELECT start_date, end_date, status_type FROM employee_status WHERE employee_id = ?\");          while ($emp = $employees-&gt;fetch_assoc()) {         $emp_id = $emp['id'];         $schedule = []; \/\/ \u041e\u0431\u044a\u0435\u0434\u0438\u043d\u0435\u043d\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0441\u043c\u0435\u043d \u0438 \u0441\u0442\u0430\u0442\u0443\u0441\u043e\u0432                  \/\/ \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0441\u043c\u0435\u043d\u044b         $shiftQuery-&gt;bind_param(\"i\", $emp_id);         $shiftQuery-&gt;execute();         $shifts = $shiftQuery-&gt;get_result()-&gt;fetch_all(MYSQLI_ASSOC);                  foreach ($shifts as $shift) {             $schedule[$shift['shift_date']] = [                 'type' =&gt; $shift['shift_type'],                 'is_status' =&gt; false             ];         }                  \/\/ \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0441\u0442\u0430\u0442\u0443\u0441\u044b         $statusQuery-&gt;bind_param(\"i\", $emp_id);         $statusQuery-&gt;execute();         $statuses = $statusQuery-&gt;get_result()-&gt;fetch_all(MYSQLI_ASSOC);                  foreach ($statuses as $status) {             $start = new DateTime($status['start_date']);             $end = new DateTime($status['end_date']);                          \/\/ \u041f\u0435\u0440\u0435\u0431\u0438\u0440\u0430\u0435\u043c \u0432\u0441\u0435 \u0434\u0430\u0442\u044b \u043f\u0435\u0440\u0438\u043e\u0434\u0430 \u0441\u0442\u0430\u0442\u0443\u0441\u0430 (\u0432\u043a\u043b\u044e\u0447\u0430\u044f \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0439 \u0434\u0435\u043d\u044c)             for ($date = $start; $date &lt;= $end; $date-&gt;modify('+1 day')) {                 $dateStr = $date-&gt;format('Y-m-d');                 $schedule[$dateStr] = [                     'type' =&gt; $status['status_type'],                     'is_status' =&gt; true                 ];             }         }                  \/\/ \u0424\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u0441 \u0442\u0438\u043f\u0430\u043c\u0438 (\u0441\u0442\u0430\u0442\u0443\u0441\u044b \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u044e\u0442 \u0441\u043c\u0435\u043d\u044b)         $formattedShifts = [];         foreach ($schedule as $date =&gt; $item) {             $formattedShifts[$date] = $item['type'];         }                  $result[] = [             \"id\" =&gt; $emp_id,             \"fullname\" =&gt; $emp['fullname'],             \"shifts\" =&gt; $formattedShifts         ];     }          echo json_encode($result);      } catch (Exception $e) {     http_response_code(500);     echo json_encode(['error' =&gt; 'Database error: ' . $e-&gt;getMessage()]); } ?&gt;<\/code><\/pre>\n<h3>get_employees.php\u00a0(\u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u0441\u043f\u0438\u0441\u043a\u0430 \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u043e\u0432, \u043b\u0435\u0436\u0438\u0442 \u0432\u00a0schedule\/api):<\/h3>\n<pre><code class=\"php\">&lt;?php include '..\/includes\/db.php'; header('Content-Type: application\/json');  $result = $conn-&gt;query(\"SELECT id, fullname FROM employees ORDER BY fullname\"); $employees = [];  while ($row = $result-&gt;fetch_assoc()) {     $employees[] = $row; }  echo json_encode($employees);  ?&gt;<\/code><\/pre>\n<h3>save_auto_schedule.php\u00a0(\u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0435 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u0433\u0440\u0430\u0444\u0438\u043a\u0430 \u043f\u043e\u0441\u043b\u0435 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438, \u043b\u0435\u0436\u0438\u0442 \u0432\u00a0schedule\/api):<\/h3>\n<pre><code class=\"php\">&lt;?php include '..\/includes\/db.php'; header('Content-Type: application\/json');  $data = json_decode(file_get_contents(\"php:\/\/input\"), true); $employeeId = $data['employee_id']; $shifts = $data['shifts'];  try {     $conn-&gt;begin_transaction();          foreach ($shifts as $shift) {         $stmt = $conn-&gt;prepare(\"INSERT INTO shifts (employee_id, shift_date, shift_type)                                VALUES (?, ?, ?)                               ON DUPLICATE KEY UPDATE shift_type = VALUES(shift_type)\");         $stmt-&gt;bind_param(\"iss\", $employeeId, $shift['date'], $shift['shiftType']);         $stmt-&gt;execute();     }          $conn-&gt;commit();     echo json_encode(['success' =&gt; true]); } catch (Exception $e) {     $conn-&gt;rollback();     http_response_code(500);     echo json_encode(['success' =&gt; false, 'message' =&gt; $e-&gt;getMessage()]); } ?&gt;<\/code><\/pre>\n<h3>set_schedule.php\u00a0(\u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0438 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0433\u0440\u0430\u0444\u0438\u043a\u0430 \u0434\u043b\u044f \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u0430, \u043b\u0435\u0436\u0438\u0442 \u0432\u00a0schedule\/api):<\/h3>\n<pre><code class=\"php\">&lt;?php include '..\/includes\/db.php'; include '..\/includes\/functions.php';  header('Content-Type: application\/json');  $data = json_decode(file_get_contents(\"php:\/\/input\"), true); $employeeId = $data['employee_id']; $date = $data['date']; $shiftType = $data['shift_type'];  if (!employeeExists($employeeId)) {     echo json_encode(['success' =&gt; false, 'message' =&gt; '\u0421\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d']);     exit; }  if (!validateDate($date)) {     echo json_encode(['success' =&gt; false, 'message' =&gt; '\u041d\u0435\u0432\u0435\u0440\u043d\u044b\u0439 \u0444\u043e\u0440\u043c\u0430\u0442 \u0434\u0430\u0442\u044b']);     exit; }  if (!in_array($shiftType, ['day', 'night', 'off'])) {     echo json_encode(['success' =&gt; false, 'message' =&gt; '\u041d\u0435\u0432\u0435\u0440\u043d\u044b\u0439 \u0442\u0438\u043f \u0441\u043c\u0435\u043d\u044b']);     exit; }  $stmt = $conn-&gt;prepare(\"SELECT id FROM shifts WHERE employee_id = ? AND shift_date = ?\"); $stmt-&gt;bind_param(\"is\", $employeeId, $date); $stmt-&gt;execute(); $result = $stmt-&gt;get_result();  if ($result-&gt;num_rows &gt; 0) {     $stmt = $conn-&gt;prepare(\"UPDATE shifts SET shift_type = ? WHERE employee_id = ? AND shift_date = ?\");     $stmt-&gt;bind_param(\"sis\", $shiftType, $employeeId, $date); } else {     $stmt = $conn-&gt;prepare(\"INSERT INTO shifts (employee_id, shift_date, shift_type) VALUES (?, ?, ?)\");     $stmt-&gt;bind_param(\"iss\", $employeeId, $date, $shiftType); }  if ($stmt-&gt;execute()) {     echo json_encode(['success' =&gt; true]); } else {     echo json_encode(['success' =&gt; false, 'message' =&gt; '\u041e\u0448\u0438\u0431\u043a\u0430 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445']); } ?&gt;<\/code><\/pre>\n<h3>set_status.php\u00a0(\u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0441\u0442\u0430\u0442\u0443\u0441\u0430 \u0434\u043b\u044f \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u0430 \u0437\u0430 \u043f\u0435\u0440\u0438\u043e\u0434, \u043b\u0435\u0436\u0438\u0442 \u0432\u00a0schedule\/api):<\/h3>\n<pre><code class=\"php\">&lt;?php include '..\/includes\/db.php'; header('Content-Type: application\/json');  $data = json_decode(file_get_contents(\"php:\/\/input\"), true); $employee_id = (int)$data['employee_id']; $start_date = $data['start_date']; $end_date = $data['end_date']; $status_type = $data['status_type'];  if (empty($employee_id) || empty($start_date) || empty($end_date) || empty($status_type)) {     http_response_code(400);     echo json_encode(['error' =&gt; 'All fields are required']);     exit; }  $stmt = $conn-&gt;prepare(\"DELETE FROM shifts WHERE employee_id = ? AND shift_date BETWEEN ? AND ?\"); $stmt-&gt;bind_param(\"iss\", $employee_id, $start_date, $end_date); $stmt-&gt;execute();  $stmt = $conn-&gt;prepare(\"INSERT INTO<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-470108","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/470108","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=470108"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/470108\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=470108"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=470108"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=470108"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}