好的, 让我们来详细规划第 7 部分: 高级功能实现。我们将这部分分为 3 天, 每天专注于一个高级功能。
第 7 部分:高级功能实现 (3 天)
Day 1: 实现标签功能
- 更新 Todo 模型
在
src/types/todo.ts中:
export interface Todo {
id: string;
title: string;
description: string;
completed: boolean;
createdAt: string;
tags: string[];
}- 创建 TagInput 组件
在
src/components/TagInput.tsx中:
import React from 'react';
import { MultiSelect } from '@mantine/core';
interface TagInputProps {
value: string[];
onChange: (value: string[]) => void;
data: string[];
}
export const TagInput: React.FC<TagInputProps> = ({ value, onChange, data }) => {
return (
<MultiSelect
data={data}
value={value}
onChange={onChange}
label="Tags"
placeholder="Select tags"
searchable
creatable
getCreateLabel={(query) => `+ Create ${query}`}
onCreate={(query) => {
const item = { value: query, label: query };
onChange([...value, query]);
return item;
}}
/>
);
};- 更新 TodoForm 和 TodoEditForm 组件 在这两个组件中添加 TagInput:
import { TagInput } from './TagInput';
// 在表单中添加
<TagInput
value={form.values.tags}
onChange={(value) => form.setFieldValue('tags', value)}
data={existingTags}
/>- 更新 TodoList 组件以显示标签
在
src/components/TodoList.tsx中:
import { Badge } from '@mantine/core';
// 在表格中添加标签列
<td>
{todo.tags.map((tag) => (
<Badge key={tag} mr={5}>
{tag}
</Badge>
))}
</td>- 更新 API 服务以支持标签
在
src/services/api.ts中更新相关函数以包含标签操作。
Day 2: 实现截止日期和提醒功能
- 更新 Todo 模型
在
src/types/todo.ts中:
export interface Todo {
// ... 其他字段
dueDate: string | null;
reminder: string | null;
}- 创建 DateTimePicker 组件
在
src/components/DateTimePicker.tsx中:
import React from 'react';
import { DatePicker, TimeInput } from '@mantine/dates';
import { Stack } from '@mantine/core';
interface DateTimePickerProps {
value: Date | null;
onChange: (value: Date | null) => void;
label: string;
}
export const DateTimePicker: React.FC<DateTimePickerProps> = ({ value, onChange, label }) => {
return (
<Stack spacing="xs">
<DatePicker
label={label}
value={value}
onChange={(date) => {
if (date) {
const newDateTime = new Date(date);
if (value) {
newDateTime.setHours(value.getHours(), value.getMinutes());
}
onChange(newDateTime);
} else {
onChange(null);
}
}}
/>
<TimeInput
value={value}
onChange={(time) => {
if (time && value) {
const newDateTime = new Date(value);
newDateTime.setHours(time.getHours(), time.getMinutes());
onChange(newDateTime);
}
}}
/>
</Stack>
);
};- 更新 TodoForm 和 TodoEditForm 组件 在这两个组件中添加 DateTimePicker:
import { DateTimePicker } from './DateTimePicker';
// 在表单中添加
<DateTimePicker
label="Due Date"
value={form.values.dueDate ? new Date(form.values.dueDate) : null}
onChange={(value) => form.setFieldValue('dueDate', value ? value.toISOString() : null)}
/>
<DateTimePicker
label="Reminder"
value={form.values.reminder ? new Date(form.values.reminder) : null}
onChange={(value) => form.setFieldValue('reminder', value ? value.toISOString() : null)}
/>- 更新 TodoList 组件以显示截止日期和提醒
在
src/components/TodoList.tsx中:
import { Text } from '@mantine/core';
// 在表格中添加截止日期和提醒列
<td>
<Text size="sm">{todo.dueDate ? new Date(todo.dueDate).toLocaleString() : '-'}</Text>
</td>
<td>
<Text size="sm">{todo.reminder ? new Date(todo.reminder).toLocaleString() : '-'}</Text>
</td>- 实现提醒功能
创建一个新的
src/services/reminder.ts文件:
import { showNotification } from '@mantine/notifications';
export const checkReminders = (todos: Todo[]) => {
const now = new Date();
todos.forEach((todo) => {
if (todo.reminder && new Date(todo.reminder) <= now) {
showNotification({
title: 'Reminder',
message: `Todo "${todo.title}" is due soon!`,
color: 'yellow',
});
}
});
};在 App.tsx 中定期检查提醒:
import { useEffect } from 'react';
import { checkReminders } from './services/reminder';
// 在App组件中
useEffect(() => {
const interval = setInterval(() => {
checkReminders(todos);
}, 60000); // 每分钟检查一次
return () => clearInterval(interval);
}, [todos]);Day 3: 实现数据导入/导出功能
- 创建 ImportExport 组件
在
src/components/ImportExport.tsx中:
import React from 'react';
import { Button, Group } from '@mantine/core';
import { exportTodos, importTodos } from '../services/importExport';
interface ImportExportProps {
onImport: () => void;
}
export const ImportExport: React.FC<ImportExportProps> = ({ onImport }) => {
const handleExport = async () => {
try {
await exportTodos();
} catch (error) {
console.error('Failed to export todos', error);
}
};
const handleImport = async () => {
try {
await importTodos();
onImport();
} catch (error) {
console.error('Failed to import todos', error);
}
};
return (
<Group>
<Button onClick={handleExport}>Export Todos</Button>
<Button onClick={handleImport}>Import Todos</Button>
</Group>
);
};- 创建导入/导出服务
在
src/services/importExport.ts中:
import { getTodos, createTodo } from './api';
export const exportTodos = async () => {
const response = await getTodos();
const todos = response.data;
const blob = new Blob([JSON.stringify(todos, null, 2)], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = 'todos.json';
link.click();
URL.revokeObjectURL(url);
};
export const importTodos = async () => {
return new Promise<void>((resolve, reject) => {
const input = document.createElement('input');
input.type = 'file';
input.accept = 'application/json';
input.onchange = async (event) => {
const file = (event.target as HTMLInputElement).files?.[0];
if (file) {
try {
const content = await file.text();
const todos = JSON.parse(content);
for (const todo of todos) {
await createTodo(todo);
}
resolve();
} catch (error) {
reject(error);
}
}
};
input.click();
});
};- 在 Home 组件中添加 ImportExport 组件
在
src/pages/Home.tsx中:
import { ImportExport } from '../components/ImportExport';
// 在Home组件中
const handleImport = () => {
setRefreshTrigger((prev) => prev + 1);
};
// 在JSX中添加
<ImportExport onImport={handleImport} />这个详细计划涵盖了第 7 部分的高级功能实现, 包括标签功能、截止日期和提醒功能, 以及数据导入/导出功能。每个功能都有具体的实现步骤和相关代码示例。通过这些高级功能, LightweightTodo Pro 应用将更加强大和实用。