蜗牛 发表于 2026-2-28 06:41:08

文档模式前端:目录树展示方案演进说明

<h2>文档概述</h2>
<p>本文档说明企业文档管理系统中目录树展示功能从依赖分类信息到基于标签系统 + 置顶帖配置的完整演进过程。</p>
<hr />
<h2>一、原始方案:依赖分类信息</h2>
<h3>1.1 方案描述</h3>
<p>最初的目录树展示依赖于 Discuz 论坛的分类信息体系,通过版块的分类结构来组织文档目录。</p>
<h3>1.2 存在的问题</h3>
<ol>
<li><strong>灵活性差</strong>:目录结构受限于版块分类,无法跨版块组织文档</li>
<li><strong>维护成本高</strong>:每次调整目录结构需要修改版块分类设置</li>
<li><strong>粒度粗糙</strong>:分类层级有限,难以满足复杂文档体系需求</li>
<li><strong>帖子归属单一</strong>:一个帖子只能属于一个分类,无法多维度归类</li>
</ol>
<hr />
<h2>二、过渡方案:标签系统 + 文字路径配置</h2>
<h3>2.1 方案核心</h3>
<p>引入标签系统,通过帖子标签与置顶配置帖配合,实现目录树的灵活配置。</p>
<h3>2.2 配置格式</h3>
<pre><code>
开发维护 = 网站开发维护.98
开发维护/社创开发 = 社创官网和社区开发.1
开发维护/利智官网 = 北京利智官网.2


社创开发 = tid:118,tid:140,tid:137


</code></pre>
<h3>2.3 帖子标签</h3>
<pre><code>#目录_社创开发
#目录_开发维护
</code></pre>
<h3>2.4 技术实现</h3>
<h4>2.4.1 标签解析函数</h4>
<pre><code class="language-php">function extract_directory_tags($tags_str) {
    $dir_names = array();
    preg_match_all('/#目录_([^#,\s]+)/', $tags_str, $matches);
    if($matches) {
      foreach($matches as $name) {
            // 将路径分隔符统一转换为点号
            $name = preg_replace('/[\/\-、]/', '.', $name);
            $dir_names[] = $name;
      }
    }
    return $dir_names;
}
</code></pre>
<h4>2.4.2 配置帖解析</h4>
<pre><code class="language-php">function parse_config_message($message) {
    $config = array(
      'directories' =&gt; array(),
      'posts' =&gt; array()
    );

    // 解析 标签
    if(preg_match('/\(.*?)\[\/doc_directory\]/s', $message, $matches)) {
      $content = $matches;
      // 解析目录定义
      preg_match_all('/^([^=\n]+)\s*=\s*([^.\n]+)\.(\d+)/m', $content, $dir_matches);
      // ...
    }

    // 解析 标签
    if(preg_match('/\(.*?)\[\/posts\]/s', $content, $posts_matches)) {
      // ...
    }

    return $config;
}
</code></pre>
<h4>2.4.3 目录树构建</h4>
<pre><code class="language-php">function build_directory_tree(&amp;$choices, $dir_path, $thread, $sort_order = 0) {
    $parts = explode('/', $dir_path);
    $current = &amp;$choices;
    $num_path = '';

    foreach($parts as $index =&gt; $part) {
      $num = $index + 1;
      $num_path .= ($num_path ? '.' : '') . $num;
      // 创建目录节点
      // ...
      $current = &amp;$current[$num_path]['list'];
    }

    // 添加帖子
    $current[$thread_key] = array(...);
}
</code></pre>
<h3>2.5 方案局限性</h3>
<ol>
<li><strong>配置复杂</strong>:目录路径使用文字路径(如 <code>开发维护/社创开发</code>),层级关系不够直观</li>
<li><strong>匹配逻辑复杂</strong>:需要通过 <code>find_dir_path_by_name</code> 函数根据标签名反查完整路径</li>
<li><strong>排序依赖 </strong>:帖子排序完全依赖 <code></code> 段落配置,不够灵活</li>
<li><strong>标签路径限制</strong>:标签名长度有限制,不适合配置过长的路径</li>
</ol>
<hr />
<h2>三、优化方案:标签系统 + 序号配置</h2>
<h3>3.1 方案核心</h3>
<p>采用<strong>序号路径</strong>代替文字路径,配置格式更加简洁清晰,目录层级由序号直接决定。</p>
<h3>3.2 配置格式(新)</h3>
<pre><code>
1 = 开发维护 = 网站开发维护
1-1 = 社创开发 = 社创官网和社区开发
1-2 = 利智官网 = 北京利智官网
1-3 = 社通活动宝 = 活动工具社通活动宝
2 = 产品文档 = 产品相关文档
2-1 = 用户手册 = 用户使用手册


社创开发 = tid:118,tid:140,tid:137


</code></pre>
<h3>3.3 配置格式说明</h3>
<table>
<thead>
<tr>
<th>部分</th>
<th>格式</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>目录定义</td>
<td><code>序号 = 标签名 = 目录显示名</code></td>
<td>序号决定层级和排序</td>
</tr>
<tr>
<td>帖子排序</td>
<td><code>标签名 = tid:xxx,tid:yyy</code></td>
<td>可选,用于同标签下帖子排序</td>
</tr>
</tbody>
</table>
<h3>3.4 帖子标签(简化)</h3>
<p>帖子只需要添加<strong>单层标签</strong>即可:</p>
<pre><code>#目录_社创开发
#目录_开发维护
#目录_利智官网
</code></pre>
<h3>3.5 技术实现</h3>
<h4>3.5.1 新格式解析</h4>
<pre><code class="language-php">function parse_config_message($message) {
    $config = array(
      'directories' =&gt; array(),
      'posts' =&gt; array()
    );

    if(preg_match('/\(.*?)\[\/doc_directory\]/s', $message, $matches)) {
      $content = $matches;

      // 新格式:序号 = 标签名 = 目录名
      preg_match_all('/^([\d\-]+)\s*=\s*([^=]+)\s*=\s*(.+)$/m', $content, $new_matches);
      if($new_matches) {
            foreach($new_matches as $index =&gt; $num_path) {
                $num_path = trim($new_matches[$index]);
                $tag_name = trim($new_matches[$index]);
                $dir_name = trim($new_matches[$index]);

                $config['directories'][$num_path] = array(
                  'tag_name' =&gt; $tag_name,      // 标签名称(用于匹配帖子)
                  'name' =&gt; $dir_name,          // 目录显示名称
                  'sort_order' =&gt; $index,       // 排序
                  'is_new_format' =&gt; true
                );
            }
      }
    }

    return $config;
}
</code></pre>
<h4>3.5.2 标签匹配序号路径</h4>
<pre><code class="language-php">function find_num_path_by_tag($directory_config, $tag_name) {
    foreach($directory_config['directories'] as $num_path =&gt; $config) {
      if($config['tag_name'] == $tag_name) {
            return $num_path;
      }
    }
    return '';
}
</code></pre>
<h4>3.5.3 序号目录树构建</h4>
<pre><code class="language-php">function create_directory_node_new(&amp;$choices, $num_path, $name) {
    // 将 1-1-1 转换为数组
    $parts = explode('-', $num_path);
    $current = &amp;$choices;
    $key_path = '';
    $num_path_dot = '';

    foreach($parts as $index =&gt; $part) {
      $key_path .= ($key_path ? '-' : '') . $part;
      $num_path_dot .= ($num_path_dot ? '.' : '') . $part;

      if(!isset($current[$num_path_dot])) {
            $current[$num_path_dot] = array(
                'key' =&gt; $key_path,
                'num' =&gt; $num_path_dot,
                'level' =&gt; $index + 1,
                'name' =&gt; $name,
                'type' =&gt; 'directory',
                'href' =&gt; generate_dir_link($num_path_dot),
                'list' =&gt; array(),
                'sort_order' =&gt; $index
            );
      }
      $current = &amp;$current[$num_path_dot]['list'];
    }
}
</code></pre>
<h4>3.5.4 帖子添加到目录</h4>
<pre><code class="language-php">function add_thread_to_directory_new(&amp;$choices, $num_path, $thread, $sort_order = 0) {
    $parts = explode('-', $num_path);
    $current = &amp;$choices;
    $num_path_dot = implode('.', $parts);

    // 导航到最后的目录
    foreach($parts as $index =&gt; $part) {
      $path = implode('.', array_slice($parts, 0, $index + 1));
      if(isset($current[$path])) {
            $current = &amp;$current[$path]['list'];
      } else {
            return; // 目录不存在,跳过
      }
    }

    // 添加帖子
    $thread_key = 'tid_' . $thread['tid'];
    if(!isset($current[$thread_key])) {
      $current[$thread_key] = array(
            'key' =&gt; $thread_key,
            'num' =&gt; $thread['tid'],
            'name' =&gt; $thread['subject'],
            'type' =&gt; 'thread',
            'href' =&gt; generate_thread_link($thread['tid']),
            'list' =&gt; array(),
            'sort_order' =&gt; $sort_order
      );
    }
}
</code></pre>
<h3>3.6 方案优势</h3>
<table>
<thead>
<tr>
<th>对比项</th>
<th>过渡方案</th>
<th>优化方案</th>
</tr>
</thead>
<tbody>
<tr>
<td>配置格式</td>
<td>文字路径(开发维护/社创开发)</td>
<td>序号路径(1-1)</td>
</tr>
<tr>
<td>层级关系</td>
<td>需要通过 <code>/</code> 解析</td>
<td>直接通过 <code>-</code> 体现</td>
</tr>
<tr>
<td>标签要求</td>
<td>可使用单层或完整路径</td>
<td>仅需单层标签</td>
</tr>
<tr>
<td>匹配逻辑</td>
<td>需要反查路径</td>
<td>直接通过标签名匹配</td>
</tr>
<tr>
<td>目录排序</td>
<td>依赖配置顺序</td>
<td>序号自动决定</td>
</tr>
<tr>
<td>可维护性</td>
<td>较复杂</td>
<td>简洁清晰</td>
</tr>
<tr>
<td>扩展性</td>
<td>调整结构需修改多处</td>
<td>调整序号即可</td>
</tr>
</tbody>
</table>
<h3>3.7 目录层级示例</h3>
<pre><code>配置:
1 = 开发维护 = 网站开发维护
1-1 = 社创开发 = 社创官网和社区开发
1-1-1 = 前端开发 = 前端相关开发文档
1-2 = 利智官网 = 北京利智官网
2 = 产品文档 = 产品相关文档

生成的目录树:
├── 1. 网站开发维护
│   ├── 1.1 社创官网和社区开发
│   │   └── 1.1.1 前端开发
│   └── 1.2 北京利智官网
└── 2. 产品相关文档
</code></pre>
<hr />
<h2>四、两种格式兼容</h2>
<h3>4.1 自动识别机制</h3>
<p>系统会自动识别配置格式,新格式优先:</p>
<pre><code class="language-php">// 检查是否使用新格式
$is_new_format = false;
foreach($directory_config['directories'] as $num_path =&gt; $config) {
    if(!empty($config['is_new_format'])) {
      $is_new_format = true;
      break;
    }
}

if($is_new_format) {
    // 新格式处理
} else {
    // 旧格式处理(兼容)
}
</code></pre>
<h3>4.2 迁移建议</h3>
<ol>
<li><strong>新配置推荐使用新格式</strong>:序号配置更清晰易维护</li>
<li><strong>旧配置可逐步迁移</strong>:两种格式兼容,不影响现有功能</li>
<li><strong>混合使用不建议</strong>:同一配置帖中建议只使用一种格式</li>
</ol>
<hr />
<h2>五、核心数据流</h2>
<pre><code>┌─────────────────────────────────────────────────────────────┐
│                     用户发帖/编辑                           │
│            添加标签:#目录_社创开发                           │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                  Discuz 标签系统                            │
│         pre_common_tag + pre_common_tagitem               │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                   置顶配置帖                             │
│ 定义目录结构和序号                            │
│ 定义帖子排序(可选)                                  │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                  directory_tree.php                         │
│1. parse_directory_config() - 解析配置帖                     │
│2. get_directory_threads() - 获取带标签帖子                  │
│3. find_num_path_by_tag() - 标签匹配序号                      │
│4. create_directory_node_new() - 构建目录树                  │
│5. add_thread_to_directory_new() - 添加帖子                  │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                  $flquery 全局变量                        │
│         包含完整的目录树结构(choices 数组)                  │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                      模板文件渲染                           │
│            forumdisplay.htm / viewthread.htm               │
│                   循环输出目录树                              │
└─────────────────────────────────────────────────────────────┘
</code></pre>
<hr />
<h2>六、文件清单</h2>
<table>
<thead>
<tr>
<th>文件路径</th>
<th>说明</th>
<th>备注</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>template/xmyc_doc/php/directory_tree.php</code></td>
<td>PC 版目录树生成</td>
<td>核心逻辑</td>
</tr>
<tr>
<td><code>template/xmyc_touch_doc/touch/php/directory_tree.php</code></td>
<td>移动版目录树生成</td>
<td>核心逻辑</td>
</tr>
<tr>
<td><code>template/xmyc_doc/forum/forumdisplay.htm</code></td>
<td>PC 版版块列表页</td>
<td>目录树展示</td>
</tr>
<tr>
<td><code>template/xmyc_touch_doc/touch/forum/forumdisplay.htm</code></td>
<td>移动版版块列表页</td>
<td>目录树展示</td>
</tr>
<tr>
<td><code>template/xmyc_doc/static/js/tree.js</code></td>
<td>PC 版树形菜单 JS</td>
<td>折叠展开</td>
</tr>
<tr>
<td><code>template/xmyc_touch_doc/static/js/tree.js</code></td>
<td>移动版树形菜单 JS</td>
<td>折叠展开</td>
</tr>
</tbody>
</table>
<hr />
<h2>七、总结</h2>
<p>从依赖分类信息到标签系统 + 置顶帖配置,目录树展示方案经历了以下演进:</p>
<ol>
<li><strong>解耦合</strong>:不再依赖 Discuz 版块分类,实现跨版块文档组织</li>
<li><strong>灵活性</strong>:通过标签和配置实现多维度文档归类</li>
<li><strong>可维护性</strong>:序号配置格式简洁直观,易于维护</li>
<li><strong>兼容性</strong>:新旧格式兼容,平滑迁移</li>
</ol>
<p>优化后的方案核心特点:</p>
<ul>
<li><strong>配置简单</strong>:<code>序号 = 标签名 = 目录名</code> 三要素清晰明了</li>
<li><strong>标签简洁</strong>:帖子只需单层标签,降低维护成本</li>
<li><strong>层级清晰</strong>:序号直接体现目录层级关系</li>
<li><strong>扩展容易</strong>:调整序号即可改变目录结构</li>
</ul>
<hr />
<p><em>文档版本:1.0</em><br />
<em>更新日期:2026-02-28</em></p>
页: [1]
查看完整版本: 文档模式前端:目录树展示方案演进说明