This commit is contained in:
maigamo 2025-04-23 13:06:41 +08:00
parent e40c1161fc
commit 9fe90fb01e
8 changed files with 276 additions and 244 deletions

View file

@ -1,10 +1,10 @@
{
"id": "daily-task-auto-generator",
"name": "Daily Task Auto Generator",
"version": "1.0.1",
"version": "1.0.0",
"minAppVersion": "0.15.0",
"description": "Automatically generate daily tasks in specified folders with custom templates",
"author": "maigamo",
"authorUrl": "https://github.com/maigamo",
"isDesktopOnly": false
}
}

View file

@ -40,6 +40,7 @@ export type TranslationKey =
| 'notification.taskAdded'
| 'notification.taskExists'
| 'notification.error'
| 'notification.generating'
// 星期
| 'weekday.mon'
@ -167,6 +168,7 @@ const translationsZH: Record<TranslationKey, string> = {
'notification.taskAdded': '今日任务已添加',
'notification.taskExists': '今日任务已存在',
'notification.error': '错误:',
'notification.generating': '正在生成今日任务...',
// 星期
'weekday.mon': '星期一',
@ -239,6 +241,7 @@ const translationsEN: Record<TranslationKey, string> = {
'notification.taskAdded': 'Today\'s task has been added',
'notification.taskExists': 'Today\'s task already exists',
'notification.error': 'Error: ',
'notification.generating': 'Generating today\'s tasks...',
// 星期
'weekday.mon': 'Monday',

View file

@ -4,11 +4,7 @@ import { DailyTaskSettingTab, SettingsManager } from './settings/settings';
import { setCurrentLanguage } from './i18n/i18n';
import { isWorkday } from './utils/dateUtils';
import { TaskGenerator } from './taskGenerator';
// 定义插件图标
const ICON = `<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5"/>
</svg>`;
import { DAILY_TASK_ICON } from './ui/icons';
/**
*
@ -24,10 +20,8 @@ export default class DailyTaskPlugin extends Plugin {
*
*/
async onload() {
console.log('Loading Daily Task Auto Generator plugin');
// 添加插件图标
addIcon('daily-task', ICON);
addIcon('daily-task', DAILY_TASK_ICON);
// 初始化设置管理器
this.settingsManager = new SettingsManager(this);
@ -53,9 +47,7 @@ export default class DailyTaskPlugin extends Plugin {
// 延迟10秒后检查是否需要自动生成任务
// 这样可以确保Obsidian完全加载避免与启动过程冲突
console.log('计划在10秒后检查是否需要自动生成任务');
setTimeout(async () => {
console.log('开始检查是否需要自动生成任务');
await this.checkAutoGenerate();
}, 10000);
}
@ -64,7 +56,7 @@ export default class DailyTaskPlugin extends Plugin {
*
*/
onunload() {
console.log('Unloading Daily Task Auto Generator plugin');
// 插件卸载清理工作
}
/**
@ -75,25 +67,20 @@ export default class DailyTaskPlugin extends Plugin {
switch (settings.autoGenerateMode) {
case AutoGenerateMode.DAILY:
// 每天自动生成(静默模式,不打开文件,减少日志)
console.log('根据设置,每天自动生成任务(静默模式)');
// 每天自动生成(静默模式,不打开文件)
await this.taskGenerator.generateDailyTask(false, true);
break;
case AutoGenerateMode.WORKDAY:
// 工作日自动生成(静默模式,不打开文件,减少日志
// 工作日自动生成(静默模式,不打开文件
if (isWorkday()) {
console.log('根据设置,工作日自动生成任务(静默模式)');
await this.taskGenerator.generateDailyTask(false, true);
} else {
console.log('今天不是工作日,跳过自动生成任务');
}
break;
case AutoGenerateMode.NONE:
default:
// 不自动生成
console.log('已禁用自动生成任务功能');
break;
}
}

View file

@ -11,7 +11,7 @@ declare class DailyTaskPlugin {
app: App;
}
// CSS 相关代码
// CSS 相关常量class名称
const SettingsSectionCSS = "daily-task-settings-section";
const ButtonCSS = "daily-task-button";
const PreviewButtonCSS = "daily-task-preview-button";
@ -21,71 +21,19 @@ const VerticalStackCSS = "daily-task-vertical-stack";
const TextRightCSS = "daily-task-text-right";
const TextCenterCSS = "daily-task-text-center";
const ScrollbarSlimCSS = "daily-task-slim-scrollbar";
const SaveIndicatorCSS = "daily-task-save-indicator";
const SuccessIconCSS = "daily-task-success-icon";
const SettingTopSpaceCSS = "daily-task-setting-top-space";
const InputContainerCSS = "daily-task-input-container";
const InputCSS = "daily-task-input";
/**
*
* CSS文件
*/
function addCustomStyles() {
const cssText = `
.${SettingsSectionCSS} {
margin-top: 24px;
margin-bottom: 24px;
padding: 12px 0;
border-top: 1px solid var(--background-modifier-border);
}
.${ButtonCSS} {
margin-top: 6px;
margin-bottom: 6px;
}
.${PreviewButtonCSS}, .${ResetButtonCSS} {
display: inline-block;
text-align: center !important;
width: 100%;
}
.${EditorCSS} {
height: 200px;
margin-top: 12px;
margin-bottom: 12px;
}
.${VerticalStackCSS} {
display: flex;
flex-direction: column;
}
.${TextRightCSS} {
text-align: right;
}
.${TextCenterCSS} {
text-align: center !important;
}
.${ScrollbarSlimCSS} .CodeMirror-vscrollbar {
width: 20% !important;
}
/* 自定义通知样式 */
.daily-task-success-notice {
background-color: rgba(0, 255, 127, 0.2) !important;
}
.daily-task-warning-notice {
background-color: rgba(255, 165, 0, 0.2) !important;
}
.daily-task-error-notice {
background-color: rgba(255, 69, 0, 0.2) !important;
}
`;
// 添加自定义样式
const styleElement = document.createElement('style');
styleElement.textContent = cssText;
document.head.appendChild(styleElement);
// 样式已移至src/styles.css无需在此处添加内联样式
// 插件加载时会自动加载styles.css文件
}
/**
@ -127,7 +75,7 @@ export class DailyTaskSettingTab extends PluginSettingTab {
// 添加顶部间距(增加间距以改善界面美观)
const topSpacing = containerEl.createEl('div');
topSpacing.style.marginTop = '30px';
topSpacing.classList.add(SettingTopSpaceCSS);
// 根目录设置
const rootDirSetting = new Setting(containerEl)
@ -136,9 +84,7 @@ export class DailyTaskSettingTab extends PluginSettingTab {
// 创建输入框容器,使其可以包含额外元素
const inputContainer = document.createElement('div');
inputContainer.style.display = 'flex';
inputContainer.style.width = '100%';
inputContainer.style.position = 'relative';
inputContainer.classList.add(InputContainerCSS);
rootDirSetting.controlEl.appendChild(inputContainer);
this.rootDirInput = new TextComponent(inputContainer)
@ -153,37 +99,23 @@ export class DailyTaskSettingTab extends PluginSettingTab {
}
});
// 给input元素直接设置placeholder属性
// 给input元素设置类和placeholder属性
if (this.rootDirInput && this.rootDirInput.inputEl) {
this.rootDirInput.inputEl.classList.add(InputCSS);
this.rootDirInput.inputEl.placeholder = 'DailyTasks';
// 增加宽度
this.rootDirInput.inputEl.style.width = '100%';
// 美化输入框样式
this.rootDirInput.inputEl.style.borderRadius = '4px';
this.rootDirInput.inputEl.style.padding = '8px 35px 8px 10px';
this.rootDirInput.inputEl.style.transition = 'all 0.3s ease';
}
// 添加自动保存指示器
const saveIndicator = document.createElement('div');
saveIndicator.classList.add('save-indicator');
saveIndicator.style.position = 'absolute';
saveIndicator.style.right = '10px';
saveIndicator.style.top = '50%';
saveIndicator.style.transform = 'translateY(-50%)';
saveIndicator.style.opacity = '0';
saveIndicator.style.transition = 'opacity 0.3s ease';
saveIndicator.classList.add(SaveIndicatorCSS);
inputContainer.appendChild(saveIndicator);
// 创建保存成功图标
const saveSuccessIcon = createSpan({cls: 'svg-icon lucide-check'});
saveSuccessIcon.style.color = '#4CAF50';
saveSuccessIcon.style.width = '18px';
saveSuccessIcon.style.height = '18px';
const saveSuccessIcon = createSpan({cls: `svg-icon lucide-check ${SuccessIconCSS}`});
saveIndicator.appendChild(saveSuccessIcon);
// 记录自动保存定时器
let autoSaveTimer: number | null = null;
let autoSaveTimer: NodeJS.Timeout | null = null;
// 自动保存方法
this.autoSaveRootDir = async (value: string) => {
@ -199,18 +131,17 @@ export class DailyTaskSettingTab extends PluginSettingTab {
pathToSave = 'DailyTasks'; // 默认存放目录
}
// 保存设置
// 实际保存设置
await this.settingsManager.updateSettings({ rootDir: pathToSave });
this.dirtySettings = false;
// 显示保存成功指示器
// 显示保存成功的视觉反馈
saveIndicator.style.opacity = '1';
// 3秒后隐藏
setTimeout(() => {
saveIndicator.style.opacity = '0';
}, 2000);
}, 800) as unknown as number;
}, 1500);
}, 800);
};
// 自动生成模式

View file

@ -88,4 +88,96 @@
.daily-task-slim-scrollbar::-webkit-scrollbar-thumb:hover {
background: var(--interactive-accent-hover);
}
/* 设置组件样式 */
.daily-task-settings-section {
margin-top: 24px;
margin-bottom: 24px;
padding: 12px 0;
border-top: 1px solid var(--background-modifier-border);
}
.daily-task-button {
margin-top: 6px;
margin-bottom: 6px;
}
.daily-task-preview-button, .daily-task-reset-button {
display: inline-block;
text-align: center !important;
width: 100%;
}
.daily-task-editor {
height: 200px;
margin-top: 12px;
margin-bottom: 12px;
}
.daily-task-vertical-stack {
display: flex;
flex-direction: column;
}
.daily-task-text-right {
text-align: right;
}
.daily-task-text-center {
text-align: center !important;
}
.daily-task-slim-scrollbar .CodeMirror-vscrollbar {
width: 20% !important;
}
/* 自定义通知样式 */
.daily-task-success-notice {
background-color: rgba(0, 255, 127, 0.2) !important;
}
.daily-task-warning-notice {
background-color: rgba(255, 165, 0, 0.2) !important;
}
.daily-task-error-notice {
background-color: rgba(255, 69, 0, 0.2) !important;
}
/* 输入框样式 */
.daily-task-input {
width: 100%;
border-radius: 4px;
padding: 8px 35px 8px 10px;
transition: all 0.3s ease;
}
/* 保存指示器样式 */
.daily-task-save-indicator {
position: absolute;
right: 10px;
top: 50%;
transform: translateY(-50%);
opacity: 0;
transition: opacity 0.3s ease;
}
/* 成功图标样式 */
.daily-task-success-icon {
color: #4CAF50;
width: 18px;
height: 18px;
}
/* 设置页面顶部间距 */
.daily-task-setting-top-space {
margin-top: 30px;
}
/* 输入容器样式 */
.daily-task-input-container {
display: flex;
width: 100%;
position: relative;
}

View file

@ -1,4 +1,4 @@
import { App, Notice, TFile, Vault } from "obsidian";
import { App, Notice, TAbstractFile, TFile, Vault } from "obsidian";
import { getTranslation } from "./i18n/i18n";
import { SettingsManager } from "./settings/settings";
import { appendToFile, ensureFileExists, ensureFolderExists, getTaskFilePath, todayTaskExists, fileContains, getYesterdayDate, getYesterdayTaskFilePath, extractTasksForDate, analyzeTaskCompletion, yesterdayStatisticsExists, generateStatisticsContent } from "./utils/fileUtils";
@ -33,7 +33,6 @@ export class TaskGenerator {
// 获取任务文件路径
const filePath = getTaskFilePath(rootDir);
if (!quietMode) console.log(`生成任务文件路径: ${filePath}`);
// 解析年份和月份
const pathParts = filePath.split('/');
@ -42,41 +41,39 @@ export class TaskGenerator {
const yearFolder = `${rootDir}/${year}`;
// 确保根目录存在
if (!quietMode) console.log(`正在确保根目录存在: ${rootDir}`);
const rootCreated = await ensureFolderExists(this.vault, rootDir);
if (!rootCreated) {
console.error(`无法访问或创建根目录: ${rootDir}`);
throw new Error(`无法访问根目录: ${rootDir},可能是存在同名文件或权限问题`);
}
if (!quietMode) console.log(`根目录确认: ${rootDir}`);
// 确保年份目录存在
if (!quietMode) console.log(`正在确保年份目录存在: ${yearFolder}`);
const yearCreated = await ensureFolderExists(this.vault, yearFolder);
if (!yearCreated) {
console.error(`无法访问或创建年份目录: ${yearFolder}`);
throw new Error(`无法访问年份目录: ${yearFolder},可能是存在同名文件或权限问题`);
}
if (!quietMode) console.log(`年份目录确认: ${yearFolder}`);
// 确保月份文件存在
if (!quietMode) console.log(`正在确保月份文件存在: ${filePath} (${monthName})`);
const fileCreated = await ensureFileExists(this.vault, filePath);
if (!fileCreated) {
console.error(`无法访问或创建月份文件: ${filePath}`);
throw new Error(`无法访问月份文件: ${filePath},请检查是否存在同名目录或权限问题`);
}
if (!quietMode) console.log(`月份文件确认: ${filePath}`);
// 检查今日任务是否已存在
const date = getCurrentDate();
// 更改检查方式:不仅检查纯日期,也检查带图标的日期格式
const dateRegex = new RegExp(`## [^\\n]*${date}[^\\n]*\\n`);
const fileContent = await this.vault.read(this.vault.getAbstractFileByPath(filePath) as TFile);
// 使用instanceof检查确保文件对象有效
const abstractFile = this.vault.getAbstractFileByPath(filePath);
if (!abstractFile || !(abstractFile instanceof TFile)) {
throw new Error(`找不到有效的文件: ${filePath}`);
}
const fileContent = await this.vault.read(abstractFile);
const existingTaskCheck = dateRegex.test(fileContent);
if (existingTaskCheck) {
console.log(`今日(${date})任务已存在于文件中,跳过创建`);
if (!quietMode) console.log(`今日(${date})任务已存在于文件中,跳过创建`);
// 如果需要打开文件
if (openFile) {
@ -117,11 +114,10 @@ export class TaskGenerator {
: renderedContent;
// 追加到文件
if (!quietMode) console.log(`正在向文件追加内容`);
const success = await appendToFile(this.vault, filePath, fullContent);
if (success) {
console.log(`✅ 任务内容追加成功 ${date}`);
if (!quietMode) console.log(`✅ 任务内容追加成功 ${date}`);
// 如果需要打开文件
if (openFile) {
@ -138,9 +134,6 @@ export class TaskGenerator {
} else {
throw new Error(`文件创建成功但无法打开: ${filePath}`);
}
} else {
// 静默模式,只在控制台记录
console.log(`✨ 今日(${date})任务已静默添加,无需打开文件`);
}
} else {
throw new Error(`无法向文件追加内容: ${filePath}`);
@ -171,14 +164,11 @@ export class TaskGenerator {
const yesterdayDate = getYesterdayDate();
const yesterdayFilePath = getYesterdayTaskFilePath(rootDir);
if (!quietMode) console.log(`正在获取昨日(${yesterdayDate})任务统计,文件路径: ${yesterdayFilePath}`);
// 检查今日的内容中是否已经包含昨日统计
const todayFilePath = getTaskFilePath(rootDir);
const statsExists = await yesterdayStatisticsExists(this.vault, todayFilePath, todayDate);
if (statsExists) {
if (!quietMode) console.log('昨日统计信息已存在,跳过生成');
return '';
}
@ -187,55 +177,33 @@ export class TaskGenerator {
// 如果找不到昨日任务内容
if (!yesterdayContent) {
if (!quietMode) console.log(`找不到昨日(${yesterdayDate})任务内容,跳过统计`);
return '';
}
// 分析任务完成情况
const taskStats = analyzeTaskCompletion(yesterdayContent);
if (!quietMode) {
console.log(`昨日任务统计: 总数=${taskStats.totalTasks}, 已完成=${taskStats.completedTasks}`);
console.log(`未完成任务: ${taskStats.unfinishedTasksList.length}`);
}
// 如果没有任务,不生成统计信息
if (taskStats.totalTasks === 0) {
if (!quietMode) console.log('昨日没有任务,跳过统计');
return '';
}
// 确保在所有语言环境下都调用generateStatisticsContent
// 生成统计内容
return generateStatisticsContent(taskStats, getTranslation);
} catch (error) {
console.error(`生成昨日统计信息时出错:`, error);
return ''; // 出错时返回空字符串,不影响今日任务生成
if (!quietMode) console.error("生成昨日统计出错:", error);
return '';
}
}
/**
*
*
* @returns
*/
async addTaskManually(): Promise<boolean> {
try {
const settings = this.settingsManager.getSettings();
const rootDir = settings.rootDir.trim() || 'DailyTasks'; // 使用默认目录
// 显示开始生成的通知
this.showWarningNotice(`${getTranslation('notification.generating')}`);
// 检查今日任务是否已存在
const exists = await todayTaskExists(this.vault, rootDir);
if (exists) {
// 任务已存在,显示提示
this.showWarningNotice(`📌 ${getTranslation('notification.taskExists')}`);
return false;
}
// 生成任务
return await this.generateDailyTask();
// 调用任务生成逻辑,打开文件
return await this.generateDailyTask(true);
} catch (error) {
console.error("Error adding task manually:", error);
console.error("手动添加任务失败:", error);
// 显示错误通知
const errorMsg = error instanceof Error ? error.message : String(error);
@ -247,49 +215,28 @@ export class TaskGenerator {
/**
*
* @param message
*/
private showSuccessNotice(message: string): void {
const notice = new Notice(
message,
this.settingsManager.getSettings().successNotificationDuration
);
// 添加成功样式
if (notice.noticeEl) {
notice.noticeEl.addClass('daily-task-success-notice');
}
const notice = new Notice(message, 4000);
// 使用CSS类而不是内联样式
notice.noticeEl.classList.add('daily-task-success-notice');
}
/**
*
* @param message
*/
private showWarningNotice(message: string): void {
const notice = new Notice(
message,
this.settingsManager.getSettings().successNotificationDuration
);
// 添加警告样式
if (notice.noticeEl) {
notice.noticeEl.addClass('daily-task-warning-notice');
}
const notice = new Notice(message, 3000);
// 使用CSS类而不是内联样式
notice.noticeEl.classList.add('daily-task-warning-notice');
}
/**
*
* @param message
*/
private showErrorNotice(message: string): void {
const notice = new Notice(
message,
this.settingsManager.getSettings().successNotificationDuration
);
// 添加错误样式
if (notice.noticeEl) {
notice.noticeEl.addClass('daily-task-error-notice');
}
const notice = new Notice(message, 5000);
// 使用CSS类而不是内联样式
notice.noticeEl.classList.add('daily-task-error-notice');
}
}

57
src/ui/icons.ts Normal file
View file

@ -0,0 +1,57 @@
/**
*
* SVG图标便
*/
/**
* -
*/
export const DAILY_TASK_ICON = `<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5"/>
</svg>`;
/**
* -
*/
export const SETTINGS_ICON = `<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="3"></circle>
<path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"></path>
</svg>`;
/**
* -
*/
export const ADD_TASK_ICON = `<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<line x1="12" y1="5" x2="12" y2="19"></line>
<line x1="5" y1="12" x2="19" y2="12"></line>
</svg>`;
/**
* -
*/
export const STATISTICS_ICON = `<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<line x1="18" y1="20" x2="18" y2="10"></line>
<line x1="12" y1="20" x2="12" y2="4"></line>
<line x1="6" y1="20" x2="6" y2="14"></line>
</svg>`;
/**
* -
*/
export const RESET_ICON = `<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M3 2v6h6"></path>
<path d="M21 12A9 9 0 0 0 6 5.3L3 8"></path>
<path d="M21 22v-6h-6"></path>
<path d="M3 12a9 9 0 0 0 15 6.7l3-2.7"></path>
</svg>`;
/**
* -
*/
export const TEMPLATE_ICON = `<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
<polyline points="14 2 14 8 20 8"></polyline>
<line x1="16" y1="13" x2="8" y2="13"></line>
<line x1="16" y1="17" x2="8" y2="17"></line>
<polyline points="10 9 9 9 8 9"></polyline>
</svg>`;

View file

@ -173,10 +173,10 @@ export async function appendToFile(vault: Vault, path: string, content: string):
*/
export async function fileContains(vault: Vault, path: string, content: string): Promise<boolean> {
try {
const file = vault.getAbstractFileByPath(path);
if (file && file instanceof TFile) {
const abstractFile = vault.getAbstractFileByPath(path);
if (abstractFile && abstractFile instanceof TFile) {
try {
const currentContent = await vault.read(file);
const currentContent = await vault.read(abstractFile);
return currentContent.includes(content);
} catch (e) {
console.error(`读取文件内容时出错: ${e}`);
@ -215,22 +215,24 @@ export function getTaskFilePath(rootDir: string): string {
* @returns
*/
export async function todayTaskExists(vault: Vault, rootDir: string): Promise<boolean> {
const taskFilePath = getTaskFilePath(rootDir);
const date = getCurrentDate();
// 查找文件是否存在以及是否包含今天的日期标题(包括带图标格式)
try {
console.log(`检查今日任务是否存在于: ${taskFilePath}`);
// 更改检查方式:改用正则表达式匹配任何包含当前日期的标题行
const file = vault.getAbstractFileByPath(taskFilePath);
if (file && file instanceof TFile) {
const content = await vault.read(file);
const dateRegex = new RegExp(`## [^\\n]*${date}[^\\n]*\\n`);
return dateRegex.test(content);
const date = getCurrentDate();
const filePath = getTaskFilePath(rootDir);
// 获取文件
const abstractFile = vault.getAbstractFileByPath(filePath);
if (!abstractFile || !(abstractFile instanceof TFile)) {
return false; // 文件不存在
}
return false;
// 读取文件内容
const content = await vault.read(abstractFile);
// 更改检查方式:不仅检查纯日期,也检查带图标的日期格式
const dateRegex = new RegExp(`## [^\\n]*${date}[^\\n]*\\n`);
return dateRegex.test(content);
} catch (error) {
console.error(`检查今日任务时出错:`, error);
console.error("Error checking if today's task exists:", error);
return false;
}
}
@ -306,36 +308,47 @@ function getMonthNameEN(monthIndex: number): string {
}
/**
*
* @param vault Obsidian保险库
*
* @param vault Obsidian文件系统
* @param filePath
* @param date YYYY-MM-DD格式
* @returns null
* @param date (YYYY-MM-DD)
* @returns null
*/
export async function extractTasksForDate(vault: Vault, filePath: string, date: string): Promise<string | null> {
try {
// 检查文件是否存在
const file = vault.getAbstractFileByPath(filePath);
if (!file || !(file instanceof TFile)) {
console.log(`找不到文件: ${filePath}`);
return null;
// 获取文件
const abstractFile = vault.getAbstractFileByPath(filePath);
if (!abstractFile || !(abstractFile instanceof TFile)) {
return null; // 文件不存在
}
// 读取文件内容
const content = await vault.read(file);
const content = await vault.read(abstractFile);
// 寻找日期标题,支持带图标格式
const dateHeaderRegex = new RegExp(`## [^\\n]*${date}[^\\n]*\\n(.*?)(?=\\n## |$)`, 's');
const match = content.match(dateHeaderRegex);
// 找到日期标题行的位置
const dateRegex = new RegExp(`## [^\\n]*${date}[^\\n]*\\n`);
const match = content.match(dateRegex);
if (match && match[1]) {
return match[1].trim();
if (!match || match.index === undefined) {
return null; // 找不到日期
}
console.log(`找不到日期 ${date} 的任务内容`);
return null;
// 找到本日期部分的结束位置(下一个二级标题或文件结尾)
const startPos = match.index;
const nextHeadingMatch = content.slice(startPos + match[0].length).match(/\n## /);
let endPos: number;
if (nextHeadingMatch && nextHeadingMatch.index !== undefined) {
endPos = startPos + match[0].length + nextHeadingMatch.index;
} else {
endPos = content.length;
}
// 提取任务部分,包括标题
return content.slice(startPos, endPos).trim();
} catch (error) {
console.error(`提取任务内容时出错: ${error}`);
console.error(`Error extracting tasks for date ${date}:`, error);
return null;
}
}
@ -382,30 +395,32 @@ export function analyzeTaskCompletion(taskContent: string): {
}
/**
*
* @param vault Obsidian保险库
* @param filePath
* @param date
* @returns
*
* @param vault Obsidian文件系统
* @param filePath
* @param date
* @returns
*/
export async function yesterdayStatisticsExists(vault: Vault, filePath: string, date: string): Promise<boolean> {
try {
// 检查文件是否存在
const file = vault.getAbstractFileByPath(filePath);
if (!file || !(file instanceof TFile)) {
console.log(`找不到文件: ${filePath}`);
return false;
// 获取文件
const abstractFile = vault.getAbstractFileByPath(filePath);
if (!abstractFile || !(abstractFile instanceof TFile)) {
return false; // 文件不存在
}
// 读取文件内容
const content = await vault.read(file);
const content = await vault.read(abstractFile);
// 寻找今日日期下的昨日统计标题,支持带图标格式
const statisticsTitleRegex = new RegExp(`## [^\\n]*${date}[^\\n]*\\n.*?${getTranslation('statistics.title')}`, 's');
return statisticsTitleRegex.test(content);
// 检查是否包含昨日统计标记
const yesterdayDate = getYesterdayDate();
const statsTitle = getTranslation('statistics.title');
const statsRegex = new RegExp(`## [^\\n]*${date}[^\\n]*[\\s\\S]*?${statsTitle}`);
return statsRegex.test(content);
} catch (error) {
console.error(`检查昨日统计信息时出错: ${error}`);
return false;
console.error(`Error checking if yesterday statistics exists:`, error);
return false; // 出错时假设不存在
}
}