- 重复提醒完成流程优化: - 勾选完成重复提醒后,自动移除repeat_type、repeat_interval、next_reminder_date - 自动创建下一周期的新提醒记录 - 合并API调用,确保状态更新原子性 - 逾期列表展开/收起功能: - 默认收起,最多显示3条逾期提醒 - 超过3条时显示"还有 X 个逾期提醒..."链接 - 展开后底部显示"收起"按钮 - 时间显示优化: - 无时间提醒(00:00)只显示日期,不显示时间 - 归档列表同样适用此规则 - 其他优化: - 归档抖动动画反馈 - 分类折叠功能 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
198 lines
5.9 KiB
TypeScript
198 lines
5.9 KiB
TypeScript
import { useEffect } from 'react';
|
|
import {
|
|
Container,
|
|
Title,
|
|
Text,
|
|
Stack,
|
|
Paper,
|
|
Group,
|
|
Button,
|
|
ActionIcon,
|
|
Box,
|
|
} from '@mantine/core';
|
|
import { IconArrowLeft, IconRotateClockwise, IconTrash, IconArchive } from '@tabler/icons-react';
|
|
import { useNavigate } from 'react-router-dom';
|
|
import { useAppStore } from '../stores';
|
|
import type { Event } from '../types';
|
|
|
|
/**
|
|
* 格式化日期显示,根据是否有时间选择显示格式
|
|
*/
|
|
function formatArchiveDate(dateStr: string): string {
|
|
const date = new Date(dateStr);
|
|
const hours = date.getHours();
|
|
const minutes = date.getMinutes();
|
|
const hasExplicitTime = hours !== 0 || minutes !== 0;
|
|
|
|
if (hasExplicitTime) {
|
|
return date.toLocaleString('zh-CN', {
|
|
month: 'numeric',
|
|
day: 'numeric',
|
|
hour: '2-digit',
|
|
minute: '2-digit',
|
|
hour12: false,
|
|
});
|
|
} else {
|
|
return date.toLocaleString('zh-CN', {
|
|
month: 'numeric',
|
|
day: 'numeric',
|
|
});
|
|
}
|
|
}
|
|
|
|
export function ArchivePage() {
|
|
const navigate = useNavigate();
|
|
const events = useAppStore((state) => state.events);
|
|
const fetchEvents = useAppStore((state) => state.fetchEvents);
|
|
const updateEventById = useAppStore((state) => state.updateEventById);
|
|
const deleteEventById = useAppStore((state) => state.deleteEventById);
|
|
|
|
// 页面加载时获取数据
|
|
useEffect(() => {
|
|
const isAuthenticated = useAppStore.getState().isAuthenticated;
|
|
if (!isAuthenticated) {
|
|
navigate('/login', { replace: true });
|
|
} else {
|
|
fetchEvents();
|
|
}
|
|
}, [navigate, fetchEvents]);
|
|
|
|
// 获取已归档的提醒(已过期且已勾选的)
|
|
const archivedReminders = events.filter((e) => {
|
|
if (e.type !== 'reminder' || !e.is_completed) return false;
|
|
if (!e.date) return false; // 跳过无日期的
|
|
const eventDate = new Date(e.date);
|
|
const now = new Date();
|
|
return eventDate < now; // 仅已过期的
|
|
}).sort((a, b) => {
|
|
if (!a.date || !b.date) return 0;
|
|
return new Date(b.date).getTime() - new Date(a.date).getTime();
|
|
});
|
|
|
|
const handleRestore = async (event: Event) => {
|
|
await updateEventById(event.id, { is_completed: false });
|
|
};
|
|
|
|
const handleDelete = async (event: Event) => {
|
|
await deleteEventById(event.id);
|
|
};
|
|
|
|
return (
|
|
<Box
|
|
style={{
|
|
minHeight: '100vh',
|
|
background: '#faf9f7',
|
|
paddingTop: 80,
|
|
paddingBottom: 40,
|
|
}}
|
|
>
|
|
<Container size="xs">
|
|
{/* Header */}
|
|
<Group mb="lg">
|
|
<Button
|
|
variant="subtle"
|
|
color="gray"
|
|
size="xs"
|
|
leftSection={<IconArrowLeft size={14} />}
|
|
onClick={() => navigate(-1)}
|
|
style={{
|
|
letterSpacing: '0.1em',
|
|
borderRadius: 2,
|
|
}}
|
|
>
|
|
返回
|
|
</Button>
|
|
<Group gap="sm">
|
|
<IconArchive size={20} color="#666" />
|
|
<Title
|
|
order={2}
|
|
style={{
|
|
fontWeight: 300,
|
|
fontSize: '1.25rem',
|
|
letterSpacing: '0.15em',
|
|
color: '#1a1a1a',
|
|
}}
|
|
>
|
|
归档
|
|
</Title>
|
|
</Group>
|
|
</Group>
|
|
|
|
{/* Content */}
|
|
<Paper p="md" withBorder radius={4}>
|
|
{archivedReminders.length === 0 ? (
|
|
<Stack align="center" justify="center" py="xl">
|
|
<Text c="#999" size="sm" ta="center" style={{ letterSpacing: '0.05em' }}>
|
|
暂无已归档的提醒
|
|
</Text>
|
|
<Text size="xs" c="#bbb" ta="center" mt={4}>
|
|
完成的提醒会自动归档到这里
|
|
</Text>
|
|
</Stack>
|
|
) : (
|
|
<Stack gap="sm">
|
|
{archivedReminders.map((event) => (
|
|
<Paper
|
|
key={event.id}
|
|
p="sm"
|
|
radius={2}
|
|
withBorder
|
|
style={{
|
|
background: 'rgba(0, 0, 0, 0.02)',
|
|
borderColor: 'rgba(0, 0, 0, 0.06)',
|
|
}}
|
|
>
|
|
<Group justify="space-between" wrap="nowrap">
|
|
<Stack gap={4} style={{ flex: 1 }}>
|
|
<Text
|
|
size="sm"
|
|
fw={400}
|
|
lineClamp={1}
|
|
style={{
|
|
textDecoration: 'line-through',
|
|
color: '#999',
|
|
letterSpacing: '0.03em',
|
|
}}
|
|
>
|
|
{event.title}
|
|
</Text>
|
|
<Text size="xs" c="#bbb">
|
|
{formatArchiveDate(event.date)}
|
|
</Text>
|
|
{event.content && (
|
|
<Text size="xs" c="#bbb" lineClamp={1}>
|
|
{event.content}
|
|
</Text>
|
|
)}
|
|
</Stack>
|
|
<Group gap={4}>
|
|
<ActionIcon
|
|
size="sm"
|
|
variant="subtle"
|
|
onClick={() => handleRestore(event)}
|
|
style={{ color: '#666' }}
|
|
title="恢复"
|
|
>
|
|
<IconRotateClockwise size={14} />
|
|
</ActionIcon>
|
|
<ActionIcon
|
|
size="sm"
|
|
variant="subtle"
|
|
onClick={() => handleDelete(event)}
|
|
style={{ color: '#999' }}
|
|
title="删除"
|
|
>
|
|
<IconTrash size={14} />
|
|
</ActionIcon>
|
|
</Group>
|
|
</Group>
|
|
</Paper>
|
|
))}
|
|
</Stack>
|
|
)}
|
|
</Paper>
|
|
</Container>
|
|
</Box>
|
|
);
|
|
}
|