
💡 项目介绍
dg-man 是一个用 Electron + Vue3 做的桌面数字人 / 桌面宠物 🐶
它会乖乖待在桌面角落陪你,能提醒你喝水、起身动一动、记得特殊日,还能发邮件、出声、弹系统通知。
技术栈:Electron + electron-vite + Vue3 + three.js / VRM 捏脸动画,主进程和渲染进程走 IPC 通信。透明窗口 + 鼠标穿透 + 视线追踪,纯纯的桌面挂件。
✅ 本次实现内容(一口气肝完)
1️⃣ 特殊日(农历 / 公历)计算与列表
保存时把特殊日算成公历 calcDate落盘:公历用「当前年 + 月日」,农历先把月日转公历再锚定今年。列表按 calcDate比较剩余天数:>0 正常、≤30 主题色高亮、<0 已过期。
2️⃣ 农历库大换血
手写 lunar.js(UMD)在 Vite 里导入各种报错,折腾 ESM 后仍不稳定。直接换成 npm 依赖 lunar-javascript,删掉本地lib/lunar.js,全部改用import { Lunar } from 'lunar-javascript'。
3️⃣ 提醒调度器(需求 3.6)全套上线
四种提醒方式,且随改随保存即时生效:
📧 邮件:nodemailer,账号密码全走 key.json(写进.gitignore不入库,另附key.example.json模板)🔔 自有铃声:你上传的音频 + 默认水滴声 🎤 人物语音:浏览器 TTS,还会按性别挑音色 💬 系统通知
内容模板:一般提醒(昵称提醒你xxx啦)+ 特殊日合并提醒(剩 15 天内每天催你,多个合并一条)。
4️⃣ 调度内核 + 优化
- 单定时器 next-event 模式
:主进程只挂一个 setTimeout指最近到期项,到点统一派发再重排,空闲零开销。 - 去重优化
:只有「提醒相关设置」变了才重排,改模型 / LLM 等无关设置不瞎折腾。
5️⃣ 对话框 UI 与互动数据 UI
💬 对话框(ChatApp.vue):独立聊天窗,气泡式对话流 + 文字 / 选图发送 + 窗口高度自适应(底边固定向上生长);当前为本地渲染演示,未接 LLM/TTS。 📊 互动数据(InteractApp.vue):按「天」分组的互动记录浏览(用户对话 / AI 回复 / 系统动作);当前为 mock 数据,无持久化。 🎯 入口:右键菜单开「互动数据」,Ctrl+M 开对话框(chatHotkey 可改)。 📌 定位:界面骨架已画好,是后续「接 LLM 聊天 + 记忆持久化」的承载容器。
🧱 卡点难点(踩坑最爽的部分)
🌙 农历算错原生
<input type="date">只产公历,勾「农历」只是个 flag,旧逻辑把公历月日当农历喂进去 → 错。改成Solar.fromYmd(...).getLunar()取真农历月日再锚定今年。📦 手写 lunar 库 ESM 报错UMD 的
module.exports在 Vite 里没法静态合成命名导出,转 ESM 也踩坑。结论:别硬刚,直接换成熟 npm 包。⏰ 调度器「永远不触发」致命 bug到期判定写成
now >= nextAtFor(it, now),但nextAtFor在「当前时刻」会算出未来值 → 永远判「没到点」,循环 / 一次性 / 特殊日全哑火。 ✅ 修法:单独存「排定时刻」scheduledAt比对,不再触发瞬间重算。🔔 系统通知死活不弹走主进程
Notification,Windows 上缺 appId 经常不显示。 ✅ 改走渲染进程window.Notification——和你久坐锁屏那套一样稳。🖼️ 控制台狂报 file:// 被拦列表缩略图兜底用了本地
file://路径,被 Electron 安全策略拦截报错(图其实还能显示,因为 data URL 后来补上了)。 ✅ 去掉兜底,统一让主进程读成 data URL。🛠️ 沙箱拦 Edit/Write本环境对这两个文件拦截了备份机制,最后改用 Bash + Python 打补丁,照样修完且构建通过。
🗺️ 后续规划
🚀 自定义协议 app://直接加载图片 / 模型资源(比 data URL 更省、更 scalable,也是我之前项目的做法)🎙️ 接云端 TTS,音色更自然 💬 记忆 Tab + 独立聊天窗接 LLM ⏱️ 特殊日提醒窗口 / 时点微调 🧪 真机跑一遍确认提醒 / 通知 / 语音全链路
🤝 邀请一起搞
如果你也对 桌面宠物 / Electron / 数字人 / 独立开发 感兴趣,欢迎来一起玩!
关注、提 issue、一起写功能都行~评论区聊聊你在做的项目 👇
#Electron #桌面宠物 #Vue3 #数字人 #独立开发 #前端 #开源 #效率工具
夜雨聆风