Your IP : 216.73.217.78


Current Path : /home/seto/testhive.pm/admin/
Upload File :
Current File : /home/seto/testhive.pm/admin/assignments.php

<?php
require_once __DIR__ . '/../includes/auth.php';
require_once __DIR__ . '/../includes/db.php';
require_once __DIR__ . '/_layout.php';

// Clear all assignments
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['clear_all'])) {
    db()->exec("DELETE FROM page_assignments");
    header('Location: /admin/assignments.php'); exit;
}

$campaignId = (int)($_GET['campaign_id'] ?? 0);

// Campaigns for filter dropdown
$campaigns = db()->query("SELECT id, name FROM campaigns ORDER BY name")->fetchAll();

// Assignments query — filter by campaign if selected, limit 500
$today = date('Y-m-d');
$where = $campaignId ? "AND pa.campaign_id = " . $campaignId : '';
$assignments = db()->query(
    "SELECT pa.expires_at, pa.assigned_at, pa.page_id, pa.link_id,
            d.domain, p.url,
            c.name AS campaign_name,
            l.text AS link_text,
            (SELECT COUNT(*) FROM impressions_daily WHERE page_id=pa.page_id AND date='$today') AS page_imp_today,
            (SELECT COUNT(*) FROM impressions_daily WHERE page_id=pa.page_id)                   AS page_imp_total,
            (SELECT COUNT(*) FROM impressions_daily WHERE link_id=pa.link_id AND date='$today') AS link_imp_today,
            (SELECT COUNT(*) FROM impressions_daily WHERE link_id=pa.link_id)                   AS link_imp_total
     FROM page_assignments pa
     JOIN pages     p ON p.id = pa.page_id
     JOIN donors    d ON d.id = p.donor_id
     JOIN campaigns c ON c.id = pa.campaign_id
     JOIN links     l ON l.id = pa.link_id
     WHERE 1=1 $where
     ORDER BY pa.expires_at ASC
     LIMIT 500"
)->fetchAll();

$totalAssigned = (int)db()->query("SELECT COUNT(*) FROM page_assignments")->fetchColumn();
$totalPages    = (int)db()->query("SELECT COUNT(*) FROM pages")->fetchColumn();

layout_head('Assignments');
?>

<!-- Toolbar -->
<div class="d-flex gap-2 mb-3 align-items-center flex-wrap">
  <form method="post" class="d-inline" onsubmit="return confirm('Удалить ВСЕ assignments?')">
    <input type="hidden" name="clear_all" value="1">
    <button class="btn btn-outline-danger btn-sm">Clear All</button>
  </form>

  <button id="btn-redistribute" class="btn btn-primary btn-sm">Redistribute</button>

  <div id="progress-wrap" class="d-none align-items-center gap-2">
    <div class="progress" style="width:200px;height:20px">
      <div id="progress-bar" class="progress-bar progress-bar-striped progress-bar-animated"
           role="progressbar" style="width:0%"></div>
    </div>
    <span id="progress-text" class="small text-muted">0 / 0</span>
  </div>

  <span class="text-muted small ms-2">
    Assigned: <?= number_format($totalAssigned) ?> / <?= number_format($totalPages) ?> pages
  </span>
</div>

<!-- Campaign filter -->
<div class="mb-3" style="max-width:300px">
  <form method="get">
    <select name="campaign_id" class="form-select form-select-sm" onchange="this.form.submit()">
      <option value="0">— Все кампании —</option>
      <?php foreach ($campaigns as $c): ?>
        <option value="<?= $c['id'] ?>" <?= $campaignId === (int)$c['id'] ? 'selected' : '' ?>>
          <?= htmlspecialchars($c['name']) ?>
        </option>
      <?php endforeach ?>
    </select>
  </form>
</div>

<!-- Table -->
<div class="card shadow-sm">
<div class="table-responsive">
<table class="table table-sm table-hover mb-0 small">
<thead class="table-light">
  <tr>
    <th>Domain</th>
    <th>URL</th>
    <th>Campaign</th>
    <th>Link text</th>
    <th class="text-center">Стр. 👁 <span tabindex="0" data-bs-toggle="popover" data-bs-trigger="hover focus" data-bs-html="true" data-bs-placement="top" data-bs-content="&lt;div class='small'&gt;&lt;b&gt;Показы страницы&lt;/b&gt;&lt;br&gt;Сколько раз эта страница донора показала любую ссылку.&lt;br&gt;&lt;br&gt;Формат: &lt;b&gt;сегодня&lt;/b&gt; / всего&lt;/div&gt;" style="display:inline-flex;align-items:center;justify-content:center;width:14px;height:14px;border-radius:50%;background:#adb5bd;color:#fff;font-size:10px;font-weight:600;cursor:default;vertical-align:middle;user-select:none">?</span></th>
    <th class="text-center">Ссыл. 👁 <span tabindex="0" data-bs-toggle="popover" data-bs-trigger="hover focus" data-bs-html="true" data-bs-placement="top" data-bs-content="&lt;div class='small'&gt;&lt;b&gt;Показы ссылки&lt;/b&gt;&lt;br&gt;Сколько раз конкретный текст этой ссылки был показан на любой странице.&lt;br&gt;&lt;br&gt;Формат: &lt;b&gt;сегодня&lt;/b&gt; / всего&lt;/div&gt;" style="display:inline-flex;align-items:center;justify-content:center;width:14px;height:14px;border-radius:50%;background:#adb5bd;color:#fff;font-size:10px;font-weight:600;cursor:default;vertical-align:middle;user-select:none">?</span></th>
    <th>Expires</th>
  </tr>
</thead>
<tbody>
<?php if (empty($assignments)): ?>
  <tr><td colspan="7" class="text-center text-muted py-3">Нет assignments</td></tr>
<?php endif ?>
<?php
$sumPageToday = $sumPageTotal = $sumLinkToday = $sumLinkTotal = 0;
foreach ($assignments as $a):
    $expired = time() > (int)$a['expires_at'];
    $sumPageToday += (int)$a['page_imp_today'];
    $sumPageTotal += (int)$a['page_imp_total'];
    $sumLinkToday += (int)$a['link_imp_today'];
    $sumLinkTotal += (int)$a['link_imp_total'];
?>
<tr class="<?= $expired ? 'table-warning' : '' ?>">
  <td><?= htmlspecialchars($a['domain']) ?></td>
  <td class="text-truncate" style="max-width:180px">
    <?= htmlspecialchars($a['url']) ?>
    <a href="<?= 'http://' . htmlspecialchars($a['domain']) . htmlspecialchars($a['url']) ?>" target="_blank" rel="noopener" class="ms-1 text-muted" title="Открыть страницу" style="opacity:.5;vertical-align:middle"><svg xmlns="http://www.w3.org/2000/svg" width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg></a>
  </td>
  <td><?= htmlspecialchars($a['campaign_name']) ?></td>
  <td class="text-truncate" style="max-width:180px"><?= htmlspecialchars(mb_substr($a['link_text'], 0, 70)) ?></td>
  <td class="text-center text-nowrap">
    <span class="fw-semibold"><?= (int)$a['page_imp_today'] ?></span>
    <span class="text-muted"> / <?= (int)$a['page_imp_total'] ?></span>
  </td>
  <td class="text-center text-nowrap">
    <span class="fw-semibold"><?= (int)$a['link_imp_today'] ?></span>
    <span class="text-muted"> / <?= (int)$a['link_imp_total'] ?></span>
  </td>
  <td class="text-nowrap"><?= $expired ? '<span class="text-danger">истёк</span> ' : '' ?><?= date('Y-m-d', (int)$a['expires_at']) ?></td>
</tr>
<?php endforeach ?>
<?php if (!empty($assignments)): ?>
<tr class="table-light fw-semibold">
  <td colspan="4" class="text-end text-muted">Итого:</td>
  <td class="text-center text-nowrap"><?= $sumPageToday ?> / <?= $sumPageTotal ?></td>
  <td class="text-center text-nowrap"><?= $sumLinkToday ?> / <?= $sumLinkTotal ?></td>
  <td></td>
</tr>
<?php endif ?>
</tbody>
</table>
</div>
</div>
<?php if (count($assignments) === 500): ?>
  <p class="text-muted small mt-2">Показаны первые 500 записей. Используйте фильтр по кампании для детального просмотра.</p>
<?php endif ?>

<script>
document.getElementById('btn-redistribute').addEventListener('click', function () {
  if (!confirm('Удалить все текущие assignments и перераспределить заново?')) return;

  const btn     = this;
  const wrap    = document.getElementById('progress-wrap');
  const bar     = document.getElementById('progress-bar');
  const txt     = document.getElementById('progress-text');

  btn.disabled = true;
  wrap.classList.remove('d-none');
  wrap.classList.add('d-flex');

  function runBatch(offset) {
    fetch('/api/redistribute.php?offset=' + offset)
      .then(r => r.json())
      .then(data => {
        const pct = data.total > 0 ? Math.round(data.done / data.total * 100) : 100;
        bar.style.width = pct + '%';
        txt.textContent = data.done + ' / ' + data.total;
        if (data.finished) {
          bar.classList.remove('progress-bar-animated');
          bar.classList.add('bg-success');
          txt.textContent = 'Готово! ' + data.done + ' страниц, assigned: ' + data.assigned;
          btn.disabled = false;
          // Reload after 1.5s to show updated counts
          setTimeout(() => location.reload(), 1500);
        } else {
          runBatch(data.done);
        }
      })
      .catch(err => {
        txt.textContent = 'Ошибка: ' + err;
        btn.disabled = false;
      });
  }

  runBatch(0);
});
</script>

<script>
document.addEventListener('DOMContentLoaded', function () {
  document.querySelectorAll('[data-bs-toggle="popover"]').forEach(function (el) {
    new bootstrap.Popover(el, { sanitize: false });
  });
});
</script>
<?php layout_foot() ?>