Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

232 строки
7.2KB

  1. <?php
  2. declare(strict_types=1);
  3. namespace App\Controllers;
  4. use App\Models\SwimLane;
  5. use App\Repositories\CardMovementRepository;
  6. use App\Repositories\CardRepository;
  7. use App\Repositories\SwimLaneRepository;
  8. use App\Services\AuthService;
  9. use Core\Controller;
  10. use Core\Request;
  11. class SwimLanesController extends Controller
  12. {
  13. private function lanes(): SwimLaneRepository
  14. {
  15. return new SwimLaneRepository(database());
  16. }
  17. private function cards(): CardRepository
  18. {
  19. return new CardRepository(database());
  20. }
  21. private function cardMovements(): CardMovementRepository
  22. {
  23. return new CardMovementRepository(database());
  24. }
  25. public function store(Request $request): mixed
  26. {
  27. if (!AuthService::isLoggedIn()) {
  28. return $this->json(['ok' => false, 'error' => 'Unauthorized'], 401);
  29. }
  30. $boardId = (int) $request->input('board_id', 0);
  31. $name = trim((string) $request->input('name', ''));
  32. if ($boardId === 0 || $name === '') {
  33. return $this->json(['ok' => false, 'error' => 'board_id and name are required']);
  34. }
  35. $now = date('Y-m-d H:i:s');
  36. $username = AuthService::getCurrentUsername();
  37. $lane = new SwimLane();
  38. $lane->boardId = $boardId;
  39. $lane->name = $name;
  40. $lane->position = $this->lanes()->maxPosition($boardId) + 1;
  41. $lane->createdAt = $now;
  42. $lane->createdBy = $username;
  43. $lane->updatedAt = $now;
  44. $lane->updatedBy = $username;
  45. $this->lanes()->insert($lane);
  46. return $this->json(['ok' => true, 'id' => $lane->id, 'name' => $lane->name, 'position' => $lane->position]);
  47. }
  48. public function update(Request $request, int $id): mixed
  49. {
  50. if (!AuthService::isLoggedIn()) {
  51. return $this->json(['ok' => false, 'error' => 'Unauthorized'], 401);
  52. }
  53. $name = trim((string) $request->input('name', ''));
  54. if ($name === '') {
  55. return $this->json(['ok' => false, 'error' => 'name is required']);
  56. }
  57. $row = $this->lanes()->find($id);
  58. if ($row === null) {
  59. return $this->json(['ok' => false, 'error' => 'Not found'], 404);
  60. }
  61. $lane = SwimLane::fromRow($row);
  62. $lane->name = $name;
  63. $lane->updatedAt = date('Y-m-d H:i:s');
  64. $lane->updatedBy = AuthService::getCurrentUsername();
  65. $this->lanes()->update($lane);
  66. return $this->json(['ok' => true]);
  67. }
  68. public function toggleCount(Request $request, int $id): mixed
  69. {
  70. if (!AuthService::isLoggedIn()) {
  71. return $this->json(['ok' => false, 'error' => 'Unauthorized'], 401);
  72. }
  73. $row = $this->lanes()->find($id);
  74. if ($row === null) {
  75. return $this->json(['ok' => false, 'error' => 'Not found'], 404);
  76. }
  77. $show = (string) $request->input('show_card_count', '0') === '1';
  78. $this->lanes()->updateShowCardCount($id, $show, date('Y-m-d H:i:s'), AuthService::getCurrentUsername());
  79. return $this->json(['ok' => true, 'show_card_count' => $show]);
  80. }
  81. public function toggleExport(Request $request, int $id): mixed
  82. {
  83. if (!AuthService::isLoggedIn()) {
  84. return $this->json(['ok' => false, 'error' => 'Unauthorized'], 401);
  85. }
  86. $row = $this->lanes()->find($id);
  87. if ($row === null) {
  88. return $this->json(['ok' => false, 'error' => 'Not found'], 404);
  89. }
  90. $show = (string) $request->input('show_export_button', '0') === '1';
  91. $this->lanes()->updateShowExportButton($id, $show, date('Y-m-d H:i:s'), AuthService::getCurrentUsername());
  92. return $this->json(['ok' => true, 'show_export_button' => $show]);
  93. }
  94. public function updateCardAgeSettings(Request $request, int $id): mixed
  95. {
  96. if (!AuthService::isLoggedIn()) {
  97. return $this->json(['ok' => false, 'error' => 'Unauthorized'], 401);
  98. }
  99. $row = $this->lanes()->find($id);
  100. if ($row === null) {
  101. return $this->json(['ok' => false, 'error' => 'Not found'], 404);
  102. }
  103. $showCardAge = (string) $request->input('show_card_age', '0') === '1';
  104. $cardAgeWarningDays = max(0, (int) $request->input('card_age_warning_days', 0));
  105. $this->lanes()->updateCardAgeSettings(
  106. $id,
  107. $showCardAge,
  108. $cardAgeWarningDays,
  109. date('Y-m-d H:i:s'),
  110. AuthService::getCurrentUsername()
  111. );
  112. return $this->json([
  113. 'ok' => true,
  114. 'show_card_age' => $showCardAge,
  115. 'card_age_warning_days' => $cardAgeWarningDays,
  116. ]);
  117. }
  118. public function export(int $id): mixed
  119. {
  120. if (!AuthService::isLoggedIn()) {
  121. return $this->redirect('/auth/login');
  122. }
  123. $row = $this->lanes()->find($id);
  124. if ($row === null) {
  125. return new \Core\Response('Not found', 404);
  126. }
  127. $lane = \App\Models\SwimLane::fromRow($row);
  128. $cards = $this->cards()->findBySwimLaneId($id);
  129. $out = fopen('php://memory', 'wb');
  130. fputcsv($out, ['Job #', 'Job Name', 'Customer', 'Delivery Date', 'Quantity', 'Notes'], ',', '"', '\\');
  131. foreach ($cards as $card) {
  132. fputcsv($out, [
  133. $card->jobNumber,
  134. $card->jobName,
  135. $card->customerName,
  136. $card->deliveryDate ?? '',
  137. $card->quantity ?? '',
  138. $card->notes,
  139. ], ',', '"', '\\');
  140. }
  141. rewind($out);
  142. $csv = (string) stream_get_contents($out);
  143. fclose($out);
  144. $slug = trim((string) preg_replace('/[^a-z0-9]+/i', '-', $lane->name), '-');
  145. $filename = ($slug ?: 'lane') . '-' . date('Y-m-d') . '.csv';
  146. return new \Core\Response($csv, 200, [
  147. 'Content-Type' => 'text/csv; charset=utf-8',
  148. 'Content-Disposition' => 'attachment; filename="' . $filename . '"',
  149. ]);
  150. }
  151. public function destroy(int $id): mixed
  152. {
  153. if (!AuthService::isLoggedIn()) {
  154. return $this->json(['ok' => false, 'error' => 'Unauthorized'], 401);
  155. }
  156. $this->cardMovements()->deleteBySwimLaneId($id);
  157. $this->cards()->deleteBySwimLaneId($id);
  158. $this->lanes()->delete($id);
  159. return $this->json(['ok' => true]);
  160. }
  161. public function reorder(): mixed
  162. {
  163. if (!AuthService::isLoggedIn()) {
  164. return $this->json(['ok' => false, 'error' => 'Unauthorized'], 401);
  165. }
  166. $raw = file_get_contents('php://input');
  167. $items = json_decode((string) $raw, true);
  168. if (!is_array($items)) {
  169. return $this->json(['ok' => false, 'error' => 'Invalid JSON payload']);
  170. }
  171. $now = date('Y-m-d H:i:s');
  172. $username = AuthService::getCurrentUsername();
  173. foreach ($items as $item) {
  174. $laneId = (int) ($item['id'] ?? 0);
  175. $position = (int) ($item['position'] ?? 0);
  176. if ($laneId > 0) {
  177. $this->lanes()->updatePosition($laneId, $position, $now, $username);
  178. }
  179. }
  180. return $this->json(['ok' => true]);
  181. }
  182. }

Powered by TurnKey Linux.