- 의견 내용 패널에 '수정' 토글 → 본문 편집·저장(계정 스코프·2000자 제한) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
127 lines
6.4 KiB
PHP
127 lines
6.4 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
/** @var object $row */
|
|
use App\Models\FeedbackModel;
|
|
?>
|
|
<style>
|
|
/* 의견 상세: 레이아웃 body의 select-none 상속을 무효화하여 본문 텍스트를 복사 가능하게 함 */
|
|
.fb-selectable, .fb-selectable * {
|
|
-webkit-user-select: text;
|
|
-moz-user-select: text;
|
|
-ms-user-select: text;
|
|
user-select: text;
|
|
}
|
|
</style>
|
|
<div class="fb-selectable">
|
|
<section class="border-b border-gray-300 p-2 shrink-0 bg-control-panel flex items-center justify-between gap-2">
|
|
<span class="text-sm font-bold text-gray-700">의견 상세 #<?= (int) $row->fb_idx ?></span>
|
|
<a href="<?= site_url('admin/feedback') ?>" class="text-sm text-gray-600 hover:underline">목록으로</a>
|
|
</section>
|
|
|
|
<div class="grid grid-cols-1 lg:grid-cols-2 gap-3 mt-2">
|
|
<section class="border border-gray-300 rounded-lg overflow-hidden">
|
|
<div class="px-3 py-2 border-b bg-gray-50 text-sm font-semibold text-gray-700 flex items-center justify-between">
|
|
<span>의견 내용</span>
|
|
<button type="button" id="fb-content-edit-btn" class="text-xs font-medium text-blue-600 hover:underline">수정</button>
|
|
</div>
|
|
<div class="p-3 space-y-2 text-sm">
|
|
<!-- 보기 모드 -->
|
|
<div id="fb-content-view">
|
|
<p class="whitespace-pre-wrap text-gray-800"><?= esc((string) $row->fb_content) ?></p>
|
|
</div>
|
|
<!-- 수정 모드 -->
|
|
<form id="fb-content-edit" action="<?= site_url('admin/feedback/' . (int) $row->fb_idx . '/content') ?>" method="post" class="hidden">
|
|
<?= csrf_field() ?>
|
|
<textarea name="fb_content" rows="6" maxlength="2000" class="w-full border border-gray-300 rounded px-2 py-1.5 text-sm"><?= esc((string) $row->fb_content) ?></textarea>
|
|
<div class="flex gap-2 mt-2">
|
|
<button type="submit" class="bg-btn-search text-white px-4 py-1.5 rounded-sm text-sm">수정 저장</button>
|
|
<button type="button" id="fb-content-cancel" class="bg-gray-200 text-gray-700 px-4 py-1.5 rounded-sm text-sm hover:bg-gray-300">취소</button>
|
|
</div>
|
|
</form>
|
|
<hr class="my-2"/>
|
|
<?php
|
|
// 화면 URL — embed 파라미터를 떼고 전체 화면 절대 URL로 변환(클릭 시 해당 화면으로 바로 이동).
|
|
$fbUrlRaw = (string) ($row->fb_page_url ?? '');
|
|
$fbUrlOpen = $fbUrlRaw;
|
|
if ($fbUrlOpen !== '' && ! preg_match('#^https?://#i', $fbUrlOpen)) {
|
|
$fbUrlOpen = (string) preg_replace('/([?&])embed=1(?=&|$)/', '$1', $fbUrlOpen);
|
|
$fbUrlOpen = rtrim($fbUrlOpen, '?&');
|
|
$fbUrlOpen = base_url(ltrim($fbUrlOpen, '/'));
|
|
}
|
|
?>
|
|
<dl class="grid grid-cols-[5rem_1fr] gap-y-1 text-[12px] text-gray-600">
|
|
<dt class="font-semibold">화면</dt>
|
|
<dd>
|
|
<?= esc((string) ($row->fb_page_title ?: '-')) ?><br>
|
|
<?php if ($fbUrlRaw !== ''): ?>
|
|
<a href="<?= esc($fbUrlOpen, 'attr') ?>" target="_blank" rel="noopener" class="text-blue-600 hover:underline break-all"><?= esc($fbUrlRaw) ?></a>
|
|
<?php else: ?>
|
|
<span class="text-gray-400">-</span>
|
|
<?php endif; ?>
|
|
</dd>
|
|
<dt class="font-semibold">작성자</dt><dd><?= esc((string) ($row->fb_mb_name ?? '')) ?> (idx <?= (int) $row->fb_mb_idx ?>, level <?= (int) $row->fb_mb_level ?>)</dd>
|
|
<dt class="font-semibold">지자체</dt><dd><?= (int) ($row->fb_lg_idx ?? 0) ?></dd>
|
|
<dt class="font-semibold">일시</dt><dd><?= esc((string) ($row->fb_regdate ?? '')) ?></dd>
|
|
<dt class="font-semibold">브라우저</dt><dd class="break-all text-gray-400"><?= esc((string) ($row->fb_user_agent ?? '')) ?></dd>
|
|
</dl>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="border border-gray-300 rounded-lg overflow-hidden">
|
|
<div class="px-3 py-2 border-b bg-gray-50 text-sm font-semibold text-gray-700">처리</div>
|
|
<form action="<?= site_url('admin/feedback/' . (int) $row->fb_idx . '/status') ?>" method="post" class="p-3 space-y-3">
|
|
<?= csrf_field() ?>
|
|
<div>
|
|
<label class="block text-xs font-bold text-gray-700 mb-1">상태</label>
|
|
<select name="fb_status" class="border border-gray-300 rounded px-2 py-1.5 text-sm w-40">
|
|
<?php foreach (FeedbackModel::STATUSES as $s): ?>
|
|
<option value="<?= esc($s, 'attr') ?>" <?= (string) $row->fb_status === $s ? 'selected' : '' ?>><?= esc(FeedbackModel::statusLabel($s)) ?></option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<label class="block text-xs font-bold text-gray-700 mb-1">처리 메모</label>
|
|
<textarea name="fb_admin_memo" rows="4" class="w-full border border-gray-300 rounded px-2 py-1.5 text-sm" maxlength="2000"><?= esc((string) ($row->fb_admin_memo ?? '')) ?></textarea>
|
|
</div>
|
|
<button type="submit" class="bg-btn-search text-white px-4 py-1.5 rounded-sm text-sm">저장</button>
|
|
</form>
|
|
</section>
|
|
</div>
|
|
|
|
<?php $files = $files ?? []; ?>
|
|
<?php if (! empty($files)): ?>
|
|
<section class="border border-gray-300 rounded-lg overflow-hidden mt-3">
|
|
<div class="px-3 py-2 border-b bg-gray-50 text-sm font-semibold text-gray-700">첨부 이미지 (<?= count($files) ?>)</div>
|
|
<div class="p-3 flex flex-wrap gap-3">
|
|
<?php foreach ($files as $f): ?>
|
|
<figure class="m-0">
|
|
<a href="<?= site_url('admin/feedback/file/' . (int) $f->ff_idx) ?>" target="_blank" rel="noopener">
|
|
<img src="<?= site_url('admin/feedback/file/' . (int) $f->ff_idx) ?>" alt="첨부 이미지"
|
|
style="max-width:280px;max-height:220px;border:1px solid #e5e7eb;border-radius:6px;"/>
|
|
</a>
|
|
<figcaption class="text-[11px] text-gray-400 mt-1"><?= $f->ff_kind === 'capture' ? '화면 캡처' : '사용자 첨부' ?></figcaption>
|
|
</figure>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
</section>
|
|
<?php endif; ?>
|
|
</div><!-- /.fb-selectable -->
|
|
|
|
<script>
|
|
(function () {
|
|
var btn = document.getElementById('fb-content-edit-btn');
|
|
var view = document.getElementById('fb-content-view');
|
|
var edit = document.getElementById('fb-content-edit');
|
|
var cancel = document.getElementById('fb-content-cancel');
|
|
if (!btn || !view || !edit) return;
|
|
var show = function (editing) {
|
|
view.classList.toggle('hidden', editing);
|
|
edit.classList.toggle('hidden', !editing);
|
|
btn.classList.toggle('hidden', editing);
|
|
if (editing) { var ta = edit.querySelector('textarea'); if (ta) ta.focus(); }
|
|
};
|
|
btn.addEventListener('click', function () { show(true); });
|
|
if (cancel) cancel.addEventListener('click', function () { show(false); });
|
|
})();
|
|
</script>
|