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

如何遍历嵌套Folder结构并实现Outlook风格邮件搜索过滤

复刻Outlook嵌套文件夹邮件搜索功能

需求说明

基于给定的多层嵌套Folder/Email TypeScript接口结构(层级深度未知),结合Vuetify的v-text-field搜索输入框,实现以下功能:

  • 实时根据搜索词筛选邮件,严格维持原有文件夹层级结构
  • 仅保留包含至少一封匹配邮件的文件夹(包括父文件夹,即使父文件夹自身无匹配邮件,但子层级有)
  • 每个保留的文件夹中仅保留匹配搜索词的邮件

核心实现逻辑

  1. 邮件匹配规则:遍历邮件的所有可搜索属性,进行不区分大小写的模糊匹配,包括:
    • 发件人/收件人/抄送人/密送人的姓名、邮箱地址
    • 邮件主题、正文、正文预览
    • 附件的文件名
  2. 递归文件夹处理:因为文件夹层级未知,必须用递归遍历所有层级:
    • 先筛选当前文件夹下的匹配邮件
    • 再递归处理子文件夹,得到筛选后的子文件夹列表
    • 若当前文件夹存在匹配邮件,或存在筛选后的子文件夹,则保留该文件夹,并替换其邮件列表和子文件夹列表为筛选结果

具体代码实现

1. TypeScript工具函数

// 检查单封邮件是否匹配搜索词
const isEmailMatch = (email: Email, searchTerm: string): boolean => {
  if (!searchTerm.trim()) return true; // 空搜索词返回全部
  const lowerSearch = searchTerm.toLowerCase();

  // 检查联系人列表(to/cc/bcc)
  const checkContacts = (contacts: Contact[]): boolean => {
    return contacts.some(contact => 
      (contact.name?.toLowerCase().includes(lowerSearch)) || 
      (contact.email_address.toString().includes(lowerSearch))
    );
  };

  // 检查附件文件名
  const checkAttachments = (attachments: FileAttachment[]): boolean => {
    return attachments.some(att => att.file_name.toLowerCase().includes(lowerSearch));
  };

  // 综合所有可搜索属性
  return (
    email.from.name?.toLowerCase().includes(lowerSearch) ||
    email.from.email_address.toString().includes(lowerSearch) ||
    checkContacts(email.to) ||
    checkContacts(email.cc) ||
    checkContacts(email.bcc) ||
    email.subject.toLowerCase().includes(lowerSearch) ||
    email.body.toLowerCase().includes(lowerSearch) ||
    email.body_preview.toLowerCase().includes(lowerSearch) ||
    checkAttachments(email.file_attachments)
  );
};

// 递归筛选文件夹结构
const filterFolders = (folders: Folder[], searchTerm: string): Folder[] => {
  return folders.reduce((acc, folder) => {
    // 筛选当前文件夹下的匹配邮件
    const filteredEmails = folder.emails.filter(email => isEmailMatch(email, searchTerm));
    // 递归处理子文件夹
    const filteredSubFolders = folder.folders ? filterFolders(folder.folders, searchTerm) : [];

    // 只有当存在匹配邮件或非空的子文件夹时,才保留当前文件夹
    if (filteredEmails.length > 0 || filteredSubFolders.length > 0) {
      acc.push({
        ...folder,
        emails: filteredEmails,
        folders: filteredSubFolders.length > 0 ? filteredSubFolders : null
      });
    }
    return acc;
  }, [] as Folder[]);
};

2. Vue组件中集成

假设你的组件中有原始文件夹数据originalFolders,结合Vuetify的搜索框,使用计算属性实时返回筛选后的结果:

<template>
  <v-text-field
    v-model="search"
    append-inner-icon="mdi-magnify"
    label="动态搜索"
    density="compact"
    variant="outlined"
    clearable
    rounded
    hide-details
    single-line
    flat
    color="primaryDarken4"
  />

  <!-- 这里是你的文件夹/邮件展示组件,绑定filteredFolders -->
  <mail-folder-tree :folders="filteredFolders" />
</template>

<script setup lang="ts">
import { ref, computed } from 'vue';
import type { Folder } from '@/types';

const search = ref('');
const originalFolders = ref<Folder[]>([]); // 假设这里是从后端获取的原始文件夹数据

const filteredFolders = computed(() => {
  if (!search.value.trim()) return originalFolders.value;
  return filterFolders(originalFolders.value, search.value);
});

// 引入上面定义的isEmailMatch和filterFolders函数
</script>

注意事项

  • 若邮件数量极大,建议在后端做搜索优化(比如全文索引),前端仅做轻量筛选
  • 可以根据需求调整匹配规则,比如添加日期范围筛选、附件类型筛选等
  • 递归处理时注意性能,若层级极深可考虑尾递归优化

内容的提问来源于stack exchange,提问作者Qiuzman

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 16:44:54