getCustomPerspectiveTasks.ts•7.31 kB
import { executeOmniFocusScript } from '../../utils/scriptExecution.js';
export interface GetCustomPerspectiveTasksOptions {
perspectiveName: string;
hideCompleted?: boolean;
limit?: number;
showHierarchy?: boolean;
}
export async function getCustomPerspectiveTasks(options: GetCustomPerspectiveTasksOptions): Promise<string> {
const { perspectiveName, hideCompleted = true, limit = 1000, showHierarchy = false } = options;
if (!perspectiveName) {
return "❌ **错误**: 透视名称不能为空";
}
try {
// Execute the get custom perspective tasks script
const result = await executeOmniFocusScript('@getCustomPerspectiveTasks.js', {
perspectiveName: perspectiveName
});
// 处理各种可能的返回类型(避免之前的错误)
let data: any;
if (typeof result === 'string') {
try {
data = JSON.parse(result);
} catch (parseError) {
throw new Error(`解析字符串结果失败: ${result}`);
}
} else if (typeof result === 'object' && result !== null) {
data = result;
} else {
throw new Error(`脚本执行返回了无效的结果类型: ${typeof result}, 值: ${result}`);
}
// 检查是否有错误
if (!data.success) {
throw new Error(data.error || 'Unknown error occurred');
}
// 处理taskMap数据(新的层级结构)
const taskMap = data.taskMap || {};
const allTasks = Object.values(taskMap);
// 过滤已完成任务(如果需要)
let filteredTasks = allTasks;
if (hideCompleted) {
filteredTasks = allTasks.filter((task: any) => !task.completed);
}
if (filteredTasks.length === 0) {
return `**透视任务:${perspectiveName}**\n\n暂无${hideCompleted ? '未完成' : ''}任务。`;
}
// 根据是否显示层级关系选择不同的输出格式
if (showHierarchy) {
return formatHierarchicalTasks(perspectiveName, taskMap, hideCompleted);
} else {
return formatFlatTasks(perspectiveName, filteredTasks, limit, data.count);
}
} catch (error) {
console.error('Error in getCustomPerspectiveTasks:', error);
return `❌ **错误**: ${error instanceof Error ? error.message : String(error)}`;
}
}
// 格式化层级任务显示
function formatHierarchicalTasks(perspectiveName: string, taskMap: any, hideCompleted: boolean): string {
const header = `**透视任务:${perspectiveName}** (层级视图)\n\n`;
// 找到所有根任务(parent为null的任务)
const rootTasks = Object.values(taskMap).filter((task: any) => task.parent === null);
// 过滤已完成任务
const filteredRootTasks = hideCompleted
? rootTasks.filter((task: any) => !task.completed)
: rootTasks;
if (filteredRootTasks.length === 0) {
return header + `暂无${hideCompleted ? '未完成' : ''}根任务。`;
}
// 递归渲染任务树
const taskTreeLines: string[] = [];
filteredRootTasks.forEach((rootTask: any, index: number) => {
const isLast = index === filteredRootTasks.length - 1;
renderTaskTree(rootTask, taskMap, hideCompleted, '', isLast, taskTreeLines);
});
return header + taskTreeLines.join('\n');
}
// 递归渲染任务树
function renderTaskTree(task: any, taskMap: any, hideCompleted: boolean, prefix: string, isLast: boolean, lines: string[]): void {
// 当前任务的树状前缀
const currentPrefix = prefix + (isLast ? '└─ ' : '├─ ');
// 渲染当前任务
let taskLine = currentPrefix + formatTaskName(task);
lines.push(taskLine);
// 添加任务详细信息(缩进显示)
const detailPrefix = prefix + (isLast ? ' ' : '│ ');
const taskDetails = formatTaskDetails(task);
if (taskDetails.length > 0) {
taskDetails.forEach(detail => {
lines.push(detailPrefix + detail);
});
}
// 处理子任务
if (task.children && task.children.length > 0) {
const childTasks = task.children
.map((childId: string) => taskMap[childId])
.filter((child: any) => child && (!hideCompleted || !child.completed));
childTasks.forEach((childTask: any, index: number) => {
const isLastChild = index === childTasks.length - 1;
const childPrefix = prefix + (isLast ? ' ' : '│ ');
renderTaskTree(childTask, taskMap, hideCompleted, childPrefix, isLastChild, lines);
});
}
}
// 格式化任务名称
function formatTaskName(task: any): string {
let name = `**${task.name}**`;
if (task.completed) {
name = `~~${name}~~ [完成]`;
} else if (task.flagged) {
name = `[重要] ${name}`;
}
return name;
}
// 格式化任务详细信息
function formatTaskDetails(task: any): string[] {
const details: string[] = [];
if (task.project) {
details.push(`项目: ${task.project}`);
}
if (task.tags && task.tags.length > 0) {
details.push(`标签: ${task.tags.join(', ')}`);
}
if (task.dueDate) {
const dueDate = new Date(task.dueDate).toLocaleDateString();
details.push(`截止: ${dueDate}`);
}
if (task.estimatedMinutes) {
const hours = Math.floor(task.estimatedMinutes / 60);
const minutes = task.estimatedMinutes % 60;
if (hours > 0) {
details.push(`预估: ${hours}h${minutes > 0 ? ` ${minutes}m` : ''}`);
} else {
details.push(`预估: ${minutes}m`);
}
}
if (task.note && task.note.trim()) {
const notePreview = task.note.trim().substring(0, 60);
details.push(`备注: ${notePreview}${task.note.length > 60 ? '...' : ''}`);
}
return details;
}
// 格式化平铺任务显示(保持原有功能)
function formatFlatTasks(perspectiveName: string, tasks: any[], limit: number, totalCount: number): string {
// 限制任务数量
let displayTasks = tasks;
if (limit && limit > 0) {
displayTasks = tasks.slice(0, limit);
}
// 生成任务列表
const taskList = displayTasks.map((task: any, index: number) => {
let taskText = `${index + 1}. **${task.name}**`;
if (task.project) {
taskText += `\n 项目: ${task.project}`;
}
if (task.tags && task.tags.length > 0) {
taskText += `\n 标签: ${task.tags.join(', ')}`;
}
if (task.dueDate) {
const dueDate = new Date(task.dueDate).toLocaleDateString();
taskText += `\n 截止: ${dueDate}`;
}
if (task.flagged) {
taskText += `\n [重要]`;
}
if (task.estimatedMinutes) {
const hours = Math.floor(task.estimatedMinutes / 60);
const minutes = task.estimatedMinutes % 60;
if (hours > 0) {
taskText += `\n 预估: ${hours}h${minutes > 0 ? ` ${minutes}m` : ''}`;
} else {
taskText += `\n 预估: ${minutes}m`;
}
}
if (task.note && task.note.trim()) {
const notePreview = task.note.trim().substring(0, 100);
taskText += `\n 备注: ${notePreview}${task.note.length > 100 ? '...' : ''}`;
}
return taskText;
}).join('\n\n');
const header = `**透视任务:${perspectiveName}** (${displayTasks.length}个任务)\n\n`;
const footer = totalCount > displayTasks.length ? `\n\n提示: 共找到 ${totalCount} 个任务,显示 ${displayTasks.length} 个` : '';
return header + taskList + footer;
}