mirror of
https://github.com/timeshiftsauce/CeruMusic.git
synced 2025-11-25 03:15:07 +08:00
fix
This commit is contained in:
@@ -50,7 +50,7 @@
|
||||
"marked": "^16.1.2",
|
||||
"mitt": "^3.0.1",
|
||||
"NeteaseCloudMusicApi": "^4.27.0",
|
||||
"node-fetch": "^3.3.2",
|
||||
"node-fetch": "2",
|
||||
"pinia": "^3.0.3",
|
||||
"tdesign-vue-next": "^1.15.2",
|
||||
"vue-router": "^4.5.1"
|
||||
|
||||
@@ -1,19 +1,64 @@
|
||||
import { app, shell, BrowserWindow, ipcMain, Tray } from 'electron'
|
||||
import { is } from '@electron-toolkit/utils'
|
||||
import { app, shell, BrowserWindow, ipcMain, Tray, Menu } from 'electron'
|
||||
import { join } from 'path'
|
||||
|
||||
import { electronApp, optimizer, is } from '@electron-toolkit/utils'
|
||||
import icon from '../../resources/logo.png?asset'
|
||||
import path from 'node:path'
|
||||
import musicService from './services/music'
|
||||
import pluginService from './services/plugin'
|
||||
import useWindow from './window/index'
|
||||
|
||||
import aiEvents from './events/ai'
|
||||
|
||||
let tray: Tray | null = null
|
||||
let mainWindow: BrowserWindow | null = null
|
||||
// 使用对象包装布尔值,以便通过引用传递
|
||||
const isQuittingState = { value: false }
|
||||
const tray: { value: Tray | null } = { value: null }
|
||||
let isQuitting = false
|
||||
|
||||
function createTray(): void {
|
||||
// 创建系统托盘
|
||||
const trayIconPath = path.join(__dirname, '../../resources/logo.png')
|
||||
tray = new Tray(trayIconPath)
|
||||
|
||||
// 创建托盘菜单
|
||||
const contextMenu = Menu.buildFromTemplate([
|
||||
{
|
||||
label: '显示窗口',
|
||||
click: () => {
|
||||
if (mainWindow) {
|
||||
mainWindow.show()
|
||||
mainWindow.focus()
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '播放/暂停',
|
||||
click: () => {
|
||||
// 这里可以添加播放控制逻辑
|
||||
mainWindow?.webContents.send('music-control')
|
||||
}
|
||||
},
|
||||
{ type: 'separator' },
|
||||
{
|
||||
label: '退出',
|
||||
click: () => {
|
||||
isQuitting = true
|
||||
app.quit()
|
||||
}
|
||||
}
|
||||
])
|
||||
|
||||
tray.setContextMenu(contextMenu)
|
||||
tray.setToolTip('Ceru Music')
|
||||
|
||||
// 双击托盘图标显示窗口
|
||||
tray.on('click', () => {
|
||||
if (mainWindow) {
|
||||
if (mainWindow.isVisible()) {
|
||||
mainWindow.hide()
|
||||
} else {
|
||||
mainWindow.show()
|
||||
mainWindow.focus()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function createWindow(): void {
|
||||
// Create the browser window.
|
||||
@@ -47,13 +92,13 @@ function createWindow(): void {
|
||||
|
||||
// 阻止窗口关闭,改为隐藏到系统托盘
|
||||
mainWindow.on('close', (event) => {
|
||||
if (!isQuittingState.value) {
|
||||
if (!isQuitting) {
|
||||
event.preventDefault()
|
||||
mainWindow?.hide()
|
||||
|
||||
// 显示托盘通知
|
||||
if (tray.value) {
|
||||
tray.value.displayBalloon({
|
||||
if (tray) {
|
||||
tray.displayBalloon({
|
||||
iconType: 'info',
|
||||
title: 'Ceru Music',
|
||||
content: '已最小化到系统托盘啦,点击托盘图标可重新打开~'
|
||||
@@ -95,14 +140,98 @@ ipcMain.handle('service-music-request', async (_, api, args) => {
|
||||
|
||||
aiEvents(mainWindow)
|
||||
|
||||
app.on('before-quit', () => {
|
||||
isQuittingState.value = true
|
||||
// This method will be called when Electron has finished
|
||||
// initialization and is ready to create browser windows.
|
||||
// Some APIs can only be used after this event occurs.
|
||||
app.whenReady().then(() => {
|
||||
// Set app user model id for windows
|
||||
electronApp.setAppUserModelId('com.cerulean.music')
|
||||
|
||||
// Default open or close DevTools by F12 in development
|
||||
// and ignore CommandOrControl + R in production.
|
||||
// see https://github.com/alex8088/electron-toolkit/tree/master/packages/utils
|
||||
app.on('browser-window-created', (_, window) => {
|
||||
optimizer.watchWindowShortcuts(window)
|
||||
})
|
||||
|
||||
// IPC test
|
||||
ipcMain.on('ping', () => console.log('pong'))
|
||||
|
||||
// 窗口控制 IPC 处理
|
||||
ipcMain.on('window-minimize', () => {
|
||||
const window = BrowserWindow.getFocusedWindow()
|
||||
if (window) {
|
||||
window.minimize()
|
||||
}
|
||||
})
|
||||
|
||||
ipcMain.on('window-maximize', () => {
|
||||
const window = BrowserWindow.getFocusedWindow()
|
||||
if (window) {
|
||||
if (window.isMaximized()) {
|
||||
window.unmaximize()
|
||||
} else {
|
||||
window.maximize()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
ipcMain.on('window-close', () => {
|
||||
const window = BrowserWindow.getFocusedWindow()
|
||||
if (window) {
|
||||
window.close()
|
||||
}
|
||||
})
|
||||
|
||||
// Mini 模式 IPC 处理 - 最小化到系统托盘
|
||||
ipcMain.on('window-mini-mode', (_, isMini) => {
|
||||
if (mainWindow) {
|
||||
if (isMini) {
|
||||
// 进入 Mini 模式:隐藏窗口到系统托盘
|
||||
mainWindow.hide()
|
||||
// 显示托盘通知(可选)
|
||||
if (tray) {
|
||||
tray.displayBalloon({
|
||||
title: '澜音 Music',
|
||||
content: '已最小化到系统托盘啦,点击托盘图标可重新打开~'
|
||||
})
|
||||
}
|
||||
} else {
|
||||
// 退出 Mini 模式:显示窗口
|
||||
mainWindow.show()
|
||||
mainWindow.focus()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// 全屏模式 IPC 处理
|
||||
ipcMain.on('window-toggle-fullscreen', () => {
|
||||
if (mainWindow) {
|
||||
const isFullScreen = mainWindow.isFullScreen()
|
||||
mainWindow.setFullScreen(!isFullScreen)
|
||||
}
|
||||
})
|
||||
|
||||
createWindow()
|
||||
createTray()
|
||||
|
||||
app.on('activate', function () {
|
||||
// On macOS it's common to re-create a window in the app when the
|
||||
// dock icon is clicked and there are no other windows open.
|
||||
if (BrowserWindow.getAllWindows().length === 0) createWindow()
|
||||
})
|
||||
})
|
||||
|
||||
// 创建窗口并注册window服务
|
||||
app.whenReady().then(() => {
|
||||
// 先创建窗口
|
||||
createWindow()
|
||||
// 然后注册window服务,确保mainWindow已经创建
|
||||
useWindow(() => {}, ipcMain, app, mainWindow, isQuittingState, tray)
|
||||
// 当所有窗口关闭时不退出应用,因为我们有系统托盘
|
||||
app.on('window-all-closed', () => {
|
||||
// 在 macOS 上,应用通常会保持活跃状态
|
||||
// 在其他平台上,我们也保持应用运行,因为有系统托盘
|
||||
})
|
||||
|
||||
// 应用退出前的清理
|
||||
app.on('before-quit', () => {
|
||||
isQuitting = true
|
||||
})
|
||||
|
||||
// In this file you can include the rest of your app's specific main process
|
||||
// code. You can also put them in separate files and require them here.
|
||||
|
||||
4
src/renderer/auto-imports.d.ts
vendored
4
src/renderer/auto-imports.d.ts
vendored
@@ -5,4 +5,6 @@
|
||||
// Generated by unplugin-auto-import
|
||||
// biome-ignore lint: disable
|
||||
export {}
|
||||
declare global {}
|
||||
declare global {
|
||||
|
||||
}
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
# 音频播放器控件功能完善
|
||||
|
||||
## Core Features
|
||||
|
||||
- 播放列表管理(添加/删除/排序)
|
||||
|
||||
- 音量调节控件
|
||||
|
||||
- 多种播放模式(顺序/随机/单曲循环)
|
||||
|
||||
- 播放列表导出/导入功能
|
||||
|
||||
- 播放列表一键清空功能
|
||||
|
||||
## Tech Stack
|
||||
|
||||
{
|
||||
"Web": {
|
||||
"arch": "vue",
|
||||
"component": "tdesign"
|
||||
}
|
||||
}
|
||||
|
||||
## Design
|
||||
|
||||
现代简约风格,深色背景配合高对比度控件,主色调为TDesign主题蓝(#0052D9),包含固定底部播放控制区、垂直弹出式音量控制、图标式播放模式选择器和可拖拽排序的播放列表侧边栏。新增导出/导入功能使用TDesign对话框组件,提供文件导出/导入和内容复制/粘贴两种方式,所有导出内容进行加密处理。清空功能添加二次确认对话框防止误操作。
|
||||
|
||||
## Plan
|
||||
|
||||
Note:
|
||||
|
||||
- [ ] is holding
|
||||
- [/] is doing
|
||||
- [x] is done
|
||||
|
||||
---
|
||||
|
||||
[ ] 扩展Pinia状态管理,在ControlAudioStore中添加音量控制、播放模式和播放列表相关状态
|
||||
|
||||
[ ] 创建VolumeControl.vue组件,实现音量调节滑动条和静音按钮功能
|
||||
|
||||
[ ] 创建PlayModeSelector.vue组件,实现三种播放模式的切换功能
|
||||
|
||||
[ ] 创建PlaylistManager.vue组件,实现播放列表的基本显示功能
|
||||
|
||||
[ ] 在PlaylistManager组件中实现添加和删除曲目功能
|
||||
|
||||
[ ] 集成拖拽排序功能到PlaylistManager组件
|
||||
|
||||
[ ] 将新组件集成到主播放器界面,调整布局确保合理性
|
||||
|
||||
[ ] 实现播放列表与音频控制的联动,确保播放状态正确反映
|
||||
|
||||
[ ] 添加键盘快捷键支持和状态反馈机制
|
||||
|
||||
[ ] 进行组件间通信测试,确保功能协调工作
|
||||
|
||||
[ ] 创建播放列表加密/解密工具函数
|
||||
|
||||
[ ] 实现播放列表导出功能(文件导出和内容复制)
|
||||
|
||||
[ ] 实现播放列表导入功能(文件导入和内容粘贴)
|
||||
|
||||
[ ] 实现播放列表一键清空功能及二次确认机制
|
||||
|
||||
[ ] 测试导出/导入功能的加密解密正确性
|
||||
Reference in New Issue
Block a user