mirror of
https://github.com/maigamo/Daily-Task-Auto-Generator.git
synced 2026-07-22 05:48:30 +00:00
The interface was optimized and some bugs were fixed
This commit is contained in:
parent
2d27bde9d7
commit
e717e56245
7 changed files with 465 additions and 28 deletions
|
|
@ -16,6 +16,16 @@ export type TranslationKey =
|
|||
| 'settings.mode.none'
|
||||
| 'settings.mode.daily'
|
||||
| 'settings.mode.workday'
|
||||
|
||||
// 文件生成模式相关
|
||||
| 'settings.fileGenerationMode'
|
||||
| 'settings.fileGenerationMode.desc'
|
||||
| 'settings.mode.monthly'
|
||||
| 'settings.mode.dailyFile'
|
||||
| 'settings.dailyFilePrefix'
|
||||
| 'settings.dailyFilePrefix.desc'
|
||||
| 'notification.dailyFileExists'
|
||||
|
||||
| 'settings.language'
|
||||
| 'settings.language.desc'
|
||||
| 'settings.language.auto'
|
||||
|
|
@ -145,6 +155,16 @@ const translationsZH: Record<TranslationKey, string> = {
|
|||
'settings.mode.none': '❌ 关闭',
|
||||
'settings.mode.daily': '📆 每天',
|
||||
'settings.mode.workday': '💼 仅工作日',
|
||||
|
||||
// 文件生成模式相关
|
||||
'settings.fileGenerationMode': '📄 文件生成模式',
|
||||
'settings.fileGenerationMode.desc': '选择任务文件的生成方式',
|
||||
'settings.mode.monthly': '📅 月度文件',
|
||||
'settings.mode.dailyFile': '📆 日度文件',
|
||||
'settings.dailyFilePrefix': '🏷️ 文件名前缀',
|
||||
'settings.dailyFilePrefix.desc': '日度文件模式下的文件名前缀(可选)',
|
||||
'notification.dailyFileExists': '今日任务文件已存在',
|
||||
|
||||
'settings.language': '🔤 界面语言',
|
||||
'settings.language.desc': '选择插件界面显示的语言',
|
||||
'settings.language.auto': '🔍 自动检测',
|
||||
|
|
@ -221,6 +241,16 @@ const translationsEN: Record<TranslationKey, string> = {
|
|||
'settings.mode.none': '❌ Off',
|
||||
'settings.mode.daily': '📆 Daily',
|
||||
'settings.mode.workday': '💼 Workdays only',
|
||||
|
||||
// 文件生成模式相关
|
||||
'settings.fileGenerationMode': '📄 File Generation Mode',
|
||||
'settings.fileGenerationMode.desc': 'Choose how task files are generated',
|
||||
'settings.mode.monthly': '📅 Monthly Files',
|
||||
'settings.mode.dailyFile': '📆 Daily Files',
|
||||
'settings.dailyFilePrefix': '🏷️ File Name Prefix',
|
||||
'settings.dailyFilePrefix.desc': 'Optional prefix for daily file names',
|
||||
'notification.dailyFileExists': 'Today\'s task file already exists',
|
||||
|
||||
'settings.language': '🔤 Interface language',
|
||||
'settings.language.desc': 'Select the language for the plugin interface',
|
||||
'settings.language.auto': '🔍 Auto detect',
|
||||
|
|
|
|||
|
|
@ -7,6 +7,14 @@ export enum AutoGenerateMode {
|
|||
WORKDAY = 'workday' // 仅工作日自动生成
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件生成模式枚举
|
||||
*/
|
||||
export enum FileGenerationMode {
|
||||
MONTHLY = 'monthly', // 月度文件模式(默认)
|
||||
DAILY = 'daily' // 日度文件模式
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置界面语言
|
||||
*/
|
||||
|
|
@ -25,6 +33,10 @@ export interface DailyTaskSettings {
|
|||
autoGenerateMode: AutoGenerateMode; // 自动生成模式
|
||||
language: string; // 界面语言
|
||||
|
||||
// 文件生成模式配置
|
||||
fileGenerationMode: FileGenerationMode; // 文件生成模式
|
||||
dailyFilePrefix: string; // 日度文件前缀(仅日度模式使用)
|
||||
|
||||
// 模板配置
|
||||
templateZh: string; // 中文任务模板
|
||||
templateEn: string; // 英文任务模板
|
||||
|
|
@ -87,6 +99,8 @@ export const DEFAULT_SETTINGS: DailyTaskSettings = {
|
|||
rootDir: 'DailyTasks',
|
||||
autoGenerateMode: AutoGenerateMode.WORKDAY,
|
||||
language: Language.AUTO,
|
||||
fileGenerationMode: FileGenerationMode.MONTHLY, // 默认为月度文件模式
|
||||
dailyFilePrefix: '', // 默认无前缀
|
||||
templateZh: DEFAULT_TEMPLATE_ZH,
|
||||
templateEn: DEFAULT_TEMPLATE_EN,
|
||||
customTemplate: '', // 默认为空,表示使用语言相关的默认模板
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { App, ButtonComponent, DropdownComponent, Notice, Plugin, PluginSettingTab, Setting, TextAreaComponent, TextComponent, ToggleComponent } from 'obsidian';
|
||||
import { AutoGenerateMode, DEFAULT_SETTINGS, DEFAULT_TEMPLATE_EN, DEFAULT_TEMPLATE_ZH, DailyTaskSettings, Language } from '../models/settings';
|
||||
import { AutoGenerateMode, DEFAULT_SETTINGS, DEFAULT_TEMPLATE_EN, DEFAULT_TEMPLATE_ZH, DailyTaskSettings, Language, FileGenerationMode } from '../models/settings';
|
||||
import { getTranslation, setCurrentLanguage } from '../i18n/i18n';
|
||||
import { renderTemplate } from '../utils/templateEngine';
|
||||
import { TaskGenerator } from '../taskGenerator';
|
||||
|
|
@ -45,12 +45,19 @@ export class DailyTaskSettingTab extends PluginSettingTab {
|
|||
// 目录输入框
|
||||
rootDirInput: TextComponent | null = null;
|
||||
|
||||
// 日度文件前缀输入框
|
||||
dailyFilePrefixInput: TextComponent | null = null;
|
||||
dailyFilePrefixSetting: HTMLElement | null = null;
|
||||
|
||||
// 标记设置是否已修改但未保存
|
||||
dirtySettings: boolean = false;
|
||||
|
||||
// 自动保存目录的方法
|
||||
autoSaveRootDir: (value: string) => Promise<void>;
|
||||
|
||||
// 自动保存日度文件前缀的方法
|
||||
autoSaveDailyFilePrefix: (value: string) => Promise<void>;
|
||||
|
||||
constructor(app: App, plugin: Plugin) {
|
||||
super(app, plugin);
|
||||
this.plugin = plugin;
|
||||
|
|
@ -210,6 +217,141 @@ export class DailyTaskSettingTab extends PluginSettingTab {
|
|||
toggleContainer.appendChild(option);
|
||||
});
|
||||
|
||||
// 文件生成模式设置
|
||||
const fileGenSetting = new Setting(containerEl)
|
||||
.setName(getTranslation('settings.fileGenerationMode'))
|
||||
.setDesc(getTranslation('settings.fileGenerationMode.desc'));
|
||||
|
||||
// 创建文件生成模式选择器(二选滑块)
|
||||
const fileGenToggleContainer = document.createElement('div');
|
||||
fileGenToggleContainer.classList.add('mode-toggle-container');
|
||||
fileGenSetting.controlEl.appendChild(fileGenToggleContainer);
|
||||
|
||||
const fileGenModes = [
|
||||
{ value: FileGenerationMode.MONTHLY, label: getTranslation('settings.mode.monthly') },
|
||||
{ value: FileGenerationMode.DAILY, label: getTranslation('settings.mode.dailyFile') }
|
||||
];
|
||||
|
||||
// 文件生成模式滑块指示器
|
||||
const fileGenSlider = document.createElement('div');
|
||||
fileGenSlider.classList.add('mode-toggle-slider');
|
||||
fileGenToggleContainer.appendChild(fileGenSlider);
|
||||
|
||||
// 更新文件生成模式滑块位置
|
||||
const updateFileGenSlider = (index: number) => {
|
||||
// 移除之前的位置类(二选滑块)
|
||||
fileGenSlider.classList.remove('slider-position-0', 'slider-position-1');
|
||||
// 添加新的位置类
|
||||
fileGenSlider.classList.add(`slider-position-${index}`);
|
||||
};
|
||||
|
||||
// 设置当前文件生成模式
|
||||
let currentFileGenModeIndex = fileGenModes.findIndex(mode => mode.value === settings.fileGenerationMode);
|
||||
if (currentFileGenModeIndex === -1) {
|
||||
// 如果没有找到有效的模式,设置为月度模式(默认)
|
||||
currentFileGenModeIndex = 0;
|
||||
this.settingsManager.updateSettings({ fileGenerationMode: FileGenerationMode.MONTHLY });
|
||||
}
|
||||
updateFileGenSlider(currentFileGenModeIndex);
|
||||
|
||||
// 创建文件生成模式选项
|
||||
fileGenModes.forEach((mode, index) => {
|
||||
const option = document.createElement('div');
|
||||
option.classList.add('mode-toggle-option');
|
||||
option.textContent = mode.label;
|
||||
|
||||
if (mode.value === settings.fileGenerationMode) {
|
||||
option.classList.add('active');
|
||||
}
|
||||
|
||||
option.addEventListener('click', async () => {
|
||||
// 更新视觉状态
|
||||
fileGenToggleContainer.querySelectorAll('.mode-toggle-option').forEach(el => {
|
||||
el.classList.remove('active');
|
||||
});
|
||||
option.classList.add('active');
|
||||
|
||||
// 更新滑块位置
|
||||
updateFileGenSlider(index);
|
||||
|
||||
// 保存设置
|
||||
await this.settingsManager.updateSettings({ fileGenerationMode: mode.value });
|
||||
|
||||
// 更新日度文件前缀设置的显示状态
|
||||
this.updateDailyFilePrefixVisibility(mode.value);
|
||||
});
|
||||
|
||||
fileGenToggleContainer.appendChild(option);
|
||||
});
|
||||
|
||||
// 日度文件前缀设置
|
||||
const dailyFilePrefixSetting = new Setting(containerEl)
|
||||
.setName(getTranslation('settings.dailyFilePrefix'))
|
||||
.setDesc(getTranslation('settings.dailyFilePrefix.desc'));
|
||||
|
||||
this.dailyFilePrefixSetting = dailyFilePrefixSetting.controlEl.parentElement;
|
||||
|
||||
// 创建前缀输入框容器
|
||||
const prefixInputContainer = document.createElement('div');
|
||||
prefixInputContainer.classList.add(InputContainerCSS);
|
||||
dailyFilePrefixSetting.controlEl.appendChild(prefixInputContainer);
|
||||
|
||||
this.dailyFilePrefixInput = new TextComponent(prefixInputContainer)
|
||||
.setValue(settings.dailyFilePrefix || '')
|
||||
.onChange(async (value) => {
|
||||
// 设置已更改,准备自动保存
|
||||
this.dirtySettings = true;
|
||||
|
||||
// 启动自动保存定时器
|
||||
this.autoSaveDailyFilePrefix(value);
|
||||
});
|
||||
|
||||
// 给input元素设置类和placeholder属性
|
||||
if (this.dailyFilePrefixInput && this.dailyFilePrefixInput.inputEl) {
|
||||
this.dailyFilePrefixInput.inputEl.classList.add(InputCSS);
|
||||
this.dailyFilePrefixInput.inputEl.placeholder = getTranslation('settings.dailyFilePrefix.desc');
|
||||
}
|
||||
|
||||
// 添加前缀自动保存指示器
|
||||
const prefixSaveIndicator = document.createElement('div');
|
||||
prefixSaveIndicator.classList.add(SaveIndicatorCSS);
|
||||
prefixInputContainer.appendChild(prefixSaveIndicator);
|
||||
|
||||
// 创建前缀保存成功图标
|
||||
const prefixSaveSuccessIcon = document.createElement('span');
|
||||
prefixSaveSuccessIcon.classList.add('svg-icon', 'lucide-check', SuccessIconCSS);
|
||||
prefixSaveIndicator.appendChild(prefixSaveSuccessIcon);
|
||||
|
||||
// 记录前缀自动保存定时器
|
||||
let prefixAutoSaveTimer: number | null = null;
|
||||
|
||||
// 前缀自动保存方法
|
||||
this.autoSaveDailyFilePrefix = async (value: string) => {
|
||||
// 清除之前的定时器
|
||||
if (prefixAutoSaveTimer !== null) {
|
||||
window.clearTimeout(prefixAutoSaveTimer);
|
||||
}
|
||||
|
||||
// 设置新的定时器,延迟800ms保存(在用户停止输入后)
|
||||
prefixAutoSaveTimer = window.setTimeout(async () => {
|
||||
// 实际保存设置
|
||||
await this.settingsManager.updateSettings({ dailyFilePrefix: value });
|
||||
this.dirtySettings = false;
|
||||
|
||||
// 显示保存成功的视觉反馈
|
||||
prefixSaveIndicator.classList.add('save-indicator-visible');
|
||||
prefixSaveIndicator.classList.remove('save-indicator-hidden');
|
||||
window.setTimeout(() => {
|
||||
prefixSaveIndicator.classList.remove('save-indicator-visible');
|
||||
prefixSaveIndicator.classList.add('save-indicator-hidden');
|
||||
}, 1500);
|
||||
|
||||
}, 800);
|
||||
};
|
||||
|
||||
// 初始化日度文件前缀设置的可见性
|
||||
this.updateDailyFilePrefixVisibility(settings.fileGenerationMode);
|
||||
|
||||
// 语言设置
|
||||
// TODO: 应该使用Obsidian API的app.i18n.locale获取系统语言设置
|
||||
// 需要在manifest.json中设置minAppVersion: "1.8.0"或更高
|
||||
|
|
@ -398,9 +540,9 @@ export class DailyTaskSettingTab extends PluginSettingTab {
|
|||
resetBtn.buttonEl.addClass('daily-task-button-common');
|
||||
resetBtn.buttonEl.addClass('daily-task-button-lg');
|
||||
|
||||
// 添加重置图标
|
||||
// 添加重置图标 - 使用撤销图标更直观
|
||||
const resetIcon = document.createElement('span');
|
||||
resetIcon.classList.add('svg-icon', 'lucide-refresh-cw');
|
||||
resetIcon.classList.add('svg-icon', 'lucide-undo2');
|
||||
resetBtn.buttonEl.prepend(resetIcon);
|
||||
|
||||
// 添加重置事件
|
||||
|
|
@ -447,9 +589,9 @@ export class DailyTaskSettingTab extends PluginSettingTab {
|
|||
resetDefaultBtn.buttonEl.addClass('daily-task-button-common');
|
||||
resetDefaultBtn.buttonEl.addClass('daily-task-button-lg');
|
||||
|
||||
// 添加重置图标
|
||||
// 添加重置图标 - 使用返回主页图标表示恢复到默认状态
|
||||
const resetIcon2 = document.createElement('span');
|
||||
resetIcon2.classList.add('svg-icon', 'lucide-refresh-cw');
|
||||
resetIcon2.classList.add('svg-icon', 'lucide-home');
|
||||
resetDefaultBtn.buttonEl.prepend(resetIcon2);
|
||||
|
||||
// 为全局重置按钮添加事件处理
|
||||
|
|
@ -506,6 +648,20 @@ export class DailyTaskSettingTab extends PluginSettingTab {
|
|||
this.addTaskButton.buttonEl.prepend(calendarIcon);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新日度文件前缀设置的可见性
|
||||
* @param mode 文件生成模式
|
||||
*/
|
||||
private updateDailyFilePrefixVisibility(mode: FileGenerationMode): void {
|
||||
if (!this.dailyFilePrefixSetting) return;
|
||||
|
||||
if (mode === FileGenerationMode.DAILY) {
|
||||
this.dailyFilePrefixSetting.style.display = 'block';
|
||||
} else {
|
||||
this.dailyFilePrefixSetting.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新模板预览
|
||||
*/
|
||||
|
|
@ -725,4 +881,4 @@ export class SettingsManager {
|
|||
hasCustomTemplate(): boolean {
|
||||
return !!this.settings.customTemplate;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +1,10 @@
|
|||
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";
|
||||
import { appendToFile, ensureFileExists, ensureFolderExists, getTaskFilePath, todayTaskExists, fileContains, getYesterdayDate, getYesterdayTaskFilePath, extractTasksForDate, analyzeTaskCompletion, yesterdayStatisticsExists, generateStatisticsContent, getTaskFilePathByMode, getDailyTaskFilePath, getDailyTaskFolderPaths, dailyTaskFileExists, createDailyTaskFile } from "./utils/fileUtils";
|
||||
import { renderTemplate } from "./utils/templateEngine";
|
||||
import { getCurrentDate } from "./utils/dateUtils";
|
||||
import { FileGenerationMode } from "./models/settings";
|
||||
|
||||
/**
|
||||
* 任务生成器
|
||||
|
|
@ -21,12 +22,28 @@ export class TaskGenerator {
|
|||
}
|
||||
|
||||
/**
|
||||
* 生成每日任务
|
||||
* 生成每日任务(主入口方法)
|
||||
* @param openFile 是否打开文件
|
||||
* @param quietMode 静默模式,减少日志输出
|
||||
* @returns 成功或失败
|
||||
*/
|
||||
async generateDailyTask(openFile: boolean = true, quietMode: boolean = false): Promise<boolean> {
|
||||
const settings = this.settingsManager.getSettings();
|
||||
|
||||
if (settings.fileGenerationMode === FileGenerationMode.MONTHLY) {
|
||||
return await this.generateMonthlyTask(openFile, quietMode);
|
||||
} else {
|
||||
return await this.generateDailyTaskFile(openFile, quietMode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成月度任务文件(原有逻辑)
|
||||
* @param openFile 是否打开文件
|
||||
* @param quietMode 静默模式,减少日志输出
|
||||
* @returns 成功或失败
|
||||
*/
|
||||
private async generateMonthlyTask(openFile: boolean = true, quietMode: boolean = false): Promise<boolean> {
|
||||
try {
|
||||
const settings = this.settingsManager.getSettings();
|
||||
const rootDir = settings.rootDir.trim() || 'DailyTasks'; // 使用默认目录
|
||||
|
|
@ -145,6 +162,107 @@ export class TaskGenerator {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成日度任务文件(新增逻辑)
|
||||
* @param openFile 是否打开文件
|
||||
* @param quietMode 静默模式,减少日志输出
|
||||
* @returns 成功或失败
|
||||
*/
|
||||
private async generateDailyTaskFile(openFile: boolean = true, quietMode: boolean = false): Promise<boolean> {
|
||||
try {
|
||||
const settings = this.settingsManager.getSettings();
|
||||
const rootDir = settings.rootDir.trim() || 'DailyTasks';
|
||||
const prefix = settings.dailyFilePrefix || '';
|
||||
|
||||
// 获取日度任务文件路径
|
||||
const filePath = getDailyTaskFilePath(rootDir, prefix);
|
||||
|
||||
// 检查文件是否已存在
|
||||
const fileExists = await dailyTaskFileExists(this.vault, rootDir, prefix);
|
||||
|
||||
if (fileExists) {
|
||||
// 如果需要打开文件
|
||||
if (openFile) {
|
||||
// 显示提示并打开文件
|
||||
this.showWarningNotice(`📌 ${getTranslation('notification.dailyFileExists')}`);
|
||||
const file = this.vault.getAbstractFileByPath(filePath);
|
||||
if (file && file instanceof TFile) {
|
||||
const leaf = this.app.workspace.getLeaf();
|
||||
await leaf.openFile(file);
|
||||
}
|
||||
}
|
||||
|
||||
return true; // 文件已存在,视为成功
|
||||
}
|
||||
|
||||
// 获取年份和月份文件夹路径
|
||||
const { yearPath, monthPath } = getDailyTaskFolderPaths(rootDir);
|
||||
|
||||
// 确保根目录存在
|
||||
const rootCreated = await ensureFolderExists(this.vault, rootDir);
|
||||
if (!rootCreated) {
|
||||
throw new Error(`无法访问根目录: ${rootDir},可能是存在同名文件或权限问题`);
|
||||
}
|
||||
|
||||
// 确保年份目录存在
|
||||
const yearCreated = await ensureFolderExists(this.vault, yearPath);
|
||||
if (!yearCreated) {
|
||||
throw new Error(`无法访问年份目录: ${yearPath},可能是存在同名文件或权限问题`);
|
||||
}
|
||||
|
||||
// 确保月份目录存在
|
||||
const monthCreated = await ensureFolderExists(this.vault, monthPath);
|
||||
if (!monthCreated) {
|
||||
throw new Error(`无法访问月份目录: ${monthPath},可能是存在同名文件或权限问题`);
|
||||
}
|
||||
|
||||
// 获取任务模板内容
|
||||
let template = '';
|
||||
if (this.settingsManager.hasCustomTemplate()) {
|
||||
// 使用用户自定义模板
|
||||
template = this.settingsManager.getSettings().customTemplate;
|
||||
} else {
|
||||
// 使用语言相关的默认模板
|
||||
template = this.settingsManager.getTemplateByLanguage();
|
||||
}
|
||||
|
||||
// 渲染模板
|
||||
const renderedContent = renderTemplate(template);
|
||||
|
||||
// 创建日度任务文件(不追加,直接创建完整文件)
|
||||
const success = await createDailyTaskFile(this.vault, filePath, renderedContent);
|
||||
|
||||
if (success) {
|
||||
// 如果需要打开文件
|
||||
if (openFile) {
|
||||
// 打开创建的文件
|
||||
const file = this.vault.getAbstractFileByPath(filePath);
|
||||
if (file && file instanceof TFile) {
|
||||
const leaf = this.app.workspace.getLeaf();
|
||||
await leaf.openFile(file);
|
||||
|
||||
// 延迟一下再显示通知,确保文件已经打开
|
||||
setTimeout(() => {
|
||||
this.showSuccessNotice(`✨ ${getTranslation('notification.taskAdded')}`);
|
||||
}, 300);
|
||||
} else {
|
||||
throw new Error(`文件创建成功但无法打开: ${filePath}`);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new Error(`无法创建日度任务文件: ${filePath}`);
|
||||
}
|
||||
|
||||
return success;
|
||||
} catch (error) {
|
||||
// 显示错误通知
|
||||
const errorMsg = error instanceof Error ? error.message : String(error);
|
||||
this.showErrorNotice(`${getTranslation('notification.error')} ${errorMsg}`);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成昨日任务统计信息
|
||||
|
|
|
|||
|
|
@ -36,20 +36,21 @@ export function setTextContentByLines(targetEl: HTMLElement, textContent: string
|
|||
targetEl.removeChild(targetEl.firstChild);
|
||||
}
|
||||
|
||||
// 将内容按行分割
|
||||
const lines = textContent.split('\n');
|
||||
// 创建预格式化的div来保持原始格式
|
||||
const preEl = document.createElement('div');
|
||||
preEl.style.whiteSpace = 'pre-wrap';
|
||||
preEl.style.wordWrap = 'break-word';
|
||||
preEl.style.textAlign = 'left';
|
||||
preEl.style.margin = '0';
|
||||
preEl.style.padding = '0';
|
||||
preEl.style.fontFamily = 'inherit';
|
||||
preEl.style.lineHeight = 'inherit';
|
||||
|
||||
// 为每行创建一个div
|
||||
lines.forEach((line, index) => {
|
||||
const lineEl = document.createElement('div');
|
||||
lineEl.textContent = line;
|
||||
targetEl.appendChild(lineEl);
|
||||
|
||||
// 如果不是最后一行,添加换行符
|
||||
if (index < lines.length - 1) {
|
||||
targetEl.appendChild(document.createElement('br'));
|
||||
}
|
||||
});
|
||||
// 直接设置文本内容,保持原始格式
|
||||
preEl.textContent = textContent;
|
||||
|
||||
// 添加到目标元素
|
||||
targetEl.appendChild(preEl);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import { getCurrentDate, getCurrentMonth, getCurrentYear, getLocalizedMonthName,
|
|||
import { getTranslation, TranslationKey } from '../i18n/i18n';
|
||||
import { Notice } from 'obsidian';
|
||||
import { DEFAULT_SETTINGS } from '../settings/index';
|
||||
import { FileGenerationMode } from '../models/settings';
|
||||
|
||||
/**
|
||||
* 文件操作工具函数
|
||||
|
|
@ -175,6 +176,113 @@ export function getTaskFilePath(rootDir: string): string {
|
|||
return normalizePath(`${rootDir}/${yearDir}/${monthFile}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据文件生成模式和配置生成任务文件路径
|
||||
* @param rootDir 根目录
|
||||
* @param mode 文件生成模式
|
||||
* @param prefix 日度文件前缀(仅日度模式使用)
|
||||
* @returns 任务文件路径
|
||||
*/
|
||||
export function getTaskFilePathByMode(rootDir: string, mode: FileGenerationMode, prefix: string = ''): string {
|
||||
if (mode === FileGenerationMode.MONTHLY) {
|
||||
return getTaskFilePath(rootDir);
|
||||
} else {
|
||||
return getDailyTaskFilePath(rootDir, prefix);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据当前日期生成日度任务文件路径
|
||||
* @param rootDir 根目录
|
||||
* @param prefix 文件名前缀
|
||||
* @returns 日度任务文件路径,格式为:rootDir/year/monthFolder/prefix+date.md
|
||||
*/
|
||||
export function getDailyTaskFilePath(rootDir: string, prefix: string = ''): string {
|
||||
const now = new Date();
|
||||
const year = now.getFullYear();
|
||||
const month = now.getMonth() + 1; // 1-12
|
||||
const day = now.getDate();
|
||||
|
||||
const yearDir = year.toString();
|
||||
// 使用数字格式的月份文件夹,保持两位数格式
|
||||
const monthFolder = month.toString().padStart(2, '0');
|
||||
|
||||
// 生成日期字符串 YYYY-MM-DD
|
||||
const dateStr = `${year}-${month.toString().padStart(2, '0')}-${day.toString().padStart(2, '0')}`;
|
||||
|
||||
// 构建文件名:前缀 + 日期 + .md
|
||||
const fileName = prefix.trim() ? `${prefix.trim()}${dateStr}.md` : `${dateStr}.md`;
|
||||
|
||||
return normalizePath(`${rootDir}/${yearDir}/${monthFolder}/${fileName}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取日度任务文件的年份和月份文件夹路径
|
||||
* @param rootDir 根目录
|
||||
* @returns 包含年份路径和月份路径的对象
|
||||
*/
|
||||
export function getDailyTaskFolderPaths(rootDir: string): { yearPath: string; monthPath: string } {
|
||||
const now = new Date();
|
||||
const year = now.getFullYear();
|
||||
const month = now.getMonth() + 1; // 1-12
|
||||
|
||||
const yearDir = year.toString();
|
||||
const monthFolder = month.toString().padStart(2, '0');
|
||||
|
||||
const yearPath = normalizePath(`${rootDir}/${yearDir}`);
|
||||
const monthPath = normalizePath(`${rootDir}/${yearDir}/${monthFolder}`);
|
||||
|
||||
return { yearPath, monthPath };
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查日度任务文件是否已存在
|
||||
* @param vault Obsidian文件系统
|
||||
* @param rootDir 根目录
|
||||
* @param prefix 文件名前缀
|
||||
* @returns 是否已存在
|
||||
*/
|
||||
export async function dailyTaskFileExists(vault: Vault, rootDir: string, prefix: string = ''): Promise<boolean> {
|
||||
const filePath = getDailyTaskFilePath(rootDir, prefix);
|
||||
const file = vault.getAbstractFileByPath(filePath);
|
||||
return file !== null && file instanceof TFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建完整的日度任务文件(不追加内容)
|
||||
* @param vault Obsidian文件系统
|
||||
* @param filePath 文件路径
|
||||
* @param content 文件内容
|
||||
* @returns 是否成功创建
|
||||
*/
|
||||
export async function createDailyTaskFile(vault: Vault, filePath: string, content: string): Promise<boolean> {
|
||||
try {
|
||||
const normalizedPath = normalizePath(filePath);
|
||||
|
||||
// 确保文件夹结构存在
|
||||
const folderPath = normalizedPath.substring(0, normalizedPath.lastIndexOf('/'));
|
||||
if (folderPath) {
|
||||
const folderExists = await ensureFolderExists(vault, folderPath);
|
||||
if (!folderExists) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 检查文件是否已存在
|
||||
const existingFile = vault.getAbstractFileByPath(normalizedPath);
|
||||
if (existingFile) {
|
||||
return false; // 文件已存在,不重复创建
|
||||
}
|
||||
|
||||
// 创建新文件
|
||||
await vault.create(normalizedPath, content);
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查今日任务是否已存在
|
||||
* @param vault Obsidian文件系统
|
||||
|
|
|
|||
24
styles.css
24
styles.css
|
|
@ -256,15 +256,20 @@ button {
|
|||
|
||||
/* 模板预览容器 */
|
||||
.template-preview {
|
||||
background-color: var(--background-primary);
|
||||
border: 1px solid var(--background-modifier-border);
|
||||
border-radius: 5px;
|
||||
margin-top: 15px;
|
||||
padding: 15px;
|
||||
margin-top: 10px;
|
||||
max-height: 200px;
|
||||
overflow-y: auto;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
border: 1px dashed var(--background-modifier-border);
|
||||
border-radius: 8px;
|
||||
background-color: var(--background-secondary);
|
||||
display: none;
|
||||
max-height: 200px;
|
||||
overflow: auto;
|
||||
box-shadow: inset 0 0 5px rgba(0,0,0,0.1);
|
||||
text-align: left;
|
||||
line-height: 1.6;
|
||||
font-family: var(--font-text);
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.template-preview.visible {
|
||||
|
|
@ -672,6 +677,11 @@ button {
|
|||
max-height: 200px;
|
||||
overflow: auto;
|
||||
box-shadow: inset 0 0 5px rgba(0,0,0,0.1);
|
||||
text-align: left;
|
||||
line-height: 1.6;
|
||||
font-family: var(--font-text);
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.template-preview.visible {
|
||||
|
|
|
|||
Loading…
Reference in a new issue