---
目标完成度:
锻炼:
阅读:
语言:
睡觉习惯:
date: <% tp.file.title %>
---
<%*
const MAX_DAYS = 30;
const baseDate = moment(tp.file.title, "YYYY-MM-DD", true).isValid()
    ? moment(tp.file.title, "YYYY-MM-DD")
    : moment();
let tomorrowGoals = "";
let pastGoalsBlock = "";
let carriedForwardBlock = "";
let foundDate = null;
let daysAgo = 0;

function getSection(content, heading) {
    const match = content.match(new RegExp(`## ${heading}\\n([\\s\\S]*?)(?=\\n## |\\n---|\\n#[^#]|$)`));
    return match ? match[1].trim() : "";
}

function getUncheckedTasks(block) {
    return block
        .split('\n')
        .map(line => line.trimEnd())
        .filter(line => /^- \[ \] .+/.test(line))
        .join('\n');
}

function getTomorrowGoals(block) {
    return block
        .split('\n')
        .filter(line => !/^-\s*\[\s*\]\s*$/.test(line.trim()) && line.trim() !== '-' && line.trim() !== '- ')
        .filter(line => !/^-\s*\[[xX]\]/.test(line.trim()))
        .join('\n')
        .trim();
}

function dedupeLines(lines) {
    return lines
        .filter(line => line.trim())
        .filter((line, index, arr) => arr.findIndex(item => item.trim() === line.trim()) === index);
}

for (let i = 1; i <= MAX_DAYS; i++) {
    const targetDate = baseDate.clone().subtract(i, 'days').format('YYYY-MM-DD');
    const targetPath = `5.todo/date/${targetDate}.md`;
    const targetFile = app.vault.getAbstractFileByPath(targetPath);

    if (!targetFile) continue;

    // Read the note source directly so Templater doesn't recursively execute nested templates.
    const content = await app.vault.read(targetFile);
    const candidateTomorrowGoals = getTomorrowGoals(getSection(content, "明日目标"));

    const tomorrowLines = new Set(
        candidateTomorrowGoals
            .split('\n')
            .map(line => line.trim())
            .filter(Boolean)
    );

    const candidatePastGoalsBlock = dedupeLines([
        ...getUncheckedTasks(getSection(content, "今日目标")).split('\n'),
        ...getUncheckedTasks(getSection(content, "往日目标")).split('\n'),
    ])
        .filter(line => !tomorrowLines.has(line.trim()))
        .join('\n');

    const candidateCarriedForwardBlock = dedupeLines([
        ...getUncheckedTasks(getSection(content, "今日记录")).split('\n'),
        ...getUncheckedTasks(getSection(content, "延续目标")).split('\n'),
    ])
        .filter(line => !tomorrowLines.has(line.trim()))
        .join('\n');

    if (candidateTomorrowGoals || candidatePastGoalsBlock || candidateCarriedForwardBlock) {
        tomorrowGoals = candidateTomorrowGoals;
        pastGoalsBlock = candidatePastGoalsBlock;
        carriedForwardBlock = candidateCarriedForwardBlock;
        foundDate = targetDate;
        daysAgo = i;
        break;
    }
}

const todayGoals = tomorrowGoals || "- [ ] ";
const carriedBlock = carriedForwardBlock ? carriedForwardBlock : "(无延续任务)";
const pastGoals = pastGoalsBlock ? pastGoalsBlock : "(无往日目标)";
const sourcePrefix = foundDate && daysAgo > 1
    ? `> [!note] 来自 ${foundDate}(${daysAgo} 天前)\n\n`
    : "";
-%>
## 今日目标
<% todayGoals %>

## 往日目标
<% sourcePrefix + pastGoals %>

## scheduled
```dataviewjs
const date = dv.date(dv.current().file.name);
if (date) {
  const scheduledTasks = dv.pages().file.tasks
    .where(t => !t.completed && t.scheduled && t.scheduled <= date)
    .sort(t => t.scheduled, 'asc');

  const todayTasks = scheduledTasks.where(t => t.scheduled.equals(date));
  const carriedTasks = scheduledTasks.where(t => t.scheduled < date);

  if (todayTasks.length > 0) {
    dv.taskList(todayTasks, false);
  }

  if (carriedTasks.length > 0) {
    dv.taskList(carriedTasks, false);
  }

  if (todayTasks.length === 0 && carriedTasks.length === 0) {
    dv.paragraph("(无 scheduled 任务)");
  }
}

```

## 延续目标
<% sourcePrefix + carriedBlock %>

## 今日复盘
- 做了什么:
- 没做的话为什么:
- 今日亮点:
- 想法/反思/心情:

## 明日目标
- [ ] 
 
## 今日记录