mirror of
https://github.com/kuaifan/dootask.git
synced 2025-12-12 19:35:50 +00:00
perf: 优化下载工具
This commit is contained in:
parent
f6850fc795
commit
0833018399
314
electron/electron-down.js
vendored
314
electron/electron-down.js
vendored
@ -1,149 +1,14 @@
|
|||||||
|
const {BrowserWindow, screen} = require('electron')
|
||||||
|
const path = require('path');
|
||||||
|
const Store = require("electron-store");
|
||||||
const loger = require("electron-log");
|
const loger = require("electron-log");
|
||||||
const Store = require('electron-store');
|
const {default: electronDl, download} = require("@dootask/electron-dl");
|
||||||
const store = new Store({
|
const utils = require("./utils");
|
||||||
name: 'download-manager',
|
const {DownloadManager} = require("./utils/download");
|
||||||
defaults: {
|
|
||||||
downloadHistory: [],
|
|
||||||
}
|
|
||||||
});
|
|
||||||
const electronDl = require("@dootask/electron-dl").default;
|
|
||||||
|
|
||||||
class DownloadManager {
|
|
||||||
constructor() {
|
|
||||||
this.downloadHistory = store.get('downloadHistory', []);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换下载项格式
|
|
||||||
* @param {Electron.DownloadItem} downloadItem
|
|
||||||
*/
|
|
||||||
convertItem(downloadItem) {
|
|
||||||
return {
|
|
||||||
filename: downloadItem.getFilename(),
|
|
||||||
path: downloadItem.getSavePath(),
|
|
||||||
url: downloadItem.getURL(),
|
|
||||||
urls: downloadItem.getURLChain(),
|
|
||||||
mine: downloadItem.getMimeType(),
|
|
||||||
received: downloadItem.getReceivedBytes(),
|
|
||||||
total: downloadItem.getTotalBytes(),
|
|
||||||
percent: downloadItem.getPercentComplete(),
|
|
||||||
speed: downloadItem.getCurrentBytesPerSecond(),
|
|
||||||
state: downloadItem.getState(),
|
|
||||||
paused: downloadItem.isPaused(),
|
|
||||||
startTime: downloadItem.getStartTime(),
|
|
||||||
endTime: downloadItem.getEndTime(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 添加下载项
|
|
||||||
* @param {Electron.DownloadItem} downloadItem
|
|
||||||
*/
|
|
||||||
addDownloadItem(downloadItem) {
|
|
||||||
this.downloadHistory.unshift({
|
|
||||||
...this.convertItem(downloadItem),
|
|
||||||
_source: downloadItem,
|
|
||||||
});
|
|
||||||
store.set('downloadHistory', this.downloadHistory.slice(0, 100)); // 限制最多100个下载项
|
|
||||||
loger.info(`Download item added: ${downloadItem.getSavePath()}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新下载项
|
|
||||||
* @param {string} path
|
|
||||||
*/
|
|
||||||
updateDownloadItem(path) {
|
|
||||||
const item = this.downloadHistory.find(d => d.path === path)
|
|
||||||
if (!item) {
|
|
||||||
loger.warn(`Download item not found for path: ${path}`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const downloadItem = item._source;
|
|
||||||
if (!downloadItem) {
|
|
||||||
loger.warn(`Download item not found for path: ${path}`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Object.assign(item, this.convertItem(downloadItem))
|
|
||||||
store.set('downloadHistory', this.downloadHistory);
|
|
||||||
loger.info(`Download item updated: ${path} - ${item.state} (${item.percent}%)`);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 暂停下载项
|
|
||||||
* @param {string} path
|
|
||||||
*/
|
|
||||||
pauseDownloadItem(path) {
|
|
||||||
const item = this.downloadHistory.find(d => d.path === path)
|
|
||||||
if (!item) {
|
|
||||||
loger.warn(`Download item not found for path: ${path}`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const downloadItem = item._source;
|
|
||||||
if (!downloadItem) {
|
|
||||||
loger.warn(`Download item not found for path: ${path}`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
downloadItem.pause();
|
|
||||||
this.updateDownloadItem(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 恢复下载项
|
|
||||||
* @param {string} path
|
|
||||||
*/
|
|
||||||
resumeDownloadItem(path) {
|
|
||||||
const item = this.downloadHistory.find(d => d.path === path)
|
|
||||||
if (!item) {
|
|
||||||
loger.warn(`Download item not found for path: ${path}`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const downloadItem = item._source;
|
|
||||||
if (!downloadItem) {
|
|
||||||
loger.warn(`Download item not found for path: ${path}`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
downloadItem.resume();
|
|
||||||
this.updateDownloadItem(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 取消下载项
|
|
||||||
* @param {string} path
|
|
||||||
*/
|
|
||||||
cancelDownloadItem(path) {
|
|
||||||
const item = this.downloadHistory.find(d => d.path === path)
|
|
||||||
if (!item) {
|
|
||||||
loger.warn(`Download item not found for path: ${path}`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const downloadItem = item._source;
|
|
||||||
if (!downloadItem) {
|
|
||||||
loger.warn(`Download item not found for path: ${path}`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
downloadItem.cancel();
|
|
||||||
this.updateDownloadItem(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 取消所有下载项
|
|
||||||
*/
|
|
||||||
cancelAllDownloadItems() {
|
|
||||||
this.downloadHistory.forEach(item => {
|
|
||||||
this.cancelDownloadItem(item.path);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 清空下载历史
|
|
||||||
*/
|
|
||||||
clearHistory() {
|
|
||||||
this.downloadHistory = [];
|
|
||||||
store.set('downloadHistory', []);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
const store = new Store();
|
||||||
const downloadManager = new DownloadManager();
|
const downloadManager = new DownloadManager();
|
||||||
|
let downloadWindow = null;
|
||||||
|
|
||||||
function initialize(options = {}) {
|
function initialize(options = {}) {
|
||||||
// 下载配置
|
// 下载配置
|
||||||
@ -155,20 +20,181 @@ function initialize(options = {}) {
|
|||||||
|
|
||||||
onStarted: (item) => {
|
onStarted: (item) => {
|
||||||
downloadManager.addDownloadItem(item);
|
downloadManager.addDownloadItem(item);
|
||||||
|
syncDownloadItems();
|
||||||
},
|
},
|
||||||
onProgress: (item) => {
|
onProgress: (item) => {
|
||||||
downloadManager.updateDownloadItem(item.path);
|
downloadManager.updateDownloadItem(item.path);
|
||||||
|
syncDownloadItems();
|
||||||
},
|
},
|
||||||
onCancel: (item) => {
|
onCancel: (item) => {
|
||||||
downloadManager.updateDownloadItem(item.getSavePath())
|
downloadManager.updateDownloadItem(item.getSavePath())
|
||||||
|
syncDownloadItems();
|
||||||
},
|
},
|
||||||
onCompleted: (item) => {
|
onCompleted: (item) => {
|
||||||
downloadManager.updateDownloadItem(item.path);
|
downloadManager.updateDownloadItem(item.path);
|
||||||
|
syncDownloadItems();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function syncDownloadItems() {
|
||||||
|
// 同步下载项到渲染进程
|
||||||
|
if (downloadWindow) {
|
||||||
|
downloadWindow.webContents.send('download-items', downloadManager.getDownloadItems());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getLanguagePack(codeOrPack) {
|
||||||
|
if (codeOrPack && typeof codeOrPack === 'object') {
|
||||||
|
return codeOrPack;
|
||||||
|
}
|
||||||
|
const code = (codeOrPack || 'zh').toString();
|
||||||
|
return {
|
||||||
|
code,
|
||||||
|
title: '下载管理器',
|
||||||
|
// todo
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function open(language = 'zh', theme = 'light') {
|
||||||
|
// 获取语言包
|
||||||
|
const finalLanguage = getLanguagePack(language);
|
||||||
|
|
||||||
|
// 如果窗口已存在,直接显示
|
||||||
|
if (downloadWindow) {
|
||||||
|
// 更新窗口数据
|
||||||
|
await updateDownloadWindow(language, theme)
|
||||||
|
// 显示窗口并聚焦
|
||||||
|
downloadWindow.show();
|
||||||
|
downloadWindow.focus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 窗口默认参数
|
||||||
|
const downloadWindowOptions = {
|
||||||
|
width: 700,
|
||||||
|
height: 480,
|
||||||
|
minWidth: 500,
|
||||||
|
minHeight: 350,
|
||||||
|
center: true,
|
||||||
|
show: false,
|
||||||
|
autoHideMenuBar: true,
|
||||||
|
title: finalLanguage.title,
|
||||||
|
backgroundColor: utils.getDefaultBackgroundColor(),
|
||||||
|
webPreferences: {
|
||||||
|
preload: path.join(__dirname, 'electron-preload.js'),
|
||||||
|
webSecurity: true,
|
||||||
|
nodeIntegration: true,
|
||||||
|
contextIsolation: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 恢复窗口位置
|
||||||
|
const downloadWindowBounds = store.get('downloadWindowBounds', {});
|
||||||
|
if (
|
||||||
|
downloadWindowBounds.width !== undefined &&
|
||||||
|
downloadWindowBounds.height !== undefined &&
|
||||||
|
downloadWindowBounds.x !== undefined &&
|
||||||
|
downloadWindowBounds.y !== undefined
|
||||||
|
) {
|
||||||
|
// 获取所有显示器的可用区域
|
||||||
|
const displays = screen.getAllDisplays();
|
||||||
|
// 检查窗口是否在任意一个屏幕内
|
||||||
|
let isInScreen = false;
|
||||||
|
for (const display of displays) {
|
||||||
|
const area = display.workArea;
|
||||||
|
if (
|
||||||
|
downloadWindowBounds.x + downloadWindowBounds.width > area.x &&
|
||||||
|
downloadWindowBounds.x < area.x + area.width &&
|
||||||
|
downloadWindowBounds.y + downloadWindowBounds.height > area.y &&
|
||||||
|
downloadWindowBounds.y < area.y + area.height
|
||||||
|
) {
|
||||||
|
isInScreen = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 如果超出所有屏幕,则移动到主屏幕可见区域
|
||||||
|
if (!isInScreen) {
|
||||||
|
const primaryArea = screen.getPrimaryDisplay().workArea;
|
||||||
|
downloadWindowBounds.x = primaryArea.x + 50;
|
||||||
|
downloadWindowBounds.y = primaryArea.y + 50;
|
||||||
|
// 防止窗口太大超出屏幕
|
||||||
|
downloadWindowBounds.width = Math.min(downloadWindowBounds.width, primaryArea.width - 100);
|
||||||
|
downloadWindowBounds.height = Math.min(downloadWindowBounds.height, primaryArea.height - 100);
|
||||||
|
}
|
||||||
|
downloadWindowOptions.width = downloadWindowBounds.width;
|
||||||
|
downloadWindowOptions.height = downloadWindowBounds.height;
|
||||||
|
downloadWindowOptions.center = false;
|
||||||
|
downloadWindowOptions.x = downloadWindowBounds.x;
|
||||||
|
downloadWindowOptions.y = downloadWindowBounds.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建窗口
|
||||||
|
downloadWindow = new BrowserWindow(downloadWindowOptions);
|
||||||
|
|
||||||
|
// 禁止修改窗口标题
|
||||||
|
downloadWindow.on('page-title-updated', (event) => {
|
||||||
|
event.preventDefault()
|
||||||
|
})
|
||||||
|
|
||||||
|
// 监听窗口关闭保存窗口位置
|
||||||
|
downloadWindow.on('close', () => {
|
||||||
|
const bounds = downloadWindow.getBounds();
|
||||||
|
store.set('downloadWindowBounds', bounds);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 监听窗口关闭事件
|
||||||
|
downloadWindow.on('closed', () => {
|
||||||
|
downloadWindow = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 加载下载管理器页面
|
||||||
|
const htmlPath = path.join(__dirname, 'render', 'download', 'index.html');
|
||||||
|
const themeParam = (theme === 'dark' ? 'dark' : 'light');
|
||||||
|
await downloadWindow.loadFile(htmlPath, {query: {theme: themeParam}});
|
||||||
|
|
||||||
|
// 将语言包发送到渲染进程
|
||||||
|
downloadWindow.webContents.once('dom-ready', () => {
|
||||||
|
updateDownloadWindow(language, theme)
|
||||||
|
});
|
||||||
|
|
||||||
|
// 显示窗口
|
||||||
|
downloadWindow.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
function close() {
|
||||||
|
if (downloadWindow) {
|
||||||
|
downloadWindow.close();
|
||||||
|
downloadWindow = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function destroy() {
|
||||||
|
if (downloadWindow) {
|
||||||
|
downloadWindow.destroy();
|
||||||
|
downloadWindow = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function updateDownloadWindow(language, theme) {
|
||||||
|
if (downloadWindow) {
|
||||||
|
try {
|
||||||
|
const finalLanguage = getLanguagePack(language);
|
||||||
|
downloadWindow.setTitle(finalLanguage.title);
|
||||||
|
downloadWindow.webContents.send('download-theme', theme);
|
||||||
|
downloadWindow.webContents.send('download-language', finalLanguage);
|
||||||
|
syncDownloadItems()
|
||||||
|
} catch (error) {
|
||||||
|
loger.error(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
initialize
|
initialize,
|
||||||
|
download,
|
||||||
|
open,
|
||||||
|
close,
|
||||||
|
destroy,
|
||||||
|
updateDownloadWindow
|
||||||
}
|
}
|
||||||
|
|||||||
8
electron/electron-preload.js
vendored
8
electron/electron-preload.js
vendored
@ -32,7 +32,13 @@ contextBridge.exposeInMainWorld(
|
|||||||
'electron', {
|
'electron', {
|
||||||
request: (msg, callback, error) => {
|
request: (msg, callback, error) => {
|
||||||
msg.reqId = reqId++;
|
msg.reqId = reqId++;
|
||||||
reqInfo[msg.reqId] = {callback: callback, error: error};
|
if (typeof callback !== "function") {
|
||||||
|
callback = function () {};
|
||||||
|
}
|
||||||
|
if (typeof error !== "function") {
|
||||||
|
error = function () {};
|
||||||
|
}
|
||||||
|
reqInfo[msg.reqId] = {callback, error};
|
||||||
if (msg.action == 'watchFile') {
|
if (msg.action == 'watchFile') {
|
||||||
fileChangedListeners[msg.path] = msg.listener;
|
fileChangedListeners[msg.path] = msg.listener;
|
||||||
delete msg.listener;
|
delete msg.listener;
|
||||||
|
|||||||
55
electron/electron.js
vendored
55
electron/electron.js
vendored
@ -123,9 +123,6 @@ if (!fs.existsSync(cacheDir)) {
|
|||||||
fs.mkdirSync(cacheDir, { recursive: true });
|
fs.mkdirSync(cacheDir, { recursive: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
// 初始化下载配置
|
|
||||||
electronDown.initialize()
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 启动web服务
|
* 启动web服务
|
||||||
*/
|
*/
|
||||||
@ -345,10 +342,10 @@ function createMainWindow() {
|
|||||||
// 新窗口处理
|
// 新窗口处理
|
||||||
mainWindow.webContents.setWindowOpenHandler(({url}) => {
|
mainWindow.webContents.setWindowOpenHandler(({url}) => {
|
||||||
if (allowedCalls.test(url)) {
|
if (allowedCalls.test(url)) {
|
||||||
openExternal(url)
|
openExternal(url).catch(() => {})
|
||||||
} else {
|
} else {
|
||||||
utils.onBeforeOpenWindow(mainWindow.webContents, url).then(() => {
|
utils.onBeforeOpenWindow(mainWindow.webContents, url).then(() => {
|
||||||
openExternal(url)
|
openExternal(url).catch(() => {})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return {action: 'deny'}
|
return {action: 'deny'}
|
||||||
@ -587,10 +584,10 @@ function createChildWindow(args) {
|
|||||||
// 新窗口处理
|
// 新窗口处理
|
||||||
browser.webContents.setWindowOpenHandler(({url}) => {
|
browser.webContents.setWindowOpenHandler(({url}) => {
|
||||||
if (allowedCalls.test(url)) {
|
if (allowedCalls.test(url)) {
|
||||||
openExternal(url)
|
openExternal(url).catch(() => {})
|
||||||
} else {
|
} else {
|
||||||
utils.onBeforeOpenWindow(browser.webContents, url).then(() => {
|
utils.onBeforeOpenWindow(browser.webContents, url).then(() => {
|
||||||
openExternal(url)
|
openExternal(url).catch(() => {})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return {action: 'deny'}
|
return {action: 'deny'}
|
||||||
@ -866,7 +863,7 @@ function createWebTabWindow(args) {
|
|||||||
})
|
})
|
||||||
browserView.webContents.setWindowOpenHandler(({url}) => {
|
browserView.webContents.setWindowOpenHandler(({url}) => {
|
||||||
if (allowedCalls.test(url)) {
|
if (allowedCalls.test(url)) {
|
||||||
openExternal(url)
|
openExternal(url).catch(() => {})
|
||||||
} else {
|
} else {
|
||||||
createWebTabWindow({url})
|
createWebTabWindow({url})
|
||||||
}
|
}
|
||||||
@ -1102,6 +1099,8 @@ if (!getTheLock) {
|
|||||||
}
|
}
|
||||||
// SameSite
|
// SameSite
|
||||||
utils.useCookie()
|
utils.useCookie()
|
||||||
|
// 初始化下载
|
||||||
|
electronDown.initialize()
|
||||||
// 创建主窗口
|
// 创建主窗口
|
||||||
createMainWindow()
|
createMainWindow()
|
||||||
// 预创建子窗口
|
// 预创建子窗口
|
||||||
@ -1293,7 +1292,7 @@ ipcMain.on('webTabExternal', (event) => {
|
|||||||
if (!item) {
|
if (!item) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
openExternal(item.view.webContents.getURL())
|
openExternal(item.view.webContents.getURL()).catch(() => {})
|
||||||
event.returnValue = "ok"
|
event.returnValue = "ok"
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -1358,6 +1357,7 @@ ipcMain.on('childWindowCloseAll', (event) => {
|
|||||||
})
|
})
|
||||||
preloadWindow?.close()
|
preloadWindow?.close()
|
||||||
mediaWindow?.close()
|
mediaWindow?.close()
|
||||||
|
electronDown.close()
|
||||||
event.returnValue = "ok"
|
event.returnValue = "ok"
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -1370,6 +1370,7 @@ ipcMain.on('childWindowDestroyAll', (event) => {
|
|||||||
})
|
})
|
||||||
preloadWindow?.destroy()
|
preloadWindow?.destroy()
|
||||||
mediaWindow?.destroy()
|
mediaWindow?.destroy()
|
||||||
|
electronDown.destroy()
|
||||||
event.returnValue = "ok"
|
event.returnValue = "ok"
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -1714,6 +1715,7 @@ ipcMain.on('updateQuitAndInstall', (event, args) => {
|
|||||||
})
|
})
|
||||||
preloadWindow?.destroy()
|
preloadWindow?.destroy()
|
||||||
mediaWindow?.destroy()
|
mediaWindow?.destroy()
|
||||||
|
electronDown.destroy()
|
||||||
|
|
||||||
// 启动更新子窗口
|
// 启动更新子窗口
|
||||||
createUpdaterWindow(args.updateTitle)
|
createUpdaterWindow(args.updateTitle)
|
||||||
@ -2611,7 +2613,7 @@ function getPluginFile(plugin) {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function uninstallPlugin(plugin) {
|
async function uninstallPlugin(plugin) {
|
||||||
const pluginFile = getPluginFile(plugin);
|
const pluginFile = getPluginFile(plugin);
|
||||||
|
|
||||||
if (pluginFile != null) {
|
if (pluginFile != null) {
|
||||||
@ -2672,7 +2674,7 @@ async function deleteFile(file) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function windowAction(method) {
|
async function windowAction(method) {
|
||||||
let win = BrowserWindow.getFocusedWindow();
|
let win = BrowserWindow.getFocusedWindow();
|
||||||
|
|
||||||
if (win) {
|
if (win) {
|
||||||
@ -2692,16 +2694,14 @@ function windowAction(method) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function openExternal(url) {
|
async function openExternal(url) {
|
||||||
//Only open http(s), mailto, tel, and callto links
|
//Only open http(s), mailto, tel, and callto links
|
||||||
if (allowedUrls.test(url)) {
|
if (allowedUrls.test(url)) {
|
||||||
shell.openExternal(url).catch(_ => {});
|
await shell.openExternal(url)
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function watchFile(path) {
|
async function watchFile(path) {
|
||||||
let win = BrowserWindow.getFocusedWindow();
|
let win = BrowserWindow.getFocusedWindow();
|
||||||
|
|
||||||
if (win) {
|
if (win) {
|
||||||
@ -2713,12 +2713,13 @@ function watchFile(path) {
|
|||||||
prev: prev
|
prev: prev
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
} // Ignore
|
// Ignore
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function unwatchFile(path) {
|
async function unwatchFile(path) {
|
||||||
fs.unwatchFile(path);
|
fs.unwatchFile(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2747,7 +2748,7 @@ ipcMain.on("rendererReq", async (event, args) => {
|
|||||||
ret = await getDocumentsFolder();
|
ret = await getDocumentsFolder();
|
||||||
break;
|
break;
|
||||||
case 'checkFileExists':
|
case 'checkFileExists':
|
||||||
ret = await checkFileExists(args.pathParts);
|
ret = checkFileExists(args.pathParts);
|
||||||
break;
|
break;
|
||||||
case 'showOpenDialog':
|
case 'showOpenDialog':
|
||||||
dialogOpen = true;
|
dialogOpen = true;
|
||||||
@ -2768,7 +2769,7 @@ ipcMain.on("rendererReq", async (event, args) => {
|
|||||||
ret = await uninstallPlugin(args.plugin);
|
ret = await uninstallPlugin(args.plugin);
|
||||||
break;
|
break;
|
||||||
case 'getPluginFile':
|
case 'getPluginFile':
|
||||||
ret = await getPluginFile(args.plugin);
|
ret = getPluginFile(args.plugin);
|
||||||
break;
|
break;
|
||||||
case 'isPluginsEnabled':
|
case 'isPluginsEnabled':
|
||||||
ret = enablePlugins;
|
ret = enablePlugins;
|
||||||
@ -2780,7 +2781,7 @@ ipcMain.on("rendererReq", async (event, args) => {
|
|||||||
ret = await readFile(args.filename, args.encoding);
|
ret = await readFile(args.filename, args.encoding);
|
||||||
break;
|
break;
|
||||||
case 'clipboardAction':
|
case 'clipboardAction':
|
||||||
ret = await clipboardAction(args.method, args.data);
|
ret = clipboardAction(args.method, args.data);
|
||||||
break;
|
break;
|
||||||
case 'deleteFile':
|
case 'deleteFile':
|
||||||
ret = await deleteFile(args.file);
|
ret = await deleteFile(args.file);
|
||||||
@ -2797,6 +2798,15 @@ ipcMain.on("rendererReq", async (event, args) => {
|
|||||||
case 'openExternal':
|
case 'openExternal':
|
||||||
ret = await openExternal(args.url);
|
ret = await openExternal(args.url);
|
||||||
break;
|
break;
|
||||||
|
case 'openDownloadWindow':
|
||||||
|
ret = await electronDown.open(args.language || 'zh', args.theme || 'light');
|
||||||
|
break;
|
||||||
|
case 'createDownloadTask':
|
||||||
|
ret = await electronDown.download(mainWindow, args.url, args.options || {});
|
||||||
|
break;
|
||||||
|
case 'updateDownloadWindow':
|
||||||
|
ret = await electronDown.updateDownloadWindow(args.language, args.theme);
|
||||||
|
break;
|
||||||
case 'watchFile':
|
case 'watchFile':
|
||||||
ret = await watchFile(args.path);
|
ret = await watchFile(args.path);
|
||||||
break;
|
break;
|
||||||
@ -2804,12 +2814,13 @@ ipcMain.on("rendererReq", async (event, args) => {
|
|||||||
ret = await unwatchFile(args.path);
|
ret = await unwatchFile(args.path);
|
||||||
break;
|
break;
|
||||||
case 'getCurDir':
|
case 'getCurDir':
|
||||||
ret = await getCurDir();
|
ret = getCurDir();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
event.reply('mainResp', {success: true, data: ret, reqId: args.reqId});
|
event.reply('mainResp', {success: true, data: ret, reqId: args.reqId});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
event.reply('mainResp', {error: true, msg: e.message, e: e, reqId: args.reqId});
|
event.reply('mainResp', {error: true, msg: e.message, e: e, reqId: args.reqId});
|
||||||
|
loger.error('Renderer request error', e.message, e.stack);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@ -79,10 +79,10 @@
|
|||||||
"files": [
|
"files": [
|
||||||
"render/**/*",
|
"render/**/*",
|
||||||
"public/**/*",
|
"public/**/*",
|
||||||
|
"utils/**/*",
|
||||||
"electron-menu.js",
|
"electron-menu.js",
|
||||||
"electron-preload.js",
|
"electron-preload.js",
|
||||||
"electron.js",
|
"electron.js"
|
||||||
"utils.js"
|
|
||||||
],
|
],
|
||||||
"extraFiles": [
|
"extraFiles": [
|
||||||
{
|
{
|
||||||
|
|||||||
1
electron/render/download/index.html
Normal file
1
electron/render/download/index.html
Normal file
@ -0,0 +1 @@
|
|||||||
|
123
|
||||||
161
electron/utils/download.js
vendored
Normal file
161
electron/utils/download.js
vendored
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
const loger = require("electron-log");
|
||||||
|
const Store = require('electron-store');
|
||||||
|
const store = new Store({
|
||||||
|
name: 'download-manager',
|
||||||
|
defaults: {
|
||||||
|
downloadHistory: [],
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
class DownloadManager {
|
||||||
|
constructor() {
|
||||||
|
this.downloadHistory = store.get('downloadHistory', []);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 转换下载项格式
|
||||||
|
* @param {Electron.DownloadItem} downloadItem
|
||||||
|
*/
|
||||||
|
convertItem(downloadItem) {
|
||||||
|
return {
|
||||||
|
filename: downloadItem.getFilename(),
|
||||||
|
path: downloadItem.getSavePath(),
|
||||||
|
url: downloadItem.getURL(),
|
||||||
|
urls: downloadItem.getURLChain(),
|
||||||
|
mine: downloadItem.getMimeType(),
|
||||||
|
received: downloadItem.getReceivedBytes(),
|
||||||
|
total: downloadItem.getTotalBytes(),
|
||||||
|
percent: downloadItem.getPercentComplete(),
|
||||||
|
speed: downloadItem.getCurrentBytesPerSecond(),
|
||||||
|
state: downloadItem.getState(),
|
||||||
|
paused: downloadItem.isPaused(),
|
||||||
|
startTime: downloadItem.getStartTime(),
|
||||||
|
endTime: downloadItem.getEndTime(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加下载项
|
||||||
|
* @param {Electron.DownloadItem} downloadItem
|
||||||
|
*/
|
||||||
|
addDownloadItem(downloadItem) {
|
||||||
|
this.downloadHistory.unshift({
|
||||||
|
...this.convertItem(downloadItem),
|
||||||
|
_source: downloadItem,
|
||||||
|
});
|
||||||
|
if (this.downloadHistory.length > 1000) {
|
||||||
|
this.downloadHistory = this.downloadHistory.slice(0, 1000);
|
||||||
|
}
|
||||||
|
store.set('downloadHistory', this.downloadHistory);
|
||||||
|
loger.info(`Download item added: ${downloadItem.getSavePath()}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取下载列表
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
getDownloadItems() {
|
||||||
|
return this.downloadHistory.map(item => {
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
_source: undefined, // 移除源对象,避免序列化问题
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新下载项
|
||||||
|
* @param {string} path
|
||||||
|
*/
|
||||||
|
updateDownloadItem(path) {
|
||||||
|
const item = this.downloadHistory.find(d => d.path === path)
|
||||||
|
if (!item) {
|
||||||
|
loger.warn(`Download item not found for path: ${path}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const downloadItem = item._source;
|
||||||
|
if (!downloadItem) {
|
||||||
|
loger.warn(`Download item not found for path: ${path}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Object.assign(item, this.convertItem(downloadItem))
|
||||||
|
store.set('downloadHistory', this.downloadHistory);
|
||||||
|
loger.info(`Download item updated: ${path} - ${item.state} (${item.percent}%)`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 暂停下载项
|
||||||
|
* @param {string} path
|
||||||
|
*/
|
||||||
|
pauseDownloadItem(path) {
|
||||||
|
const item = this.downloadHistory.find(d => d.path === path)
|
||||||
|
if (!item) {
|
||||||
|
loger.warn(`Download item not found for path: ${path}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const downloadItem = item._source;
|
||||||
|
if (!downloadItem) {
|
||||||
|
loger.warn(`Download item not found for path: ${path}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
downloadItem.pause();
|
||||||
|
this.updateDownloadItem(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 恢复下载项
|
||||||
|
* @param {string} path
|
||||||
|
*/
|
||||||
|
resumeDownloadItem(path) {
|
||||||
|
const item = this.downloadHistory.find(d => d.path === path)
|
||||||
|
if (!item) {
|
||||||
|
loger.warn(`Download item not found for path: ${path}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const downloadItem = item._source;
|
||||||
|
if (!downloadItem) {
|
||||||
|
loger.warn(`Download item not found for path: ${path}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
downloadItem.resume();
|
||||||
|
this.updateDownloadItem(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 取消下载项
|
||||||
|
* @param {string} path
|
||||||
|
*/
|
||||||
|
cancelDownloadItem(path) {
|
||||||
|
const item = this.downloadHistory.find(d => d.path === path)
|
||||||
|
if (!item) {
|
||||||
|
loger.warn(`Download item not found for path: ${path}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const downloadItem = item._source;
|
||||||
|
if (!downloadItem) {
|
||||||
|
loger.warn(`Download item not found for path: ${path}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
downloadItem.cancel();
|
||||||
|
this.updateDownloadItem(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 取消所有下载项
|
||||||
|
*/
|
||||||
|
cancelAllDownloadItems() {
|
||||||
|
this.downloadHistory.forEach(item => {
|
||||||
|
this.cancelDownloadItem(item.path);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清空下载历史
|
||||||
|
*/
|
||||||
|
clearHistory() {
|
||||||
|
this.downloadHistory = [];
|
||||||
|
store.set('downloadHistory', []);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { DownloadManager };
|
||||||
@ -2150,3 +2150,4 @@ API URL
|
|||||||
需要先设置 AI 助理
|
需要先设置 AI 助理
|
||||||
|
|
||||||
打开签到机器人
|
打开签到机器人
|
||||||
|
下载内容
|
||||||
|
|||||||
@ -401,20 +401,14 @@ export default {
|
|||||||
if (this.isMeetingUrlStrict(url)) {
|
if (this.isMeetingUrlStrict(url)) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
// 同域名下载链接
|
||||||
|
if (this.isDownloadUrl(url)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
// 同域名规则
|
// 同域名规则
|
||||||
if ($A.getDomain(url) == $A.getDomain($A.mainUrl())) {
|
if ($A.getDomain(url) == $A.getDomain($A.mainUrl())) {
|
||||||
try {
|
try {
|
||||||
const {pathname, searchParams} = new URL(url);
|
const {pathname, searchParams} = new URL(url);
|
||||||
// uploads/ 上传文件
|
|
||||||
// api/dialog/msg/download 会话文件
|
|
||||||
// api/project/task/filedown 任务文件
|
|
||||||
if (/^\/(uploads|api\/dialog\/msg\/download|api\/project\/task\/filedown)/.test(pathname)) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
// api/file/content?down=yes 文件下载
|
|
||||||
if (/^\/api\/file\/content/.test(pathname) && searchParams.get('down') === 'yes') {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
// meeting/1234567890/xxxxx 会议
|
// meeting/1234567890/xxxxx 会议
|
||||||
if (/^\/meeting\/\d+\/\S+$/.test(pathname)) {
|
if (/^\/meeting\/\d+\/\S+$/.test(pathname)) {
|
||||||
const meetingId = pathname.split('/')[2];
|
const meetingId = pathname.split('/')[2];
|
||||||
@ -438,6 +432,32 @@ export default {
|
|||||||
return 0;
|
return 0;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
isDownloadUrl(url) {
|
||||||
|
if ($A.getDomain(url) == $A.getDomain($A.mainUrl())) {
|
||||||
|
try {
|
||||||
|
const {pathname, searchParams} = new URL(url);
|
||||||
|
// 匹配常见的下载相关路径
|
||||||
|
const downloadPathPatterns = [
|
||||||
|
'/uploads', // 上传文件
|
||||||
|
'/api/dialog/msg/download', // 会话文件
|
||||||
|
'/api/project/task/filedown', // 任务文件
|
||||||
|
'/api/file/download/pack', // 文件打包下载
|
||||||
|
'/api/approve/down', // 审批导出下载
|
||||||
|
'/api/project/task/down', // 任务导出下载
|
||||||
|
'/api/system/checkin/down' // 签到导出下载
|
||||||
|
];
|
||||||
|
if (downloadPathPatterns.some(pattern => $A.leftExists(pathname, pattern))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// 匹配文件内容下载(/api/file/content 带参数 down=yes)
|
||||||
|
if ($A.leftExists(pathname, '/api/file/content') && searchParams.get('down') === 'yes') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} catch (e) {}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
isApplicationProtocol(url) {
|
isApplicationProtocol(url) {
|
||||||
const protocols = [
|
const protocols = [
|
||||||
'thunder:', // 迅雷专有链接
|
'thunder:', // 迅雷专有链接
|
||||||
@ -576,6 +596,10 @@ export default {
|
|||||||
return true;
|
return true;
|
||||||
} else if (urlType === 1) {
|
} else if (urlType === 1) {
|
||||||
// 使用默认浏览器打开
|
// 使用默认浏览器打开
|
||||||
|
if (this.isDownloadUrl(url)) {
|
||||||
|
this.$store.dispatch('downUrl', url)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// 使用内置浏览器打开
|
// 使用内置浏览器打开
|
||||||
|
|||||||
@ -9,7 +9,7 @@
|
|||||||
<!-- 胶囊工具栏 -->
|
<!-- 胶囊工具栏 -->
|
||||||
<div v-if="capsuleMenuShow" class="micro-modal-cmask"></div>
|
<div v-if="capsuleMenuShow" class="micro-modal-cmask"></div>
|
||||||
<div class="micro-modal-capsule" :style="capsuleStyle">
|
<div class="micro-modal-capsule" :style="capsuleStyle">
|
||||||
<div class="micro-modal-capsule-item" v-touchclick="onCapsuleMore">
|
<div class="micro-modal-capsule-item" @click="onCapsuleMore">
|
||||||
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<path d="M2 11C3.10457 11 4 10.1046 4 9C4 7.89543 3.10457 7 2 7C0.895431 7 0 7.89543 0 9C0 10.1046 0.895431 11 2 11Z" fill="currentColor"/>
|
<path d="M2 11C3.10457 11 4 10.1046 4 9C4 7.89543 3.10457 7 2 7C0.895431 7 0 7.89543 0 9C0 10.1046 0.895431 11 2 11Z" fill="currentColor"/>
|
||||||
<path d="M9 12C10.6569 12 12 10.6569 12 9C12 7.34315 10.6569 6 9 6C7.34315 6 6 7.34315 6 9C6 10.6569 7.34315 12 9 12Z" fill="currentColor"/>
|
<path d="M9 12C10.6569 12 12 10.6569 12 9C12 7.34315 10.6569 6 9 6C7.34315 6 6 7.34315 6 9C6 10.6569 7.34315 12 9 12Z" fill="currentColor"/>
|
||||||
@ -17,7 +17,7 @@
|
|||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<div class="micro-modal-capsule-line"></div>
|
<div class="micro-modal-capsule-line"></div>
|
||||||
<div class="micro-modal-capsule-item" v-touchclick="attemptClose">
|
<div class="micro-modal-capsule-item" @click="attemptClose">
|
||||||
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<path d="M9 16C12.866 16 16 12.866 16 9C16 5.13401 12.866 2 9 2C5.13401 2 2 5.13401 2 9C2 12.866 5.13401 16 9 16Z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
<path d="M9 16C12.866 16 16 12.866 16 9C16 5.13401 12.866 2 9 2C5.13401 2 2 5.13401 2 9C2 12.866 5.13401 16 9 16Z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
<path d="M9 12C10.6569 12 12 10.6569 12 9C12 7.34315 10.6569 6 9 6C7.34315 6 6 7.34315 6 9C6 10.6569 7.34315 12 9 12Z" fill="currentColor"/>
|
<path d="M9 12C10.6569 12 12 10.6569 12 9C12 7.34315 10.6569 6 9 6C7.34315 6 6 7.34315 6 9C6 10.6569 7.34315 12 9 12Z" fill="currentColor"/>
|
||||||
@ -48,13 +48,12 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import TransferDom from "../../directives/transfer-dom";
|
import TransferDom from "../../directives/transfer-dom";
|
||||||
import touchclick from "../../directives/touchclick";
|
|
||||||
import ResizeLine from "../ResizeLine.vue";
|
import ResizeLine from "../ResizeLine.vue";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'MicroModal',
|
name: 'MicroModal',
|
||||||
components: {ResizeLine},
|
components: {ResizeLine},
|
||||||
directives: {TransferDom, touchclick},
|
directives: {TransferDom},
|
||||||
props: {
|
props: {
|
||||||
open: {
|
open: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
|
|||||||
@ -392,6 +392,7 @@ import notificationKoro from "notification-koro1";
|
|||||||
import emitter from "../store/events";
|
import emitter from "../store/events";
|
||||||
import SearchBox from "../components/SearchBox.vue";
|
import SearchBox from "../components/SearchBox.vue";
|
||||||
import transformEmojiToHtml from "../utils/emoji";
|
import transformEmojiToHtml from "../utils/emoji";
|
||||||
|
import {languageName} from "../language";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
@ -516,6 +517,7 @@ export default {
|
|||||||
'cacheDialogs',
|
'cacheDialogs',
|
||||||
'cacheProjects',
|
'cacheProjects',
|
||||||
'projectTotal',
|
'projectTotal',
|
||||||
|
'themeName',
|
||||||
'wsOpenNum',
|
'wsOpenNum',
|
||||||
'columnTemplate',
|
'columnTemplate',
|
||||||
|
|
||||||
@ -629,7 +631,8 @@ export default {
|
|||||||
menu() {
|
menu() {
|
||||||
const {userIsAdmin} = this;
|
const {userIsAdmin} = this;
|
||||||
const array = [
|
const array = [
|
||||||
{path: 'taskBrowse', name: '最近打开的任务'}
|
{path: 'taskBrowse', name: '最近打开的任务'},
|
||||||
|
{path: 'download', name: '下载内容', visible: !!this.$Electron},
|
||||||
];
|
];
|
||||||
if (userIsAdmin) {
|
if (userIsAdmin) {
|
||||||
array.push(...[
|
array.push(...[
|
||||||
@ -643,7 +646,6 @@ export default {
|
|||||||
{path: 'archivedProject', name: '已归档的项目'},
|
{path: 'archivedProject', name: '已归档的项目'},
|
||||||
|
|
||||||
{path: 'team', name: '团队管理', divided: true},
|
{path: 'team', name: '团队管理', divided: true},
|
||||||
{path: 'complaint', name: '举报管理'},
|
|
||||||
])
|
])
|
||||||
} else {
|
} else {
|
||||||
array.push(...[
|
array.push(...[
|
||||||
@ -727,6 +729,19 @@ export default {
|
|||||||
this.$store.dispatch("getProjectByQueue", 600);
|
this.$store.dispatch("getProjectByQueue", 600);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
themeName: {
|
||||||
|
handler(theme) {
|
||||||
|
if (this.$Electron) {
|
||||||
|
$A.Electron.request({
|
||||||
|
action: 'updateDownloadWindow',
|
||||||
|
language: languageName,
|
||||||
|
theme,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
immediate: true
|
||||||
|
},
|
||||||
|
|
||||||
'cacheProjects.length': {
|
'cacheProjects.length': {
|
||||||
handler() {
|
handler() {
|
||||||
this.$nextTick(_ => {
|
this.$nextTick(_ => {
|
||||||
@ -819,6 +834,13 @@ export default {
|
|||||||
case 'complaint':
|
case 'complaint':
|
||||||
this.complaintShow = true;
|
this.complaintShow = true;
|
||||||
return;
|
return;
|
||||||
|
case 'download':
|
||||||
|
$A.Electron.request({
|
||||||
|
action: 'openDownloadWindow',
|
||||||
|
language: languageName,
|
||||||
|
theme: this.themeName,
|
||||||
|
});
|
||||||
|
return;
|
||||||
case 'logout':
|
case 'logout':
|
||||||
$A.modalConfirm({
|
$A.modalConfirm({
|
||||||
title: '退出登录',
|
title: '退出登录',
|
||||||
@ -978,6 +1000,13 @@ export default {
|
|||||||
this.onAddMenu('task')
|
this.onAddMenu('task')
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 76: // L - 下载内容(+ alt)
|
||||||
|
if (e.altKey) {
|
||||||
|
e.preventDefault();
|
||||||
|
this.settingRoute('download')
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case 85: // U - 创建群组
|
case 85: // U - 创建群组
|
||||||
this.onCreateGroup([this.userId])
|
this.onCreateGroup([this.userId])
|
||||||
break;
|
break;
|
||||||
|
|||||||
@ -88,7 +88,7 @@ export default {
|
|||||||
]
|
]
|
||||||
|
|
||||||
if (this.$Electron || this.$isEEUIApp) {
|
if (this.$Electron || this.$isEEUIApp) {
|
||||||
menu.push({path: 'keyboard', name: '键盘设置', desc: ' (Beta)'})
|
menu.push({path: 'keyboard', name: '键盘设置'})
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($A.isDooServer() && this.$isEEUIApp) {
|
if ($A.isDooServer() && this.$isEEUIApp) {
|
||||||
|
|||||||
@ -7,6 +7,11 @@
|
|||||||
{{mateName}}<div class="input-box-push">+</div>Shift<div class="input-box-push">+</div><Input class="input-box-key" v-model="formData.screenshot_key" :maxlength="2"/>
|
{{mateName}}<div class="input-box-push">+</div>Shift<div class="input-box-push">+</div><Input class="input-box-key" v-model="formData.screenshot_key" :maxlength="2"/>
|
||||||
</div>
|
</div>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
|
<FormItem :label="$L('下载内容')" prop="download_key">
|
||||||
|
<div class="input-box">
|
||||||
|
{{mateName}}<div class="input-box-push">+</div>{{altName}}<div class="input-box-push">+</div>L
|
||||||
|
</div>
|
||||||
|
</FormItem>
|
||||||
<FormItem :label="$L('新建项目')">
|
<FormItem :label="$L('新建项目')">
|
||||||
<div class="input-box">
|
<div class="input-box">
|
||||||
{{mateName}}<div class="input-box-push">+</div>B
|
{{mateName}}<div class="input-box-push">+</div>B
|
||||||
@ -14,7 +19,7 @@
|
|||||||
</FormItem>
|
</FormItem>
|
||||||
<FormItem :label="$L('新建任务')">
|
<FormItem :label="$L('新建任务')">
|
||||||
<div class="input-box">
|
<div class="input-box">
|
||||||
{{mateName}}<div class="input-box-push">+</div>N (K)
|
{{mateName}}<div class="input-box-push">+</div>N
|
||||||
</div>
|
</div>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
<FormItem :label="$L('新会议')">
|
<FormItem :label="$L('新会议')">
|
||||||
@ -71,7 +76,7 @@ export default {
|
|||||||
loadIng: 0,
|
loadIng: 0,
|
||||||
|
|
||||||
mateName: /macintosh|mac os x/i.test(navigator.userAgent) ? 'Command' : 'Ctrl',
|
mateName: /macintosh|mac os x/i.test(navigator.userAgent) ? 'Command' : 'Ctrl',
|
||||||
|
altName: /macintosh|mac os x/i.test(navigator.userAgent) ? 'Option' : 'Alt',
|
||||||
|
|
||||||
formData: {
|
formData: {
|
||||||
screenshot_key: '',
|
screenshot_key: '',
|
||||||
|
|||||||
12
resources/assets/js/store/actions.js
vendored
12
resources/assets/js/store/actions.js
vendored
@ -465,10 +465,14 @@ export default {
|
|||||||
url = $A.urlAddParams(url, params);
|
url = $A.urlAddParams(url, params);
|
||||||
}
|
}
|
||||||
if ($A.Electron) {
|
if ($A.Electron) {
|
||||||
$A.Electron.request({action: 'openExternal', url}, () => {
|
$A.Electron.request({
|
||||||
// 成功
|
action: 'createDownloadTask',
|
||||||
}, () => {
|
url
|
||||||
// 失败
|
});
|
||||||
|
$A.Electron.request({
|
||||||
|
action: 'openDownloadWindow',
|
||||||
|
language: languageName,
|
||||||
|
theme: state.themeName,
|
||||||
});
|
});
|
||||||
} else if ($A.isEEUIApp) {
|
} else if ($A.isEEUIApp) {
|
||||||
$A.eeuiAppOpenWeb(url);
|
$A.eeuiAppOpenWeb(url);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user