├── .gitignore
├── .npmrc
├── LICENSE
├── README.md
├── auto-imports.d.ts
├── components.d.ts
├── index.html
├── jsconfig.json
├── main.js
├── package.json
├── pnpm-lock.yaml
├── preload
└── index.js
├── public
└── icons
│ └── icon.png
├── scripts
├── afterPack.js
└── rename.js
├── src
├── App.vue
├── assets
│ ├── defaultBGI.jpg
│ ├── main.css
│ └── voices
│ │ ├── pomodoro
│ │ ├── default
│ │ │ ├── focus.wav
│ │ │ ├── longBreak.wav
│ │ │ └── shortBreak.wav
│ │ ├── dingzhen
│ │ │ ├── focus.wav
│ │ │ ├── longBreak.wav
│ │ │ └── shortBreak.wav
│ │ ├── jiaran
│ │ │ ├── focus.wav
│ │ │ ├── longBreak.wav
│ │ │ └── shortBreak.wav
│ │ └── kobe
│ │ │ ├── focus.wav
│ │ │ ├── longBreak.wav
│ │ │ └── shortBreak.wav
│ │ ├── timer
│ │ ├── default
│ │ │ ├── fullTime.wav
│ │ │ └── halfTime.wav
│ │ ├── dingzhen
│ │ │ ├── fullTime.wav
│ │ │ └── halfTime.wav
│ │ ├── jiaran
│ │ │ ├── fullTime.wav
│ │ │ └── halfTime.wav
│ │ └── kobe
│ │ │ ├── fullTime.wav
│ │ │ └── halfTime.wav
│ │ └── todos
│ │ ├── default
│ │ └── remind.wav
│ │ ├── dingzhen
│ │ └── remind.wav
│ │ ├── jiaran
│ │ └── remind.wav
│ │ └── kobe
│ │ └── remind.wav
├── components
│ └── ToDoList.vue
├── main.js
├── router
│ └── index.js
├── stores
│ ├── CustomSettings.js
│ ├── CustomToDoStore.js
│ ├── HasVisitedBefore.js
│ └── ToDo.js
└── views
│ ├── desktop
│ ├── CustomToDo.vue
│ ├── Pomodoro.vue
│ └── Timer.vue
│ ├── fullscreen
│ ├── Pomodoro.vue
│ └── Timer.vue
│ ├── layout
│ ├── LayOutContainer.vue
│ └── LayOutSettings.vue
│ ├── pc
│ ├── About.vue
│ ├── AddCustomToDo.vue
│ ├── CustomToDo.vue
│ ├── PlainToDo.vue
│ ├── Pomodoro.vue
│ └── Timer.vue
│ └── settings
│ ├── AppearanceSettings.vue
│ ├── ClockSettings.vue
│ ├── GlobalSettings.vue
│ └── ToDoSettings.vue
├── vite.config.js
├── 软件使用说明书.md
└── 项目开发笔记.md
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | .DS_Store
12 | dist
13 | dist-ssr
14 | coverage
15 | *.local
16 |
17 | .vscode
18 | dist_electron
19 |
20 |
21 | /cypress/videos/
22 | /cypress/screenshots/
23 |
24 | # Editor directories and files
25 | .vscode/*
26 | !.vscode/extensions.json
27 | .idea
28 | *.suo
29 | *.ntvs*
30 | *.njsproj
31 | *.sln
32 | *.sw?
33 |
34 | *.tsbuildinfo
35 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | node-linker=hoisted
2 | ELECTRON_MIRROR=https://npmmirror.com/mirrors/electron/
3 | ELECTRON_BUILDER_BINARIES_MIRROR=https://npmmirror.com/mirrors/electron-builder-binaries/
4 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 Albert Zhang
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # iTime
2 |
3 | ## 介绍 📘
4 |
5 | iTime🕰️ 是一款基于**vue3**、**arco design**、**electron**开发的桌面端效率应用,slogan 是`让每一秒都刚刚好`,意为提高您的效率,帮助您充分利用自己的每一秒。项目功能模块有**待办模块**、**倒计时模块**、**番茄钟模块**、**自定义设置模块**。
6 | ## 项目预览 👀
7 | 视频版本(B站):[基于electron开发的桌面端效率软件—第一期【功能介绍】](https://www.bilibili.com/video/BV1Yt421W79i)
8 |
9 | 文字版本:移步[iTime软件使用介绍](https://github.com/AZCodingAccount/iTime/blob/master/软件使用说明书.md),内有详细功能介绍与Gif图
10 |
11 | ## 代码仓库 🌟
12 |
13 | - Gitee:https://gitee.com/AZCodingAccount/iTime
14 | - GitHub:https://github.com/AZCodingAccount/iTime
15 |
16 | ## 快速开始 🚀
17 |
18 | - **拉取项目** (您需要先安装 Git)
19 |
20 | ```bash
21 | # Gitee
22 | git pull https://gitee.com/AZCodingAccount/iTime.git
23 | # GitHub
24 | git pull https://github.com/AZCodingAccount/iTime.git
25 | ```
26 |
27 | - 运行项目
28 |
29 |
30 |
31 | ```bash
32 | cd 拉取项目目录
33 | pnpm i # 安装依赖
34 | pnpm dev # 运行vue程序
35 | pnpm start # 运行electron桌面程序
36 | ```
37 |
38 | ℹ️ 在开发环境下,您需要设置相应的图片和语音路径,默认路径为生产环境下的
39 |
40 | ## 项目技术应用 🛠️
41 |
42 | 1. `Vue3`+`Electron`为主要开发技术
43 | 2. 采用`aro design`组件库并进行一定程度定制
44 | 3. 数据持久化采用`pinia`
45 | 4. 引入`quill`富文本编辑器
46 | 5. 第三方包
47 | 1. `uuid`生成 TODO 随机 id
48 | 2. `dayjs`格式化时间
49 | 3. `electron-is-dev`判断开发或生产环境
50 | 4. `electron-win-state`持久化窗口状态
51 | 5. `pinia-plugin-persistedstate`持久化 pinia
52 | 6. [`unplugin-vue-components`](https://github.com/antfu/unplugin-vue-components)+ [`unplugin-auto-import`](https://github.com/antfu/unplugin-auto-import) 按需引入组件
53 | 6. 打包使用`electron-builder`
54 |
55 | ## 未来 🔮
56 |
57 | - 🪄 自定义外观
58 | - 📸 集成截图和 OCR 功能
59 | - 🤖 集成 ChatGPT
60 |
61 | ## 贡献 🤝
62 |
63 | 项目欢迎任何形式的贡献
64 |
65 | - 提出[issue](https://github.com/AZCodingAccount/iTime/issues)报告 bug 或要求新功能
66 | - 提交[PR](https://github.com/AZCodingAccount/iTime/pulls)帮助完善应用
67 |
--------------------------------------------------------------------------------
/auto-imports.d.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | /* prettier-ignore */
3 | // @ts-nocheck
4 | // noinspection JSUnusedGlobalSymbols
5 | // Generated by unplugin-auto-import
6 | export {}
7 | declare global {
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/components.d.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | /* prettier-ignore */
3 | // @ts-nocheck
4 | // Generated by unplugin-vue-components
5 | // Read more: https://github.com/vuejs/core/pull/3399
6 | export {}
7 |
8 | declare module 'vue' {
9 | export interface GlobalComponents {
10 | AButton: typeof import('@arco-design/web-vue')['Button']
11 | ACard: typeof import('@arco-design/web-vue')['Card']
12 | ACollapse: typeof import('@arco-design/web-vue')['Collapse']
13 | ACollapseItem: typeof import('@arco-design/web-vue')['CollapseItem']
14 | ADatePicker: typeof import('@arco-design/web-vue')['DatePicker']
15 | ADivider: typeof import('@arco-design/web-vue')['Divider']
16 | AForm: typeof import('@arco-design/web-vue')['Form']
17 | AFormItem: typeof import('@arco-design/web-vue')['FormItem']
18 | AInput: typeof import('@arco-design/web-vue')['Input']
19 | AInputNumber: typeof import('@arco-design/web-vue')['InputNumber']
20 | AInputTag: typeof import('@arco-design/web-vue')['InputTag']
21 | ALayout: typeof import('@arco-design/web-vue')['Layout']
22 | ALayoutContent: typeof import('@arco-design/web-vue')['LayoutContent']
23 | ALayoutHeader: typeof import('@arco-design/web-vue')['LayoutHeader']
24 | ALayoutSider: typeof import('@arco-design/web-vue')['LayoutSider']
25 | AList: typeof import('@arco-design/web-vue')['List']
26 | AListItem: typeof import('@arco-design/web-vue')['ListItem']
27 | AListItemMeta: typeof import('@arco-design/web-vue')['ListItemMeta']
28 | AMenu: typeof import('@arco-design/web-vue')['Menu']
29 | AMenuItem: typeof import('@arco-design/web-vue')['MenuItem']
30 | AModal: typeof import('@arco-design/web-vue')['Modal']
31 | AOption: typeof import('@arco-design/web-vue')['Option']
32 | AProgress: typeof import('@arco-design/web-vue')['Progress']
33 | ASelect: typeof import('@arco-design/web-vue')['Select']
34 | ASlider: typeof import('@arco-design/web-vue')['Slider']
35 | ASwitch: typeof import('@arco-design/web-vue')['Switch']
36 | ATag: typeof import('@arco-design/web-vue')['Tag']
37 | ATextarea: typeof import('@arco-design/web-vue')['Textarea']
38 | ATimePicker: typeof import('@arco-design/web-vue')['TimePicker']
39 | AUpload: typeof import('@arco-design/web-vue')['Upload']
40 | RouterLink: typeof import('vue-router')['RouterLink']
41 | RouterView: typeof import('vue-router')['RouterView']
42 | ToDoList: typeof import('./src/components/ToDoList.vue')['default']
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | iTime
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/jsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "paths": {
4 | "@/*": ["./src/*"]
5 | }
6 | },
7 | "exclude": ["node_modules", "dist"]
8 | }
9 |
--------------------------------------------------------------------------------
/main.js:
--------------------------------------------------------------------------------
1 | // 导入模块,不能使用ES6的语法
2 | const {
3 | app,
4 | BrowserWindow,
5 | Menu,
6 | ipcMain,
7 | shell,
8 | globalShortcut,
9 | Notification,
10 | dialog,
11 | powerSaveBlocker,
12 | } = require("electron");
13 | const path = require("path");
14 | const WinState = require("electron-win-state").default;
15 | const fs = require("fs");
16 | // 检查是否已经有一个实例运行
17 | const isSingleInstance = app.requestSingleInstanceLock();
18 |
19 | if (!isSingleInstance) {
20 | // 如果已经有一个实例在运行,关闭当前实例并退出
21 | app.quit();
22 | }
23 | let isDev = false;
24 | async function checkIsDev() {
25 | const module = await import("electron-is-dev");
26 | isDev = module.default;
27 | // 全局捕获一下
28 | try {
29 | console.log(isDev);
30 | work();
31 | } catch (error) {
32 | dialog.showMessageBox({
33 | type: "error", // 对话框类型
34 | title: "未知错误", // 标题栏文本
35 | message: "未知错误,请联系开发者", // 主消息文本
36 | // detail: error.message, // 详细错误信息
37 | buttons: ["确定"], // 对话框按钮
38 | });
39 | }
40 | }
41 | checkIsDev();
42 |
43 | const work = () => {
44 | if (process.platform === "win32") {
45 | app.setAppUserModelId(app.name);
46 | }
47 | // 创建一个窗口
48 | let win = null;
49 | let globalSettings = []; // 用户全局配置 position:0|voice:1
50 |
51 | // 创建主窗口
52 | const createWindow = () => {
53 | // 防止打开两个主窗口程序
54 | if (win != null) {
55 | return;
56 | }
57 | const winState = new WinState({});
58 | win = new BrowserWindow({
59 | ...WinState.winOptions,
60 | icon: "public/icons/icon.png", // 指定图标路径
61 | webPreferences: {
62 | devTools: false,
63 | webSecurity: false, // 禁用 Web 安全策略
64 | nodeIntegration: true, // 启用集成
65 | backgroundThrottling: false, // 取消节流
66 | // 不安全,不建议使用
67 | // nodeIntegration: true, // 启用Node.js集成
68 | // contextIsolation: false, // 取消上下文隔离
69 | sandbox: false, // 取消沙箱模式
70 | preload: path.resolve(__dirname, "./preload"), // 在预加载脚本中执行 Electron API
71 | },
72 | });
73 | win.setSize(1100, 700); // 显式设置窗口大小,因为之前的大小被缓存了
74 | win.center(); // 使窗口居中
75 | win.setMenu(null); // 去掉窗口
76 | if (isDev) {
77 | win.loadURL("http://localhost:5173");
78 | } else {
79 | win.loadFile(path.join("dist", "index.html"));
80 | }
81 | // win.webContents.openDevTools(); // 打开开发者工具
82 | winState.manage(win); // 配置持久化
83 | win.on("ready-to-show", () => {
84 | win.show();
85 | });
86 | // 配置所有外部url都使用浏览器打开
87 | win.webContents.setWindowOpenHandler(({ url }) => {
88 | shell.openExternal(url); // 使用外部浏览器打开
89 | return { action: "deny" }; // 阻止 Electron 打开新窗口
90 | });
91 | };
92 |
93 | // 创建待办小挂件窗口
94 | const addToDoToDesktop = (title, content) => {
95 | let todoWindow = new BrowserWindow({
96 | width: 400,
97 | height: 300,
98 | transparent: true, // 透明
99 | frame: false, // 无边框窗口
100 | skipTaskbar: true, // 不在任务栏中显示
101 | webPreferences: {
102 | sandbox: false, // 取消沙箱模式
103 | backgroundThrottling: false, // 取消节流
104 | preload: path.resolve(__dirname, "./preload"), // 配置预加载脚本
105 | },
106 | });
107 |
108 | // 加载本地文件(测试过程中通过url访问)
109 | if (isDev) {
110 | todoWindow.loadURL("http://localhost:5173/#/desktop/customtodo");
111 | } else {
112 | // 导航到特定路由
113 | todoWindow.loadURL(
114 | `file://${path.join(
115 | __dirname,
116 | "dist",
117 | "index.html"
118 | )}#/desktop/customtodo`
119 | );
120 | }
121 |
122 | // 等待加载完成以后并且延迟500ms发送消息
123 | // 自行测试时间,之前我的100ms就可以,但是电脑性能慢一点需要的时间更多,我索性就直接500ms了
124 | todoWindow.webContents.on("did-finish-load", () => {
125 | setTimeout(() => {
126 | todoWindow.webContents.send("load-html-content", title, content);
127 | console.log("Message sent after delay!");
128 | }, 500); // 延迟时间,以毫秒为单位
129 | });
130 | todoWindow.setAlwaysOnTop(globalSettings[0].todoP); // 动态配置是否置顶
131 |
132 | // todoWindow.webContents.openDevTools(); // 打开开发者工具
133 |
134 | todoWindow.on("closed", () => {
135 | todoWindow = null;
136 | });
137 | // 优雅的打开窗口
138 | todoWindow.once("ready-to-show", () => {
139 | todoWindow.show();
140 | });
141 | // hook这个右键消息,禁用窗口
142 | todoWindow.hookWindowMessage(278, function (e) {
143 | todoWindow.setEnabled(false); //窗口禁用
144 | setTimeout(() => {
145 | todoWindow.setEnabled(true); //窗口启用
146 | }, 1);
147 | return true;
148 | });
149 | };
150 | // 创建全屏计时器窗口
151 | const createTimerWindow = () => {
152 | let timerWindow = new BrowserWindow({
153 | frame: false,
154 | fullscreen: true,
155 | resizable: false, // 不允许重新设置尺寸
156 | skipTaskbar: true, // 不在任务栏中显示
157 | webPreferences: {
158 | sandbox: false, // 取消沙箱模式
159 | preload: path.resolve(__dirname, "./preload"), // 预加载脚本
160 | backgroundThrottling: false, // 取消节流
161 | },
162 | });
163 | if (isDev) {
164 | timerWindow.loadURL("http://localhost:5173/#/fullscreen/timer");
165 | } else {
166 | // timerWindow
167 | // .loadFile(path.join(__dirname, "dist", "index.html"))
168 | // .then(() => {
169 | // timerWindow.loadURL(
170 | // `file://${path.join(
171 | // __dirname,
172 | // "dist",
173 | // "index.html"
174 | // )}#/fullscreen/timer`
175 | // );
176 | // });
177 | timerWindow.loadURL(
178 | `file://${path.join(__dirname, "dist", "index.html")}#/fullscreen/timer`
179 | );
180 | }
181 | timerWindow.on("closed", () => {
182 | timerWindow = null;
183 | });
184 | // 优雅的打开窗口
185 | timerWindow.on("ready-to-show", () => {
186 | timerWindow.show();
187 | });
188 | };
189 | // 创建定时器小挂件窗口
190 | const createTimerWidgetWindow = () => {
191 | let timerWidgetWindow = new BrowserWindow({
192 | width: 354,
193 | height: 84,
194 | transparent: true, // 透明
195 | frame: false, // 无边框窗口
196 | skipTaskbar: true, // 不在任务栏中显示
197 | resizable: false, // 不允许重新设置尺寸
198 | webPreferences: {
199 | sandbox: false, // 取消沙箱模式
200 | preload: path.resolve(__dirname, "./preload"), // 配置预加载脚本
201 | backgroundThrottling: false, // 取消节流
202 | },
203 | });
204 | if (isDev) {
205 | timerWidgetWindow.loadURL("http://localhost:5173/#/desktop/timer");
206 | } else {
207 | // timerWidgetWindow
208 | // .loadFile(path.join(__dirname, "dist", "index.html"))
209 | // .then(() => {
210 | // timerWidgetWindow.loadURL(
211 | // `file://${path.join(
212 | // __dirname,
213 | // "dist",
214 | // "index.html"
215 | // )}#/desktop/timer`
216 | // );
217 | // });
218 | timerWidgetWindow.loadURL(
219 | `file://${path.join(__dirname, "dist", "index.html")}#/desktop/timer`
220 | );
221 | }
222 | timerWidgetWindow.on("closed", () => {
223 | timerWidgetWindow = null;
224 | });
225 | // 优雅的打开窗口
226 | timerWidgetWindow.once("ready-to-show", () => {
227 | timerWidgetWindow.show();
228 | });
229 | timerWidgetWindow.setAlwaysOnTop(globalSettings[0].timerP); // 动态设置窗口位置
230 | // hook这个右键消息,取消右键
231 | timerWidgetWindow.hookWindowMessage(278, function (e) {
232 | timerWidgetWindow.setEnabled(false); //窗口禁用
233 | setTimeout(() => {
234 | timerWidgetWindow.setEnabled(true); //窗口启用
235 | }, 1);
236 | return true;
237 | });
238 | };
239 | // 创建全屏番茄钟窗口
240 | const createPomodoroWindow = () => {
241 | let pomodoroWindow = new BrowserWindow({
242 | frame: false,
243 | fullscreen: true,
244 | resizable: false,
245 | skipTaskbar: true, // 不在任务栏中显示
246 | webPreferences: {
247 | // webSecurity: false, // 允许加载本地文件
248 | // allowFileAccess: true, // 允许访问文件
249 | sandbox: false, // 取消沙箱模式
250 | backgroundThrottling: false, // 取消节流
251 | preload: path.resolve(__dirname, "./preload"),
252 | },
253 | });
254 | if (isDev) {
255 | pomodoroWindow.loadURL("http://localhost:5173/#/fullscreen/pomodoro");
256 | } else {
257 | // pomodoroWindow
258 | // .loadFile(path.join(__dirname, "dist", "index.html"))
259 | // .then(() => {
260 | // pomodoroWindow.loadURL(
261 | // `file://${path.join(
262 | // __dirname,
263 | // "dist",
264 | // "index.html"
265 | // )}#/fullscreen/pomodoro`
266 | // );
267 | // });
268 | pomodoroWindow.loadURL(
269 | `file://${path.join(
270 | __dirname,
271 | "dist",
272 | "index.html"
273 | )}#/fullscreen/pomodoro`
274 | );
275 | } // 清除窗口状态
276 | pomodoroWindow.on("closed", () => {
277 | pomodoroWindow = null;
278 | });
279 | // 优雅的打开窗口
280 | pomodoroWindow.on("ready-to-show", () => {
281 | pomodoroWindow.show();
282 | });
283 | };
284 | // 创建番茄钟小挂件窗口
285 | const createPomodoroWidgetWindow = () => {
286 | let pomodoroWidgetWindow = new BrowserWindow({
287 | width: 374,
288 | height: 104,
289 | transparent: true, // 透明
290 | frame: false, // 无边框窗口
291 | resizable: false,
292 | skipTaskbar: true, // 不在任务栏中显示
293 | webPreferences: {
294 | backgroundThrottling: false, // 取消节流
295 | sandbox: false, // 取消沙箱模式
296 | preload: path.resolve(__dirname, "./preload"), // 配置预加载脚本
297 | },
298 | });
299 | if (isDev) {
300 | pomodoroWidgetWindow.loadURL("http://localhost:5173/#/desktop/pomodoro");
301 | } else {
302 | // pomodoroWidgetWindow
303 | // .loadFile(path.join(__dirname, "dist", "index.html"))
304 | // .then(() => {
305 | // pomodoroWidgetWindow.loadURL(
306 | // `file://${path.join(
307 | // __dirname,
308 | // "dist",
309 | // "index.html"
310 | // )}#/desktop/pomodoro`
311 | // );
312 | // });
313 | pomodoroWidgetWindow.loadURL(
314 | `file://${path.join(__dirname, "dist", "index.html")}#/desktop/pomodoro`
315 | );
316 | } // 清除窗口状态
317 | pomodoroWidgetWindow.on("closed", () => {
318 | pomodoroWidgetWindow = null;
319 | });
320 | pomodoroWidgetWindow.on("closed", () => {
321 | pomodoroWidgetWindow = null;
322 | });
323 | pomodoroWidgetWindow.setAlwaysOnTop(globalSettings[0].pomodoroP); // 动态设置窗口位置
324 |
325 | // pomodoroWidgetWindow.webContents.openDevTools();
326 | pomodoroWidgetWindow.once("ready-to-show", () => {
327 | pomodoroWidgetWindow.show();
328 | });
329 | // hook这个右键消息,禁用右键菜单
330 | pomodoroWidgetWindow.hookWindowMessage(278, function (e) {
331 | pomodoroWidgetWindow.setEnabled(false); //窗口禁用
332 | setTimeout(() => {
333 | pomodoroWidgetWindow.setEnabled(true); //窗口启用
334 | }, 1);
335 | return true;
336 | });
337 | };
338 | app.whenReady().then(() => {
339 | createWindow();
340 |
341 | // 阻止应用进入低功耗模式
342 | const id = powerSaveBlocker.start("prevent-app-suspension");
343 |
344 | app.on("activate", () => {
345 | if (BrowserWindow.getAllWindows().length === 0) {
346 | createWindow();
347 | }
348 | });
349 | });
350 | // 适配mac
351 | app.on("window-all-closed", () => {
352 | if (process.platform !== "darwin") {
353 | app.quit();
354 | }
355 | });
356 | // 获取当前操作系统
357 | ipcMain.handle("get-current-os", async (event) => {
358 | return process.platform;
359 | });
360 | // 删除待办
361 | const removeToDo = (id) => {
362 | win.webContents.send("remove-todo", id);
363 | };
364 | // 编辑待办
365 | const editToDo = (id) => {
366 | win.webContents.send("edit-todo", id);
367 | };
368 | let contextMenu = null;
369 | // 创建右键菜单
370 | ipcMain.on("show-context-menu", (event, type, id, title, content) => {
371 | const menuTemplate = [];
372 | // 根据类型添加不同的菜单项
373 | if (type === "customToDo") {
374 | menuTemplate.push({
375 | label: "添加待办挂件",
376 | click: () => {
377 | addToDoToDesktop(title, content);
378 | },
379 | });
380 | menuTemplate.push({
381 | label: "编辑待办",
382 | click: () => {
383 | // 直接把数据传给添加新待办那个组件过去就行了,顺便编辑成功把待办删除了
384 | editToDo(id);
385 | },
386 | });
387 | menuTemplate.push({
388 | label: "删除待办",
389 | click: () => {
390 | // 发送消息告诉本地存储里面的东西可以删除了
391 | removeToDo(id);
392 | },
393 | });
394 | }
395 |
396 | // 创建菜单
397 | contextMenu = Menu.buildFromTemplate(menuTemplate);
398 |
399 | contextMenu.popup(BrowserWindow.fromWebContents(event.sender)); // 弹出菜单
400 | });
401 |
402 | // 打开倒计时窗口 @params type |f:全屏|a: add widget
403 | ipcMain.on("open-timer-window", (event, type) => {
404 | if (type === "f") {
405 | createTimerWindow();
406 | } else if (type === "a") {
407 | // 添加小挂件
408 | createTimerWidgetWindow();
409 | }
410 | });
411 | // 打开番茄钟窗口 @params type |f:全屏|a: add widget
412 | ipcMain.on("open-pomodoro-window", (event, type) => {
413 | if (type === "f") {
414 | createPomodoroWindow();
415 | } else if (type === "a") {
416 | // 添加小挂件
417 | createPomodoroWidgetWindow();
418 | }
419 | });
420 | // 移除窗口
421 | ipcMain.on("remove-window", (event) => {
422 | const window = BrowserWindow.fromWebContents(event.sender);
423 | if (window) {
424 | window.close();
425 | }
426 | });
427 |
428 | // 保存文件
429 | ipcMain.handle("save-file", (event, type, originFilePath) => {
430 | const pathDir = "backgrounds";
431 |
432 | if (type && originFilePath) {
433 | // 获取原始文件的扩展名
434 | const fileExtension = path.extname(originFilePath);
435 | const fileName = type + fileExtension; // 构造新文件名
436 | const newFilePath = path.join(process.resourcesPath, pathDir, fileName);
437 | console.log(newFilePath);
438 | // 确保backgrounds目录存在
439 | if (!fs.existsSync(path.join(process.resourcesPath, pathDir))) {
440 | fs.mkdirSync(path.join(process.resourcesPath, pathDir), {
441 | recursive: true,
442 | });
443 | }
444 |
445 | return new Promise((resolve, reject) => {
446 | // 读取原始文件内容
447 | fs.readFile(originFilePath, (readErr, data) => {
448 | if (readErr) {
449 | reject(readErr);
450 | } else {
451 | // 将内容写入新文件
452 | fs.writeFile(newFilePath, data, (writeErr) => {
453 | if (writeErr) {
454 | reject(writeErr);
455 | } else {
456 | // 返回新文件的路径
457 | let pathName = "/" + pathDir + "/" + fileName;
458 | resolve(pathName);
459 | }
460 | });
461 | }
462 | });
463 | });
464 | }
465 | return null;
466 | });
467 | // 同步全局配置
468 | ipcMain.on("sync-else-setting", (event, settings) => {
469 | // 更新全局的值即可
470 | globalSettings = settings;
471 | });
472 |
473 | // 全局快捷键设置
474 | ipcMain.handle("shortcut-setting", async (event, keys) => {
475 | globalShortcutSettings = keys;
476 | let isOccupied = false; // 标记下方有没有被占用的快捷键
477 | if (keys) {
478 | // 挨个检查有没有注册过的快捷键
479 | if (
480 | !globalShortcut.register(keys.fPomodoro, () => {
481 | // 全屏番茄钟
482 | createPomodoroWindow();
483 | })
484 | ) {
485 | isOccupied = true;
486 | }
487 | if (
488 | !globalShortcut.register(keys.wPomodoro, () => {
489 | // 番茄钟挂件
490 | createPomodoroWidgetWindow();
491 | })
492 | ) {
493 | isOccupied = true;
494 | }
495 | if (
496 | !globalShortcut.register(keys.fTimer, () => {
497 | // 全屏计时器
498 | createTimerWindow();
499 | })
500 | ) {
501 | isOccupied = true;
502 | }
503 | if (
504 | !globalShortcut.register(keys.wTimer, () => {
505 | // 计时器挂件
506 | createTimerWidgetWindow();
507 | })
508 | ) {
509 | isOccupied = true;
510 | }
511 | }
512 | return isOccupied;
513 | });
514 |
515 | // 禁用所有快捷键
516 | ipcMain.on("disable-all-shortcut", () => {
517 | globalShortcut.unregisterAll();
518 | });
519 |
520 | // 调用原生api给用户通知
521 | // @params type |pomodoro-shortBreak|pomodoro-longBreak|pomodoro-work|timer-half|timer-full|todo
522 | ipcMain.on("notification-user", (event, type) => {
523 | // 也可以传进来title和body,考虑扩展性
524 | if (Notification.isSupported()) {
525 | let notification = null;
526 | switch (type) {
527 | case "pomodoro-shortBreak":
528 | notification = new Notification({
529 | title: "短休息时间到",
530 | body: "时间到了,短短的休息一会儿吧",
531 | silent: true, // 静音通知
532 | });
533 | break;
534 | case "pomodoro-longBreak":
535 | notification = new Notification({
536 | title: "长休息时间到",
537 | body: "你太棒了,接下来是长休息时间",
538 | silent: true, // 静音通知
539 | });
540 | break;
541 | case "pomodoro-work":
542 | notification = new Notification({
543 | title: "专注时间到",
544 | body: "好了,开始专注吧",
545 | silent: true, // 静音通知
546 | });
547 | break;
548 | case "timer-half":
549 | notification = new Notification({
550 | title: "倒计时过半",
551 | body: "时间已经过去一半了",
552 | silent: true, // 静音通知
553 | });
554 | break;
555 | case "timer-full":
556 | notification = new Notification({
557 | title: "倒计时结束",
558 | body: "倒计时结束了",
559 | silent: true, // 静音通知
560 | });
561 | break;
562 | case "todo":
563 | notification = new Notification({
564 | title: "待办提醒",
565 | body: "您现在有计划的安排,提醒您一下哈",
566 | silent: true, // 静音通知
567 | });
568 | break;
569 | }
570 |
571 | notification.show();
572 | }
573 | });
574 | };
575 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "iTime",
3 | "version": "1.1.0",
4 | "description": "基于electron+vue3+arco design开发的桌面效率工具",
5 | "author": "AlbertZhang",
6 | "private": true,
7 | "main": "main.js",
8 | "homepage": "./",
9 | "scripts": {
10 | "dev": "vite",
11 | "build": "vite build",
12 | "preview": "vite preview",
13 | "start": "nodemon --exec electron . --watch ./ --ext .js,.html,.css,.vue",
14 | "electron:build": "electron-builder"
15 | },
16 | "build": {
17 | "appId": "com.albertzhang.itime",
18 | "productName": "iTime",
19 | "asar": true,
20 | "directories": {
21 | "output": "dist_electron"
22 | },
23 | "nsis": {
24 | "oneClick": false,
25 | "allowToChangeInstallationDirectory": true,
26 | "deleteAppDataOnUninstall": true
27 | },
28 | "extraFiles": [
29 | {
30 | "from": "src/assets",
31 | "to": "resources/assets"
32 | },
33 | {
34 | "from": "软件使用说明书.md",
35 | "to": "软件使用说明书.md"
36 | }
37 | ],
38 | "afterPack": "scripts/afterPack.js",
39 | "artifactBuildCompleted": "scripts/rename.js",
40 | "files": [
41 | "dist/**/*",
42 | "main.js",
43 | "preload/**/*",
44 | "package.json",
45 | "scripts/**/*"
46 | ],
47 | "win": {
48 | "target": [
49 | {
50 | "target": "nsis"
51 | },
52 | {
53 | "target": "portable"
54 | },
55 | {
56 | "target": "msi"
57 | }
58 | ],
59 | "icon": "dist/icons/icon.png"
60 | },
61 | "mac": {
62 | "target": [
63 | "dmg",
64 | "zip"
65 | ],
66 | "hardenedRuntime": true
67 | }
68 | },
69 | "dependencies": {
70 | "@arco-design/web-vue": "^2.54.3",
71 | "@vueup/vue-quill": "^1.2.0",
72 | "dayjs": "^1.11.10",
73 | "electron-is-dev": "^3.0.1",
74 | "electron-win-state": "^1.1.22",
75 | "pinia": "^2.1.7",
76 | "pinia-plugin-persistedstate": "^3.2.1",
77 | "unplugin-vue-components": "^0.26.0",
78 | "uuid": "^9.0.1",
79 | "vue": "^3.3.11",
80 | "vue-router": "^4.2.5"
81 | },
82 | "devDependencies": {
83 | "@vitejs/plugin-vue": "^4.5.2",
84 | "electron": "^28.1.4",
85 | "electron-builder": "^24.9.1",
86 | "unplugin-auto-import": "^0.17.3",
87 | "vite": "^5.0.10"
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/preload/index.js:
--------------------------------------------------------------------------------
1 | const { contextBridge, ipcRenderer } = require("electron");
2 |
3 | contextBridge.exposeInMainWorld("electron", {
4 | // 渲染进程向主进程发消息
5 | // 展示右键菜单
6 | showContextMenu: (type, id, title, content) =>
7 | ipcRenderer.send("show-context-menu", type, id, title, content),
8 | // 移除窗口,都可以使用这个方法
9 | removeWindow: () => {
10 | ipcRenderer.send("remove-window");
11 | },
12 | // 打开一个全屏的倒计时窗口
13 | // @params type 'f' 全屏|'a' 打开挂件
14 | openTimerWindow: (type) => {
15 | ipcRenderer.send("open-timer-window", type);
16 | },
17 | // 打开一个番茄钟窗口
18 | // @params type 'f' 全屏|'a' 打开挂件
19 | openPomodoroWindow: (type) => {
20 | ipcRenderer.send("open-pomodoro-window", type);
21 | },
22 | // 退出窗口
23 | // 同步系统设置
24 | syncElseSetting: (customSettings) => {
25 | ipcRenderer.send("sync-else-setting", customSettings);
26 | },
27 | // 禁用所有快捷键
28 | disableAllShortcut: () => {
29 | ipcRenderer.send("disable-all-shortcut");
30 | },
31 | notificationUser: (type) => {
32 | ipcRenderer.send("notification-user", type);
33 | },
34 |
35 | // 主进程向渲染进程发消息
36 | // 参数是一个回调函数,用的话直接使用回调函数即可。
37 | // 接收参数
38 | loadHtmlContent: (callback) => {
39 | ipcRenderer.on("load-html-content", (event, title, content) => {
40 | callback(title, content);
41 | });
42 | },
43 | // 删除待办
44 | removeToDo: (callback) => {
45 | ipcRenderer.on("remove-todo", (event, id) => {
46 | console.log("删除待办", id);
47 | callback(id);
48 | });
49 | },
50 | // 编辑待办
51 | editToDo: (callback) => {
52 | ipcRenderer.on("edit-todo", (event, id) => {
53 | callback(id);
54 | });
55 | },
56 |
57 | // 双向通信
58 | // 保存文件
59 | saveFile: (type, originFilePath) =>
60 | ipcRenderer.invoke("save-file", type, originFilePath),
61 | // 快捷键设置
62 | shortcutSetting: (customSettingsForIpc) =>
63 | ipcRenderer.invoke("shortcut-setting", customSettingsForIpc),
64 | // 获取当前系统
65 | getCurrentOS: () => ipcRenderer.invoke("get-current-os"), // 直接在预加载进程也可以访问到
66 | // 获取app路径
67 | getAppPath: () => process.resourcesPath,
68 | });
69 |
--------------------------------------------------------------------------------
/public/icons/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AZCodingAccount/iTime/6e4d2b39cb80cd2ccd984537195228ed3c81060a/public/icons/icon.png
--------------------------------------------------------------------------------
/scripts/afterPack.js:
--------------------------------------------------------------------------------
1 | const path = require("path");
2 | const fs = require("fs-extra");
3 |
4 | module.exports = async (context) => {
5 | const unpackedDir = path.join(context.appOutDir, "locales");
6 |
7 | // 删除除 zh-CN.pak 之外的所有文件
8 | const files = await fs.readdir(unpackedDir);
9 | for (const file of files) {
10 | if (!file.endsWith("zh-CN.pak")) {
11 | await fs.remove(path.join(unpackedDir, file));
12 | }
13 | }
14 |
15 | // 删除特定的文件
16 | const filesToDelete = ["LICENSE.electron.txt", "LICENSES.chromium.html"];
17 |
18 | for (const fileName of filesToDelete) {
19 | const filePath = path.join(context.appOutDir, fileName);
20 | if (await fs.pathExists(filePath)) {
21 | await fs.remove(filePath);
22 | }
23 | }
24 | };
25 |
--------------------------------------------------------------------------------
/scripts/rename.js:
--------------------------------------------------------------------------------
1 | const fs = require("fs");
2 | const path = require("path");
3 | // 主打就是一点体力活都不干
4 | module.exports = async function (params) {
5 | // 读取版本号
6 | const packageJson = require("../package.json");
7 | const version = packageJson.version;
8 | let artifact = params.file;
9 | let originFile = artifact;
10 |
11 | const ext = path.extname(artifact);
12 | // 处理版本号前缀,注意空格
13 | artifact = artifact.replace(` ${version}`, `-${version}`);
14 | let newName;
15 |
16 | if (ext === ".exe" && !artifact.includes("Setup")) {
17 | // 不用安装的程序
18 | newName = artifact.replace(/\.exe$/, "-windows-no-installer.exe");
19 | } else if (ext === ".exe") {
20 | // 常规安装包
21 | newName = artifact.replace(
22 | ` Setup-${version}.exe`,
23 | `-${version}-windows-installer.exe`
24 | );
25 | } else {
26 | newName = artifact;
27 | }
28 |
29 | // 重命名
30 | if (newName) {
31 | fs.renameSync(originFile, newName);
32 | }
33 | };
34 |
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
--------------------------------------------------------------------------------
/src/assets/defaultBGI.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AZCodingAccount/iTime/6e4d2b39cb80cd2ccd984537195228ed3c81060a/src/assets/defaultBGI.jpg
--------------------------------------------------------------------------------
/src/assets/main.css:
--------------------------------------------------------------------------------
1 | /* 全局样式 */
2 | html,
3 | body {
4 | width: 100%;
5 | height: 100%;
6 | margin: 0;
7 | padding: 0;
8 | border: 0;
9 | /* 或者灰色,#f5f5f5 */
10 | /* background-color: #f5f5f5; */
11 | /* background-color: rgba(0, 0, 0, 0); */
12 | }
13 | * {
14 | margin: 0;
15 | user-select: none;
16 | }
17 | a {
18 | text-decoration: none;
19 | color: inherit;
20 | }
21 |
22 | #app {
23 | width: 100%;
24 | height: 100%;
25 | margin: 0;
26 | padding: 0;
27 | border: 0;
28 | }
29 | html {
30 | /* 禁用滚动条,因为用的无框架窗口,默认就会有一个滚动条,所以去掉 */
31 | overflow-y: hidden;
32 | }
33 |
34 | /*定义滚动条高宽及背景 高宽分别对应横竖滚动条的尺寸*/
35 | ::-webkit-scrollbar {
36 | width: 2px; /*滚动条宽度*/
37 | /*height: 2px; !*滚动条高度*!*/
38 | }
39 |
40 | /*定义滚动条轨道 内阴影+圆角*/
41 | ::-webkit-scrollbar-track {
42 | /*-webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3);*/
43 | /*border-radius: 10px; !*滚动条的背景区域的圆角*!*/
44 | /*background-color: red;!*滚动条的背景颜色*!*/
45 | }
46 |
47 | /*定义滑块 内阴影+圆角*/
48 | ::-webkit-scrollbar-thumb {
49 | border-radius: 99px; /*滚动条的圆角*/
50 | /*-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, .3);*/
51 | /*background-color: green; !*滚动条的背景颜色*!*/
52 | }
53 |
54 | /* 在这里自定义一些html全局样式,其实需要定义的也不算多,就一个列表和标题。需要自己把握间距了~~~ */
55 | /* 原本40px */
56 | ul {
57 | padding-inline-start: 17px;
58 | }
59 | ol {
60 | padding-inline-start: 25px;
61 | }
62 | ul li{
63 | padding-left: 4px;
64 | }
65 |
66 | ol li{
67 | padding-left: 2px;
68 | }
69 | /* 原本没有间距 */
70 | li {
71 | margin: 0.8em 0;
72 | }
73 | /* marker用于定制元素的样式(比如大小颜色),before用于改变样式,比如改变标点符号,必须加!important,不然会被覆盖 */
74 | /* 无序列表 */
75 | .ql-container ul > li::before {
76 | content: var(--ulIcon, "●") !important;
77 | }
78 |
79 | .card ul > li::marker {
80 | content: var(--ulIcon, "●") !important;
81 | }
82 |
83 | /* h1 原本0.67em */
84 | h1 {
85 | margin: 0.2em 0;
86 | }
87 | /* p */
88 | p {
89 | margin: 0.5em;
90 | }
91 |
--------------------------------------------------------------------------------
/src/assets/voices/pomodoro/default/focus.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AZCodingAccount/iTime/6e4d2b39cb80cd2ccd984537195228ed3c81060a/src/assets/voices/pomodoro/default/focus.wav
--------------------------------------------------------------------------------
/src/assets/voices/pomodoro/default/longBreak.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AZCodingAccount/iTime/6e4d2b39cb80cd2ccd984537195228ed3c81060a/src/assets/voices/pomodoro/default/longBreak.wav
--------------------------------------------------------------------------------
/src/assets/voices/pomodoro/default/shortBreak.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AZCodingAccount/iTime/6e4d2b39cb80cd2ccd984537195228ed3c81060a/src/assets/voices/pomodoro/default/shortBreak.wav
--------------------------------------------------------------------------------
/src/assets/voices/pomodoro/dingzhen/focus.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AZCodingAccount/iTime/6e4d2b39cb80cd2ccd984537195228ed3c81060a/src/assets/voices/pomodoro/dingzhen/focus.wav
--------------------------------------------------------------------------------
/src/assets/voices/pomodoro/dingzhen/longBreak.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AZCodingAccount/iTime/6e4d2b39cb80cd2ccd984537195228ed3c81060a/src/assets/voices/pomodoro/dingzhen/longBreak.wav
--------------------------------------------------------------------------------
/src/assets/voices/pomodoro/dingzhen/shortBreak.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AZCodingAccount/iTime/6e4d2b39cb80cd2ccd984537195228ed3c81060a/src/assets/voices/pomodoro/dingzhen/shortBreak.wav
--------------------------------------------------------------------------------
/src/assets/voices/pomodoro/jiaran/focus.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AZCodingAccount/iTime/6e4d2b39cb80cd2ccd984537195228ed3c81060a/src/assets/voices/pomodoro/jiaran/focus.wav
--------------------------------------------------------------------------------
/src/assets/voices/pomodoro/jiaran/longBreak.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AZCodingAccount/iTime/6e4d2b39cb80cd2ccd984537195228ed3c81060a/src/assets/voices/pomodoro/jiaran/longBreak.wav
--------------------------------------------------------------------------------
/src/assets/voices/pomodoro/jiaran/shortBreak.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AZCodingAccount/iTime/6e4d2b39cb80cd2ccd984537195228ed3c81060a/src/assets/voices/pomodoro/jiaran/shortBreak.wav
--------------------------------------------------------------------------------
/src/assets/voices/pomodoro/kobe/focus.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AZCodingAccount/iTime/6e4d2b39cb80cd2ccd984537195228ed3c81060a/src/assets/voices/pomodoro/kobe/focus.wav
--------------------------------------------------------------------------------
/src/assets/voices/pomodoro/kobe/longBreak.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AZCodingAccount/iTime/6e4d2b39cb80cd2ccd984537195228ed3c81060a/src/assets/voices/pomodoro/kobe/longBreak.wav
--------------------------------------------------------------------------------
/src/assets/voices/pomodoro/kobe/shortBreak.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AZCodingAccount/iTime/6e4d2b39cb80cd2ccd984537195228ed3c81060a/src/assets/voices/pomodoro/kobe/shortBreak.wav
--------------------------------------------------------------------------------
/src/assets/voices/timer/default/fullTime.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AZCodingAccount/iTime/6e4d2b39cb80cd2ccd984537195228ed3c81060a/src/assets/voices/timer/default/fullTime.wav
--------------------------------------------------------------------------------
/src/assets/voices/timer/default/halfTime.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AZCodingAccount/iTime/6e4d2b39cb80cd2ccd984537195228ed3c81060a/src/assets/voices/timer/default/halfTime.wav
--------------------------------------------------------------------------------
/src/assets/voices/timer/dingzhen/fullTime.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AZCodingAccount/iTime/6e4d2b39cb80cd2ccd984537195228ed3c81060a/src/assets/voices/timer/dingzhen/fullTime.wav
--------------------------------------------------------------------------------
/src/assets/voices/timer/dingzhen/halfTime.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AZCodingAccount/iTime/6e4d2b39cb80cd2ccd984537195228ed3c81060a/src/assets/voices/timer/dingzhen/halfTime.wav
--------------------------------------------------------------------------------
/src/assets/voices/timer/jiaran/fullTime.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AZCodingAccount/iTime/6e4d2b39cb80cd2ccd984537195228ed3c81060a/src/assets/voices/timer/jiaran/fullTime.wav
--------------------------------------------------------------------------------
/src/assets/voices/timer/jiaran/halfTime.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AZCodingAccount/iTime/6e4d2b39cb80cd2ccd984537195228ed3c81060a/src/assets/voices/timer/jiaran/halfTime.wav
--------------------------------------------------------------------------------
/src/assets/voices/timer/kobe/fullTime.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AZCodingAccount/iTime/6e4d2b39cb80cd2ccd984537195228ed3c81060a/src/assets/voices/timer/kobe/fullTime.wav
--------------------------------------------------------------------------------
/src/assets/voices/timer/kobe/halfTime.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AZCodingAccount/iTime/6e4d2b39cb80cd2ccd984537195228ed3c81060a/src/assets/voices/timer/kobe/halfTime.wav
--------------------------------------------------------------------------------
/src/assets/voices/todos/default/remind.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AZCodingAccount/iTime/6e4d2b39cb80cd2ccd984537195228ed3c81060a/src/assets/voices/todos/default/remind.wav
--------------------------------------------------------------------------------
/src/assets/voices/todos/dingzhen/remind.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AZCodingAccount/iTime/6e4d2b39cb80cd2ccd984537195228ed3c81060a/src/assets/voices/todos/dingzhen/remind.wav
--------------------------------------------------------------------------------
/src/assets/voices/todos/jiaran/remind.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AZCodingAccount/iTime/6e4d2b39cb80cd2ccd984537195228ed3c81060a/src/assets/voices/todos/jiaran/remind.wav
--------------------------------------------------------------------------------
/src/assets/voices/todos/kobe/remind.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AZCodingAccount/iTime/6e4d2b39cb80cd2ccd984537195228ed3c81060a/src/assets/voices/todos/kobe/remind.wav
--------------------------------------------------------------------------------
/src/components/ToDoList.vue:
--------------------------------------------------------------------------------
1 |
58 |
59 |
60 |
61 |
62 |
68 |
69 |
70 |
71 |
79 | {{ todo.content }}
80 |
81 |
82 |
83 |
84 |
88 |
97 |
{{
114 | dayjs(todo.remindTime).format("MM-DD HH:mm")
115 | }}
117 |
118 |
119 |
120 |
121 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
153 |
154 |
155 |
156 |
157 |
158 |
236 |
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 | import "./assets/main.css";
2 | import { createApp } from "vue";
3 | import App from "./App.vue";
4 | // 引入vue-router和pinia
5 | import router from "./router";
6 | import { createPinia } from "pinia";
7 | import piniaPluginPersistedstate from "pinia-plugin-persistedstate"; // 持久化插件
8 | // 引入图标
9 | import ArcoVueIcon from "@arco-design/web-vue/es/icon";
10 | import "@arco-design/web-vue/dist/arco.css";
11 |
12 | const app = createApp(App);
13 | app.use(ArcoVueIcon);
14 |
15 | // 引入并挂载
16 | app.use(createPinia().use(piniaPluginPersistedstate)).use(router).mount("#app");
17 |
--------------------------------------------------------------------------------
/src/router/index.js:
--------------------------------------------------------------------------------
1 | import { createRouter, createWebHashHistory } from "vue-router";
2 |
3 | const router = createRouter({
4 | history: createWebHashHistory(import.meta.env.BASE_URL), // 主要是hash模式
5 | routes: [
6 | {
7 | // 软件主界面
8 | path: "/",
9 | component: () => import("@/views/layout/LayOutContainer.vue"), // 使用箭头函数可以懒加载
10 | redirect: "/plain/todo",
11 | children: [
12 | {
13 | path: "/plain/todo",
14 | component: () => import("@/views/pc/PlainToDo.vue"),
15 | },
16 | {
17 | path: "/add/customtodo",
18 | component: () => import("@/views/pc/AddCustomToDo.vue"),
19 | },
20 | {
21 | path: "/custom/todo",
22 | component: () => import("@/views/pc/CustomToDo.vue"),
23 | },
24 | {
25 | path: "/settings",
26 | redirect: "/settings/global",
27 | component: () => import("@/views/layout/LayOutSettings.vue"),
28 | children: [
29 | {
30 | path: "/settings/global",
31 | component: () => import("@/views/settings/GlobalSettings.vue"),
32 | },
33 | {
34 | path: "/settings/todo",
35 | component: () => import("@/views/settings/ToDoSettings.vue"),
36 | },
37 | {
38 | path: "/settings/clock",
39 | component: () => import("@/views/settings/ClockSettings.vue"),
40 | },
41 | {
42 | path: "/settings/appearance",
43 | component: () =>
44 | import("@/views/settings/AppearanceSettings.vue"),
45 | },
46 | ],
47 | },
48 | { path: "/about", component: () => import("@/views/pc/About.vue") },
49 | {
50 | path: "/timer",
51 | component: () => import("@/views/pc/Timer.vue"),
52 | },
53 | {
54 | path: "/pomodoro",
55 | component: () => import("@/views/pc/Pomodoro.vue"),
56 | },
57 | ],
58 | },
59 | // 桌面用的三个路径
60 | {
61 | path: "/desktop/customtodo",
62 | component: () => import("@/views/desktop/CustomToDo.vue"),
63 | },
64 | {
65 | path: "/desktop/timer",
66 | component: () => import("@/views/desktop/Timer.vue"),
67 | },
68 | {
69 | path: "/desktop/pomodoro",
70 | component: () => import("@/views/desktop/Pomodoro.vue"),
71 | },
72 | // 全屏跳转的路径
73 | {
74 | path: "/fullscreen/timer",
75 | component: () => import("@/views/fullscreen/Timer.vue"),
76 | },
77 | {
78 | path: "/fullscreen/pomodoro",
79 | component: () => import("@/views/fullscreen/Pomodoro.vue"),
80 | },
81 | ],
82 | });
83 |
84 | export default router;
85 |
--------------------------------------------------------------------------------
/src/stores/CustomSettings.js:
--------------------------------------------------------------------------------
1 | import { defineStore } from "pinia";
2 | import { ref, watchEffect } from "vue";
3 | // 定义待办列表
4 | export const useCustomSettingsStore = defineStore(
5 | "customSettings",
6 | () => {
7 | const customSettings = ref({}); // 自定义设置,必须暴露出去,不然持久化不生效
8 | // 有自定义快捷键、自定义番茄钟设置,自定义字体设置
9 | // 默认番茄钟设置
10 | customSettings.value["pomodoroSettings"] = {
11 | duration: 25,
12 | shortBreakDuration: 5,
13 | longBreakDuration: 15,
14 | longBreakInterval: 4,
15 | };
16 | // // 测试设置
17 | // customSettings.value["pomodoroSettings"] = {
18 | // duration: 0.1,
19 | // shortBreakDuration: 0.1,
20 | // longBreakDuration: 0.1,
21 | // longBreakInterval: 2,
22 | // };
23 |
24 | const currentPath = window.electron.getAppPath();
25 |
26 | // customSettings.value["f-pomodoro-bgi"] =
27 | // "file:///C:/Users/Albert%20han/Desktop/easyToDo/dist_electron/win-unpacked/resources/assets/defaultBGI.jpg";
28 | // 对windows做处理
29 | // "C:\\Users\\Albert han\\Desktop\\easyToDo\\dist_electron\\win-unpacked\\resources/assets/defaultBGI.jpg"
30 | // 首先加上file前缀 file:/// 如果包含\\,替换成/ 如果包含空格、替换成%20
31 | const originValue = `${currentPath}/assets/defaultBGI.jpg`;
32 | const formattedValue = originValue
33 | .replace(/\\/g, "/")
34 | .replace(/\s/g, "%20");
35 | const targetValue = `file:///${formattedValue}`;
36 | // 默认番茄钟背景图设置
37 | customSettings.value["f-pomodoro-bgi"] = targetValue;
38 | customSettings.value["w-pomodoro-bgi"] = "none";
39 |
40 | // 待办图标样式
41 | customSettings.value["todo-icons"] = {
42 | olIcon: "1.",
43 | ulIcon: "●",
44 | };
45 |
46 | // 默认快捷键设置
47 | customSettings.value["shortcutKeys"] = {
48 | fPomodoro: "Control+Alt+0",
49 | wPomodoro: "Control+Alt+9",
50 | fTimer: "Control+Alt+8",
51 | wTimer: "Control+Alt+7",
52 | };
53 | let defaultShortcutKeys = ref({
54 | fPomodoro: "Control+Alt+0",
55 | wPomodoro: "Control+Alt+9",
56 | fTimer: "Control+Alt+8",
57 | wTimer: "Control+Alt+7",
58 | });
59 |
60 | // 默认位置设置,是否在顶层
61 | customSettings.value["position"] = {
62 | pomodoroP: true,
63 | timerP: true,
64 | todoP: false,
65 | };
66 |
67 | // 提示语音设置
68 | customSettings.value["voice"] = {
69 | pomodoroV: "default",
70 | timerV: "default",
71 | todoV: "default",
72 | isClosedV: false,
73 | };
74 | // 防止用户快捷键输入空值
75 | watchEffect(() => {
76 | if (customSettings.value["shortcutKeys"]["fPomodoro"] === "") {
77 | customSettings.value["shortcutKeys"]["fPomodoro"] = "Control+Alt+0";
78 | }
79 | if (customSettings.value["shortcutKeys"]["wPomodoro"] === "") {
80 | customSettings.value["shortcutKeys"]["wPomodoro"] = "Control+Alt+1";
81 | }
82 | if (customSettings.value["shortcutKeys"]["fTimer"] === "") {
83 | customSettings.value["shortcutKeys"]["fTimer"] = "Control+Alt+2";
84 | }
85 | if (customSettings.value["shortcutKeys"]["wTimer"] === "") {
86 | customSettings.value["shortcutKeys"]["wTimer"] = "Control+Alt+3";
87 | }
88 | });
89 | // 重置番茄钟背景图
90 | const resetPomodoroBGI = () => {
91 | const originValue = `${currentPath}/assets/defaultBGI.jpg`;
92 | const formattedValue = originValue
93 | .replace(/\\/g, "/")
94 | .replace(/\s/g, "%20");
95 | const targetValue = `file:///${formattedValue}`;
96 | customSettings.value["f-pomodoro-bgi"] = targetValue;
97 | customSettings.value["w-pomodoro-bgi"] = "none";
98 | };
99 | // 重置待办图标
100 | const resetForm = () => {
101 | customSettings.value["todo-icons"] = {
102 | olIcon: "1.",
103 | ulIcon: "●",
104 | };
105 | };
106 | // 重置快捷键设置
107 | const resetShortcutKeys = () => {
108 | console.log({ ...defaultShortcutKeys.value });
109 | customSettings.value["shortcutKeys"] = { ...defaultShortcutKeys.value };
110 | };
111 | // 重置位置设置
112 | const resetPositionSettings = () => {
113 | customSettings.value["position"] = {
114 | pomodoroP: true,
115 | timerP: true,
116 | todoP: false,
117 | };
118 | };
119 | // 重置语音提示设置
120 | const resetVoiceSettings = () => {
121 | customSettings.value["voice"] = {
122 | pomodoroV: "default",
123 | timerV: "default",
124 | todoV: "default",
125 | isClosedV: false,
126 | };
127 | };
128 | return {
129 | customSettings,
130 | defaultShortcutKeys,
131 | resetPomodoroBGI,
132 | resetForm,
133 | resetShortcutKeys,
134 | resetPositionSettings,
135 | resetVoiceSettings,
136 | };
137 | },
138 | { persist: true } // 持久化
139 | );
140 |
--------------------------------------------------------------------------------
/src/stores/CustomToDoStore.js:
--------------------------------------------------------------------------------
1 | import { defineStore } from "pinia";
2 | import { ref } from "vue";
3 | // 定义待办列表
4 | export const useCustomToDoStore = defineStore(
5 | "customTodoList",
6 | () => {
7 | const isFirst = ref(true); // 用来辅助实现单例模式
8 | const customTodoList = ref([]); // 待办列表,必须暴露出去,不然持久化不生效
9 |
10 | // 定义代办标题和内容(这个是自定义)
11 | // let title = ref(""); // 标题
12 | // let content = ref(""); // 内容
13 | // let createTime = ref(null); // 创建时间
14 | // 添加待办
15 | const addToDo = (id, title, content, createTime) => {
16 | customTodoList.value.unshift({ id, title, content, createTime });
17 | };
18 | // 获取待办列表
19 | const getToDoList = () => {
20 | return customTodoList.value;
21 | };
22 | // 删除待办
23 | const removeToDo = (id) => {
24 | console.log("删除待办", id, customTodoList.value);
25 | customTodoList.value = customTodoList.value.filter(
26 | (item) => item.id !== id
27 | );
28 | console.log("删除后的列表", customTodoList.value);
29 | };
30 |
31 | return { isFirst, customTodoList, addToDo, getToDoList, removeToDo };
32 | },
33 | {
34 | persist: {
35 | paths: ["customTodoList"],
36 | },
37 | } // 持久化
38 | );
39 |
--------------------------------------------------------------------------------
/src/stores/HasVisitedBefore.js:
--------------------------------------------------------------------------------
1 | import { defineStore } from "pinia";
2 | import { ref } from "vue";
3 | // 记录用户访问过哪些页面
4 | export const useHasVisitedBeforeStore = defineStore(
5 | "hasVisitedBefore",
6 | () => {
7 | const appToDo = ref(true);
8 | const appPomodoro = ref(true);
9 | const appTimer = ref(true);
10 | const fullScreenPomodoro = ref(true);
11 | const fullScreenTimer = ref(true);
12 | const widgetPomodoro = ref(true);
13 | const widgetTimer = ref(true);
14 | return {
15 | appToDo,
16 | appPomodoro,
17 | appTimer,
18 | fullScreenPomodoro,
19 | fullScreenTimer,
20 | widgetPomodoro,
21 | widgetTimer,
22 | };
23 | },
24 | { persist: true } // 持久化,必须持久化,不然那4个创建新窗口的页面没办法共享pinia值,除非你存储到sqlLite这种数据库里面
25 | );
26 |
--------------------------------------------------------------------------------
/src/stores/ToDo.js:
--------------------------------------------------------------------------------
1 | import { defineStore } from "pinia";
2 | import { ref } from "vue";
3 | // 定义待办列表
4 | export const useToDoStore = defineStore(
5 | "todoList",
6 | () => {
7 | const todoList = ref([]); // 待办列表,必须暴露出去,不然持久化不生效
8 |
9 | // 添加待办
10 | const addToDo = (id, content, tags, remindTime) => {
11 | let isFinish = false; // 待办
12 | todoList.value.unshift({ id, content, tags, isFinish, remindTime });
13 | };
14 | // 获取待办列表
15 | const getToDoList = () => {
16 | return todoList.value;
17 | };
18 | // 删除待办
19 | const deleteToDo = (id) => {
20 | todoList.value = todoList.value.filter((todo) => {
21 | if (todo.id === id) {
22 | return false;
23 | }
24 | return true;
25 | });
26 | };
27 |
28 | return { todoList, addToDo, getToDoList, deleteToDo };
29 | },
30 | { persist: true } // 持久化
31 | );
32 |
--------------------------------------------------------------------------------
/src/views/desktop/CustomToDo.vue:
--------------------------------------------------------------------------------
1 |
23 |
24 |
29 |
30 |
76 |
77 |
78 |
79 |
85 |
86 |
87 |
138 |
--------------------------------------------------------------------------------
/src/views/desktop/Pomodoro.vue:
--------------------------------------------------------------------------------
1 |
164 |
165 |
169 |
170 |
171 | {{ hintText }}
172 |
173 |
174 |
175 |
176 |
177 | {{ step }}
178 |
179 |
180 |
181 | {{ minutes }}:{{ seconds }}
182 |
183 |
184 |
240 |
241 |
242 |
246 |
250 |
254 |
255 |
256 |
257 |
323 |
--------------------------------------------------------------------------------
/src/views/desktop/Timer.vue:
--------------------------------------------------------------------------------
1 |
151 |
152 |
153 |
154 |
166 |
167 |
175 |
176 |
177 | {{ minutes }}:{{ seconds }}
178 |
179 |
180 |
208 |
209 |
213 |
217 |
218 |
219 |
220 |
256 |
--------------------------------------------------------------------------------
/src/views/fullscreen/Pomodoro.vue:
--------------------------------------------------------------------------------
1 |
164 |
165 |
170 |
171 |
172 |
173 | {{ hintText }}
174 |
175 |
176 |
177 |
178 |
179 | {{ step }}
180 |
181 |
182 |
{{ minutes }}:{{ seconds }}
183 |
184 |
240 |
241 |
242 |
243 |
247 |
251 |
255 |
256 |
257 |
258 |
333 |
--------------------------------------------------------------------------------
/src/views/fullscreen/Timer.vue:
--------------------------------------------------------------------------------
1 |
149 |
150 |
155 |
156 |
157 |
168 |
169 |
177 |
178 |
{{ minutes }}:{{ seconds }}
179 |
180 |
208 |
209 |
210 |
214 |
218 |
219 |
220 |
221 |
266 |
--------------------------------------------------------------------------------
/src/views/layout/LayOutContainer.vue:
--------------------------------------------------------------------------------
1 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
23 |
25 |
26 |
30 |
47 | 标准待办
48 |
49 |
50 |
51 |
55 |
56 |
71 |
72 | 自定义待办
73 |
74 |
75 |
76 |
80 |
81 |
100 |
101 | 添加自定义待办
102 |
103 |
104 |
105 |
106 |
131 | 倒计时
132 |
133 |
134 |
135 |
139 |
140 |
156 |
157 | 番茄钟
158 |
159 |
160 |
161 |
162 |
166 |
183 | 自定义设置
184 |
185 |
186 |
187 |
191 |
215 | 关于
216 |
217 |
218 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
262 |
--------------------------------------------------------------------------------
/src/views/layout/LayOutSettings.vue:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
30 |
31 |
36 |
--------------------------------------------------------------------------------
/src/views/pc/About.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
9 |
10 |
18 |
19 |
23 |
84 |
交流群:753963039
85 |
86 |
87 |
88 |
92 |
🔜
93 |
94 |
🪄 自定义外观
95 |
📸 集成截图和OCR功能
96 |
🤖 集成ChatGPT
97 |
98 |
99 |
100 |
101 |
106 |
107 |
110 |
111 |
235 |
236 |
237 |
238 |
254 |
--------------------------------------------------------------------------------
/src/views/pc/AddCustomToDo.vue:
--------------------------------------------------------------------------------
1 |
170 |
171 |
172 |
179 |
180 |
181 | 补充自定义代办信息
182 |
189 |
190 |
191 |
202 |
--------------------------------------------------------------------------------
/src/views/pc/CustomToDo.vue:
--------------------------------------------------------------------------------
1 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
67 |
68 |
69 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
116 |
--------------------------------------------------------------------------------
/src/views/pc/PlainToDo.vue:
--------------------------------------------------------------------------------
1 |
80 |
81 |
82 |
83 |
84 |
92 |
93 |
94 |
95 |
96 | 添加待办
97 |
98 |
105 |
106 |
107 |
108 |
115 |
116 |
117 |
118 |
123 |
129 |
130 |
131 |
141 |
--------------------------------------------------------------------------------
/src/views/pc/Pomodoro.vue:
--------------------------------------------------------------------------------
1 |
190 |
191 |
197 |
198 |
199 |
200 | {{ hintText }}
201 |
202 |
203 |
204 |
205 |
206 | {{ step }}
207 |
208 |
209 |
{{ minutes }}:{{ seconds }}
210 |
211 |
267 |
268 |
272 |
276 |
280 |
281 |
282 |
283 |
284 |
285 |
360 |
--------------------------------------------------------------------------------
/src/views/pc/Timer.vue:
--------------------------------------------------------------------------------
1 |
158 |
159 |
166 |
167 |
168 |
179 |
180 |
188 |
{{ minutes }}:{{ seconds }}
189 |
217 |
218 |
219 |
223 |
227 |
228 |
229 |
230 |
273 |
--------------------------------------------------------------------------------
/src/views/settings/AppearanceSettings.vue:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
15 |
🔜
16 |
17 |
🖌️ 自定义主题
18 |
🆙 自定义字体大小
19 |
🌈 自定义桌面挂件颜色和透明度
20 |
🔄 自定义桌面挂件宽高
21 |
22 |
24 |
25 |
26 |
36 |
--------------------------------------------------------------------------------
/src/views/settings/ClockSettings.vue:
--------------------------------------------------------------------------------
1 |
131 |
132 |
133 |
134 |
140 |
145 |
153 |
154 |
159 |
167 |
168 |
173 |
181 |
182 |
187 |
195 |
196 |
197 | 恢复默认设置
198 |
199 |
200 |
201 |
202 |
203 |
207 | 更改全屏背景图:
208 |
209 |
217 |
218 |
225 |
229 |
![]()
230 |
231 |
232 |
233 |
245 |
246 |
252 |
253 |
254 |
255 |
259 | 更改组件背景图:
260 |
261 |
269 |
270 |
277 |
281 |
![]()
282 |
283 |
284 |
285 |
297 |
298 |
304 |
305 |
306 |
307 |
308 |
恢复默认背景
311 |
312 |
313 |
314 |
328 |
--------------------------------------------------------------------------------
/src/views/settings/GlobalSettings.vue:
--------------------------------------------------------------------------------
1 |
160 |
161 |
162 |
163 |
164 |
174 | 快捷键设置
175 |
176 |
177 |
178 | 开始录制
181 | 结束录制
182 |
183 |
184 |
185 |
186 | 开始录制
189 | 结束录制
190 |
191 |
192 |
193 | 开始录制
196 | 结束录制
197 |
198 |
199 |
200 | 开始录制
203 | 结束录制
204 |
205 |
206 | 恢复默认设置
207 |
208 |
209 |
210 |
211 |
212 | 挂件是否在顶层设置
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 | 恢复默认设置
225 |
226 |
227 |
228 |
229 |
230 | 提示语音设置
231 |
232 |
237 | 东雪莲
238 | 丁真
239 | 嘉然
240 | 科比
241 |
242 |
243 |
244 |
245 |
246 | 东雪莲
247 | 丁真
248 | 嘉然
249 | 科比
250 |
251 |
252 |
253 |
254 | 东雪莲
255 | 丁真
256 | 嘉然
257 | 科比
258 |
259 |
260 |
261 |
262 |
263 |
264 | 恢复默认
265 |
266 |
267 |
268 |
269 |
270 |
--------------------------------------------------------------------------------
/src/views/settings/ToDoSettings.vue:
--------------------------------------------------------------------------------
1 |
33 |
34 |
35 |
36 |
37 |
38 |
43 | 1.
44 | 🔢
45 | 🆙
46 | 😊
47 |
48 |
49 |
50 |
55 | ●
56 | ★
57 | ■
58 | 🙂
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
72 |
73 |
74 |
80 |
81 |
82 | 恢复默认设置
83 |
84 |
85 |
86 |
87 |
93 |
--------------------------------------------------------------------------------
/vite.config.js:
--------------------------------------------------------------------------------
1 | import { fileURLToPath, URL } from "node:url";
2 |
3 | import { defineConfig } from "vite";
4 | import vue from "@vitejs/plugin-vue";
5 | import AutoImport from "unplugin-auto-import/vite";
6 | import Components from "unplugin-vue-components/vite";
7 | import { ArcoResolver } from "unplugin-vue-components/resolvers";
8 |
9 | // import path from "path"; // 新增
10 |
11 | // https://vitejs.dev/config/
12 | // 配置自动按需引入
13 | export default defineConfig({
14 | base: "./", // 设置为相对路径
15 | plugins: [
16 | vue(),
17 | AutoImport({
18 | resolvers: [ArcoResolver()],
19 | }),
20 | Components({
21 | resolvers: [
22 | ArcoResolver({
23 | sideEffect: true,
24 | }),
25 | ],
26 | }),
27 | ],
28 | resolve: {
29 | alias: {
30 | "@": fileURLToPath(new URL("./src", import.meta.url)),
31 | },
32 | },
33 | });
34 |
--------------------------------------------------------------------------------
/软件使用说明书.md:
--------------------------------------------------------------------------------
1 | # iTime软件使用说明书📄
2 |
3 | ## 软件介绍📘
4 |
5 | iTime🕰️ 是一款基于vue3+arco design+electron开发的桌面端效率应用,slogan是`让每一秒都刚刚好`🌟,意为提高您的效率,帮助您充分利用自己的每一秒。
6 |
7 | ## 功能介绍🔧
8 |
9 | 目前iTime有四个模块,分别是待办📝、倒计时⏳、番茄钟🍅、自定义设置⚙️,与这四个功能相辅相成的有**屏幕挂件**🖥️、**提示语音**🔊。下面将详细介绍这四个功能,**每个小功能之前都会有一个演示的gif动图**
10 |
11 | ### 待办功能📝
12 |
13 | 待办功能分为标准待办和自定义待办部分:
14 |
15 | 标准待办动图:
16 |
17 |
18 |
19 | - 标准待办中,您每新增一个代办需要填写待办的**内容**✍️、**标签(可选)**🏷️、**提醒时间**⏰这三个部分,**时间**和**内容**是必需的,以便程序知道何时提醒您。
20 |
21 | 💡为了ui展示的合理性,建议您每个待办不要超过**5个**标签
22 |
23 | 自定义待办动图:
24 |
25 |
26 |
27 | - 自定义待办中,您可以把待办当做一个便签📌,在富文本编辑器编辑好以后保存,去预览界面,右键发送待办挂件即可成为屏幕挂件。
28 |
29 | ### 倒计时功能⏳
30 |
31 |
32 |
33 | 倒计时器有三种使用方式:
34 |
35 | - 在软件主界面启动倒计时器
36 | - 左键双击全屏倒计时器
37 | - 右键双击发送倒计时器成为挂件
38 |
39 | ❗倒计时器的范围是**0.1-999**分钟。
40 |
41 | ❗您可以在获取焦点后按**R**键重置倒计时器
42 |
43 | ### 番茄钟功能🍅
44 |
45 |
46 |
47 | ℹ️:上述gif番茄钟时间参数是为了方便开发时设置的参数、实际并不暴露给定范围外的接口
48 |
49 | 与倒计时器类似,也支持上述三种方式使用番茄钟。番茄钟了解链接:[番茄钟如何提高效率](https://www.zhihu.com/question/330121574)
50 |
51 | - 在软件主界面启动倒计时器
52 | - 左键双击全屏倒计时器
53 | - 右键双击发送倒计时器成为挂件
54 |
55 | ℹ️ 番茄钟可以自定义`长休息`🌴、`短休息`☕、`专注时间`⏲️、`轮数`🔄4个选项,稍后会介绍。
56 |
57 | ### 自定义设置⚙️
58 |
59 | 我们暴露出了一些接口供用户自定义,包含**全局快捷键设置**⌨️、**挂件位置设置**📍、**提示语音设置**🔊、**待办列表项设置**🗃️、**番茄钟参数设置**🕒、**番茄钟与计时器背景图设置**🖼️,下面详细介绍:
60 |
61 |
62 |
63 | - 全局快捷键设置⌨️。自定义快捷键全屏显示番茄钟、召唤番茄钟挂件、全屏显示计时器、召唤计时器挂件4个功能。
64 | - 挂件是否在顶层设置🔝。如果选择顶层,那么挂件将一直悬浮在屏幕上,三个挂件可以设置是否在顶层。
65 | - 提示语音设置🔊。在番茄钟、计时器、待办达到一定条件后软件会播放提示语音,您可以自定义提示语音的AI角色和是否开启提示语音。
66 |
67 |
68 |
69 | - 待办列表项设置🗃️。您可以自定义有序列表和无序列表前面显示的图标。
70 |
71 |
72 |
73 | 番茄钟参数设置🕒。如前所述、您可以在一定范围内自定义番茄钟的4个参数。
74 |
75 | - 番茄钟和计时器背景图设置🖼️。默认情况下桌面挂件的样式是半透明的灰色。您可以自定义全屏的背景图和挂件的背景图。
76 |
77 | ## 快捷键介绍⌨️
78 |
79 | ### 待办📝
80 |
81 | 标准待办中**Ctrl/Command+Alt+Enter**调出添加待办窗口。
82 |
83 | 自定义代办中富文本编辑器选项:
84 |
85 | - **\"-"+空格**➡️ 无序列表
86 | - **1+“.“**➡️ 有序列表
87 | - **Ctrl/Command+B**➡️ 将选中文本加粗
88 | - **Ctrl/Command+I**➡️ 将选中文本斜体
89 | - **Ctrl/Command+U**➡️ 将选中文本加下划线
90 |
91 | 自定义代办中操作选项:
92 |
93 | - **Ctrl/Command+Alt+Enter**调出确认窗口
94 | - 标题窗口+**Enter**即可添加
95 |
96 | ### 定时器&番茄钟⏲️
97 |
98 | **全局快捷键⌨️**
99 |
100 | - **Ctrl/Command+Alt+0**全屏番茄钟
101 | - **Ctrl/Command+Alt+9**召唤番茄钟挂件
102 | - **Ctrl/Command+Alt+8**全屏计时器
103 | - **Ctrl/Command+Alt+7**召唤计时器挂件
104 |
105 | **组件快捷键⚡**
106 |
107 | - **F**全屏
108 | - 全屏模式按**F**退出
109 | - **A**添加挂件
110 | - 挂件模式下按**E**删除挂件
111 |
112 | **鼠标设置🖱️**
113 |
114 | - **左键双击背景**全屏
115 | - **右键双击背景**添加挂件
116 | - 全屏模式下**左键双击背景**退出
117 | - 挂件模式下**左键双击时间**删除挂件
118 |
119 | ## 语音内容🔊
120 |
121 | 我们采用内置音频的方式来提醒,软件不需连接互联网
122 |
123 | | 事件 | 语音内容 |
124 | | ------------ | -------------------------------- |
125 | | 番茄钟短休息 | 时间到了,短短的休息一会儿吧 |
126 | | 番茄钟长休息 | 你太棒了,接下来是长休息时间 |
127 | | 番茄钟专注 | 好了,开始专注吧 |
128 | | 倒计时过半 | 时间已经过去一半了 |
129 | | 倒计时结束 | 倒计时结束了 |
130 | | 待办提醒 | 您现在有计划的安排,提醒您一下哈 |
131 |
132 | 这些提示的英文版本
133 |
134 | | 事件 | 语音内容 |
135 | | ------------ | ------------------------------------------ |
136 | | 番茄钟短休息 | Take a short break, time's up. |
137 | | 番茄钟长休息 | You're doing great, time for a long break. |
138 | | 番茄钟专注 | Alright, time to focus. |
139 | | 倒计时过半 | Half the time has passed. |
140 | | 倒计时结束 | The countdown is over. |
141 | | 待办提醒 | You have scheduled tasks, just a reminder. |
142 |
143 |
--------------------------------------------------------------------------------