多软件归属:软件→分类两级,配置全部入库 (#1)
原先分类写死在 config.example.php,后台改不了;也没有「软件」概念。 现在改为数据库驱动的两级结构,后台可配(管理界面待做)。 ## 数据层(lib/db.php) - 新增 software / categories / statuses 三张表 - categories.software_id 外键:每个软件有自己的分类集合,可同名互不干扰 - threads 加 software_id / category_id;老 category 文本列保留不删(可回退) - fb_db_migrate_taxonomy() 幂等迁移:建表 → 空表灌初始数据 → 回填老帖子 ## 迁移实测 - 老 5 个分类(使用问题/Bug 反馈/功能建议/同步问题/其他)原样落进默认软件 - 老帖子按 category slug 回填 category_id,匹配不到的留 NULL ## 状态(5 个) 待处理 / 处理中 / 已解决 / 已关闭 / 不予考虑(wontfix) 每个状态带 user_note「给用户看的话」,后台可改,将进邮件正文。 待处理 = 刚提交:您提交的反馈已收到,我们正在处理中。 ## 前台 - index.php:软件切换条 + 分类 chip(一级软件、二级分类) - new.php:选软件、分类下拉随软件变、服务端校验分类归属 - URL:?sw=<slug>&cat=<slug>;老链接 ?cat=xxx 解析不到时退回全部,200 不 404 ## 界面一致性 按用户要求去掉「单软件时隐藏软件选择器」的逻辑: 所有界面一致,配一个就列一个,配多个就列多个。 ## 兼容 fb_categories() 现在必须传软件 id;fb_statuses() 返回行数组, 另有 fb_status_keys() 取 key=>name 映射。 验证:WSL 内临时实例实测——单软件显示 1 个软件条;两软件各显示 自己的分类集合与帖子,互不串;无 PHP 警告/致命错误。
This commit is contained in:
@@ -4,13 +4,27 @@
|
||||
*/
|
||||
require __DIR__ . '/lib/bootstrap.php';
|
||||
|
||||
$pdo = fb_db();
|
||||
$cats = fb_categories();
|
||||
$err = '';
|
||||
$atts = []; // 校验失败时保留已上传的附件
|
||||
$catKeys = array_keys($cats);
|
||||
$form = [
|
||||
'category' => $catKeys ? (string)$catKeys[0] : 'other',
|
||||
$pdo = fb_db();
|
||||
$err = '';
|
||||
$atts = []; // 校验失败时保留已上传的附件
|
||||
|
||||
/* ---- 软件:URL 带 sw 就用它,否则落到默认软件 ---- */
|
||||
$swList = fb_softwares(true);
|
||||
$sw = null;
|
||||
$swKey = isset($_GET['sw']) ? (string)$_GET['sw'] : '';
|
||||
if ($swKey !== '') {
|
||||
$sw = fb_software($swKey);
|
||||
if (!$sw || (int)$sw['enabled'] !== 1) { $sw = null; }
|
||||
}
|
||||
if ($sw === null && $swList) { $sw = $swList[0]; }
|
||||
$swId = $sw ? (int)$sw['id'] : 0;
|
||||
|
||||
$cats = fb_categories($swId);
|
||||
$catKeys = [];
|
||||
foreach ($cats as $c) { $catKeys[] = (int)$c['id']; }
|
||||
|
||||
$form = [
|
||||
'category_id' => $catKeys ? (string)$catKeys[0] : '',
|
||||
'title' => '',
|
||||
'body' => '',
|
||||
'name' => '',
|
||||
@@ -19,16 +33,27 @@ $form = [
|
||||
];
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
foreach (['category', 'title', 'body', 'name', 'email', 'phone'] as $k) {
|
||||
foreach (['category_id', 'title', 'body', 'name', 'email', 'phone'] as $k) {
|
||||
$form[$k] = trim(isset($_POST[$k]) ? (string)$_POST[$k] : '');
|
||||
}
|
||||
// POST 里带了 software_id 时以它为准(切换软件后表单会跟着变)
|
||||
if (isset($_POST['software_id']) && ctype_digit((string)$_POST['software_id'])) {
|
||||
$swPost = fb_software((int)$_POST['software_id']);
|
||||
if ($swPost && (int)$swPost['enabled'] === 1) {
|
||||
$sw = $swPost;
|
||||
$swId = (int)$swPost['id'];
|
||||
}
|
||||
}
|
||||
$capInput = isset($_POST['captcha']) ? (string)$_POST['captcha'] : '';
|
||||
$hp = trim(isset($_POST['website']) ? (string)$_POST['website'] : '');
|
||||
$t0 = isset($_POST['t0']) ? (int)$_POST['t0'] : 0;
|
||||
|
||||
list($attOk, $attList, $attErr) = fb_attach_parse(isset($_POST['attachments']) ? $_POST['attachments'] : '');
|
||||
|
||||
if (!isset($cats[$form['category']])) { $form['category'] = 'other'; }
|
||||
// 分类必须属于这个软件,否则视为未选
|
||||
$curCatId = ctype_digit($form['category_id']) ? (int)$form['category_id'] : 0;
|
||||
$curCat = $curCatId ? fb_category($curCatId) : null;
|
||||
if (!$curCat || (int)$curCat['software_id'] !== $swId) { $curCat = null; $form['category_id'] = ''; }
|
||||
|
||||
if (!fb_csrf_ok(isset($_POST['csrf']) ? $_POST['csrf'] : '')) {
|
||||
$err = '会话已过期,请重新提交。';
|
||||
@@ -66,9 +91,12 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$now = time();
|
||||
// 审核:开启后新提交默认不公开(visible=0),管理员通过后才会出现在列表
|
||||
$visible = fb_moderation_on() ? 0 : 1;
|
||||
$ins = $pdo->prepare('INSERT INTO threads(title, body, category, author_name, author_email, author_phone, status, visible, reply_count, created_at, updated_at, ip_hash) VALUES(?,?,?,?,?,?,?,?,0,?,?,?)');
|
||||
$ins = $pdo->prepare('INSERT INTO threads(title, body, category, category_id, software_id, author_name, author_email, author_phone, status, visible, reply_count, created_at, updated_at, ip_hash) VALUES(?,?,?,?,?,?,?,?,?,?,0,?,?,?)');
|
||||
$ins->execute([
|
||||
$form['title'], $form['body'], $form['category'],
|
||||
$form['title'], $form['body'],
|
||||
$curCat ? (string)$curCat['slug'] : 'other', // 老列留个值,便于回退与检索
|
||||
$curCat ? (int)$curCat['id'] : null,
|
||||
$swId > 0 ? $swId : null,
|
||||
$form['name'], $form['email'],
|
||||
$form['phone'] !== '' ? $form['phone'] : null,
|
||||
'open', $visible, $now, $now, fb_ip_hash(),
|
||||
@@ -99,14 +127,31 @@ fb_layout_head('我要反馈', ['robots' => 'noindex,follow']);
|
||||
<label>请勿填写此栏<input type="text" name="website" tabindex="-1" autocomplete="off"></label>
|
||||
</div>
|
||||
|
||||
<?php if ($sw): ?>
|
||||
<input type="hidden" name="software_id" value="<?php echo (int)$sw['id']; ?>">
|
||||
<div class="field">
|
||||
<span>所属软件 <b class="req">*</b><i class="hint">换软件会刷新下面的分类</i></span>
|
||||
<div class="chips">
|
||||
<?php foreach ($swList as $one): ?>
|
||||
<a class="chip <?php echo ((int)$one['id'] === $swId) ? 'on' : ''; ?>"
|
||||
href="new.php?sw=<?php echo e(urlencode((string)$one['slug'])); ?>"><?php echo e((string)$one['name']); ?></a>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php elseif ($sw): ?>
|
||||
<input type="hidden" name="software_id" value="<?php echo (int)$sw['id']; ?>">
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($cats): ?>
|
||||
<label class="field">
|
||||
<span>问题分类 <b class="req">*</b></span>
|
||||
<select name="category">
|
||||
<?php foreach ($cats as $k => $v): ?>
|
||||
<option value="<?php echo e($k); ?>" <?php echo $form['category'] === $k ? 'selected' : ''; ?>><?php echo e($v); ?></option>
|
||||
<select name="category_id" required>
|
||||
<?php foreach ($cats as $c): ?>
|
||||
<option value="<?php echo (int)$c['id']; ?>" <?php echo $form['category_id'] === (string)$c['id'] ? 'selected' : ''; ?>><?php echo e((string)$c['name']); ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</label>
|
||||
<?php endif; ?>
|
||||
|
||||
<label class="field">
|
||||
<span>标题 <b class="req">*</b></span>
|
||||
|
||||
Reference in New Issue
Block a user