| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160 |
- <?php
- require_once __DIR__ . '/lib/identity.php';
- require_once __DIR__ . '/lib/render.php';
- $actor = current_actor('ICG');
- $job_filter = isset($_GET['job']) ? (int) $_GET['job'] : 0;
- $limit = isset($_GET['limit']) ? max(50, min(1000, (int) $_GET['limit'])) : 200;
- $where = '1=1';
- $params = [];
- if ($job_filter > 0) {
- $where = 'h.job_id = ?';
- $params[] = $job_filter;
- }
- $sql = "
- SELECT h.*, j.job AS job_label, j.description AS job_description,
- v.slug AS vendor_slug, v.name AS vendor_name
- FROM job_history h
- LEFT JOIN jobs j ON j.id = h.job_id
- LEFT JOIN vendors v ON v.id = j.vendor_id
- WHERE $where
- ORDER BY h.id DESC
- LIMIT $limit
- ";
- $stmt = db()->prepare($sql);
- $stmt->execute($params);
- $rows = $stmt->fetchAll();
- function fmt_long_date(?string $ts): string {
- if (!$ts) return '';
- try {
- $dt = new DateTimeImmutable($ts . ' UTC');
- return $dt->setTimezone(new DateTimeZone(date_default_timezone_get()))
- ->format('Y-m-d g:i a');
- } catch (Exception $e) {
- return h($ts);
- }
- }
- function fmt_event(array $h): string {
- $f = $h['field'];
- $old = $h['old_value'];
- $new = $h['new_value'];
- if ($f === 'created') {
- return 'Created (vendor: ' . h((string) $new) . ')';
- }
- if ($f === 'deleted') {
- return 'Deleted';
- }
- if ($f === 'partial_ship') {
- return 'Partial ship: split off ' . h((string) $new) . ' (was qty ' . h((string) $old) . ')';
- }
- $labels = [
- 'ack' => 'Acknowledgement',
- 'status' => 'Status',
- 'job' => 'Job #',
- 'material' => 'Material',
- 'description' => 'Description',
- 'qty' => 'Qty',
- 'due_date' => 'Due date',
- ];
- $label = $labels[$f] ?? $f;
- $oldDisp = ($old === null || $old === '') ? '∅' : h((string) $old);
- $newDisp = ($new === null || $new === '') ? '∅' : h((string) $new);
- return $label . ': ' . $oldDisp . ' → ' . $newDisp;
- }
- ?><!doctype html>
- <html lang="en">
- <head>
- <meta charset="utf-8">
- <title>Activity Log</title>
- <link rel="stylesheet" href="assets/app.css">
- <style>
- table.log {
- border-collapse: collapse;
- width: 100%;
- max-width: 1100px;
- font-size: 0.95rem;
- }
- table.log th, table.log td {
- padding: 0.4rem 0.7rem;
- border-bottom: 1px solid #eee;
- text-align: left;
- vertical-align: top;
- }
- table.log th {
- background: var(--c-accent-strong);
- color: #fff;
- font-weight: 600;
- font-size: 0.85rem;
- text-transform: uppercase;
- letter-spacing: 0.05em;
- }
- .log-ts { white-space: nowrap; color: var(--c-muted); font-variant-numeric: tabular-nums; }
- .log-actor { font-weight: 600; }
- .log-actor-icg { color: var(--c-accent-strong); }
- .log-actor-vend { color: var(--c-info); }
- .log-job { font-weight: 600; }
- .log-job a { color: inherit; text-decoration: none; }
- .log-job a:hover { text-decoration: underline; }
- .log-filter {
- margin: 0.5rem 0 1rem;
- color: var(--c-muted);
- }
- .log-filter a { color: var(--c-accent-strong); }
- .log-desc { max-width: 24em; }
- .log-muted { color: var(--c-muted); }
- </style>
- </head>
- <body>
- <div class="topbar">
- <h1>Activity Log</h1>
- <span class="who"><a href="PDQ.php">← Back to schedule</a></span>
- </div>
- <?php if ($job_filter > 0): ?>
- <p class="log-filter">
- Showing events for job #<?= (int) $job_filter ?>.
- <a href="log.php">Show everything →</a>
- </p>
- <?php else: ?>
- <p class="log-filter">Latest <?= count($rows) ?> events. Click a job number to filter.</p>
- <?php endif; ?>
- <table class="log">
- <thead>
- <tr>
- <th>When</th>
- <th>Who</th>
- <th>Job</th>
- <th>Description</th>
- <th>Event</th>
- </tr>
- </thead>
- <tbody>
- <?php if (!$rows): ?>
- <tr><td colspan="5" class="empty">No events recorded.</td></tr>
- <?php endif; ?>
- <?php foreach ($rows as $h):
- $actorKlass = $h['actor'] === 'ICG' ? 'log-actor-icg' : 'log-actor-vend';
- $jobLabel = $h['job_label'] !== null ? '#' . (int) $h['job_id'] . ' ' . h($h['job_label']) : '#' . (int) $h['job_id'] . ' (deleted)';
- $desc = (string) ($h['job_description'] ?? '');
- ?>
- <tr>
- <td class="log-ts"><?= fmt_long_date($h['changed_at']) ?></td>
- <td class="log-actor <?= $actorKlass ?>"><?= h($h['actor']) ?></td>
- <td class="log-job"><a href="?job=<?= (int) $h['job_id'] ?>"><?= $jobLabel ?></a></td>
- <td class="log-desc"><?= $desc === '' ? '<span class="log-muted">—</span>' : h($desc) ?></td>
- <td><?= fmt_event($h) ?></td>
- </tr>
- <?php endforeach; ?>
- </tbody>
- </table>
- </body>
- </html>
|