396 lines
11 KiB
TypeScript
396 lines
11 KiB
TypeScript
// pages/index/index.ts
|
||
import { todoStorage, ITodo, ITodoStats } from '../../utils/todoStorage';
|
||
|
||
Component({
|
||
data: {
|
||
activeTab: 'home',
|
||
stats: {} as ITodoStats,
|
||
todayTodos: [] as ITodo[],
|
||
recentTodos: [] as ITodo[],
|
||
greeting: '',
|
||
showAddSheet: false,
|
||
showDateTimePicker: false,
|
||
newTodoText: '',
|
||
newTodoPriority: 'medium' as 'high' | 'medium' | 'low',
|
||
newTodoCategory: '',
|
||
newTodoDeadline: 0,
|
||
newTodoNote: '',
|
||
dateTimeRange: [
|
||
[], // 年月日
|
||
[] // 时分
|
||
] as string[][],
|
||
dateTimeValue: [0, 0] as number[]
|
||
},
|
||
|
||
lifetimes: {
|
||
attached() {
|
||
this.loadData();
|
||
this.setGreeting();
|
||
}
|
||
},
|
||
|
||
pageLifetimes: {
|
||
show() {
|
||
this.loadData();
|
||
}
|
||
},
|
||
|
||
methods: {
|
||
// 加载数据
|
||
loadData() {
|
||
const stats = todoStorage.getStats();
|
||
const todayTodos = todoStorage.getTodayTodos();
|
||
const allTodos = todoStorage.getAllTodos();
|
||
const recentTodos = allTodos.slice(0, 5);
|
||
|
||
this.setData({
|
||
stats,
|
||
todayTodos,
|
||
recentTodos
|
||
});
|
||
},
|
||
|
||
// 获取成就图标
|
||
getAchievementIcon(completionRate: number): string {
|
||
if (completionRate === 100) return 'star-filled';
|
||
if (completionRate >= 80) return 'medal';
|
||
if (completionRate >= 60) return 'thumb-up';
|
||
if (completionRate >= 40) return 'check-circle';
|
||
if (completionRate >= 20) return 'time';
|
||
return 'hourglass';
|
||
},
|
||
|
||
// 获取成就颜色
|
||
getAchievementColor(completionRate: number): string {
|
||
if (completionRate === 100) return '#ffd700';
|
||
if (completionRate >= 80) return '#00a870';
|
||
if (completionRate >= 60) return '#0052d9';
|
||
if (completionRate >= 40) return '#ed7b2f';
|
||
if (completionRate >= 20) return '#666';
|
||
return '#999';
|
||
},
|
||
|
||
// 获取成就文本
|
||
getAchievementText(completionRate: number): string {
|
||
if (completionRate === 100) return '完美完成!';
|
||
if (completionRate >= 80) return '表现优秀';
|
||
if (completionRate >= 60) return '进展良好';
|
||
if (completionRate >= 40) return '稳步前进';
|
||
if (completionRate >= 20) return '开始行动';
|
||
return '加油冲刺';
|
||
},
|
||
|
||
// 设置问候语
|
||
setGreeting() {
|
||
const hour = new Date().getHours();
|
||
let greeting = '';
|
||
|
||
if (hour < 6) {
|
||
greeting = '夜深了,注意休息';
|
||
} else if (hour < 12) {
|
||
greeting = '早上好!新的一天开始了';
|
||
} else if (hour < 18) {
|
||
greeting = '下午好!继续加油';
|
||
} else {
|
||
greeting = '晚上好!今天过得怎么样';
|
||
}
|
||
|
||
this.setData({ greeting });
|
||
},
|
||
|
||
// 标签页切换
|
||
onTabChange(e: any) {
|
||
const targetPage = e.detail.value;
|
||
if (targetPage === 'list') {
|
||
wx.switchTab({ url: '/pages/list/list' });
|
||
} else if (targetPage === 'statistics') {
|
||
wx.switchTab({ url: '/pages/statistics/statistics' });
|
||
} else if (targetPage === 'settings') {
|
||
wx.switchTab({ url: '/pages/settings/settings' });
|
||
}
|
||
},
|
||
|
||
// 快速操作
|
||
goToTasks() {
|
||
wx.switchTab({ url: '/pages/list/list' });
|
||
},
|
||
|
||
goToStatistics() {
|
||
wx.switchTab({ url: '/pages/statistics/statistics' });
|
||
},
|
||
|
||
goToSettings() {
|
||
wx.switchTab({ url: '/pages/settings/settings' });
|
||
},
|
||
|
||
// 显示添加半屏
|
||
showAddSheet() {
|
||
this.initDateTimeRange();
|
||
this.setData({
|
||
showAddSheet: true,
|
||
newTodoText: '',
|
||
newTodoPriority: 'medium',
|
||
newTodoCategory: '',
|
||
newTodoDeadline: 0,
|
||
newTodoNote: ''
|
||
});
|
||
},
|
||
|
||
// 隐藏添加半屏
|
||
hideAddSheet() {
|
||
this.setData({ showAddSheet: false });
|
||
},
|
||
|
||
// 阻止事件冒泡
|
||
stopPropagation() {
|
||
// 空函数,用于阻止事件冒泡
|
||
},
|
||
|
||
// 输入新任务
|
||
onNewTodoInput(e: any) {
|
||
this.setData({ newTodoText: e.detail.value });
|
||
},
|
||
|
||
// 输入备注
|
||
onNewTodoNoteInput(e: any) {
|
||
this.setData({ newTodoNote: e.detail.value });
|
||
},
|
||
|
||
// 设置优先级
|
||
onPriorityChange(e: any) {
|
||
this.setData({ newTodoPriority: e.currentTarget.dataset.value });
|
||
},
|
||
|
||
// 设置分类
|
||
onCategoryChange(e: any) {
|
||
this.setData({ newTodoCategory: e.currentTarget.dataset.value });
|
||
},
|
||
|
||
// 初始化日期时间选择器
|
||
initDateTimeRange() {
|
||
const now = new Date();
|
||
const year = now.getFullYear();
|
||
const month = now.getMonth();
|
||
const date = now.getDate();
|
||
|
||
// 生成日期选项(今天及之后30天)
|
||
const dateOptions = [];
|
||
for (let i = 0; i < 30; i++) {
|
||
const d = new Date(year, month, date + i);
|
||
const dateStr = this.formatDateOption(d);
|
||
dateOptions.push(dateStr);
|
||
}
|
||
|
||
// 生成时间选项
|
||
const timeOptions = [];
|
||
for (let h = 0; h < 24; h++) {
|
||
for (let m = 0; m < 60; m += 30) {
|
||
const timeStr = `${h.toString().padStart(2, '0')}:${m.toString().padStart(2, '0')}`;
|
||
timeOptions.push(timeStr);
|
||
}
|
||
}
|
||
|
||
this.setData({
|
||
dateTimeRange: [dateOptions, timeOptions],
|
||
dateTimeValue: [0, 16] // 默认选择今天 08:00
|
||
});
|
||
},
|
||
|
||
// 格式化日期选项
|
||
formatDateOption(date: Date): string {
|
||
const now = new Date();
|
||
const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
|
||
const tomorrow = new Date(today.getTime() + 24 * 60 * 60 * 1000);
|
||
|
||
if (date.getTime() === today.getTime()) {
|
||
return '今天';
|
||
} else if (date.getTime() === tomorrow.getTime()) {
|
||
return '明天';
|
||
} else {
|
||
return `${date.getMonth() + 1}月${date.getDate()}日`;
|
||
}
|
||
},
|
||
|
||
// 显示日期时间选择器
|
||
showDateTimePicker() {
|
||
// 先触发选择器
|
||
const that = this;
|
||
wx.showActionSheet({
|
||
itemList: ['今天', '明天', '后天', '自定义日期'],
|
||
success(res) {
|
||
const now = new Date();
|
||
let selectedDate = new Date();
|
||
|
||
switch(res.tapIndex) {
|
||
case 0: // 今天
|
||
selectedDate = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 18, 0);
|
||
break;
|
||
case 1: // 明天
|
||
selectedDate = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1, 18, 0);
|
||
break;
|
||
case 2: // 后天
|
||
selectedDate = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 2, 18, 0);
|
||
break;
|
||
case 3: // 自定义
|
||
that.showCustomDatePicker();
|
||
return;
|
||
}
|
||
|
||
that.setData({
|
||
newTodoDeadline: selectedDate.getTime()
|
||
});
|
||
}
|
||
});
|
||
},
|
||
|
||
// 显示自定义日期选择器
|
||
showCustomDatePicker() {
|
||
const now = new Date();
|
||
const currentDate = `${now.getFullYear()}-${(now.getMonth() + 1).toString().padStart(2, '0')}-${now.getDate().toString().padStart(2, '0')}`;
|
||
const currentTime = `${now.getHours().toString().padStart(2, '0')}:${now.getMinutes().toString().padStart(2, '0')}`;
|
||
|
||
wx.showModal({
|
||
title: '选择截止时间',
|
||
content: '请在系统设置中选择日期和时间',
|
||
showCancel: true,
|
||
cancelText: '取消',
|
||
confirmText: '使用当前时间',
|
||
success: (res) => {
|
||
if (res.confirm) {
|
||
// 使用当前时间加1小时作为默认截止时间
|
||
const deadline = new Date();
|
||
deadline.setHours(deadline.getHours() + 1);
|
||
this.setData({
|
||
newTodoDeadline: deadline.getTime()
|
||
});
|
||
}
|
||
}
|
||
});
|
||
},
|
||
|
||
// 清除截止时间
|
||
clearDeadline() {
|
||
this.setData({
|
||
newTodoDeadline: 0
|
||
});
|
||
},
|
||
|
||
// 隐藏日期时间选择器
|
||
hideDateTimePicker() {
|
||
this.setData({ showDateTimePicker: false });
|
||
},
|
||
|
||
// 日期时间选择器改变
|
||
onDateTimeChange(e: any) {
|
||
const [dateIndex, timeIndex] = e.detail.value;
|
||
const { dateTimeRange } = this.data;
|
||
|
||
// 计算选择的日期时间
|
||
const now = new Date();
|
||
const selectedDate = new Date(now.getFullYear(), now.getMonth(), now.getDate() + dateIndex);
|
||
const timeStr = dateTimeRange[1][timeIndex];
|
||
const [hours, minutes] = timeStr.split(':').map(Number);
|
||
|
||
selectedDate.setHours(hours, minutes, 0, 0);
|
||
|
||
this.setData({
|
||
dateTimeValue: [dateIndex, timeIndex],
|
||
newTodoDeadline: selectedDate.getTime(),
|
||
showDateTimePicker: false
|
||
});
|
||
},
|
||
|
||
// 格式化日期时间显示
|
||
formatDateTime(timestamp: number): string {
|
||
const date = new Date(timestamp);
|
||
const now = new Date();
|
||
const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
|
||
const tomorrow = new Date(today.getTime() + 24 * 60 * 60 * 1000);
|
||
|
||
let dateStr = '';
|
||
if (date.toDateString() === today.toDateString()) {
|
||
dateStr = '今天';
|
||
} else if (date.toDateString() === tomorrow.toDateString()) {
|
||
dateStr = '明天';
|
||
} else {
|
||
dateStr = `${date.getMonth() + 1}月${date.getDate()}日`;
|
||
}
|
||
|
||
const timeStr = `${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}`;
|
||
return `${dateStr} ${timeStr}`;
|
||
},
|
||
|
||
// 添加新任务
|
||
addTodo() {
|
||
const { newTodoText, newTodoPriority, newTodoCategory, newTodoDeadline, newTodoNote } = this.data;
|
||
if (newTodoText.trim() === '') {
|
||
wx.showToast({
|
||
title: '请输入任务内容',
|
||
icon: 'none'
|
||
});
|
||
return;
|
||
}
|
||
|
||
todoStorage.addTodo(
|
||
newTodoText.trim(),
|
||
newTodoPriority,
|
||
newTodoCategory || undefined,
|
||
newTodoDeadline || undefined,
|
||
newTodoNote.trim() || undefined
|
||
);
|
||
|
||
this.hideAddSheet();
|
||
this.loadData();
|
||
|
||
wx.showToast({
|
||
title: '任务已添加',
|
||
icon: 'success'
|
||
});
|
||
},
|
||
|
||
// 切换任务状态
|
||
toggleTodo(e: any) {
|
||
const id = e.currentTarget.dataset.id;
|
||
todoStorage.toggleTodo(id);
|
||
this.loadData();
|
||
},
|
||
|
||
// 删除任务
|
||
deleteTodo(e: any) {
|
||
const id = e.currentTarget.dataset.id;
|
||
wx.showModal({
|
||
title: '确认删除',
|
||
content: '确定要删除这个任务吗?',
|
||
success: (res) => {
|
||
if (res.confirm) {
|
||
todoStorage.deleteTodo(id);
|
||
this.loadData();
|
||
wx.showToast({
|
||
title: '已删除',
|
||
icon: 'success'
|
||
});
|
||
}
|
||
}
|
||
});
|
||
},
|
||
|
||
// 格式化时间
|
||
formatTime(timestamp: number): string {
|
||
const date = new Date(timestamp);
|
||
const now = new Date();
|
||
const diff = now.getTime() - date.getTime();
|
||
const days = Math.floor(diff / (1000 * 60 * 60 * 24));
|
||
|
||
if (days === 0) {
|
||
return '今天';
|
||
} else if (days === 1) {
|
||
return '昨天';
|
||
} else if (days < 7) {
|
||
return `${days}天前`;
|
||
} else {
|
||
return date.toLocaleDateString();
|
||
}
|
||
}
|
||
}
|
||
});
|