用的是templater插件的模版
代码如下
<%*
// === 配置部分 ===
const 配置 = {
模拟模式: true, // true=仅预览,false=实际移动
源目录: "", // 如果留空,则扫描整个Vault;否则仅扫描该目录
目标根目录: "Pages/【环境数据】(天气)", // 移动到的目录
排除目录: ["Template", "Assets"], // 排除的目录(无论全局/局部模式均生效)
搜索关键词: "环境数据", // 可改为其他关键词(如"临时"、"草稿")
包含子目录文件: true, // 是否包含子目录中的文件
搜索范围: {
文件名: true, // 搜索文件名中的关键词
正文内容: false, // 搜索正文中的关键词
元数据: false // frontmatter,搜索YAML中的关键词
}
};
// === 增强版文件检查函数 ===
async function 检查文件匹配(文件) {
const 文件名 = 文件.name;
const 文件路径 = 文件.path;
// 基础检查
if (!文件名.endsWith('.md')) return false;
if (配置.排除目录.some(目录 => 文件路径.includes(`${目录}/`))) return false;
if (文件路径.startsWith(配置.目标根目录)) return false;
// 目录位置检查
if (!配置.包含子目录文件) {
if (配置.源目录) {
if (文件.parent.path !== 配置.源目录) return false;
} else {
if (文件路径.includes('/')) return false;
}
} else if (配置.源目录 && !文件Path.startsWith(配置.源目录)) {
return false;
}
// ★★★ 增强的搜索逻辑 ★★★
const 搜索词 = 配置.搜索关键词;
let 已匹配 = false;
// 1. 先检查文件名(最快)
if (配置.搜索范围.文件名 && 文件名.includes(搜索词)) {
console.log(`[文件名匹配] ${文件路径}`);
return true;
}
// 2. 如果需要检查内容,读取文件
if (配置.搜索范围.正文内容 || 配置.搜索范围.元数据) {
let 文件内容 = "";
try {
文件内容 = await app.vault.read(文件);
} catch (e) {
console.error(`读取文件失败: ${文件路径}`, e);
return false;
}
// 检查元数据
if (配置.搜索范围.元数据 && !已匹配) {
const 元数据块 = 文件内容.match(/^---\s*[\s\S]*?---/);
if (元数据块 && 元数据块[0].includes(搜索词)) {
console.log(`[元数据匹配] ${文件路径}`);
已匹配 = true;
}
}
// 检查正文内容
if (配置.搜索范围.正文内容 && !已匹配) {
// 移除元数据块后检查
const 纯正文 = 文件内容.replace(/^---\s*[\s\S]*?---/, '');
if (纯正文.includes(搜索词)) {
console.log(`[正文匹配] ${文件路径}`);
已匹配 = true;
}
}
}
return 已匹配;
}
// === 主流程 ===
try {
let 成功计数 = 0;
let 失败计数 = 0;
const 匹配文件列表 = [];
const 所有Markdown文件 = app.vault.getMarkdownFiles();
console.log("开始搜索文件...");
for (const 文件 of 所有Markdown文件) {
if (await 检查文件匹配(文件)) {
匹配文件列表.push(文件);
}
}
// 日志输出
console.groupCollapsed(`▼ 匹配结果 ${匹配文件列表.length}个`);
匹配文件列表.forEach(f => console.log(f.path));
console.groupEnd();
if (匹配文件列表.length === 0) {
const 范围描述 = 配置.源目录
? `目录 ${配置.源目录}${配置.包含子目录文件 ? '及其子目录' : ''}`
: `${配置.包含子目录文件 ? '整个Vault' : 'Vault根目录'}`;
return new Notice(`🔍 在${范围描述}中未找到匹配 "${配置.搜索关键词}" 的文件`);
}
// 处理文件移动
for (const 文件 of 匹配文件列表) {
const 新路径 = `${配置.目标根目录}/${文件.name}`;
try {
if (配置.模拟模式) {
console.log(`[模拟] ${文件.path} → ${新路径}`);
成功计数++;
} else {
let 实际路径 = 新路径;
for (let i = 1; app.vault.getAbstractFileByPath(实际路径); i++) {
实际路径 = 新路径.replace(/\.md$/, `_${i}.md`);
}
await app.fileManager.renameFile(文件, 实际路径);
成功计数++;
}
} catch (e) {
console.error(`移动失败: ${文件.path}`, e);
失败计数++;
}
}
// ★★★ 优化弹窗 ★★★
new Notice([
`📂 ${配置.模拟模式 ? '预览移动' : '移动完成'}`,
`🔍 匹配到: ${匹配文件列表.length}个文件`,
`✅ 成功: ${成功计数}`,
...(失败计数 > 0 ? [`❌ 失败: ${失败计数}`] : []),
`目标位置: ${配置.目标根目录}`
].join('\n'), 8000);
} catch (e) {
console.error('脚本执行错误:', e);
new Notice([
'💥 脚本错误',
e.message.length > 30 ? e.message.slice(0, 30) + '...' : e.message
].join('\n'));
}
%>
我目前用的暂时还没bug,你们可以试试看