从 0 到 1 用 Trae 开发番茄钟:解锁时间管理新姿势

我正在参加Trae「超级体验官」创意实践征文,本文所使用的 Trae 免费下载链接:https://www.trae.com.cn/?utm_source=juejin&utm_medium=juejin_trae&utm_campaign=422content

前言

番茄钟是一种时间管理方法和工具,最近由于我比较摆烂,就萌生出了想做一款属于自己的番茄钟在电脑桌面记录着我的学习,但是由于我不知道如何使用代码完成这一个小项目,我就苦恼了很久,但是最近trae突然爆火,我就想试试到底有传说中的那么厉害
image.png
下面是我制作出来的番茄钟效果展示:

番茄钟

摸鱼让trae帮我做一个番茄钟

我们下载好了之后进行登录,发现右侧栏就是我们询问ai的界面了,因为我们的这个主题是让他帮我生成一款电脑番茄钟软件,我们直接用小白话术和他对话:我现在想在电脑上做一款番茄钟应用,请你帮我实现
image.png

ai的反应速度还是蛮快的,并且回复我们的话也是很有逻辑的
他还生成了一个requirements.txt来告诉我们需要安装什么依赖
以及一个README.md来告诉我们这款软件的基本信息、功能特点、安装说明、使用方法等关键内容
image.png

等待他生成代码之后,我们直接在终端输入命令python pomodoro.py运行这个文件
下面是效果展示
image.png
但是感觉还是有点单调说实话,正常来说,番茄钟是可以进行设置番茄时间、休息时间,还能统计任务完成情况,实体番茄钟则通常具有简单直观的操作界面,通过旋转表盘或按下按钮来启动计时。

他这个初步生成的代码虽然还不错,但是的话还远远达不到我们的预期,于是我们就继续进行ai代码生成,将我们的要求输送给他

在第二次ai代码生成的时候,我对他说:
正常来说,番茄钟是可以进行设置番茄时间、休息时间,还能统计任务完成情况,实体番茄钟则通常具有简单直观的操作界面,通过旋转表盘或按下按钮来启动计时。,而不是单单就是25分钟,可以自定义设定时间,并且可以设置任务
他的回答如下,在本次ai中他在代码中增加了时间自定义的能力以及添加添加任务的需求
image.png
依旧输入命令python pomodoro.py运行下
效果如下:
image.png

体验下来我说说我的想法:能进行计时操作,可以添加任务,但是这个任务似乎点击完成任务不能消失,并且添加任务和这个时间都放在了同一个页面上,是否能搞成和手机番茄钟那样的效果呢?

下面是我在手机番茄钟找的界面效果图
对比我们当前的界面,我们缺少的是多样化的界面,历史数据统计,个人主页,导航栏
4c49e68c4a686140379a31ee0fbf20c8.jpg
有了这些需求,我们直接将这些需求喂给ai,让他帮我们解决
根绝我的需求,他会根据每个需求点来创建对应的代码文件image.png
在本次改动下
ai已经完成了对番茄钟应用的重大改进,根据我的需求实现了多页面导航和更丰富的功能。主要更新包括:

  1. 创建了新的多页面主窗口架构:

    • 实现了底部导航栏,可以在不同功能页面之间切换
    • 将原有的单一界面拆分为四个独立的功能页面
  2. 改进了计时器页面(PomodoroTimer):

    • 将原有的主窗口类改造为可重用的组件
    • 保留了核心的计时和提醒功能
  3. 新增了独立的任务管理页面(TaskManager):

    • 分离了任务列表功能
    • 实现了已完成任务的自动隐藏(移动到已完成任务列表)
    • 优化了任务管理界面的布局
  4. 添加了统计数据页面(Statistics):

    • 提供今日、本周、本月的统计数据
    • 显示专注时长和任务完成情况
    • 使用滚动区域展示详细统计信息
  5. 创建了个人主页(Profile):

    • 提供用户个性化设置
    • 可以设置默认的工作和休息时长
    • 支持主题切换和提示音设置
      这些改进使应用更加符合现代移动应用的设计理念,提供了更好的用户体验。用户现在可以:
  • 在不同功能页面之间自由切换
  • 查看任务完成历史
  • 追踪使用数据统计
  • 个性化定制应用设置
    新的界面结构更加清晰,功能更加完整,为用户提供了更好的时间管理和任务追踪体验。

但是这个代码貌似运行不了,我们直接将问题反馈给ai,让他帮我们解决问题image.png
他会逐个文件帮我分析代码,检查是否是组件的问题,以及文件之间的关联性
image.png
在代码修正之后,点击运行,效果稍微还行,有了底部的导航界面,但是还是没有达到心中预期,那么我们再次进行代码的修改
a9eb12e49b966c324ea402a0467639a9.jpg
这一次我们的要求是:这个历史数据是否能够保存呢?每次打开这个程序都会存在历史数据呢?这个任务管理虽然可以将进行中的任务进行完成,但是我如果想将这个任务删除呢?好像没有方法进行删除操作,这个主页的话能否移除这个任务列表,因为我觉得这个任务列表在底部的任务里面已经有了,那么就没必要重复出现了,界面再稍微优化下,仍然是有些单调
67867d1b4f3f39673dc0c2b67b7570a8.jpg

经过修改之后
image.png
image.png
效果还是蛮不错的,完成任务还有弹窗,并且可以进行任务的删除操作以及任务的累计操作,在工作时间结束之后系统会有提示音,但是还是不足
这个统计数据面板好像没用啊,并不能统计我完成过的任务
计时的那个页面也是的,不能统计我今天的专注时间,我在将程序退出之后,之前删除的任务也出现在这里了,并且下面的已经完成的任务没有进行统计操作

直接询问ai
image.png

image.png
代码改变之后

  1. 添加了实时记录专注时间的功能:
  • 新增 accumulated_focus_time 变量,用于累计专注时间(以秒为单位)

  • 每秒钟都会累加专注时间

  • 每满一分钟就保存一次专注时间到数据管理器中

  1. 在以下情况下会保存专注时间:
  • 每满一分钟自动保存

  • 点击暂停时保存

  • 点击重置时保存

  • 工作时间结束时保存

  • 关闭窗口时保存

  1. 优化了专注时间的计算:
  • 只在工作时间段计算专注时间

  • 保留不足一分钟的秒数,下次继续累加

  • 确保所有专注时间都被正确记录

  1. 添加了窗口关闭事件处理:
  • 在关闭窗口时保存未记录的专注时间

这些修改确保了:

  1. 专注时间会实时累计

  2. 即使中途暂停或重置,已经专注的时间也不会丢失

  3. 时间统计更加准确

现在您可以重新运行程序,专注时间应该会正确累计到统计数据中。每次暂停、重置或完成一个工作周期时,都会看到统计数据的更新。

image.png
image.png
每次我们重新进入到程序之后,他会显示我们历史的专注时长
至此,我们的番茄钟就搞定了,其实我这里的还是比较简单的,如果你们真的想开发出一个属于自己的番茄钟的话,可以多花点时间在trae上面,进行魔改
下面是我的几个改进方案,大家可以考虑下:

  • 可以对图标进行改变,改成一个番茄图标
  • 可以对提示音进行改进,每次计时完成时候将默认的声音改成二次元的声音
  • 将背景颜色进行改变
  • 对每个按钮进行一个UI设置,设置为自己喜欢的图案
  • 切换界面更加流畅不卡顿
    我发现他是使用了一个文件来保存我每次设置的任务的,然后每次启动读取这个数据来获取历史信息,这个想法确实厉害,值得学习下
    image.png

下面是我的RAEDME文件,大家可以进行一个参考

README文件详情

番茄钟应用

一个基于PyQt5开发的简洁番茄钟计时器应用,帮助用户提高工作效率和时间管理能力。具有任务管理、时间统计等功能。

功能特点

  • 可自定义工作时间(1-60分钟)和休息时间(1-30分钟)

  • 完整的任务管理系统

    • 添加、完成、删除任务

    • 查看任务完成历史

    • 任务持久化存储

  • 专注时间统计

    • 今日专注时长统计

    • 本周专注时长统计

    • 本月专注时长统计

    • 任务完成数量统计

  • 简洁直观的用户界面

    • 实时倒计时显示

    • 工作/休息状态自动切换

    • 时间结束提示音

    • 开始/暂停/继续/重置功能

  • 数据持久化

    • 自动保存专注时间

    • 自动保存任务状态

    • 程序重启后保持数据

技术实现

  • 使用PyQt5构建图形用户界面

  • 采用QTimer实现精确计时

  • JSON文件实现数据持久化存储

  • 模块化设计,功能解耦

  • 使用winsound实现提示音效

安装说明

  1. 确保已安装Python 3.x

  2. 安装依赖包:

    
    pip install -r requirements.txt
    
    

使用方法

  1. 运行程序:

    
    python main.py
    
    
  2. 操作说明:

    • 计时功能:

      • 点击"开始"按钮启动计时器

      • 计时过程中可点击"暂停"按钮暂停计时

      • 暂停状态下可点击"继续"按钮继续计时

      • 点击"重置"按钮重置计时器

      • 时间结束时会自动切换工作/休息状态并播放提示音

    • 任务管理:

      • 在任务页面可以添加新任务

      • 点击"完成任务"标记任务为已完成

      • 点击"删除任务"移除任务

    • 统计功能:

      • 在统计页面可以查看专注时间统计

      • 包括今日、本周、本月的专注时长

      • 查看各时间段内完成的任务数量

项目结构


番茄钟软件/

├── main.py           # 程序入口

├── main_window.py    # 主窗口管理

├── pomodoro.py       # 番茄钟计时器

├── task_manager.py   # 任务管理模块

├── statistics.py     # 统计功能模块

├── data_manager.py   # 数据管理模块

├── profile.py        # 用户配置模块

├── requirements.txt  # 项目依赖文件

└── pomodoro_data.json # 数据存储文件

开发环境

  • Python 3.x

  • PyQt5 >= 5.15.0

  • Windows操作系统(提示音功能)

数据存储

应用数据存储在 pomodoro_data.json 文件中,包含:

  • 任务列表

  • 已删除的任务

  • 专注时间记录

注意事项

  1. 专注时间会在以下情况自动保存:

    • 每完成一个工作周期

    • 暂停计时器时

    • 重置计时器时

    • 关闭程序时

  2. 统计数据实时更新,可以随时查看当前的专注状况

  3. 所有数据都会自动保存,重启程序后可以继续查看历史记录

具体代码

data_manager.py

import json

from datetime import datetime, timedelta

import os

  

class DataManager:

    def __init__(self):

        self.data_file = 'pomodoro_data.json'

        self.tasks = []

        self.focus_time = []  # [(duration_minutes, datetime), ...]

        self.deleted_tasks = []  # 存储已删除的任务

        self.load_data()

    def save_data(self):

        data = {

            'tasks': [{

                'content': task['content'],

                'created_at': task['created_at'].isoformat(),

                'completed': task['completed'],

                'completed_at': task['completed_at'].isoformat() if task.get('completed_at') else None

            } for task in self.tasks],

            'focus_time': [[duration, dt.isoformat()] for duration, dt in self.focus_time],

            'deleted_tasks': [{

                'content': task['content'],

                'created_at': task['created_at'].isoformat(),

                'completed': task['completed'],

                'completed_at': task['completed_at'].isoformat() if task.get('completed_at') else None,

                'deleted_at': task['deleted_at'].isoformat()

            } for task in self.deleted_tasks]

        }

        with open(self.data_file, 'w', encoding='utf-8') as f:

            json.dump(data, f, ensure_ascii=False, indent=2)

    def load_data(self):

        if not os.path.exists(self.data_file):

            return

        try:

            with open(self.data_file, 'r', encoding='utf-8') as f:

                data = json.load(f)

                # 使用集合来去除重复的任务

                unique_tasks = {}

                for task in data.get('tasks', []):

                    key = (task['content'], task['created_at'])

                    if key not in unique_tasks:

                        unique_tasks[key] = {

                            'content': task['content'],

                            'created_at': datetime.fromisoformat(task['created_at']),

                            'completed': task['completed'],

                            'completed_at': datetime.fromisoformat(task['completed_at']) if task.get('completed_at') else None

                        }

                self.tasks = list(unique_tasks.values())

                self.focus_time = [(duration, datetime.fromisoformat(dt))

                                  for duration, dt in data.get('focus_time', [])]

                if 'deleted_tasks' in data:

                    self.deleted_tasks = [{

                        'content': task['content'],

                        'created_at': datetime.fromisoformat(task['created_at']),

                        'completed': task['completed'],

                        'completed_at': datetime.fromisoformat(task['completed_at']) if task.get('completed_at') else None,

                        'deleted_at': datetime.fromisoformat(task['deleted_at'])

                    } for task in data['deleted_tasks']]

        except Exception as e:

            print(f'Error loading data: {e}')

    def add_task(self, task):

        # 检查是否存在相同内容和创建时间的任务

        for existing_task in self.tasks:

            if (existing_task['content'] == task['content'] and

                existing_task['created_at'] == task['created_at']):

                return  # 如果任务已存在,则不添加

        self.tasks.append(task)

        self.save_data()

    def update_task(self, task):

        for i, t in enumerate(self.tasks):

            if t['content'] == task['content'] and not t['completed']:

                self.tasks[i] = task

                break

        self.save_data()

    def add_focus_time(self, duration_minutes):

        self.focus_time.append((duration_minutes, datetime.now()))

        self.save_data()

    def get_tasks(self):

        return self.tasks

    def get_focus_time(self):

        return self.focus_time

    def delete_task(self, task_content):

        for i, task in enumerate(self.tasks):

            if task['content'] == task_content:

                deleted_task = self.tasks.pop(i)

                deleted_task['deleted_at'] = datetime.now()

                self.deleted_tasks.append(deleted_task)

                self.save_data()

                break

    def get_deleted_tasks(self):

        return self.deleted_tasks

  

    def get_statistics(self, period='today'):

        now = datetime.now()

        if period == 'today':

            start_time = datetime(now.year, now.month, now.day)

        elif period == 'week':

            start_time = now - timedelta(days=now.weekday())

            start_time = datetime(start_time.year, start_time.month, start_time.day)

        elif period == 'month':

            start_time = datetime(now.year, now.month, 1)

        else:

            return 0, 0  # 默认返回0

  

        # 计算专注时间

        total_focus_time = sum(duration for duration, dt in self.focus_time if dt >= start_time)

        # 计算完成的任务数

        completed_tasks = sum(1 for task in self.tasks

                            if task['completed']

                            and task.get('completed_at')

                            and task['completed_at'] >= start_time)

        return total_focus_time, completed_tasks

  

    def get_today_focus_time(self):

        total_time, _ = self.get_statistics('today')

        hours = total_time // 60

        minutes = total_time % 60

        return f"{hours}小时{minutes}分钟"

main_window.py

import sys

from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,

                           QStackedWidget, QPushButton, QLabel)

from PyQt5.QtCore import Qt

from PyQt5.QtGui import QFont

from pomodoro import PomodoroTimer

from task_manager import TaskManager

from statistics import Statistics

from profile import Profile

  

class MainWindow(QMainWindow):

    def __init__(self):

        super().__init__()

        self.setWindowTitle('番茄钟')

        self.setGeometry(100, 100, 400, 600)

        # 创建主窗口部件

        central_widget = QWidget()

        self.setCentralWidget(central_widget)

        layout = QVBoxLayout(central_widget)

        # 创建堆叠部件用于页面切换

        self.stack = QStackedWidget()

        # 添加各个页面

        self.timer_page = PomodoroTimer()

        self.task_page = QWidget()

        self.stats_page = QWidget()

        self.profile_page = QWidget()

        # 创建各个页面的实例

        self.task_page = TaskManager()

        self.stats_page = Statistics()

        self.profile_page = Profile()

        # 将页面添加到堆叠部件中

        self.stack.addWidget(self.timer_page)

        self.stack.addWidget(self.task_page)

        self.stack.addWidget(self.stats_page)

        self.stack.addWidget(self.profile_page)

        layout.addWidget(self.stack)

        # 创建底部导航栏

        nav_bar = QHBoxLayout()

        # 创建导航按钮

        self.timer_btn = QPushButton('计时')

        self.task_btn = QPushButton('任务')

        self.stats_btn = QPushButton('统计')

        self.profile_btn = QPushButton('我的')

        # 设置按钮点击事件

        self.timer_btn.clicked.connect(lambda: self.stack.setCurrentIndex(0))

        self.task_btn.clicked.connect(lambda: self.stack.setCurrentIndex(1))

        self.stats_btn.clicked.connect(lambda: self.stack.setCurrentIndex(2))

        self.profile_btn.clicked.connect(lambda: self.stack.setCurrentIndex(3))

        # 添加按钮到导航栏

        nav_bar.addWidget(self.timer_btn)

        nav_bar.addWidget(self.task_btn)

        nav_bar.addWidget(self.stats_btn)

        nav_bar.addWidget(self.profile_btn)

        layout.addLayout(nav_bar)

  
  

def main():

    app = QApplication(sys.argv)

    window = MainWindow()

    window.show()

    sys.exit(app.exec_())

  

if __name__ == '__main__':

    main()

main.py

import sys

from PyQt5.QtWidgets import QApplication

from main_window import MainWindow

  

def main():

    app = QApplication(sys.argv)

    window = MainWindow()

    window.show()

    sys.exit(app.exec_())

  

if __name__ == '__main__':

    main()

pomdoro.py

import sys

from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QPushButton, QLabel,

                           QSpinBox, QHBoxLayout)

from PyQt5.QtCore import QTimer, Qt

from PyQt5.QtGui import QFont

import winsound

from datetime import datetime

from data_manager import DataManager

  

class PomodoroTimer(QMainWindow):

    def __init__(self, parent=None):

        super().__init__(parent)

        # 初始化变量

        self.work_duration = 25  # 默认工作时间(分钟)

        self.break_duration = 5   # 默认休息时间(分钟)

        self.time_left = self.work_duration * 60

        self.is_break = False

        self.timer = QTimer()

        self.timer.timeout.connect(self.update_timer)

        self.is_running = False

        self.data_manager = DataManager()

        self.accumulated_focus_time = 0  # 累计专注时间(秒)

        self.last_focus_time = None  # 上次记录时间

        # 创建专注时间更新计时器

        self.focus_timer = QTimer()

        self.focus_timer.timeout.connect(self.update_focus_time)

        self.focus_timer.start(60000)  # 每分钟更新一次

        # 创建主窗口部件

        central_widget = QWidget()

        self.setCentralWidget(central_widget)

        layout = QVBoxLayout(central_widget)

        # 创建时间设置部分

        time_settings = QHBoxLayout()

        # 工作时间设置

        work_layout = QVBoxLayout()

        work_label = QLabel('工作时间(分钟):')

        self.work_spinbox = QSpinBox()

        self.work_spinbox.setRange(1, 60)

        self.work_spinbox.setValue(self.work_duration)

        self.work_spinbox.valueChanged.connect(self.update_work_duration)

        work_layout.addWidget(work_label)

        work_layout.addWidget(self.work_spinbox)

        time_settings.addLayout(work_layout)

        # 休息时间设置

        break_layout = QVBoxLayout()

        break_label = QLabel('休息时间(分钟):')

        self.break_spinbox = QSpinBox()

        self.break_spinbox.setRange(1, 30)

        self.break_spinbox.setValue(self.break_duration)

        self.break_spinbox.valueChanged.connect(self.update_break_duration)

        break_layout.addWidget(break_label)

        break_layout.addWidget(self.break_spinbox)

        time_settings.addLayout(break_layout)

        layout.addLayout(time_settings)

        # 创建时间显示标签

        self.time_label = QLabel('25:00')

        self.time_label.setAlignment(Qt.AlignCenter)

        self.time_label.setFont(QFont('Arial', 60))

        layout.addWidget(self.time_label)

        # 创建状态标签

        self.status_label = QLabel('工作时间')

        self.status_label.setAlignment(Qt.AlignCenter)

        self.status_label.setFont(QFont('Arial', 20))

        layout.addWidget(self.status_label)

        # 创建专注信息显示

        self.focus_label = QLabel('今日专注:0小时0分钟')

        self.focus_label.setAlignment(Qt.AlignCenter)

        self.focus_label.setFont(QFont('Arial', 12))

        layout.addWidget(self.focus_label)

        # 创建控制按钮

        button_layout = QHBoxLayout()

        self.start_button = QPushButton('开始')

        self.start_button.clicked.connect(self.toggle_timer)

        button_layout.addWidget(self.start_button)

        self.reset_button = QPushButton('重置')

        self.reset_button.clicked.connect(self.reset_timer)

        button_layout.addWidget(self.reset_button)

        layout.addLayout(button_layout)

        # 初始化显示

        self.update_focus_time()

    def update_timer(self):

        if self.time_left > 0:

            self.time_left -= 1

            if not self.is_break:  # 只在工作时间计算专注时间

                self.accumulated_focus_time += 1

                # 每分钟保存一次专注时间

                if self.accumulated_focus_time % 60 == 0:

                    self.save_focus_time()

            minutes = self.time_left // 60

            seconds = self.time_left % 60

            self.time_label.setText(f'{minutes:02d}:{seconds:02d}')

        else:

            self.timer.stop()

            winsound.Beep(1000, 1000)  # 发出提示音

            if not self.is_break:

                # 保存剩余的专注时间

                self.save_focus_time()

                self.accumulated_focus_time = 0

                self.time_left = self.break_duration * 60

                self.is_break = True

                self.status_label.setText('休息时间')

            else:

                self.time_left = self.work_duration * 60

                self.is_break = False

                self.status_label.setText('工作时间')

            self.is_running = False

            self.start_button.setText('开始')

            self.update_display()

    def toggle_timer(self):

        if not self.is_running:

            self.timer.start(1000)

            self.is_running = True

            self.start_button.setText('暂停')

            if not self.is_break:

                self.last_focus_time = datetime.now()

        else:

            self.timer.stop()

            self.is_running = False

            self.start_button.setText('继续')

            if not self.is_break:

                self.save_focus_time()

    def reset_timer(self):

        if self.is_running and not self.is_break:

            self.save_focus_time()

        self.timer.stop()

        self.time_left = self.work_duration * 60

        self.is_break = False

        self.is_running = False

        self.start_button.setText('开始')

        self.status_label.setText('工作时间')

        self.accumulated_focus_time = 0

        self.update_display()

    def save_focus_time(self):

        # 保存累计的专注时间(转换为分钟)

        if self.accumulated_focus_time > 0:

            minutes = self.accumulated_focus_time // 60

            if minutes > 0:

                self.data_manager.add_focus_time(minutes)

                self.accumulated_focus_time = self.accumulated_focus_time % 60  # 保留不足1分钟的秒数

                self.update_focus_time()

    def update_work_duration(self, value):

        self.work_duration = value

        if not self.is_running and not self.is_break:

            self.time_left = value * 60

            self.update_display()

    def update_break_duration(self, value):

        self.break_duration = value

    def update_focus_time(self):

        # 使用 DataManager 的统计功能获取今日专注时间

        self.focus_label.setText(f'今日专注:{self.data_manager.get_today_focus_time()}')

    def update_display(self):

        minutes = self.time_left // 60

        seconds = self.time_left % 60

        self.time_label.setText(f'{minutes:02d}:{seconds:02d}')

    def showEvent(self, event):

        super().showEvent(event)

        self.update_focus_time()  # 每次显示页面时更新专注时间

    def closeEvent(self, event):

        if self.is_running and not self.is_break:

            self.save_focus_time()  # 确保关闭窗口时保存专注时间

        super().closeEvent(event)

profile.py

from PyQt5.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QLabel, QPushButton,

                           QComboBox, QSpinBox, QLineEdit)

from PyQt5.QtCore import Qt

from PyQt5.QtGui import QFont

import json

import os

  

class Profile(QWidget):

    def __init__(self, parent=None):

        super().__init__(parent)

        self.setup_ui()

    def setup_ui(self):

        layout = QVBoxLayout(self)

        # 标题

        title = QLabel('个人主页')

        title.setAlignment(Qt.AlignCenter)

        title.setFont(QFont('Arial', 20))

        layout.addWidget(title)

        # 用户信息

        info_layout = QVBoxLayout()

        # 用户名设置

        username_layout = QHBoxLayout()

        username_label = QLabel('用户名:')

        self.username_edit = QLineEdit()

        username_layout.addWidget(username_label)

        username_layout.addWidget(self.username_edit)

        info_layout.addLayout(username_layout)

        # 默认工作时长设置

        work_time_layout = QHBoxLayout()

        work_time_label = QLabel('默认工作时长(分钟):')

        self.work_time_spin = QSpinBox()

        self.work_time_spin.setRange(1, 60)

        self.work_time_spin.setValue(25)

        work_time_layout.addWidget(work_time_label)

        work_time_layout.addWidget(self.work_time_spin)

        info_layout.addLayout(work_time_layout)

        # 默认休息时长设置

        break_time_layout = QHBoxLayout()

        break_time_label = QLabel('默认休息时长(分钟):')

        self.break_time_spin = QSpinBox()

        self.break_time_spin.setRange(1, 30)

        self.break_time_spin.setValue(5)

        break_time_layout.addWidget(break_time_label)

        break_time_layout.addWidget(self.break_time_spin)

        info_layout.addLayout(break_time_layout)

        # 主题设置

        theme_layout = QHBoxLayout()

        theme_label = QLabel('主题:')

        self.theme_combo = QComboBox()

        self.theme_combo.addItems(['浅色', '深色'])

        theme_layout.addWidget(theme_label)

        theme_layout.addWidget(self.theme_combo)

        info_layout.addLayout(theme_layout)

        # 提示音设置

        sound_layout = QHBoxLayout()

        sound_label = QLabel('提示音:')

        self.sound_combo = QComboBox()

        self.sound_combo.addItems(['默认', '静音'])

        sound_layout.addWidget(sound_label)

        sound_layout.addWidget(self.sound_combo)

        info_layout.addLayout(sound_layout)

        layout.addLayout(info_layout)

        # 保存按钮

        save_button = QPushButton('保存设置')

        save_button.clicked.connect(self.save_settings)

        layout.addWidget(save_button)

        # 添加弹性空间

        layout.addStretch()

    def save_settings(self):

        settings = {

            'username': self.username_edit.text(),

            'work_time': self.work_time_spin.value(),

            'break_time': self.break_time_spin.value(),

            'theme': self.theme_combo.currentText(),

            'sound': self.sound_combo.currentText()

        }

        try:

            with open('user_settings.json', 'w', encoding='utf-8') as f:

                json.dump(settings, f, ensure_ascii=False, indent=2)

        except Exception as e:

            print(f'Error saving settings: {e}')

    def load_settings(self):

        try:

            if os.path.exists('user_settings.json'):

                with open('user_settings.json', 'r', encoding='utf-8') as f:

                    settings = json.load(f)

                    self.username_edit.setText(settings.get('username', ''))

                    self.work_time_spin.setValue(settings.get('work_time', 25))

                    self.break_time_spin.setValue(settings.get('break_time', 5))

                    theme_index = self.theme_combo.findText(settings.get('theme', '浅色'))

                    if theme_index >= 0:

                        self.theme_combo.setCurrentIndex(theme_index)

                    sound_index = self.sound_combo.findText(settings.get('sound', '默认'))

                    if sound_index >= 0:

                        self.sound_combo.setCurrentIndex(sound_index)

        except Exception as e:

            print(f'Error loading settings: {e}')

requirements.txt

PyQt5>=5.15.0

statistics.py

from PyQt5.QtWidgets import QWidget, QVBoxLayout, QLabel, QScrollArea

from PyQt5.QtCore import Qt

from PyQt5.QtGui import QFont

from datetime import datetime, timedelta

from data_manager import DataManager

  

class Statistics(QWidget):

    def __init__(self, parent=None):

        super().__init__(parent)

        self.data_manager = DataManager()

        self.setup_ui()

        self.update_statistics()

    def setup_ui(self):

        layout = QVBoxLayout(self)

        # 创建滚动区域

        scroll = QScrollArea()

        scroll.setWidgetResizable(True)

        content_widget = QWidget()

        scroll_layout = QVBoxLayout(content_widget)

        # 标题

        title = QLabel('统计数据')

        title.setAlignment(Qt.AlignCenter)

        title.setFont(QFont('Arial', 20))

        scroll_layout.addWidget(title)

        # 今日统计

        today_stats = QLabel('今日统计')

        today_stats.setFont(QFont('Arial', 16))

        scroll_layout.addWidget(today_stats)

        self.today_focus_time = QLabel('专注时长:0小时0分钟')

        self.today_completed_tasks = QLabel('完成任务:0个')

        scroll_layout.addWidget(self.today_focus_time)

        scroll_layout.addWidget(self.today_completed_tasks)

        # 本周统计

        week_stats = QLabel('本周统计')

        week_stats.setFont(QFont('Arial', 16))

        scroll_layout.addWidget(week_stats)

        self.week_focus_time = QLabel('专注时长:0小时0分钟')

        self.week_completed_tasks = QLabel('完成任务:0个')

        scroll_layout.addWidget(self.week_focus_time)

        scroll_layout.addWidget(self.week_completed_tasks)

        # 本月统计

        month_stats = QLabel('本月统计')

        month_stats.setFont(QFont('Arial', 16))

        scroll_layout.addWidget(month_stats)

        self.month_focus_time = QLabel('专注时长:0小时0分钟')

        self.month_completed_tasks = QLabel('完成任务:0个')

        scroll_layout.addWidget(self.month_focus_time)

        scroll_layout.addWidget(self.month_completed_tasks)

        # 设置滚动区域

        scroll.setWidget(content_widget)

        layout.addWidget(scroll)

    def update_statistics(self):

        # 更新今日统计

        today_focus, today_tasks = self.data_manager.get_statistics('today')

        self.today_focus_time.setText(f'专注时长:{today_focus//60}小时{today_focus%60}分钟')

        self.today_completed_tasks.setText(f'完成任务:{today_tasks}个')

        # 更新本周统计

        week_focus, week_tasks = self.data_manager.get_statistics('week')

        self.week_focus_time.setText(f'专注时长:{week_focus//60}小时{week_focus%60}分钟')

        self.week_completed_tasks.setText(f'完成任务:{week_tasks}个')

        # 更新本月统计

        month_focus, month_tasks = self.data_manager.get_statistics('month')

        self.month_focus_time.setText(f'专注时长:{month_focus//60}小时{month_focus%60}分钟')

        self.month_completed_tasks.setText(f'完成任务:{month_tasks}个')

    def showEvent(self, event):

        super().showEvent(event)

        self.update_statistics()  # 每次显示页面时更新统计数据

task_manager.py

from PyQt5.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QLabel,

                           QListWidget, QListWidgetItem, QInputDialog, QMessageBox)

from PyQt5.QtCore import Qt

from PyQt5.QtGui import QFont

from datetime import datetime

from data_manager import DataManager

  

class TaskManager(QWidget):

    def __init__(self, parent=None):

        super().__init__(parent)

        self.data_manager = DataManager()

        self.tasks = self.data_manager.get_tasks()

        self.completed_tasks = sum(1 for task in self.tasks if task['completed'])

        self.setup_ui()

        self.load_tasks()

    def setup_ui(self):

        layout = QVBoxLayout(self)

        # 标题

        title = QLabel('任务管理')

        title.setAlignment(Qt.AlignCenter)

        title.setFont(QFont('Arial', 20))

        layout.addWidget(title)

        # 任务列表

        self.active_tasks_label = QLabel('进行中的任务')

        self.active_tasks_label.setAlignment(Qt.AlignLeft)

        self.active_tasks_label.setFont(QFont('Arial', 12))

        layout.addWidget(self.active_tasks_label)

        self.active_task_list = QListWidget()

        layout.addWidget(self.active_task_list)

        # 已完成任务列表

        self.completed_tasks_label = QLabel('已完成的任务')

        self.completed_tasks_label.setAlignment(Qt.AlignLeft)

        self.completed_tasks_label.setFont(QFont('Arial', 12))

        layout.addWidget(self.completed_tasks_label)

        self.completed_task_list = QListWidget()

        layout.addWidget(self.completed_task_list)

        # 按钮布局

        button_layout = QHBoxLayout()

        self.add_button = QPushButton('添加任务')

        self.add_button.clicked.connect(self.add_task)

        button_layout.addWidget(self.add_button)

        self.complete_button = QPushButton('完成任务')

        self.complete_button.clicked.connect(self.complete_task)

        button_layout.addWidget(self.complete_button)

        self.delete_button = QPushButton('删除任务')

        self.delete_button.clicked.connect(self.delete_task)

        button_layout.addWidget(self.delete_button)

        layout.addLayout(button_layout)

        # 统计信息

        self.stats_label = QLabel('已完成任务数:0')

        self.stats_label.setAlignment(Qt.AlignCenter)

        layout.addWidget(self.stats_label)

    def load_tasks(self):

        # 清空列表

        self.active_task_list.clear()

        self.completed_task_list.clear()

        # 重新加载任务

        for task in self.tasks:

            item = QListWidgetItem(task['content'])

            if task['completed']:

                self.completed_task_list.addItem(item)

            else:

                self.active_task_list.addItem(item)

    def add_task(self):

        text, ok = QInputDialog.getText(self, '添加任务', '请输入任务内容:')

        if ok and text:

            task = {

                'content': text,

                'created_at': datetime.now(),

                'completed': False

            }

            item = QListWidgetItem(text)

            self.active_task_list.addItem(item)

            self.tasks.append(task)

            self.data_manager.add_task(task)

    def complete_task(self):

        current_item = self.active_task_list.currentItem()

        if current_item:

            # 从活动任务列表移除

            row = self.active_task_list.row(current_item)

            self.active_task_list.takeItem(row)

            # 添加到已完成任务列表

            self.completed_task_list.addItem(current_item)

            # 更新统计信息

            self.completed_tasks += 1

            self.stats_label.setText(f'已完成任务数:{self.completed_tasks}')

            # 更新任务状态

            for task in self.tasks:

                if task['content'] == current_item.text() and not task['completed']:

                    task['completed'] = True

                    task['completed_at'] = datetime.now()

                    self.data_manager.update_task(task)

                    break

            QMessageBox.information(self, '任务完成', '恭喜完成一个任务!')

    def delete_task(self):

        # 检查活动任务列表

        current_item = self.active_task_list.currentItem()

        if current_item:

            row = self.active_task_list.row(current_item)

            self.active_task_list.takeItem(row)

            # 找到要删除的任务并添加删除时间

            for task in self.tasks:

                if task['content'] == current_item.text():

                    task['deleted_at'] = datetime.now()

                    self.data_manager.deleted_tasks.append(task)

            self.tasks = [task for task in self.tasks if task['content'] != current_item.text()]

            self.data_manager.save_data()

            return

        # 检查已完成任务列表

        current_item = self.completed_task_list.currentItem()

        if current_item:

            row = self.completed_task_list.row(current_item)

            self.completed_task_list.takeItem(row)

            # 找到要删除的任务并添加删除时间

            for task in self.tasks:

                if task['content'] == current_item.text():

                    task['deleted_at'] = datetime.now()

                    self.data_manager.deleted_tasks.append(task)

            self.tasks = [task for task in self.tasks if task['content'] != current_item.text()]

            self.completed_tasks -= 1

            self.stats_label.setText(f'已完成任务数:{self.completed_tasks}')

            self.data_manager.save_data()

此外还要衷心建议下大家,只要我们有创造力,什么应用产品都能借助ai产生出来,加油各位,我们和trae一起进行迭代,变得更强

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值