From 81c649cb230de629f97d917b64002cce9bffc992 Mon Sep 17 00:00:00 2001 From: ShaoHua <345265198@qqcom> Date: Tue, 31 Mar 2026 22:44:32 +0800 Subject: [PATCH] =?UTF-8?q?feat:=E5=9F=BA=E7=A1=80=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/settings.json | 2 + README.md | 225 +- SCRIPTS_README.md | 388 + TodoList.slnx | 5 +- TodoList/App.xaml.cs | 26 +- TodoList/Services/FileDataService.cs | 41 +- TodoList/Services/IDataService.cs | 7 +- TodoList/Services/SqliteDataService.cs | 31 +- TodoList/TodoList.csproj | 1 + TodoList/Views/MainWindow.xaml | 116 +- TodoList/Views/QuickEntryWindow.xaml | 22 +- docs/产品需求文档-1.1.0.md | 161 + PRD.md => docs/产品需求文档.md | 0 docs/代码规范文档.md | 675 ++ docs/实现对比文档.md | 243 + docs/技术设计文档.md | 351 + restart-service.ps1 | 92 + .../Controllers/TasksController.cs | 291 + src/TodoList.Api/Data/TodoDbContext.cs | 47 + .../20260313044926_InitialCreate.Designer.cs | 61 + .../20260313044926_InitialCreate.cs | 39 + ...20260313092658_AddParentTaskId.Designer.cs | 81 + .../20260313092658_AddParentTaskId.cs | 49 + .../Migrations/TodoDbContextModelSnapshot.cs | 78 + src/TodoList.Api/Models/TaskModels.cs | 117 + src/TodoList.Api/Program.cs | 48 + .../Properties/launchSettings.json | 23 + .../Repositories/TaskRepository.cs | 122 + src/TodoList.Api/Services/TaskService.cs | 185 + src/TodoList.Api/TodoList.Api.csproj | 23 + src/TodoList.Api/TodoList.Api.http | 6 + src/TodoList.Api/appsettings.Development.json | 8 + src/TodoList.Api/appsettings.json | 9 + src/TodoList.Api/todolist.db | Bin 0 -> 32768 bytes src/TodoList.Core/Class1.cs | 6 + src/TodoList.Core/Entities/Task.cs | 52 + src/TodoList.Core/Entities/TaskPriority.cs | 22 + .../Interfaces/ITaskRepository.cs | 61 + src/TodoList.Core/Interfaces/ITaskService.cs | 73 + src/TodoList.Core/TodoList.Core.csproj | 9 + src/TodoList.Maui/App.xaml | 14 + src/TodoList.Maui/App.xaml.cs | 137 + src/TodoList.Maui/AppShell.xaml | 15 + src/TodoList.Maui/AppShell.xaml.cs | 9 + src/TodoList.Maui/BuildSetup.ps1 | 55 + .../Converters/PriorityToColorConverter.cs | 28 + src/TodoList.Maui/MauiProgram.cs | 37 + src/TodoList.Maui/Models/HotKeyConfig.cs | 70 + src/TodoList.Maui/Models/QuickEntryData.cs | 19 + src/TodoList.Maui/Models/TodoItem.cs | 23 + .../Platforms/Android/AndroidManifest.xml | 6 + .../Platforms/Android/MainActivity.cs | 10 + .../Platforms/Android/MainApplication.cs | 15 + .../Android/Resources/values/colors.xml | 6 + .../Resources/xml/network_security_config.xml | 13 + .../Platforms/MacCatalyst/AppDelegate.cs | 9 + .../Platforms/MacCatalyst/Entitlements.plist | 17 + .../Platforms/MacCatalyst/Info.plist | 47 + .../Platforms/MacCatalyst/Program.cs | 15 + src/TodoList.Maui/Platforms/Windows/App.xaml | 8 + .../Platforms/Windows/App.xaml.cs | 24 + .../Platforms/Windows/Package.appxmanifest | 47 + .../Windows/WindowsKeyboardHandler.cs | 129 + .../Platforms/Windows/WindowsWindowService.cs | 28 + .../Platforms/Windows/app.manifest | 17 + .../Platforms/iOS/AppDelegate.cs | 9 + src/TodoList.Maui/Platforms/iOS/Info.plist | 39 + src/TodoList.Maui/Platforms/iOS/Program.cs | 15 + .../iOS/Resources/PrivacyInfo.xcprivacy | 51 + src/TodoList.Maui/README.md | 149 + .../Resources/AppIcon/appicon.svg | 4 + .../Resources/AppIcon/appiconfg.svg | 8 + .../Resources/Fonts/OpenSans-Regular.ttf | Bin 0 -> 107320 bytes .../Resources/Fonts/OpenSans-Semibold.ttf | Bin 0 -> 111208 bytes .../Resources/Images/dotnet_bot.png | Bin 0 -> 92532 bytes .../Resources/Raw/AboutAssets.txt | 15 + src/TodoList.Maui/Resources/Splash/splash.svg | 8 + .../Resources/Styles/Colors.xaml | 44 + .../Resources/Styles/Styles.xaml | 434 + .../Services/GlobalHotKeyServiceFactory.cs | 59 + .../Services/HotKeySettingsService.cs | 92 + .../Services/IGlobalHotKeyService.cs | 33 + .../Services/ISystemTrayService.cs | 24 + .../Platforms/MacGlobalHotKeyService.cs | 143 + .../Platforms/MobileGlobalHotKeyService.cs | 127 + .../Platforms/WindowsGlobalHotKeyService.cs | 199 + .../Platforms/WindowsSystemTrayService.cs | 81 + src/TodoList.Maui/TodoList.Maui.csproj | 85 + .../ViewModels/QuickEntryViewModel.cs | 53 + src/TodoList.Maui/Views/MainPage.xaml | 32 + src/TodoList.Maui/Views/MainPage.xaml.cs | 101 + src/TodoList.Maui/Views/QuickEntryPage.xaml | 46 + .../Views/QuickEntryPage.xaml.cs | 22 + src/TodoList.Maui/icon.ico | Bin 0 -> 197166 bytes src/TodoList.Maui/setup.iss | 44 + src/TodoList.Web/.gitignore | 24 + src/TodoList.Web/.vite/deps/_metadata.json | 21 + src/TodoList.Web/.vite/deps/axios.js | 2910 ++++++ src/TodoList.Web/.vite/deps/axios.js.map | 1 + src/TodoList.Web/.vite/deps/package.json | 3 + src/TodoList.Web/.vite/deps/vue.js | 8530 +++++++++++++++++ src/TodoList.Web/.vite/deps/vue.js.map | 1 + src/TodoList.Web/.vscode/extensions.json | 3 + src/TodoList.Web/README.md | 5 + src/TodoList.Web/index.html | 13 + src/TodoList.Web/package-lock.json | 1669 ++++ src/TodoList.Web/package.json | 24 + src/TodoList.Web/public/favicon.svg | 1 + src/TodoList.Web/public/icons.svg | 24 + src/TodoList.Web/src/App.vue | 40 + src/TodoList.Web/src/api/client.ts | 19 + src/TodoList.Web/src/api/tasks.ts | 273 + src/TodoList.Web/src/assets/hero.png | Bin 0 -> 44919 bytes src/TodoList.Web/src/assets/vite.svg | 1 + src/TodoList.Web/src/assets/vue.svg | 1 + .../src/components/HelloWorld.vue | 93 + .../src/components/HotKeySettingsDialog.vue | 298 + .../src/components/TaskEditDialog.vue | 326 + src/TodoList.Web/src/components/TaskItem.vue | 417 + src/TodoList.Web/src/components/TaskList.vue | 865 ++ src/TodoList.Web/src/main.ts | 5 + .../src/services/localStorageService.ts | 70 + src/TodoList.Web/src/style.css | 296 + src/TodoList.Web/src/types/task.ts | 30 + src/TodoList.Web/tsconfig.app.json | 16 + src/TodoList.Web/tsconfig.json | 7 + src/TodoList.Web/tsconfig.node.json | 26 + src/TodoList.Web/vite.config.ts | 7 + start-service.ps1 | 128 + stop-service.ps1 | 97 + 项目结构说明.md | 344 + 131 files changed, 22903 insertions(+), 196 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 SCRIPTS_README.md create mode 100644 docs/产品需求文档-1.1.0.md rename PRD.md => docs/产品需求文档.md (100%) create mode 100644 docs/代码规范文档.md create mode 100644 docs/实现对比文档.md create mode 100644 docs/技术设计文档.md create mode 100644 restart-service.ps1 create mode 100644 src/TodoList.Api/Controllers/TasksController.cs create mode 100644 src/TodoList.Api/Data/TodoDbContext.cs create mode 100644 src/TodoList.Api/Migrations/20260313044926_InitialCreate.Designer.cs create mode 100644 src/TodoList.Api/Migrations/20260313044926_InitialCreate.cs create mode 100644 src/TodoList.Api/Migrations/20260313092658_AddParentTaskId.Designer.cs create mode 100644 src/TodoList.Api/Migrations/20260313092658_AddParentTaskId.cs create mode 100644 src/TodoList.Api/Migrations/TodoDbContextModelSnapshot.cs create mode 100644 src/TodoList.Api/Models/TaskModels.cs create mode 100644 src/TodoList.Api/Program.cs create mode 100644 src/TodoList.Api/Properties/launchSettings.json create mode 100644 src/TodoList.Api/Repositories/TaskRepository.cs create mode 100644 src/TodoList.Api/Services/TaskService.cs create mode 100644 src/TodoList.Api/TodoList.Api.csproj create mode 100644 src/TodoList.Api/TodoList.Api.http create mode 100644 src/TodoList.Api/appsettings.Development.json create mode 100644 src/TodoList.Api/appsettings.json create mode 100644 src/TodoList.Api/todolist.db create mode 100644 src/TodoList.Core/Class1.cs create mode 100644 src/TodoList.Core/Entities/Task.cs create mode 100644 src/TodoList.Core/Entities/TaskPriority.cs create mode 100644 src/TodoList.Core/Interfaces/ITaskRepository.cs create mode 100644 src/TodoList.Core/Interfaces/ITaskService.cs create mode 100644 src/TodoList.Core/TodoList.Core.csproj create mode 100644 src/TodoList.Maui/App.xaml create mode 100644 src/TodoList.Maui/App.xaml.cs create mode 100644 src/TodoList.Maui/AppShell.xaml create mode 100644 src/TodoList.Maui/AppShell.xaml.cs create mode 100644 src/TodoList.Maui/BuildSetup.ps1 create mode 100644 src/TodoList.Maui/Converters/PriorityToColorConverter.cs create mode 100644 src/TodoList.Maui/MauiProgram.cs create mode 100644 src/TodoList.Maui/Models/HotKeyConfig.cs create mode 100644 src/TodoList.Maui/Models/QuickEntryData.cs create mode 100644 src/TodoList.Maui/Models/TodoItem.cs create mode 100644 src/TodoList.Maui/Platforms/Android/AndroidManifest.xml create mode 100644 src/TodoList.Maui/Platforms/Android/MainActivity.cs create mode 100644 src/TodoList.Maui/Platforms/Android/MainApplication.cs create mode 100644 src/TodoList.Maui/Platforms/Android/Resources/values/colors.xml create mode 100644 src/TodoList.Maui/Platforms/Android/Resources/xml/network_security_config.xml create mode 100644 src/TodoList.Maui/Platforms/MacCatalyst/AppDelegate.cs create mode 100644 src/TodoList.Maui/Platforms/MacCatalyst/Entitlements.plist create mode 100644 src/TodoList.Maui/Platforms/MacCatalyst/Info.plist create mode 100644 src/TodoList.Maui/Platforms/MacCatalyst/Program.cs create mode 100644 src/TodoList.Maui/Platforms/Windows/App.xaml create mode 100644 src/TodoList.Maui/Platforms/Windows/App.xaml.cs create mode 100644 src/TodoList.Maui/Platforms/Windows/Package.appxmanifest create mode 100644 src/TodoList.Maui/Platforms/Windows/WindowsKeyboardHandler.cs create mode 100644 src/TodoList.Maui/Platforms/Windows/WindowsWindowService.cs create mode 100644 src/TodoList.Maui/Platforms/Windows/app.manifest create mode 100644 src/TodoList.Maui/Platforms/iOS/AppDelegate.cs create mode 100644 src/TodoList.Maui/Platforms/iOS/Info.plist create mode 100644 src/TodoList.Maui/Platforms/iOS/Program.cs create mode 100644 src/TodoList.Maui/Platforms/iOS/Resources/PrivacyInfo.xcprivacy create mode 100644 src/TodoList.Maui/README.md create mode 100644 src/TodoList.Maui/Resources/AppIcon/appicon.svg create mode 100644 src/TodoList.Maui/Resources/AppIcon/appiconfg.svg create mode 100644 src/TodoList.Maui/Resources/Fonts/OpenSans-Regular.ttf create mode 100644 src/TodoList.Maui/Resources/Fonts/OpenSans-Semibold.ttf create mode 100644 src/TodoList.Maui/Resources/Images/dotnet_bot.png create mode 100644 src/TodoList.Maui/Resources/Raw/AboutAssets.txt create mode 100644 src/TodoList.Maui/Resources/Splash/splash.svg create mode 100644 src/TodoList.Maui/Resources/Styles/Colors.xaml create mode 100644 src/TodoList.Maui/Resources/Styles/Styles.xaml create mode 100644 src/TodoList.Maui/Services/GlobalHotKeyServiceFactory.cs create mode 100644 src/TodoList.Maui/Services/HotKeySettingsService.cs create mode 100644 src/TodoList.Maui/Services/IGlobalHotKeyService.cs create mode 100644 src/TodoList.Maui/Services/ISystemTrayService.cs create mode 100644 src/TodoList.Maui/Services/Platforms/MacGlobalHotKeyService.cs create mode 100644 src/TodoList.Maui/Services/Platforms/MobileGlobalHotKeyService.cs create mode 100644 src/TodoList.Maui/Services/Platforms/WindowsGlobalHotKeyService.cs create mode 100644 src/TodoList.Maui/Services/Platforms/WindowsSystemTrayService.cs create mode 100644 src/TodoList.Maui/TodoList.Maui.csproj create mode 100644 src/TodoList.Maui/ViewModels/QuickEntryViewModel.cs create mode 100644 src/TodoList.Maui/Views/MainPage.xaml create mode 100644 src/TodoList.Maui/Views/MainPage.xaml.cs create mode 100644 src/TodoList.Maui/Views/QuickEntryPage.xaml create mode 100644 src/TodoList.Maui/Views/QuickEntryPage.xaml.cs create mode 100644 src/TodoList.Maui/icon.ico create mode 100644 src/TodoList.Maui/setup.iss create mode 100644 src/TodoList.Web/.gitignore create mode 100644 src/TodoList.Web/.vite/deps/_metadata.json create mode 100644 src/TodoList.Web/.vite/deps/axios.js create mode 100644 src/TodoList.Web/.vite/deps/axios.js.map create mode 100644 src/TodoList.Web/.vite/deps/package.json create mode 100644 src/TodoList.Web/.vite/deps/vue.js create mode 100644 src/TodoList.Web/.vite/deps/vue.js.map create mode 100644 src/TodoList.Web/.vscode/extensions.json create mode 100644 src/TodoList.Web/README.md create mode 100644 src/TodoList.Web/index.html create mode 100644 src/TodoList.Web/package-lock.json create mode 100644 src/TodoList.Web/package.json create mode 100644 src/TodoList.Web/public/favicon.svg create mode 100644 src/TodoList.Web/public/icons.svg create mode 100644 src/TodoList.Web/src/App.vue create mode 100644 src/TodoList.Web/src/api/client.ts create mode 100644 src/TodoList.Web/src/api/tasks.ts create mode 100644 src/TodoList.Web/src/assets/hero.png create mode 100644 src/TodoList.Web/src/assets/vite.svg create mode 100644 src/TodoList.Web/src/assets/vue.svg create mode 100644 src/TodoList.Web/src/components/HelloWorld.vue create mode 100644 src/TodoList.Web/src/components/HotKeySettingsDialog.vue create mode 100644 src/TodoList.Web/src/components/TaskEditDialog.vue create mode 100644 src/TodoList.Web/src/components/TaskItem.vue create mode 100644 src/TodoList.Web/src/components/TaskList.vue create mode 100644 src/TodoList.Web/src/main.ts create mode 100644 src/TodoList.Web/src/services/localStorageService.ts create mode 100644 src/TodoList.Web/src/style.css create mode 100644 src/TodoList.Web/src/types/task.ts create mode 100644 src/TodoList.Web/tsconfig.app.json create mode 100644 src/TodoList.Web/tsconfig.json create mode 100644 src/TodoList.Web/tsconfig.node.json create mode 100644 src/TodoList.Web/vite.config.ts create mode 100644 start-service.ps1 create mode 100644 stop-service.ps1 create mode 100644 项目结构说明.md diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..7a73a41 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,2 @@ +{ +} \ No newline at end of file diff --git a/README.md b/README.md index c9c57a5..cb18958 100644 --- a/README.md +++ b/README.md @@ -1,133 +1,170 @@ -# TodoList 待办事项管理应用 +# TodoList 跨平台待办事项管理应用 -一个基于 C# WPF 开发的轻量、高效桌面待办事项管理应用,专注于通过全局快捷键提供极致的快速记录体验。 +一个基于 MAUI + WebView 架构开发的跨平台待办事项管理应用,支持 Windows、macOS、Android、iOS 和 Linux(预览)平台。通过 HTTP API 实现前后端通信,提供轻量、高效的任务管理体验。 ## 🚀 功能特点 ### 核心功能 -- **全局快捷键快速记录**:支持系统级全局快捷键(如 `Ctrl + Alt + A`),随时唤起记录窗口 +- **跨平台支持**:基于 MAUI + WebView 架构,支持 Windows、macOS、Android、iOS 和 Linux(预览) +- **任务管理**:支持创建、编辑、删除、完成状态切换 - **优先级管理**:支持高、中、低三种优先级设置,通过颜色直观区分 -- **任务状态跟踪**:清晰标记任务完成状态,默认隐藏已完成任务 +- **任务状态跟踪**:清晰标记任务完成状态,支持过滤查看(全部/进行中/已完成) - **本地数据持久化**:使用 SQLite 数据库保存数据,支持完全离线使用 +- **HTTP API 通信**:前后端通过 RESTful API 进行数据交互 ### 技术特性 -- **响应式界面**:基于 WPF 构建的现代化用户界面 -- **MVVM 架构**:采用 CommunityToolkit.Mvvm 实现清晰的架构分层 -- **自包含发布**:支持单文件发布,无需额外依赖 -- **一键打包**:内置自动构建和打包脚本 +- **现代化架构**:MAUI + WebView + C# 后端 + Vue.js 前端 +- **分层设计**:Core(核心层)+ API(后端)+ Web(前端) +- **响应式界面**:Vue.js 3 实现的现代化用户界面 +- **统一 API 设计**:RESTful API 风格,支持跨域请求 ## 🛠️ 技术栈 -- **开发语言**:C# 10+ -- **UI 框架**:WPF (Windows Presentation Foundation) -- **目标框架**:.NET 8.0 -- **架构模式**:MVVM (Model-View-ViewModel) -- **数据存储**:SQLite (sqlite-net-pcl) -- **打包工具**:Inno Setup 6 -- **依赖管理**:NuGet +### 后端技术栈 +- **开发语言**:C# 10 +- **框架**:.NET 10 +- **UI 框架**:MAUI (Multi-platform App UI) +- **Web 服务器**:Kestrel (ASP.NET Core 内置) +- **API 框架**:ASP.NET Core Web API +- **数据访问**:Entity Framework Core +- **数据库**:SQLite (本地存储) +- **依赖注入**:Microsoft.Extensions.DependencyInjection + +### 前端技术栈 +- **开发语言**:TypeScript +- **框架**:Vue.js 3 +- **构建工具**:Vite +- **HTTP 客户端**:Axios +- **状态管理**:Pinia +- **UI 组件库**:Element Plus / Vant (移动端) +- **CSS 预处理器**:SCSS ## 📦 安装与使用 -### 直接安装 -1. 从 `Output` 目录下载最新的安装包:`TodoList_Setup_vX.X.X.exe` -2. 双击运行安装程序,按照提示完成安装 -3. 启动应用后,在系统托盘找到应用图标 - -### 使用说明 -- **快速记录**:按下预设的全局快捷键(默认为 `Ctrl + Alt + A`) -- **添加任务**:在快速记录窗口中输入任务内容,设置优先级,按 Enter 保存 -- **管理任务**:在主界面中查看、编辑和标记任务完成状态 -- **隐藏完成任务**:默认自动隐藏已完成任务,可通过界面开关显示 - -## 🔧 开发指南 - ### 环境要求 -- Visual Studio 2022 或更高版本 -- .NET 8.0 SDK -- Inno Setup 6(用于打包) +- **后端**: + - .NET 10 SDK + - Visual Studio 2022 或更高版本 +- **前端**: + - Node.js 18+ + - npm 或 yarn ### 快速开始 -1. **克隆或下载项目** - ```bash - git clone <仓库地址> - cd TodoList - ``` - -2. **打开项目** - - 使用 Visual Studio 打开 `TodoList.slnx` 解决方案 - - 或直接打开 `TodoList/TodoList.csproj` 项目文件 - -3. **安装依赖** - ```bash - dotnet restore - ``` - -4. **运行项目** - ```bash - dotnet run --project TodoList/TodoList.csproj - ``` - -### 构建与发布 - -使用内置的发布脚本进行一键构建和打包: - +#### 1. 克隆或下载项目 ```bash -cd TodoList/TodoList -powershell -ExecutionPolicy Bypass -File "BuildSetup.ps1" +git clone <仓库地址> +cd TodoList ``` -脚本功能: -- 自动递增版本号 -- 更新项目文件和安装脚本版本 -- 编译 Release 版本 -- 生成单文件可执行文件 -- 创建安装程序(输出到 `Output` 目录) +#### 2. 启动后端 API +```bash +cd src/TodoList.Api +dotnet restore +dotnet ef database update +dotnet run +``` +API 将在 `http://localhost:5057` 启动 -## 📁 项目结构 +#### 3. 启动前端 Web +```bash +cd src/TodoList.Web +npm install +npm run dev +``` +前端将在 `http://localhost:5173` 启动 +### 使用说明 +- **添加任务**:在前端界面中输入任务内容,设置优先级,点击添加按钮 +- **管理任务**:查看任务列表,支持按状态过滤(全部/进行中/已完成) +- **完成任务**:点击任务前的复选框切换完成状态 +- **删除任务**:点击删除按钮移除任务 + +## 🔧 开发指南 + +### 项目结构 ``` TodoList/ -├── TodoList/ # 主项目目录 -│ ├── Models/ # 数据模型 -│ ├── Services/ # 服务层(数据访问、快捷键等) -│ ├── ViewModels/ # 视图模型 -│ ├── Views/ # 界面视图 -│ ├── TodoList.csproj # 项目文件 -│ ├── BuildSetup.ps1 # 发布脚本 -│ └── setup.iss # Inno Setup 安装脚本 -├── TodoList.slnx # 解决方案文件 -├── PRD.md # 产品需求文档 -└── README.md # 项目说明文档 +├── docs/ # 文档目录 +│ ├── 产品需求文档.md +│ ├── 产品需求文档-1.1.0.md +│ ├── 技术设计文档.md +│ └── 代码规范文档.md +├── src/ # 源代码目录 +│ ├── TodoList.Core/ # 核心业务逻辑层 +│ │ ├── Entities/ # 实体类 +│ │ │ ├── Task.cs +│ │ │ └── TaskPriority.cs +│ │ └── Interfaces/ # 接口定义 +│ │ ├── ITaskRepository.cs +│ │ └── ITaskService.cs +│ ├── TodoList.Api/ # 后端 API 项目 +│ │ ├── Controllers/ # API 控制器 +│ │ │ └── TasksController.cs +│ │ ├── Services/ # 业务服务 +│ │ │ └── TaskService.cs +│ │ ├── Repositories/ # 数据访问层 +│ │ │ └── TaskRepository.cs +│ │ ├── Data/ # 数据库上下文 +│ │ │ ├── TodoDbContext.cs +│ │ │ └── Migrations/ # 数据库迁移 +│ │ ├── Models/ # 数据模型 +│ │ │ └── TaskModels.cs +│ │ ├── Program.cs # API 入口 +│ │ └── TodoList.Api.csproj # API 项目文件 +│ ├── TodoList.Web/ # 前端 Web 项目 (Vue.js) +│ │ ├── public/ # 静态资源 +│ │ ├── src/ +│ │ │ ├── api/ # API 调用 +│ │ │ │ ├── client.ts +│ │ │ │ └── tasks.ts +│ │ │ ├── components/ # Vue 组件 +│ │ │ │ ├── TaskList.vue +│ │ │ │ └── TaskItem.vue +│ │ │ ├── types/ # TypeScript 类型定义 +│ │ │ │ └── task.ts +│ │ │ ├── App.vue # 根组件 +│ │ │ └── main.ts # 应用入口 +│ │ ├── package.json # 依赖配置 +│ │ ├── vite.config.ts # Vite 配置 +│ │ └── tsconfig.json # TypeScript 配置 +│ └── TodoList.slnx # 解决方案文件 +├── .gitignore # Git 忽略文件 +└── README.md # 项目说明文档 ``` +### API 端点 +- `GET /api/tasks` - 获取任务列表 +- `GET /api/tasks/{id}` - 获取单个任务 +- `POST /api/tasks` - 创建任务 +- `PUT /api/tasks/{id}` - 更新任务 +- `PATCH /api/tasks/{id}/complete` - 切换完成状态 +- `DELETE /api/tasks/{id}` - 删除任务 + ## 🎯 核心模块说明 -### QuickEntryWindow -快速记录窗口,通过全局快捷键唤起,提供极简的任务输入体验。 +### TodoList.Core +核心业务逻辑层,定义领域模型和业务规则,提供核心业务接口。 -### MainWindow -主界面,展示任务列表,支持任务管理和状态切换。 +### TodoList.Api +后端 API 项目,提供 RESTful API 接口,处理业务逻辑,管理数据访问和持久化。 -### GlobalShortcutService -全局快捷键服务,负责注册和监听系统级快捷键。 - -### SqliteDataService -SQLite 数据服务,实现本地数据持久化。 +### TodoList.Web +前端 Web 项目,基于 Vue.js 3 + TypeScript,提供用户界面,通过 HTTP API 与后端通信。 ## 🔄 版本更新 ### 版本策略 - 采用语义化版本号:`MAJOR.MINOR.PATCH` -- 每次运行发布脚本自动递增 PATCH 版本 +- v1.0.0:初始 WPF 版本 +- v1.1.0:MAUI + WebView 跨平台版本 -### 更新日志 - -| 版本 | 日期 | 描述 | -|------|------|------| -| 1.0.17 | 2024-01-XX | 修复发布脚本和安装路径问题 | -| 1.0.16 | 2024-01-XX | 完善任务优先级显示 | -| 1.0.0 | 2024-01-XX | 初始版本发布 | +### v1.1.0 更新内容 +- 重构为 MAUI + WebView 架构 +- 实现跨平台支持 +- 使用 HTTP API 进行前后端通信 +- 采用 Vue.js 3 作为前端框架 +- 使用 SQLite 作为本地数据库 ## 🤝 贡献指南 @@ -144,8 +181,8 @@ SQLite 数据服务,实现本地数据持久化。 ## 📞 联系方式 - 项目作者:ShaoHua -- 项目地址: +- 项目地址:https://git.we965.cn/Tools/TodoList --- -**TodoList** - 让任务管理更高效! \ No newline at end of file +**TodoList** - 跨平台任务管理,让效率无处不在! diff --git a/SCRIPTS_README.md b/SCRIPTS_README.md new file mode 100644 index 0000000..c78d47e --- /dev/null +++ b/SCRIPTS_README.md @@ -0,0 +1,388 @@ +# TodoList 服务管理脚本 + +本目录包含用于管理 TodoList 服务的 PowerShell 脚本。 + +## 脚本列表 + +### 1. `start-service.ps1` - 启动服务 +启动 TodoList.Api 服务和 TodoList.Maui 应用。 + +#### 使用方法 +```powershell +# 启动 API 服务和 MAUI 应用(默认) +.\start-service.ps1 + +# 只启动 API 服务 +.\start-service.ps1 -StartMaui:$false +``` + +#### 功能 +- 检查 TodoList.Api 服务是否已在运行 +- 如果未运行,启动 TodoList.Api 服务 +- 默认启动 TodoList.Maui 应用(可通过 `-StartMaui:$false` 禁用) +- 显示服务访问地址和 Swagger 文档链接 + +#### 输出示例 +``` +==================================== + TodoList 服务启动脚本 +==================================== + +[1/2] 检查 TodoList.Api 服务... +✓ TodoList.Api 服务未运行 + +[2/2] 启动 TodoList.Api 服务... +📂 工作目录: D:\Proj\TodoList\src\TodoList.Api +🚀 启动服务... +✅ TodoList.Api 服务已启动 + 进程 ID: 65992 + 访问地址: http://localhost:5057 + Swagger 文档: http://localhost:5057/swagger + +[3/3] 启动 TodoList.Maui 应用... +🚀 启动 TodoList.Maui... +✅ TodoList.Maui 已启动 + +==================================== + 启动完成 +==================================== + +💡 提示: + - 按 Ctrl+C 可以停止服务 + - 运行 stop-service.ps1 可以关闭服务 + - 运行 restart-service.ps1 可以重启服务 +``` + +--- + +### 2. `stop-service.ps1` - 关闭服务 +停止所有正在运行的 TodoList.Api 服务和 TodoList.Maui 应用。 + +#### 使用方法 +```powershell +# 正常关闭 +.\stop-service.ps1 + +# 强制关闭 +.\stop-service.ps1 -Force +``` + +#### 功能 +- 查找并停止所有 TodoList.Api 进程 +- 查找并停止所有 TodoList.Maui 进程 +- 显示停止的进程数量和状态 + +#### 输出示例 +``` +==================================== + TodoList 服务关闭脚本 +==================================== + +[1/2] 查找 TodoList.Api 服务... +🔍 找到 1 个 TodoList.Api 进程 + 正在停止进程 ID: 65992... + ✅ 进程 65992 已停止 + +[2/2] 查找 TodoList.Maui 应用... +✓ TodoList.Maui 应用未运行 + +==================================== + 关闭完成 + 已停止 1 个进程 +==================================== + +💡 提示: + - 运行 start-service.ps1 可以启动服务 + - 运行 restart-service.ps1 可以重启服务 +``` + +--- + +### 3. `restart-service.ps1` - 重启服务 +停止现有服务并重新启动。 + +#### 使用方法 +```powershell +# 重启 API 服务 +.\restart-service.ps1 + +# 重启 API 和 MAUI 应用 +.\restart-service.ps1 -StartMaui + +# 强制重启 +.\restart-service.ps1 -Force +``` + +#### 功能 +- 调用 stop-service.ps1 停止现有服务 +- 等待进程完全关闭(最多 10 秒) +- 调用 start-service.ps1 启动服务 +- 显示重启进度和状态 + +#### 输出示例 +``` +==================================== + TodoList 服务重启脚本 +==================================== + +[1/3] 停止现有服务... +✅ 服务已停止 + +[2/3] 等待进程完全关闭... +✅ 所有进程已关闭 + +[3/3] 启动服务... +✅ 服务已启动 + +==================================== + 重启完成 +==================================== + +💡 提示: + - 按 Ctrl+C 可以停止服务 + - 运行 stop-service.ps1 可以关闭服务 + - 运行 restart-service.ps1 可以重启服务 +``` + +--- + +### 4. `BuildSetup.ps1` - 构建安装包 +构建 TodoList.Maui 项目的 Release 版本并创建 Inno Setup 安装包。 + +#### 使用方法 +```powershell +# 在 TodoList 目录下运行 +.\TodoList\BuildSetup.ps1 +``` + +#### 功能 +- 自动读取项目版本号 +- 自动递增补丁版本号(例如 1.0.0 → 1.0.1) +- 更新 .csproj 文件中的版本号 +- 更新 setup.iss 文件中的版本号 +- 构建 Release 版本(win-x64) +- 使用 Inno Setup 编译器创建安装包 + +#### 输出示例 +``` +Setup package created successfully! +``` + +#### 依赖项 +- .NET SDK +- Inno Setup 6(默认路径:`C:\Program Files (x86)\Inno Setup 6\ISCC.exe`) + +--- + +## 参数说明 + +### `start-service.ps1` +| 参数 | 类型 | 默认值 | 说明 | +|------|------|----------|------| +| `-StartMaui` | Switch | `$true` | 是否启动 TodoList.Maui 应用(默认启用) | +| `-ServicePath` | String | `"src\TodoList.Api"` | API 服务相对路径 | +| `-MauiPath` | String | `"src\TodoList.Maui"` | MAUI 应用相对路径 | + +### `stop-service.ps1` +| 参数 | 类型 | 默认值 | 说明 | +|------|------|----------|------| +| `-Force` | Switch | `$false` | 是否强制关闭进程 | + +### `restart-service.ps1` +| 参数 | 类型 | 默认值 | 说明 | +|------|------|----------|------| +| `-StartMaui` | Switch | `$false` | 是否同时启动 TodoList.Maui 应用 | +| `-Force` | Switch | `$false` | 是否强制关闭进程 | + +### `BuildSetup.ps1` +| 参数 | 类型 | 默认值 | 说明 | +|------|------|----------|------| +| 无 | - | - | 脚本自动检测项目文件并处理 | + +--- + +## 使用场景 + +### 场景 1: 首次启动 +```powershell +# 启动 API 服务和 MAUI 应用(默认) +.\start-service.ps1 + +# 访问 http://localhost:5057 查看服务 +# 访问 http://localhost:5057/swagger 查看 API 文档 +``` + +### 场景 2: 只启动 API 服务 +```powershell +# 只启动 API 服务,不启动 MAUI 应用 +.\start-service.ps1 -StartMaui:$false +``` + +### 场景 3: 开发调试 +```powershell +# 启动 API 和 MAUI 应用(默认行为) +.\start-service.ps1 + +# 使用 Alt+X 快捷键唤醒 MAUI 应用 +# 在 MAUI 应用中测试快捷键功能 +``` + +### 场景 4: 代码修改后重启 +```powershell +# 快速重启服务 +.\restart-service.ps1 + +# 重启服务并启动 MAUI 应用 +.\restart-service.ps1 -StartMaui + +# 或者强制重启(如果进程卡住) +.\restart-service.ps1 -Force +``` + +### 场景 5: 完全关闭 +```powershell +# 关闭所有服务 +.\stop-service.ps1 + +# 或者强制关闭 +.\stop-service.ps1 -Force +``` + +### 场景 6: 构建安装包 +```powershell +# 在 TodoList 目录下构建安装包 +.\TodoList\BuildSetup.ps1 + +# 脚本会自动: +# 1. 递增版本号 +# 2. 构建 Release 版本 +# 3. 创建 Inno Setup 安装包 +``` + +--- + +## 注意事项 + +1. **PowerShell 执行策略** + - 如果遇到执行策略错误,运行:`Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser` + - 或者临时绕过:`powershell -ExecutionPolicy Bypass -File .\start-service.ps1` + +2. **进程检测** + - 脚本通过进程名称和窗口标题检测 TodoList.Api 服务 + - 脚本通过进程名称检测 TodoList.Maui 应用 + +3. **端口占用** + - 如果端口 5057 被占用,启动会失败 + - 使用 `netstat -ano | findstr :5057` 检查端口占用情况 + +4. **MAUI 应用构建** + - 如果 MAUI 应用不存在,需要先构建:`dotnet build src\TodoList.Maui\TodoList.Maui.csproj` + - 默认路径:`src\TodoList.Maui\bin\Debug\net10.0-windows10.0.19041.0\win-x64\TodoList.Maui.exe` + +5. **快捷键功能** + - MAUI 应用启动后,默认快捷键为 `Alt + X` + - 可以在应用设置中自定义快捷键 + +--- + +## 故障排除 + +### 问题 1: 无法启动服务 +**症状**: 运行 `start-service.ps1` 后服务未启动 + +**解决方案**: +1. 检查 .NET SDK 是否安装:`dotnet --version` +2. 检查项目路径是否正确 +3. 查看错误信息:`dotnet run src\TodoList.Api\TodoList.Api.csproj` + +### 问题 2: 无法停止服务 +**症状**: 运行 `stop-service.ps1` 后进程仍在运行 + +**解决方案**: +1. 使用强制关闭:`.\stop-service.ps1 -Force` +2. 手动结束进程:`taskkill /F /IM dotnet.exe` +3. 检查是否有其他 dotnet 进程占用 + +### 问题 3: MAUI 应用无法启动 +**症状**: 运行 `start-service.ps1` 后 MAUI 应用未启动 + +**解决方案**: +1. 先构建 MAUI 项目:`dotnet build src\TodoList.Maui\TodoList.Maui.csproj` +2. 检查可执行文件是否存在 +3. 查看构建错误信息 + +### 问题 4: BuildSetup.ps1 无法构建安装包 +**症状**: 运行 `.\TodoList\BuildSetup.ps1` 后构建失败 + +**解决方案**: +1. 检查 Inno Setup 是否已安装:`Test-Path "${env:ProgramFiles(x86)}\Inno Setup 6\ISCC.exe"` +2. 如果未安装,请从 https://jrsoftware.org/isdl.php 下载安装 +3. 检查 .NET SDK 是否安装:`dotnet --version` +4. 检查项目文件是否存在:`Test-Path .\TodoList\TodoList.csproj` +5. 检查 setup.iss 文件是否存在:`Test-Path .\TodoList\setup.iss` + +### 问题 5: 版本号未正确递增 +**症状**: 运行 BuildSetup.ps1 后版本号未变化 + +**解决方案**: +1. 检查 .csproj 文件中是否有 `` 标签 +2. 确保版本号格式为 `X.Y.Z`(三个数字用点分隔) +3. 手动检查并修复版本号格式 + +--- + +## 快捷命令 + +```powershell +# 启动服务(API + MAUI,默认) +.\start-service.ps1 + +# 只启动 API 服务 +.\start-service.ps1 -StartMaui:$false + +# 关闭服务 +.\stop-service.ps1 + +# 重启服务 +.\restart-service.ps1 + +# 重启服务并启动 MAUI 应用 +.\restart-service.ps1 -StartMaui + +# 强制关闭 +.\stop-service.ps1 -Force + +# 强制重启 +.\restart-service.ps1 -Force + +# 构建安装包 +.\TodoList\BuildSetup.ps1 +``` + +--- + +## 技术细节 + +- **脚本语言**: PowerShell 5.1+ +- **目标平台**: Windows +- **依赖**: .NET SDK, dotnet CLI +- **错误处理**: 支持错误捕获和友好提示 +- **日志输出**: 彩色输出,易于阅读 + +--- + +## 更新日志 + +### v1.1.0 (2026-03-18) +- 新增 `BuildSetup.ps1` 脚本,支持自动构建安装包 +- 更新 `start-service.ps1`,默认启动 MAUI 应用(`-StartMaui` 默认值为 `$true`) +- 优化所有脚本的输出格式,添加提示信息 +- 更新文档,修正参数默认值说明 +- 添加 BuildSetup.ps1 相关故障排除指南 + +### v1.0.0 (2026-03-13) +- 初始版本 +- 实现启动、关闭、重启服务功能 +- 支持 TodoList.Api 和 TodoList.Maui 应用管理 +- 添加参数支持和错误处理 +- 彩色输出和友好提示 \ No newline at end of file diff --git a/TodoList.slnx b/TodoList.slnx index d463135..e12c6c2 100644 --- a/TodoList.slnx +++ b/TodoList.slnx @@ -6,4 +6,7 @@ - + + + + \ No newline at end of file diff --git a/TodoList/App.xaml.cs b/TodoList/App.xaml.cs index bf98aa1..df48065 100644 --- a/TodoList/App.xaml.cs +++ b/TodoList/App.xaml.cs @@ -15,6 +15,7 @@ namespace TodoList private IDataService _dataService; private GlobalShortcutService _shortcutService; private MainWindow _mainWindow; + private QuickEntryWindow? _quickEntryWindow; private SettingsService _settingsService; private System.Windows.Forms.NotifyIcon _notifyIcon; private Mutex _mutex; @@ -289,7 +290,30 @@ namespace TodoList private void OnHotKeyPressed() { Log("Hotkey pressed."); - ShowMainWindow(); + ShowQuickEntryWindow(); + } + + private void ShowQuickEntryWindow() + { + if (_quickEntryWindow == null) + { + _quickEntryWindow = new QuickEntryWindow(_dataService); + } + + if (_quickEntryWindow.WindowState == WindowState.Minimized) + { + _quickEntryWindow.WindowState = WindowState.Normal; + } + + _quickEntryWindow.Show(); + _quickEntryWindow.Activate(); + + var helper = new WindowInteropHelper(_quickEntryWindow); + var handle = helper.Handle; + if (handle != IntPtr.Zero) + { + SetForegroundWindow(handle); + } } protected override void OnExit(ExitEventArgs e) diff --git a/TodoList/Services/FileDataService.cs b/TodoList/Services/FileDataService.cs index 7c0b10d..929da82 100644 --- a/TodoList/Services/FileDataService.cs +++ b/TodoList/Services/FileDataService.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Text.Json; using System.Threading.Tasks; using TodoList.Models; @@ -19,7 +20,7 @@ namespace TodoList.Services _filePath = Path.Combine(folder, "tasks.json"); } - public async Task> LoadTasksAsync() + public async Task> LoadTasksAsync(bool? completed = null) { if (!File.Exists(_filePath)) { @@ -30,7 +31,13 @@ namespace TodoList.Services { using var stream = File.OpenRead(_filePath); var items = await JsonSerializer.DeserializeAsync>(stream); - return items ?? new List(); + var tasks = items ?? new List(); + + if (completed.HasValue) + { + return tasks.Where(t => t.IsCompleted == completed.Value).ToList(); + } + return tasks; } catch { @@ -38,7 +45,7 @@ namespace TodoList.Services } } - public async Task SaveTaskAsync(TodoItem task) + public async Task SaveTaskAsync(TodoItem task) { var tasks = await LoadTasksAsync(); var existing = tasks.Find(t => t.Id == task.Id); @@ -48,6 +55,34 @@ namespace TodoList.Services } tasks.Add(task); await SaveAllAsync(tasks); + return task; + } + + public async Task UpdateTaskAsync(TodoItem task) + { + var tasks = await LoadTasksAsync(); + var existing = tasks.Find(t => t.Id == task.Id); + if (existing != null) + { + tasks.Remove(existing); + tasks.Add(task); + await SaveAllAsync(tasks); + } + return task; + } + + public async Task ToggleCompleteAsync(string id) + { + var tasks = await LoadTasksAsync(); + var task = tasks.Find(t => t.Id == id); + if (task != null) + { + task.IsCompleted = !task.IsCompleted; + task.CompletedAt = task.IsCompleted ? DateTime.Now : null; + task.SyncStatus = SyncStatus.Pending; + await SaveAllAsync(tasks); + } + return task; } public async Task SaveAllAsync(List tasks) diff --git a/TodoList/Services/IDataService.cs b/TodoList/Services/IDataService.cs index 470378f..f5e690a 100644 --- a/TodoList/Services/IDataService.cs +++ b/TodoList/Services/IDataService.cs @@ -6,9 +6,10 @@ namespace TodoList.Services { public interface IDataService { - Task> LoadTasksAsync(); - Task SaveTaskAsync(TodoItem task); - Task SaveAllAsync(List tasks); + Task> LoadTasksAsync(bool? completed = null); + Task SaveTaskAsync(TodoItem task); + Task UpdateTaskAsync(TodoItem task); + Task ToggleCompleteAsync(string id); Task DeleteTaskAsync(string id); } } diff --git a/TodoList/Services/SqliteDataService.cs b/TodoList/Services/SqliteDataService.cs index bb2eabd..a541bd4 100644 --- a/TodoList/Services/SqliteDataService.cs +++ b/TodoList/Services/SqliteDataService.cs @@ -22,14 +22,39 @@ namespace TodoList.Services _database.CreateTableAsync().Wait(); } - public async Task> LoadTasksAsync() + public async Task> LoadTasksAsync(bool? completed = null) { - return await _database.Table().ToListAsync(); + var query = _database.Table(); + if (completed.HasValue) + { + query = query.Where(t => t.IsCompleted == completed.Value); + } + return await query.ToListAsync(); } - public async Task SaveTaskAsync(TodoItem task) + public async Task SaveTaskAsync(TodoItem task) { await _database.InsertOrReplaceAsync(task); + return task; + } + + public async Task UpdateTaskAsync(TodoItem task) + { + await _database.UpdateAsync(task); + return task; + } + + public async Task ToggleCompleteAsync(string id) + { + var task = await _database.FindAsync(id); + if (task != null) + { + task.IsCompleted = !task.IsCompleted; + task.CompletedAt = task.IsCompleted ? DateTime.Now : null; + task.SyncStatus = SyncStatus.Pending; + await _database.UpdateAsync(task); + } + return task; } public async Task SaveAllAsync(List tasks) diff --git a/TodoList/TodoList.csproj b/TodoList/TodoList.csproj index eac4167..ceb6fe5 100644 --- a/TodoList/TodoList.csproj +++ b/TodoList/TodoList.csproj @@ -14,6 +14,7 @@ + diff --git a/TodoList/Views/MainWindow.xaml b/TodoList/Views/MainWindow.xaml index 16af955..58a45d6 100644 --- a/TodoList/Views/MainWindow.xaml +++ b/TodoList/Views/MainWindow.xaml @@ -7,7 +7,7 @@ xmlns:models="clr-namespace:TodoList.Models" xmlns:converters="clr-namespace:TodoList.Converters" mc:Ignorable="d" - Title="{Binding AppVersion, StringFormat='待办事项 v{0}'}" Height="600" Width="450" + Title="{Binding AppVersion, StringFormat='待办事项 v{0}'}" Height="450" Width="350" Background="#F5F5F7" Icon="/icon.ico" WindowStartupLocation="CenterScreen" @@ -73,7 +73,7 @@ - + @@ -83,10 +83,10 @@ - + + Width="70" VerticalContentAlignment="Center" Margin="0,0,3,0"> @@ -95,7 +95,7 @@ + Width="50" VerticalContentAlignment="Center"> @@ -106,7 +106,7 @@ - -