新增「未公开」状态;待审核改列表式,只留通过并公开
用户要求:
1. 待审核/全部问题都用列表形式
2. 待审核去掉「关闭说明」整块,后面只加一个「通过并公开」按钮
3. 标题本身就是进管理页的链接,去掉「进入管理」
4. 「未公开」应当是一种状态:提交后初始状态不是「待处理」而是「未公开」
状态流转(用户定义):
提交 → 未公开
├─ 通过并公开 → 待处理 → 处理中 → 已解决 → 已关闭
└─ 直接关闭 → 已关闭(不经过待处理)
每次状态变更、每次有人回复,都给提问人发信
实现:
- statuses 新增 hidden「未公开」,sort=0 排最前,其余顺延
幂等迁移:老库检测到没有 hidden 就整体后移一位再插入,
并把 visible=0 且 status=open 的存量数据归到 hidden
- new.php 初始状态按可见性决定:未公开→hidden,公开→open
(以前一律写 open,后台「待审核」里显示的全是「待处理」,状态反映不出事实)
- approve 动作:visible=1 且 hidden→open,并用更新后的行渲染邮件
- 详情页「通过并公开」按钮原来传原状态(未公开时通过后仍是未公开),改为固定传 open
- 待审核查询改为 status=hidden(兼容老数据 visible=0 且 open),
不再用 visible=0 AND status<>closed —— 那个条件会把「已关闭但未公开」也收进来
- 新增 fb_admin_pending_row() 列表行渲染:标题即链接、右侧单个按钮
- 删除 fb_admin_thread_card() 及「关闭说明」表单
- 新增 .plist/.prow 列表样式与 .st-hidden 状态徽标(中性灰)
- mailer 补 hidden 状态的文案,避免落到兜底
验证(线上真实数据):6 个状态齐全、提交落 hidden、
待审核能查到且不含已公开、通过后转 open 并移出待审核、
后续 doing/resolved/closed 推进正常、6 个状态邮件均能渲染、
待审核行结构 10 项断言全过(无关闭说明/无 note/无进入管理/标题可点)。
测试数据已清理,用户原有 4 条数据完好。
This commit is contained in:
@@ -116,17 +116,31 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['act'])) {
|
||||
$msgType = 'error';
|
||||
|
||||
} elseif ($act === 'approve') {
|
||||
$newStatus = ((string)$t['status'] === 'closed') ? 'open' : (string)$t['status'];
|
||||
/* 「通过并公开」= 两件事一起做:
|
||||
* ① 可见性:visible=1
|
||||
* ② 状态:『未公开』→『待处理』
|
||||
*
|
||||
* 状态流转是用户在 2026-11-03 明确要求的:提交后先落「未公开」,
|
||||
* 通过了才变「待处理」;如果判定不是问题,直接走 close 变「已关闭」,
|
||||
* 中间不经过「待处理」。
|
||||
*
|
||||
* 边界:如果这条本来就已经是别的状态(比如以前误操作改成了「处理中」),
|
||||
* 通过审核不该把状态倒退回去,所以只在「未公开」时才推进。
|
||||
* 老数据可能还是 'open' + visible=0,也一并视作待推进。 */
|
||||
$oldSt = (string)$t['status'];
|
||||
$newStatus = ($oldSt === 'hidden' || $oldSt === 'open') ? 'open' : $oldSt;
|
||||
$pdo->prepare('UPDATE threads SET visible = 1, status = ?, mod_note = NULL, moderated_at = ? WHERE id = ?')
|
||||
->execute([$newStatus, time(), $id]);
|
||||
fb_mod_log('approve', $id, '通过审核并公开');
|
||||
fb_mod_log('approve', $id, '通过审核并公开(状态:' . fb_status_label($newStatus) . ')');
|
||||
|
||||
// 通知提交人「已发布」(工单 #2)
|
||||
$errA = '';
|
||||
try {
|
||||
list($okA, $errA) = fb_notify_event($pdo, 'approve', $t);
|
||||
// 用更新后的状态渲染邮件,否则信里还写着「未公开」
|
||||
$fresh = fb_admin_thread($pdo, $id);
|
||||
list($okA, $errA) = fb_notify_event($pdo, 'approve', $fresh ? $fresh : $t);
|
||||
} catch (Throwable $e) { $errA = '发信异常'; }
|
||||
$msg = '#' . $id . ' 已通过审核,现已公开显示。'
|
||||
$msg = '#' . $id . ' 已通过审核并公开,状态为「' . fb_status_label($newStatus) . '」。'
|
||||
. ($errA === '' ? '已发邮件通知提交人。' : '(邮件未发出:' . $errA . ')');
|
||||
|
||||
} elseif ($act === 'close') {
|
||||
@@ -648,16 +662,23 @@ fb_layout_head('管理后台', ['robots' => 'noindex,nofollow']);
|
||||
|
||||
<?php if ($tab === 'pending'): ?>
|
||||
<?php
|
||||
/* 「待审核」= 还没公开过的条目。
|
||||
* 判据用 status='hidden'(未公开),不再用 visible=0 这种隐式条件 ——
|
||||
* 已关闭的条目 visible 也是 0,但它是处理完了,不该出现在待审核里。
|
||||
* 顺便兼容老数据:visible=0 且状态仍是 'open' 的也一并算待审核。 */
|
||||
$pending = $pdo->query(
|
||||
"SELECT id, title, body, category, status, author_name, author_email, created_at
|
||||
FROM threads WHERE visible = 0 AND status <> 'closed' ORDER BY created_at DESC"
|
||||
"SELECT * FROM threads
|
||||
WHERE status = 'hidden' OR (visible = 0 AND status = 'open')
|
||||
ORDER BY created_at DESC"
|
||||
)->fetchAll();
|
||||
?>
|
||||
<h2 style="margin:22px 0 10px">待审核 <span class="muted">(<?php echo count($pending); ?>)</span></h2>
|
||||
<h2 style="margin:22px 0 12px">待审核 <span class="muted">(<?php echo count($pending); ?>)</span></h2>
|
||||
<?php if (!$pending): ?>
|
||||
<div class="empty"><p>当前没有待审核的反馈。</p></div>
|
||||
<?php else: ?>
|
||||
<?php foreach ($pending as $t) { echo fb_admin_thread_card($t); } ?>
|
||||
<div class="plist">
|
||||
<?php foreach ($pending as $t) { echo fb_admin_pending_row($t); } ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php elseif ($tab === 'all'): ?>
|
||||
@@ -828,7 +849,10 @@ fb_layout_head('管理后台', ['robots' => 'noindex,nofollow']);
|
||||
<form method="post" action="admin.php?tab=thread&id=<?php echo (int)$id; ?>" class="act-inline">
|
||||
<input type="hidden" name="csrf" value="<?php echo e(fb_csrf_token()); ?>">
|
||||
<input type="hidden" name="id" value="<?php echo (int)$id; ?>">
|
||||
<input type="hidden" name="status" value="<?php echo e($curStatus === 'closed' ? 'open' : $curStatus); ?>">
|
||||
<?php /* 通过并公开 = 可见 + 状态转「待处理」。
|
||||
不能沿用原状态(未公开时原状态是 hidden,通过后还是未公开,
|
||||
状态和可见性就对不上了)。 */ ?>
|
||||
<input type="hidden" name="status" value="open">
|
||||
<input type="hidden" name="also_show" value="1">
|
||||
<button class="btn primary act-btn" type="submit" name="act" value="setstatus">通过并公开</button>
|
||||
</form>
|
||||
@@ -1411,53 +1435,44 @@ fb_layout_head('管理后台', ['robots' => 'noindex,nofollow']);
|
||||
fb_layout_foot();
|
||||
|
||||
/**
|
||||
* 待审核卡片(含「通过」与「关闭并邮件告知」两个操作)
|
||||
* 待审核条目(列表式)
|
||||
*
|
||||
* 用户 2026-11-03 明确要求:
|
||||
* ① 列表形式显示,不要每张卡片塞满表单
|
||||
* ② 去掉「关闭说明」整块 —— 想关闭就点标题进管理页再填说明,
|
||||
* 列表页不承担这个职责
|
||||
* ③ 后面只留一个「通过并公开」按钮,点一下就通过
|
||||
* ④ 标题自己就是进管理页的链接,别再额外挂「进入管理」
|
||||
*/
|
||||
function fb_admin_thread_card(array $t) {
|
||||
function fb_admin_pending_row(array $t) {
|
||||
$url = 'admin.php?tab=thread&id=' . (int)$t['id'];
|
||||
ob_start(); ?>
|
||||
<div class="card-form" style="margin:0 0 16px">
|
||||
<div class="item-top">
|
||||
<div class="prow">
|
||||
<div class="prow-main">
|
||||
<?php $cSw = !empty($t['software_id']) ? fb_software((int)$t['software_id']) : null; ?>
|
||||
<?php if ($cSw): ?><span class="badge sw"><?php echo e((string)$cSw['name']); ?></span><?php endif; ?>
|
||||
<?php if (!empty($t['category_id'])): ?>
|
||||
<span class="badge cat"><?php echo e(fb_category_label((int)$t['category_id'])); ?></span>
|
||||
<?php endif; ?>
|
||||
<span class="badge st st-<?php echo e($t['status']); ?>"><?php echo e(fb_status_label($t['status'])); ?></span>
|
||||
<span class="item-title"><?php echo e($t['title']); ?></span>
|
||||
<span class="item-id" title="问题编号">#<?php echo (int)$t['id']; ?></span>
|
||||
<div class="prow-top">
|
||||
<?php if ($cSw): ?><span class="badge sw"><?php echo e((string)$cSw['name']); ?></span><?php endif; ?>
|
||||
<?php if (!empty($t['category_id'])): ?>
|
||||
<span class="badge cat"><?php echo e(fb_category_label((int)$t['category_id'])); ?></span>
|
||||
<?php endif; ?>
|
||||
<span class="badge st st-<?php echo e($t['status']); ?>"><?php echo e(fb_status_label($t['status'])); ?></span>
|
||||
<a class="prow-title" href="<?php echo e($url); ?>"><?php echo e($t['title']); ?></a>
|
||||
<span class="item-id" title="问题编号">#<?php echo (int)$t['id']; ?></span>
|
||||
</div>
|
||||
<p class="prow-ex"><?php echo e(fb_excerpt((string)$t['body'], 120)); ?></p>
|
||||
<div class="prow-meta">
|
||||
<span class="who"><?php echo e($t['author_name']); ?></span>
|
||||
<span class="dot">·</span>
|
||||
<span><?php echo e($t['author_email']); ?></span>
|
||||
<span class="dot">·</span>
|
||||
<span><?php echo e(fb_fmt_time($t['created_at'])); ?></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="item-ex" style="white-space:normal"><?php echo nl2br(e($t['body'])); ?></div>
|
||||
|
||||
<div class="item-meta">
|
||||
<span class="who"><?php echo e($t['author_name']); ?></span>
|
||||
<span class="dot">·</span>
|
||||
<span><?php echo e(fb_fmt_time($t['created_at'])); ?></span>
|
||||
<span class="dot">·</span>
|
||||
<span><?php echo e($t['author_email']); ?></span>
|
||||
<span class="dot">·</span>
|
||||
<a href="admin.php?tab=thread&id=<?php echo (int)$t['id']; ?>">进入管理</a>
|
||||
</div>
|
||||
|
||||
<div class="row2" style="margin-top:14px">
|
||||
<div class="prow-act">
|
||||
<form method="post" action="admin.php?tab=pending">
|
||||
<input type="hidden" name="csrf" value="<?php echo e(fb_csrf_token()); ?>">
|
||||
<input type="hidden" name="id" value="<?php echo (int)$t['id']; ?>">
|
||||
<div class="form-actions">
|
||||
<button class="btn primary" type="submit" name="act" value="approve">通过并公开</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<form method="post" action="admin.php?tab=pending">
|
||||
<input type="hidden" name="csrf" value="<?php echo e(fb_csrf_token()); ?>">
|
||||
<input type="hidden" name="id" value="<?php echo (int)$t['id']; ?>">
|
||||
<label class="field">
|
||||
<span>关闭说明 <b class="req">*</b> <i class="hint">判定"不是问题"时填写,会随邮件发给提问人</i></span>
|
||||
<textarea name="note" rows="4" maxlength="4000" placeholder="例如:该现象是服务器端的 CalDAV 限制,并非应用问题;建议改用…"></textarea>
|
||||
</label>
|
||||
<div class="form-actions">
|
||||
<button class="btn" type="submit" name="act" value="close">关闭并邮件告知</button>
|
||||
</div>
|
||||
<button class="btn primary" type="submit" name="act" value="approve">通过并公开</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user