2026年2月开发记录-文档类实现方案草案

文档创建者:蜗牛
浏览次数:1313
最后更新:2026-02-28
新建文档详情
排列序号: 10
配置选择: 普通文档
配置贴展示: 展示在目录

分类信息排序方案实施计划(方案 1.0 完整版)

一、项目概述

1.1 方案目标

基于 Discuz 分类信息系统实现目录树和版块列表页的统一排序,解决以下问题:

  1. 排序一致性:目录树排序和列表页排序保持一致
  2. 配置简化:发帖时直接设置排序值,无需在配置帖中查 tid
  3. 教育成本降低:使用下拉单选 + 置顶判断,无需学习特殊格式
  4. 顶级帖子展示:支持置顶说明帖自动展示在 0 级目录
  5. 配置帖可控:配置帖可通过选项控制是否展示在目录树中

1.2 核心设计

项目 值 说明
sortid 5 分类名称:文档管理
optionid=21 sort_order 类型:字串 (text),用于帖子排序值
optionid=22 is_config 类型:单选 (radio),0=普通帖子,1=配置帖子
optionid=23 show_in_tree 类型:单选 (radio),0=不展示,1=展示(仅对配置帖有效)

1.3 判断逻辑

0 级目录(顶级):displayorder > 0 AND is_config = 0
    → 自动展示所有置顶说明帖

配置帖展示:displayorder > 0 AND is_config = 1 AND show_in_tree = 1
    → 配置帖可选择是否展示在目录树中

普通帖子:displayorder = 0
    → 按 sort_order 排序归入对应目录

二、数据库设计

2.1 分类信息项目创建

2.1.1 创建分类信息(sortid=5)

在 Discuz 后台 → 分类信息 → 添加分类信息

字段 值
分类名称 文档管理
类型标识 document
显示顺序 5
可用 是

2.1.2 创建选项项目

optionid=21 - sort_order(排序值)

字段 值
所属分类 sortid=5
选项类型 字串 (text)
选项标题 排序权重
变量名 sort_order
输入提示 数字越小越靠前,如 1、2、3...
必填 否(默认 99)

optionid=22 - is_config(配置帖标识)

字段 值
所属分类 sortid=5
选项类型 单选 (radio)
选项标题 是否为配置帖
变量名 is_config
选项值 0=否\n1=是
默认值 0
必填 是

optionid=23 - show_in_tree(目录树展示控制)

字段 值
所属分类 sortid=5
选项类型 单选 (radio)
选项标题 是否展示在目录树
变量名 show_in_tree
选项值 0=不展示\n1=展示
默认值 1
权限设置 仅管理员可设置
说明 仅对配置帖有效,普通帖子始终展示

2.2 涉及的数据表

-- 分类信息选项定义表
pre_forum_typeoption

-- 分类信息选项数据表
pre_forum_typeoptionvar

-- 分类信息单选值表
pre_forum_typeoptionvalue

-- 帖子表(查询用)
pre_forum_thread

-- 标签表(现有功能)
pre_common_tag
pre_common_tagitem

2.3 索引优化建议

-- 为分类信息表添加组合索引
ALTER TABLE `pre_forum_typeoptionvar`
ADD INDEX `idx_sortid_optionid` (`sortid`, `optionid`);

ALTER TABLE `pre_forum_typeoptionvar`
ADD INDEX `idx_tid_optionid` (`tid`, `optionid`);

-- 为帖子表添加索引(如果尚未存在)
ALTER TABLE `pre_forum_thread`
ADD INDEX `idx_fid_displayorder` (`fid`, `displayorder`);

三、代码实施步骤

3.1 文件修改清单

文件 修改类型 优先级
template/xmyc_doc/php/directory_tree.php 核心重写 P0
template/xmyc_touch_doc/touch/php/directory_tree.php 核心重写 P0
template/xmyc_doc/forum/forumdisplay.htm 修改 P1
template/xmyc_touch_doc/touch/forum/forumdisplay.htm 修改 P1

3.2 directory_tree.php 核心修改

3.2.1 新增辅助函数

/**
 * 批量获取帖子的分类信息值
 * @param array $tids 帖子 ID 数组
 * @param int $optionid 选项 ID
 * @return array [tid => value]
 */
function get_typeoption_values($tids, $optionid) {
    $values = array();
    if(empty($tids)) return $values;

    $tids_str = implode(',', $tids);
    $query = DB::query("SELECT tid, value FROM ".DB::table('forum_typeoptionvar')."
                        WHERE tid IN ($tids_str) AND optionid=".intval($optionid));

    while($row = DB::fetch($query)) {
        $values[$row['tid']] = $row['value'];
    }

    return $values;
}

/**
 * 获取版块下所有相关帖子(优化版)
 * @param int $fid 版块 ID
 * @return array ['config'=>[], 'top_sticky'=>[], 'normal'=>[]]
 */
function get_directory_threads_optimized($fid) {
    $result = array(
        'config' => array(),        // 配置帖
        'top_sticky' => array(),    // 置顶说明帖(0 级目录)
        'normal' => array()         // 普通帖子
    );

    $fid = intval($fid);
    if(empty($fid)) {
        global $_G;
        $fid = intval($_G['fid']);
    }

    // 查询所有置顶帖和带目录标签的普通帖
    $query = DB::query("SELECT t.tid, t.subject, t.dateline, t.displayorder
        FROM ".DB::table('forum_thread')." t
        WHERE t.fid=".$fid."
        AND t.subject NOT LIKE '[DIR]%'
        AND t.displayorder>=0
        ORDER BY t.displayorder DESC, t.dateline DESC");

    $threads = array();
    while($row = DB::fetch($query)) {
        $threads[$row['tid']] = $row;
    }

    if(empty($threads)) {
        return $result;
    }

    $tids = array_keys($threads);

    // 批量获取分类信息
    $sort_orders = get_typeoption_values($tids, 21);      // sort_order
    $is_configs = get_typeoption_values($tids, 22);      // is_config
    $show_in_trees = get_typeoption_values($tids, 23);   // show_in_tree

    // 分类帖子
    foreach($threads as $tid => $thread) {
        $is_config = isset($is_configs[$tid]) ? $is_configs[$tid] : '0';
        $show_in_tree = isset($show_in_trees[$tid]) ? $show_in_trees[$tid] : '1';
        $sort_order = isset($sort_orders[$tid]) ? $sort_orders[$tid] : '99';

        $thread['sort_order'] = $sort_order;

        if($thread['displayorder'] > 0 && $is_config == '1') {
            // 配置帖:根据 show_in_tree 决定是否加入 0 级目录
            if($show_in_tree == '1') {
                $result['config'][$tid] = $thread;
            }
        } elseif($thread['displayorder'] > 0 && $is_config == '0') {
            // 置顶说明帖:自动加入 0 级目录
            $result['top_sticky'][$tid] = $thread;
        } else {
            // 普通帖子
            $result['normal'][$tid] = $thread;
        }
    }

    return $result;
}

3.2.2 主逻辑修改

// === 原代码 ===
// $_tagged_threads = get_directory_threads($_G['fid']);

// === 新代码 ===
// 使用优化版函数获取帖子
$all_threads = get_directory_threads_optimized($_G['fid']);

// 初始化目录树
$flquery = array(
    'choices' => array(),
    'curkey' => '',
    'source' => 'tag',
    'sortid' => 0,
    'identifier' => 'dir'
);

// 设置当前选中的目录
$dir_param = isset($_GET['dir']) ? $_GET['dir'] : '';
$flquery['curkey'] = str_replace('.', '-', trim($dir_param));

// 1. 首先添加 0 级目录(置顶帖和配置帖)
$level_0_index = 0;

// 添加置顶说明帖(displayorder > 0 AND is_config = 0)
foreach($all_threads['top_sticky'] as $tid => $thread) {
    $thread_key = 'tid_' . $tid;
    $flquery['choices'][$thread_key] = array(
        'key' => $thread_key,
        'num' => $tid,
        'level' => 0,
        'name' => $thread['subject'],
        'type' => 'thread',
        'href' => generate_thread_link($tid),
        'list' => array(),
        'sort_order' => $level_0_index++
    );
}

// 添加配置帖(displayorder > 0 AND is_config = 1 AND show_in_tree = 1)
foreach($all_threads['config'] as $tid => $thread) {
    $thread_key = 'tid_' . $tid;
    $flquery['choices'][$thread_key] = array(
        'key' => $thread_key,
        'num' => $tid,
        'level' => 0,
        'name' => $thread['subject'],
        'type' => 'thread',
        'href' => generate_thread_link($tid),
        'list' => array(),
        'sort_order' => $level_0_index++
    );
}

// 2. 处理目录配置帖,构建目录树结构
if(!empty($directory_config)) {
    // 检查是否使用新格式
    $is_new_format = false;
    foreach($directory_config['directories'] as $num_path => $config) {
        if(!empty($config['is_new_format'])) {
            $is_new_format = true;
            break;
        }
    }

    if($is_new_format) {
        // 新格式处理:序号 = 标签名 = 目录名
        foreach($directory_config['directories'] as $num_path => $config) {
            create_directory_node_new($flquery['choices'], $num_path, $config['name']);
        }

        // 添加普通帖子到对应目录(通过标签名称匹配)
        foreach($all_threads['normal'] as $tid => $thread) {
            // 获取帖子标签
            $tags_str = get_thread_tags($tid);
            $tag_names = extract_directory_tags($tags_str);

            foreach($tag_names as $tag_name) {
                $num_path = find_num_path_by_tag($directory_config, $tag_name);
                if($num_path) {
                    // 使用分类信息中的 sort_order
                    $sort_order = intval($thread['sort_order']);
                    add_thread_to_directory_new($flquery['choices'], $num_path, $thread, $sort_order);
                }
            }
        }
    } else {
        // 旧格式处理(兼容)
        // ...(保持原有逻辑)
    }
} else {
    // 没有配置帖,按标签自动生成单层目录
    foreach($all_threads['normal'] as $tid => $thread) {
        $tags_str = get_thread_tags($tid);
        $dir_names = extract_directory_tags($tags_str);

        foreach($dir_names as $dir_name) {
            build_directory_tree($flquery['choices'], $dir_name, $thread, intval($thread['sort_order']));
        }
    }
}

// === 新增辅助函数:获取帖子标签 ===
function get_thread_tags($tid) {
    $tags = '';
    $query = DB::query("SELECT tag.tagname FROM ".DB::table('common_tagitem')." ti
                        INNER JOIN ".DB::table('common_tag')." tag ON ti.tagid=tag.tagid
                        WHERE ti.itemid=".intval($tid)." AND ti.idtype='tid'");

    $tag_arr = array();
    while($row = DB::fetch($query)) {
        $tag_arr[] = $row['tagname'];
    }

    if(!empty($tag_arr)) {
        $tags = implode(' ', $tag_arr);
    }

    return $tags;
}

3.3 版块列表页模板修改

3.3.1 forumdisplay.htm 修改要点

在主题列表循环中,添加 sort_order 排序:

// 原代码(按回复时间排序)
// $orderby = 'lastpost';

// 新代码(优先按 sort_order 排序)
// 需要在查询时获取分类信息
$_G['forum']['threads_option_sort'] = 5; // 使用分类信息 sortid=5
$_G['forum']['threads_option_order'] = 21; // 使用 optionid=21 (sort_order)

在模板循环中:

<!-- 在主题列表循环前获取 sort_order -->
<!--{loop $_G['forum_threadlist'] $thread}-->
    <!--{if $thread['sortid'] == 5}-->
        <!--{eval $sort_order = $thread['option']['21'] ? $thread['option']['21'] : 99;}-->
    <!--{/if}-->
<!--{/loop}-->

四、数据迁移计划

4.1 现有帖子数据迁移

4.1.1 迁移脚本(SQL 示例)

-- 1. 为现有配置帖初始化分类信息
-- 查找 [DIR] 开头的置顶帖,设置为配置帖
INSERT INTO `pre_forum_typeoptionvar` (`sortid`, `tid`, `optionid`, `value`)
SELECT 5, tid, 22, '1'
FROM `pre_forum_thread`
WHERE subject LIKE '[DIR]%' AND displayorder > 0
ON DUPLICATE KEY UPDATE value = '1';

-- 2. 为其他置顶帖设置 is_config = 0
INSERT INTO `pre_forum_typeoptionvar` (`sortid`, `tid`, `optionid`, `value`)
SELECT 5, tid, 22, '0'
FROM `pre_forum_thread`
WHERE displayorder > 0 AND subject NOT LIKE '[DIR]%'
ON DUPLICATE KEY UPDATE value = '0';

-- 3. 为带目录标签的普通帖子设置 sort_order = 99(默认)
-- 需要先获取这些帖子的 tid(通过标签关联)
-- 这个步骤建议在 PHP 中完成,因为需要查询标签

-- 4. 为所有普通帖子设置默认值
INSERT INTO `pre_forum_typeoptionvar` (`sortid`, `tid`, `optionid`, `value`)
SELECT 5, tid, 21, '99'
FROM `pre_forum_thread`
WHERE displayorder = 0
ON DUPLICATE KEY UPDATE value = '99';

4.1.2 PHP 迁移脚本

<?php
/**
 * 数据迁移脚本:为现有帖子初始化分类信息
 * 使用方法:在 Discuz 根目录执行
 */

define('IN_DISCUZ', true);
require './source/class/class_core.php';

$discuz = C::app();
$discuz->init();

// 获取所有帖子
$query = DB::query("SELECT tid, displayorder FROM ".DB::table('forum_thread')." WHERE displayorder>=0");

$migrated_count = 0;
while($thread = DB::fetch($query)) {
    $tid = $thread['tid'];
    $displayorder = $thread['displayorder'];

    // 判断是否为配置帖
    $is_config = (strpos($thread['subject'], '[DIR]') === 0 && $displayorder > 0) ? '1' : '0';

    // 设置 is_config
    DB::insert('forum_typeoptionvar', array(
        'sortid' => 5,
        'tid' => $tid,
        'optionid' => 22,
        'value' => $is_config
    ), false, true);

    // 设置 sort_order(普通帖子默认 99)
    if($displayorder == 0) {
        DB::insert('forum_typeoptionvar', array(
            'sortid' => 5,
            'tid' => $tid,
            'optionid' => 21,
            'value' => '99'
        ), false, true);
    }

    // 设置 show_in_tree(默认展示)
    DB::insert('forum_typeoptionvar', array(
        'sortid' => 5,
        'tid' => $tid,
        'optionid' => 23,
        'value' => '1'
    ), false, true);

    $migrated_count++;
}

echo "迁移完成!共迁移 {$migrated_count} 个帖子\n";
?>

4.2 版主操作指引

发帖/编辑帖子时的操作流程:

4.2.1 发布置顶说明帖(0 级目录)

  1. 发帖时选择分类信息:文档管理
  2. 设置 是否为配置帖 = 否
  3. 设置 置顶 = 置顶
  4. 发布后自动展示在 0 级目录

4.2.2 发布配置帖

  1. 发帖时选择分类信息:文档管理
  2. 设置 是否为配置帖 = 是
  3. 设置 是否展示在目录树 = 是/否(根据需要)
  4. 设置 置顶 = 置顶
  5. 发布后可展示在 0 级目录(如果 show_in_tree=1)

4.2.3 发布普通文档帖

  1. 发帖时选择分类信息:文档管理
  2. 设置 排序权重 = 数字(如 1、2、3...)
  3. 设置 是否为配置帖 = 否
  4. 添加标签:#目录_xxx
  5. 发布后按 sort_order 归入对应目录

五、测试验证清单

5.1 单元测试

测试项 操作步骤 预期结果 状态
0 级目录 - 置顶说明帖 发布 is_config=0 的置顶帖 自动展示在 0 级目录 ☐
0 级目录 - 配置帖展示 发布 is_config=1, show_in_tree=1 的置顶帖 展示在 0 级目录 ☐
0 级目录 - 配置帖隐藏 发布 is_config=1, show_in_tree=0 的置顶帖 不展示在 0 级目录 ☐
目录树 - 新格式 配置新格式,帖子打标签 帖子正确归入目录 ☐
目录树 - 旧格式 配置旧格式,帖子打标签 帖子正确归入目录(兼容) ☐
排序 - sort_order 设置不同 sort_order 值 按数字从小到大排序 ☐
排序 - 默认值 不设置 sort_order 默认 99,排在最后 ☐
Ajax 请求 getdirectory=true 返回正确 JSON 数据 ☐

5.2 集成测试

测试项 操作步骤 预期结果 状态
目录树与列表页排序一致 设置多个帖子 sort_order 两处排序顺序相同 ☐
配置帖编辑 修改配置帖的 show_in_tree 目录树即时更新 ☐
帖子移动 移动帖子到其他版块 分类信息保持 ☐
帖子删除 删除配置帖 目录树自动移除 ☐
权限控制 普通用户编辑帖子 无法修改 show_in_tree ☐

5.3 性能测试

测试项 指标 目标值 状态
目录树生成时间 100 个帖子 < 100ms ☐
分类信息查询 批量查询 < 50ms ☐
Ajax 响应时间 目录数据请求 < 200ms ☐

六、上线部署计划

6.1 部署阶段

阶段一:数据库准备(预计 30 分钟)

  1. 在 Discuz 后台创建分类信息
  2. 创建三个选项项目
  3. 执行索引优化 SQL
  4. 负责人:数据库管理员
  5. 验收标准:后台可看到新分类信息

阶段二:代码部署(预计 1 小时)

  1. 备份原文件
  2. 部署新版 directory_tree.php
  3. 部署新版 forumdisplay.htm
  4. 负责人:开发人员
  5. 验收标准:语法检查通过

阶段三:数据迁移(预计 2 小时)

  1. 执行数据迁移脚本
  2. 验证迁移结果
  3. 抽查帖子分类信息
  4. 负责人:开发人员
  5. 验收标准:所有帖子有默认值

阶段四:测试验证(预计 4 小时)

  1. 执行单元测试
  2. 执行集成测试
  3. 执行性能测试
  4. 负责人:测试人员
  5. 验收标准:所有测试项通过

阶段五:上线切换(预计 30 分钟)

  1. 选择低峰期(如凌晨 2-4 点)
  2. 切换代码到生产环境
  3. 验证生产环境功能
  4. 负责人:运维人员
  5. 验收标准:生产环境功能正常

6.2 回滚计划

如上线后发现问题,按以下步骤回滚:

  1. 立即回滚代码:还原 directory_tree.php 到旧版本
  2. 数据保留:分类信息数据保留,不影响现有功能
  3. 问题排查:在测试环境复现并修复问题
  4. 重新上线:问题修复后重新执行上线流程

七、时间估算和里程碑

7.1 时间估算

阶段 工时 备注
数据库准备 0.5 小时 创建分类和选项
代码开发 4 小时 修改 4 个文件
数据迁移 2 小时 脚本编写 + 执行
测试验证 4 小时 完整测试用例
上线部署 1 小时 含回滚准备
总计 11.5 小时 约 1.5 个工作日

7.2 里程碑

里程碑 交付物 验收标准
M1:数据库就绪 分类信息创建完成 后台可见,选项可编辑
M2:代码完成 directory_tree.php 修改完成 单元测试通过
M3:数据迁移完成 帖子分类信息初始化 抽查验证通过
M4:测试通过 测试报告 所有测试项通过
M5:上线成功 生产环境验证 功能正常,性能达标

八、风险与应对

8.1 技术风险

风险 影响 概率 应对措施
分类信息表数据量大 查询性能下降 中 添加索引,分页查询
迁移脚本执行失败 数据不一致 低 事务处理,回滚机制
旧格式兼容问题 部分目录失效 中 保留旧代码,单独测试

8.2 业务风险

风险 影响 概率 应对措施
用户不会设置分类信息 排序混乱 高 发布操作指引,培训版主
版主权限设置错误 普通用户修改排序 中 严格权限控制,审核机制
上线后出现 bug 用户体验受损 中 快速回滚,及时修复

九、附录

9.1 相关文件路径

template/xmyc_doc/php/directory_tree.php           # PC 版核心
template/xmyc_touch_doc/touch/php/directory_tree.php # 移动版核心
template/xmyc_doc/forum/forumdisplay.htm           # PC 版列表页
template/xmyc_touch_doc/touch/forum/forumdisplay.htm # 移动版列表页

9.2 数据库表结构

pre_forum_typeoption        # 分类信息选项定义
pre_forum_typeoptionvar     # 分类信息选项数据
pre_forum_typeoptionvalue   # 分类信息单选值
pre_forum_thread            # 帖子表
pre_common_tag              # 标签表
pre_common_tagitem          # 标签项目关联表

9.3 参考资料


文档版本:1.0
创建日期:2026-02-16
创建人:蜗牛

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

站长推荐上一条 /1 下一条