Admin: clarify photo description and add comment indicators
Rename the photo field label to avoid confusion with user comments and show comment count indicators in photo actions. Let admins open a per-photo comment view from the indicator and remove comments directly from that filtered list.
This commit is contained in:
parent
8dce294249
commit
728050ced9
90
admin.php
90
admin.php
|
|
@ -213,10 +213,38 @@ if (!in_array($adminMode, ['sections', 'photos', 'comments', 'welcome'], true))
|
||||||
$adminMode = 'photos';
|
$adminMode = 'photos';
|
||||||
}
|
}
|
||||||
$previewVersion = (string)time();
|
$previewVersion = (string)time();
|
||||||
|
$commentPhotoId = (int)($_GET['comment_photo_id'] ?? ($_POST['comment_photo_id'] ?? 0));
|
||||||
|
if ($commentPhotoId < 0) {
|
||||||
|
$commentPhotoId = 0;
|
||||||
|
}
|
||||||
|
$selectedCommentPhoto = $commentPhotoId > 0 ? photoById($commentPhotoId) : null;
|
||||||
|
if (!$selectedCommentPhoto) {
|
||||||
|
$commentPhotoId = 0;
|
||||||
|
}
|
||||||
|
$photoComments = $commentPhotoId > 0 ? commentsByPhoto($commentPhotoId) : [];
|
||||||
|
$photoCommentCounts = commentCountsByPhotoIds(array_map(static fn(array $p): int => (int)$p['id'], $photos));
|
||||||
|
|
||||||
function h(string $v): string { return htmlspecialchars($v, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); }
|
function h(string $v): string { return htmlspecialchars($v, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); }
|
||||||
function assetUrl(string $path): string { $f=__DIR__ . '/' . ltrim($path,'/'); $v=is_file($f)?(string)filemtime($f):(string)time(); return $path . '?v=' . rawurlencode($v); }
|
function assetUrl(string $path): string { $f=__DIR__ . '/' . ltrim($path,'/'); $v=is_file($f)?(string)filemtime($f):(string)time(); return $path . '?v=' . rawurlencode($v); }
|
||||||
|
|
||||||
|
function commentCountsByPhotoIds(array $photoIds): array
|
||||||
|
{
|
||||||
|
$photoIds = array_values(array_unique(array_map('intval', $photoIds)));
|
||||||
|
if ($photoIds === []) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$placeholders = implode(',', array_fill(0, count($photoIds), '?'));
|
||||||
|
$st = db()->prepare("SELECT photo_id, COUNT(*) AS cnt FROM photo_comments WHERE photo_id IN ($placeholders) GROUP BY photo_id");
|
||||||
|
$st->execute($photoIds);
|
||||||
|
|
||||||
|
$map = [];
|
||||||
|
foreach ($st->fetchAll() as $row) {
|
||||||
|
$map[(int)$row['photo_id']] = (int)$row['cnt'];
|
||||||
|
}
|
||||||
|
return $map;
|
||||||
|
}
|
||||||
|
|
||||||
function saveBulkBefore(array $files, int $sectionId): array
|
function saveBulkBefore(array $files, int $sectionId): array
|
||||||
{
|
{
|
||||||
$ok = 0;
|
$ok = 0;
|
||||||
|
|
@ -564,6 +592,7 @@ function nextUniqueCodeName(string $base): string
|
||||||
<table class="tbl">
|
<table class="tbl">
|
||||||
<tr><th>До</th><th>После</th><th>Поля</th><th>Действия</th></tr>
|
<tr><th>До</th><th>После</th><th>Поля</th><th>Действия</th></tr>
|
||||||
<?php foreach($photos as $p): ?>
|
<?php foreach($photos as $p): ?>
|
||||||
|
<?php $photoCommentCount = (int)($photoCommentCounts[(int)$p['id']] ?? 0); ?>
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<?php if (!empty($p['before_file_id'])): ?>
|
<?php if (!empty($p['before_file_id'])): ?>
|
||||||
|
|
@ -600,12 +629,17 @@ function nextUniqueCodeName(string $base): string
|
||||||
<input type="hidden" name="action" value="photo_update"><input type="hidden" name="ajax" value="1"><input type="hidden" name="token" value="<?= h($tokenIncoming) ?>"><input type="hidden" name="photo_id" value="<?= (int)$p['id'] ?>">
|
<input type="hidden" name="action" value="photo_update"><input type="hidden" name="ajax" value="1"><input type="hidden" name="token" value="<?= h($tokenIncoming) ?>"><input type="hidden" name="photo_id" value="<?= (int)$p['id'] ?>">
|
||||||
<p><input class="in" name="code_name" value="<?= h((string)$p['code_name']) ?>"></p>
|
<p><input class="in" name="code_name" value="<?= h((string)$p['code_name']) ?>"></p>
|
||||||
<p><input class="in" type="number" name="sort_order" value="<?= (int)$p['sort_order'] ?>"></p>
|
<p><input class="in" type="number" name="sort_order" value="<?= (int)$p['sort_order'] ?>"></p>
|
||||||
<p><textarea class="in" name="description" placeholder="Комментарий"><?= h((string)($p['description'] ?? '')) ?></textarea></p>
|
<p><label class="small" for="descr-<?= (int)$p['id'] ?>">Описание фотографии</label><textarea id="descr-<?= (int)$p['id'] ?>" class="in" name="description" placeholder="Описание фотографии"><?= h((string)($p['description'] ?? '')) ?></textarea></p>
|
||||||
<p class="small">Фото после (опционально): <input type="file" name="after" accept="image/jpeg,image/png,image/webp,image/gif"></p>
|
<p class="small">Фото после (опционально): <input type="file" name="after" accept="image/jpeg,image/png,image/webp,image/gif"></p>
|
||||||
<div class="small js-save-status">Сохраняется автоматически при выходе из карточки.</div>
|
<div class="small js-save-status">Сохраняется автоматически при выходе из карточки.</div>
|
||||||
</form>
|
</form>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
|
<?php if ($photoCommentCount > 0): ?>
|
||||||
|
<p><a class="btn btn-secondary btn-xs" href="?token=<?= urlencode($tokenIncoming) ?>&mode=comments&comment_photo_id=<?= (int)$p['id'] ?>§ion_id=<?= (int)$activeSectionId ?>">Комментарии (<?= $photoCommentCount ?>)</a></p>
|
||||||
|
<?php else: ?>
|
||||||
|
<p class="small">Комментариев нет</p>
|
||||||
|
<?php endif; ?>
|
||||||
<form method="post" action="?token=<?= urlencode($tokenIncoming) ?>§ion_id=<?= (int)$activeSectionId ?>&mode=photos" onsubmit="return confirm('Удалить фото?')">
|
<form method="post" action="?token=<?= urlencode($tokenIncoming) ?>§ion_id=<?= (int)$activeSectionId ?>&mode=photos" onsubmit="return confirm('Удалить фото?')">
|
||||||
<input type="hidden" name="action" value="photo_delete"><input type="hidden" name="token" value="<?= h($tokenIncoming) ?>"><input type="hidden" name="photo_id" value="<?= (int)$p['id'] ?>">
|
<input type="hidden" name="action" value="photo_delete"><input type="hidden" name="token" value="<?= h($tokenIncoming) ?>"><input type="hidden" name="photo_id" value="<?= (int)$p['id'] ?>">
|
||||||
<button class="btn btn-danger" type="submit">Удалить</button>
|
<button class="btn btn-danger" type="submit">Удалить</button>
|
||||||
|
|
@ -643,21 +677,45 @@ function nextUniqueCodeName(string $base): string
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
</table>
|
</table>
|
||||||
<hr style="border:none;border-top:1px solid #eee;margin:12px 0">
|
<hr style="border:none;border-top:1px solid #eee;margin:12px 0">
|
||||||
<table class="tbl"><tr><th>Фото</th><th>Пользователь</th><th>Комментарий</th><th></th></tr>
|
<?php if ($commentPhotoId > 0 && $selectedCommentPhoto): ?>
|
||||||
<?php foreach($latestComments as $c): ?>
|
<h4 style="margin:0 0 10px">Комментарии к фото: <?= h((string)$selectedCommentPhoto['code_name']) ?></h4>
|
||||||
<tr>
|
<?php if ($photoComments === []): ?>
|
||||||
<td><?= h((string)$c['code_name']) ?></td>
|
<p class="small">К этой карточке комментариев пока нет.</p>
|
||||||
<td><?= h((string)($c['display_name'] ?? '—')) ?></td>
|
<?php else: ?>
|
||||||
<td><?= h((string)$c['comment_text']) ?></td>
|
<table class="tbl"><tr><th>Пользователь</th><th>Комментарий</th><th>Дата</th><th></th></tr>
|
||||||
<td>
|
<?php foreach($photoComments as $c): ?>
|
||||||
<form method="post" action="?token=<?= urlencode($tokenIncoming) ?>&mode=comments" onsubmit="return confirm('Удалить комментарий?')">
|
<tr>
|
||||||
<input type="hidden" name="action" value="delete_comment"><input type="hidden" name="token" value="<?= h($tokenIncoming) ?>"><input type="hidden" name="id" value="<?= (int)$c['id'] ?>">
|
<td><?= h((string)($c['display_name'] ?? '—')) ?></td>
|
||||||
<button class="btn btn-danger" type="submit">Удалить</button>
|
<td><?= nl2br(h((string)$c['comment_text'])) ?></td>
|
||||||
</form>
|
<td><?= h((string)$c['created_at']) ?></td>
|
||||||
</td>
|
<td>
|
||||||
</tr>
|
<form method="post" action="?token=<?= urlencode($tokenIncoming) ?>&mode=comments&comment_photo_id=<?= (int)$commentPhotoId ?>" onsubmit="return confirm('Удалить комментарий?')">
|
||||||
<?php endforeach; ?>
|
<input type="hidden" name="action" value="delete_comment"><input type="hidden" name="token" value="<?= h($tokenIncoming) ?>"><input type="hidden" name="id" value="<?= (int)$c['id'] ?>"><input type="hidden" name="comment_photo_id" value="<?= (int)$commentPhotoId ?>">
|
||||||
</table>
|
<button class="btn btn-danger" type="submit">Удалить</button>
|
||||||
|
</form>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</table>
|
||||||
|
<?php endif; ?>
|
||||||
|
<p style="margin-top:10px"><a href="?token=<?= urlencode($tokenIncoming) ?>&mode=comments">Показать все последние комментарии</a></p>
|
||||||
|
<?php else: ?>
|
||||||
|
<table class="tbl"><tr><th>Фото</th><th>Пользователь</th><th>Комментарий</th><th></th></tr>
|
||||||
|
<?php foreach($latestComments as $c): ?>
|
||||||
|
<tr>
|
||||||
|
<td><?= h((string)$c['code_name']) ?></td>
|
||||||
|
<td><?= h((string)($c['display_name'] ?? '—')) ?></td>
|
||||||
|
<td><?= h((string)$c['comment_text']) ?></td>
|
||||||
|
<td>
|
||||||
|
<form method="post" action="?token=<?= urlencode($tokenIncoming) ?>&mode=comments" onsubmit="return confirm('Удалить комментарий?')">
|
||||||
|
<input type="hidden" name="action" value="delete_comment"><input type="hidden" name="token" value="<?= h($tokenIncoming) ?>"><input type="hidden" name="id" value="<?= (int)$c['id'] ?>">
|
||||||
|
<button class="btn btn-danger" type="submit">Удалить</button>
|
||||||
|
</form>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</table>
|
||||||
|
<?php endif; ?>
|
||||||
</section>
|
</section>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</main>
|
</main>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user