You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React与Prisma ORM实现嵌套列表:子索引创建及文件上传需求

实现层级索引与文件上传的方案

核心思路

先定义清晰的索引节点数据结构,通过迭代法构建层级关系(替代递归),再为每个节点绑定文件上传逻辑,最终映射到实际的文件夹层级。

1. 定义索引节点结构

不管用什么语言,每个索引节点需要包含这些核心字段:

// JavaScript示例,其他语言可类比
const indexNode = {
  id: '1.1',          // 索引编号,如1.1、1.2.1
  title: 'subtitle01',// 索引标题
  parentId: '1',      // 父节点ID,根节点为空
  files: [],          // 存储该节点下的文件信息
  children: []        // 子节点列表
};

2. 迭代法构建层级索引树

递归在层级过深时容易触发栈溢出,迭代法更稳定可控:

function buildIndexTree(nodes) {
  const nodeMap = new Map();
  const rootNodes = [];

  // 第一步:将所有节点存入Map,快速查找
  nodes.forEach(node => {
    nodeMap.set(node.id, { ...node, children: [], files: [] });
  });

  // 第二步:迭代关联父子节点
  nodes.forEach(node => {
    if (node.parentId) {
      const parentNode = nodeMap.get(node.parentId);
      parentNode?.children.push(nodeMap.get(node.id));
    } else {
      rootNodes.push(nodeMap.get(node.id));
    }
  });

  return rootNodes;
}

3. 给指定索引节点上传文件

根据节点ID找到目标节点,添加文件信息并生成对应路径:

function uploadFileToIndex(nodeId, file, nodeMap) {
  const targetNode = nodeMap.get(nodeId);
  if (!targetNode) return;

  // 生成文件对应的文件夹路径(把索引的.替换成/)
  const filePath = `${targetNode.id.replace(/\./g, '/')}/${file.name}`;
  targetNode.files.push({
    name: file.name,
    tempPath: file.tempFilePath, // 上传文件的临时存储路径
    finalPath: filePath
  });

  // 这里可添加实际文件存储逻辑:比如从tempPath复制到finalPath对应的磁盘位置
}

4. 生成实际的文件夹层级

用迭代栈处理所有节点,创建对应文件夹并存储文件(Node.js示例):

const fs = require('fs').promises;
const path = require('path');

async function createFolderStructure(rootNodes, rootDir) {
  for (const root of rootNodes) {
    // 创建根节点文件夹
    const rootFolder = path.join(rootDir, root.id.replace(/\./g, '/'));
    await fs.mkdir(rootFolder, { recursive: true });

    // 存储根节点下的文件
    for (const file of root.files) {
      await fs.copyFile(file.tempPath, path.join(rootFolder, file.name));
    }

    // 用栈迭代处理所有子节点
    const stack = [...root.children];
    while (stack.length > 0) {
      const child = stack.pop();
      const childFolder = path.join(rootDir, child.id.replace(/\./g, '/'));
      await fs.mkdir(childFolder, { recursive: true });

      // 存储子节点下的文件
      for (const file of child.files) {
        await fs.copyFile(file.tempPath, path.join(childFolder, file.name));
      }

      // 将子节点的子节点推入栈,继续处理
      stack.push(...child.children);
    }
  }
}

递归方案的优化(如果坚持用递归)

如果一定要用递归,可通过尾递归优化(部分语言如JavaScript、Python支持)或限制递归深度避免栈溢出:

// 尾递归版本的层级构建
function buildTreeTailRecursive(nodes, nodeMap = new Map(), rootNodes = [], index = 0) {
  if (index >= nodes.length) return rootNodes;

  const node = nodes[index];
  const currentNode = { ...node, children: [], files: [] };
  nodeMap.set(node.id, currentNode);

  if (node.parentId) {
    nodeMap.get(node.parentId)?.children.push(currentNode);
  } else {
    rootNodes.push(currentNode);
  }

  return buildTreeTailRecursive(nodes, nodeMap, rootNodes, index + 1);
}

内容的提问来源于stack exchange,提问作者Jim Ft Dev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 16:45:05