mirror of
https://github.com/kuaifan/dootask.git
synced 2025-12-12 11:19:56 +00:00
perf: 优化桌面端通知图标
This commit is contained in:
parent
694f9a37a5
commit
07a290dbf9
9
cmd
9
cmd
@ -168,15 +168,12 @@ run_electron() {
|
|||||||
rm -rf "./electron/public"
|
rm -rf "./electron/public"
|
||||||
fi
|
fi
|
||||||
#
|
#
|
||||||
|
BUILD_FRONTEND="build"
|
||||||
if [ "$argv" == "dev" ]; then
|
if [ "$argv" == "dev" ]; then
|
||||||
switch_debug "$argv"
|
switch_debug "$argv"
|
||||||
else
|
BUILD_FRONTEND="dev"
|
||||||
mkdir -p ./electron/public
|
|
||||||
cp ./electron/index.html ./electron/public/index.html
|
|
||||||
npx vite build -- fromcmd electronBuild
|
|
||||||
echo ""
|
|
||||||
fi
|
fi
|
||||||
node ./electron/build.js $argv
|
env BUILD_FRONTEND=$BUILD_FRONTEND node ./electron/build.js $argv
|
||||||
}
|
}
|
||||||
|
|
||||||
run_exec() {
|
run_exec() {
|
||||||
|
|||||||
1
electron/.gitignore
vendored
1
electron/.gitignore
vendored
@ -6,6 +6,7 @@ package-lock.json
|
|||||||
build/
|
build/
|
||||||
dist/
|
dist/
|
||||||
updater/*
|
updater/*
|
||||||
|
cache/*
|
||||||
|
|
||||||
.devload
|
.devload
|
||||||
.native
|
.native
|
||||||
|
|||||||
18
electron/build.js
vendored
18
electron/build.js
vendored
@ -11,7 +11,7 @@ const utils = require('./utils');
|
|||||||
const config = require('../package.json')
|
const config = require('../package.json')
|
||||||
const env = require('dotenv').config({ path: './.env' })
|
const env = require('dotenv').config({ path: './.env' })
|
||||||
const argv = process.argv;
|
const argv = process.argv;
|
||||||
const {APPLEID, APPLEIDPASS, GITHUB_TOKEN, GITHUB_REPOSITORY, PUBLISH_KEY} = process.env;
|
const {BUILD_FRONTEND, APPLEID, APPLEIDPASS, GITHUB_TOKEN, GITHUB_REPOSITORY, PUBLISH_KEY} = process.env;
|
||||||
|
|
||||||
const electronDir = path.resolve(__dirname, "public");
|
const electronDir = path.resolve(__dirname, "public");
|
||||||
const nativeCachePath = path.resolve(__dirname, ".native");
|
const nativeCachePath = path.resolve(__dirname, ".native");
|
||||||
@ -21,6 +21,9 @@ const packageBakFile = path.resolve(__dirname, "package-bak.json");
|
|||||||
const platforms = ["build-mac", "build-win"];
|
const platforms = ["build-mac", "build-win"];
|
||||||
const architectures = ["arm64", "x64"];
|
const architectures = ["arm64", "x64"];
|
||||||
|
|
||||||
|
let buildChecked = false,
|
||||||
|
updaterChecked = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检测并下载更新器
|
* 检测并下载更新器
|
||||||
*/
|
*/
|
||||||
@ -459,6 +462,13 @@ function genericPublish({url, key, version, output}) {
|
|||||||
* @param data
|
* @param data
|
||||||
*/
|
*/
|
||||||
async function startBuild(data) {
|
async function startBuild(data) {
|
||||||
|
if (BUILD_FRONTEND === 'build' && !buildChecked) {
|
||||||
|
buildChecked = true
|
||||||
|
fs.mkdirSync(electronDir, { recursive: true });
|
||||||
|
fse.copySync(path.resolve(__dirname, "index.html"), path.resolve(electronDir, "index.html"))
|
||||||
|
child_process.spawnSync("npx", ["vite", "build", "--", "fromcmd", "electronBuild"], {stdio: "inherit"});
|
||||||
|
}
|
||||||
|
//
|
||||||
const {platform, archs, publish, release, notarize} = data.configure
|
const {platform, archs, publish, release, notarize} = data.configure
|
||||||
// system info
|
// system info
|
||||||
const systemInfo = {
|
const systemInfo = {
|
||||||
@ -493,7 +503,10 @@ async function startBuild(data) {
|
|||||||
// drawio
|
// drawio
|
||||||
cloneDrawio(systemInfo)
|
cloneDrawio(systemInfo)
|
||||||
// updater
|
// updater
|
||||||
await detectAndDownloadUpdater()
|
if (!updaterChecked) {
|
||||||
|
updaterChecked = true
|
||||||
|
await detectAndDownloadUpdater()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// language
|
// language
|
||||||
fse.copySync(path.resolve(__dirname, "../public/language"), path.resolve(electronDir, "language"))
|
fse.copySync(path.resolve(__dirname, "../public/language"), path.resolve(electronDir, "language"))
|
||||||
@ -569,6 +582,7 @@ async function startBuild(data) {
|
|||||||
if (appName === "public") appName = "DooTask"
|
if (appName === "public") appName = "DooTask"
|
||||||
appConfig.name = data.name;
|
appConfig.name = data.name;
|
||||||
appConfig.version = config.version;
|
appConfig.version = config.version;
|
||||||
|
appConfig.appId = data.id;
|
||||||
appConfig.build.appId = data.id;
|
appConfig.build.appId = data.id;
|
||||||
appConfig.build.artifactName = appName + "-v${version}-${os}-${arch}.${ext}";
|
appConfig.build.artifactName = appName + "-v${version}-${os}-${arch}.${ext}";
|
||||||
appConfig.build.nsis.artifactName = appName + "-v${version}-${os}-${arch}.${ext}";
|
appConfig.build.nsis.artifactName = appName + "-v${version}-${os}-${arch}.${ext}";
|
||||||
|
|||||||
55
electron/electron.js
vendored
55
electron/electron.js
vendored
@ -20,7 +20,8 @@ const isMac = process.platform === 'darwin'
|
|||||||
const isWin = process.platform === 'win32'
|
const isWin = process.platform === 'win32'
|
||||||
const allowedUrls = /^(?:https?|mailto|tel|callto):/i;
|
const allowedUrls = /^(?:https?|mailto|tel|callto):/i;
|
||||||
const allowedCalls = /^(?:mailto|tel|callto):/i;
|
const allowedCalls = /^(?:mailto|tel|callto):/i;
|
||||||
let updaterLockFile = path.join(os.tmpdir(), '.dootask_updater.lock');
|
const cacheDir = path.join(os.tmpdir(), 'dootask-cache')
|
||||||
|
let updaterLockFile = path.join(cacheDir, '.dootask_updater.lock');
|
||||||
let enableStoreBkp = true;
|
let enableStoreBkp = true;
|
||||||
let dialogOpen = false;
|
let dialogOpen = false;
|
||||||
let enablePlugins = false;
|
let enablePlugins = false;
|
||||||
@ -53,6 +54,10 @@ if (fs.existsSync(devloadCachePath)) {
|
|||||||
devloadUrl = fs.readFileSync(devloadCachePath, 'utf8')
|
devloadUrl = fs.readFileSync(devloadCachePath, 'utf8')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!fs.existsSync(cacheDir)) {
|
||||||
|
fs.mkdirSync(cacheDir, { recursive: true });
|
||||||
|
}
|
||||||
|
|
||||||
// 在最开始就注册协议为特权协议
|
// 在最开始就注册协议为特权协议
|
||||||
protocol.registerSchemesAsPrivileged([
|
protocol.registerSchemesAsPrivileged([
|
||||||
{
|
{
|
||||||
@ -85,7 +90,7 @@ function createProtocol() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const data = await fs.promises.readFile(filePath)
|
const data = await fs.promises.readFile(filePath)
|
||||||
const mimeType = getMimeType(filePath)
|
const mimeType = utils.getMimeType(filePath)
|
||||||
|
|
||||||
return new Response(data, {
|
return new Response(data, {
|
||||||
headers: {
|
headers: {
|
||||||
@ -99,24 +104,6 @@ function createProtocol() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* MIME类型判断
|
|
||||||
* @param filePath
|
|
||||||
* @returns {*|string}
|
|
||||||
*/
|
|
||||||
function getMimeType(filePath) {
|
|
||||||
const ext = path.extname(filePath).toLowerCase()
|
|
||||||
const mimeTypes = {
|
|
||||||
'.jpg': 'image/jpeg',
|
|
||||||
'.jpeg': 'image/jpeg',
|
|
||||||
'.png': 'image/png',
|
|
||||||
'.gif': 'image/gif',
|
|
||||||
'.svg': 'image/svg+xml',
|
|
||||||
'.webp': 'image/webp'
|
|
||||||
}
|
|
||||||
return mimeTypes[ext] || 'application/octet-stream'
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建主窗口
|
* 创建主窗口
|
||||||
*/
|
*/
|
||||||
@ -201,7 +188,7 @@ function createUpdaterWindow(updateTitle) {
|
|||||||
} else {
|
} else {
|
||||||
updaterPath = path.join(process.resourcesPath, 'updater', 'updater');
|
updaterPath = path.join(process.resourcesPath, 'updater', 'updater');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查updater应用是否存在
|
// 检查updater应用是否存在
|
||||||
if (!fs.existsSync(updaterPath)) {
|
if (!fs.existsSync(updaterPath)) {
|
||||||
console.log('Updater not found:', updaterPath);
|
console.log('Updater not found:', updaterPath);
|
||||||
@ -222,7 +209,7 @@ function createUpdaterWindow(updateTitle) {
|
|||||||
try {
|
try {
|
||||||
spawn('chmod', ['+x', updaterPath], {stdio: 'inherit'});
|
spawn('chmod', ['+x', updaterPath], {stdio: 'inherit'});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log('Failed to set executable permission:', e);
|
console.log('Failed to set executable permission:', e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -728,6 +715,7 @@ if (!getTheLock) {
|
|||||||
})
|
})
|
||||||
app.on('ready', () => {
|
app.on('ready', () => {
|
||||||
isReady = true
|
isReady = true
|
||||||
|
isWin && app.setAppUserModelId(config.appId)
|
||||||
// SameSite
|
// SameSite
|
||||||
utils.useCookie()
|
utils.useCookie()
|
||||||
// 创建协议
|
// 创建协议
|
||||||
@ -756,7 +744,7 @@ if (!getTheLock) {
|
|||||||
mainTray.setContextMenu(trayMenu)
|
mainTray.setContextMenu(trayMenu)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 删除updater锁文件(如果存在)
|
// 删除updater锁文件(如果存在)
|
||||||
if (fs.existsSync(updaterLockFile)) {
|
if (fs.existsSync(updaterLockFile)) {
|
||||||
try {
|
try {
|
||||||
fs.unlinkSync(updaterLockFile);
|
fs.unlinkSync(updaterLockFile);
|
||||||
@ -764,10 +752,6 @@ if (!getTheLock) {
|
|||||||
//忽略错误
|
//忽略错误
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//
|
|
||||||
if (process.platform === 'win32') {
|
|
||||||
app.setAppUserModelId(config.name)
|
|
||||||
}
|
|
||||||
// 截图对象
|
// 截图对象
|
||||||
screenshotObj = new Screenshots({
|
screenshotObj = new Screenshots({
|
||||||
singleWindow: true,
|
singleWindow: true,
|
||||||
@ -1150,7 +1134,7 @@ ipcMain.on('copyImageAt', (event, args) => {
|
|||||||
try {
|
try {
|
||||||
event.sender.copyImageAt(args.x, args.y);
|
event.sender.copyImageAt(args.x, args.y);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// log.error(e)
|
// loger.error(e)
|
||||||
}
|
}
|
||||||
event.returnValue = "ok"
|
event.returnValue = "ok"
|
||||||
})
|
})
|
||||||
@ -1212,14 +1196,7 @@ ipcMain.on('closeScreenshot', (event) => {
|
|||||||
* 通知
|
* 通知
|
||||||
*/
|
*/
|
||||||
ipcMain.on('openNotification', (event, args) => {
|
ipcMain.on('openNotification', (event, args) => {
|
||||||
const notifiy = new Notification(args);
|
utils.showNotification(args, mainWindow)
|
||||||
notifiy.addListener('click', _ => {
|
|
||||||
mainWindow.webContents.send("clickNotification", args)
|
|
||||||
})
|
|
||||||
notifiy.addListener('reply', (event, reply) => {
|
|
||||||
mainWindow.webContents.send("replyNotification", Object.assign(args, {reply}))
|
|
||||||
})
|
|
||||||
notifiy.show()
|
|
||||||
event.returnValue = "ok"
|
event.returnValue = "ok"
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -1306,13 +1283,11 @@ ipcMain.on('updateQuitAndInstall', (event, args) => {
|
|||||||
// 启动更新子窗口
|
// 启动更新子窗口
|
||||||
createUpdaterWindow(args.updateTitle)
|
createUpdaterWindow(args.updateTitle)
|
||||||
|
|
||||||
// 隐藏主窗口
|
|
||||||
mainWindow.hide()
|
|
||||||
|
|
||||||
// 退出并安装更新
|
// 退出并安装更新
|
||||||
setTimeout(_ => {
|
setTimeout(_ => {
|
||||||
|
mainWindow.hide()
|
||||||
autoUpdater.quitAndInstall(true, true)
|
autoUpdater.quitAndInstall(true, true)
|
||||||
}, 300)
|
}, 600)
|
||||||
})
|
})
|
||||||
|
|
||||||
//================================================================
|
//================================================================
|
||||||
|
|||||||
211
electron/utils.js
vendored
211
electron/utils.js
vendored
@ -1,8 +1,14 @@
|
|||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
|
const os = require("os");
|
||||||
|
const path = require('path')
|
||||||
const dayjs = require("dayjs");
|
const dayjs = require("dayjs");
|
||||||
const {shell, dialog, session} = require("electron");
|
const http = require('http')
|
||||||
|
const https = require('https')
|
||||||
|
const crypto = require('crypto')
|
||||||
|
const {shell, dialog, session, Notification} = require("electron");
|
||||||
|
const loger = require("electron-log");
|
||||||
|
|
||||||
module.exports = {
|
const utils = {
|
||||||
/**
|
/**
|
||||||
* 时间对象
|
* 时间对象
|
||||||
* @param v
|
* @param v
|
||||||
@ -160,7 +166,7 @@ module.exports = {
|
|||||||
leftDelete(string, find, lower = false) {
|
leftDelete(string, find, lower = false) {
|
||||||
string += "";
|
string += "";
|
||||||
find += "";
|
find += "";
|
||||||
if (this.leftExists(string, find, lower)) {
|
if (utils.leftExists(string, find, lower)) {
|
||||||
string = string.substring(find.length)
|
string = string.substring(find.length)
|
||||||
}
|
}
|
||||||
return string ? string : '';
|
return string ? string : '';
|
||||||
@ -185,33 +191,33 @@ module.exports = {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 打开文件
|
* 打开文件
|
||||||
* @param path
|
* @param filePath
|
||||||
*/
|
*/
|
||||||
openFile(path) {
|
openFile(filePath) {
|
||||||
if (!fs.existsSync(path)) {
|
if (!fs.existsSync(filePath)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
shell.openPath(path).then(() => {
|
shell.openPath(filePath).then(() => {
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除文件夹及文件
|
* 删除文件夹及文件
|
||||||
* @param path
|
* @param filePath
|
||||||
*/
|
*/
|
||||||
deleteFile(path) {
|
deleteFile(filePath) {
|
||||||
let files = [];
|
let files = [];
|
||||||
if (fs.existsSync(path)) {
|
if (fs.existsSync(filePath)) {
|
||||||
files = fs.readdirSync(path);
|
files = fs.readdirSync(filePath);
|
||||||
files.forEach(function (file, index) {
|
files.forEach(function (file) {
|
||||||
let curPath = path + "/" + file;
|
let curPath = filePath + "/" + file;
|
||||||
if (fs.statSync(curPath).isDirectory()) {
|
if (fs.statSync(curPath).isDirectory()) {
|
||||||
deleteFile(curPath);
|
utils.deleteFile(curPath);
|
||||||
} else {
|
} else {
|
||||||
fs.unlinkSync(curPath);
|
fs.unlinkSync(curPath);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
fs.rmdirSync(path);
|
fs.rmdirSync(filePath);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -225,14 +231,14 @@ module.exports = {
|
|||||||
let rs = fs.createReadStream(srcPath)
|
let rs = fs.createReadStream(srcPath)
|
||||||
rs.on('error', function (err) {
|
rs.on('error', function (err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.log('read error', srcPath)
|
loger.log('read error', srcPath)
|
||||||
}
|
}
|
||||||
cb && cb(err)
|
cb && cb(err)
|
||||||
})
|
})
|
||||||
let ws = fs.createWriteStream(tarPath)
|
let ws = fs.createWriteStream(tarPath)
|
||||||
ws.on('error', function (err) {
|
ws.on('error', function (err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.log('write error', tarPath)
|
loger.log('write error', tarPath)
|
||||||
}
|
}
|
||||||
cb && cb(err)
|
cb && cb(err)
|
||||||
})
|
})
|
||||||
@ -296,7 +302,7 @@ module.exports = {
|
|||||||
const contents = app.webContents
|
const contents = app.webContents
|
||||||
if (contents != null) {
|
if (contents != null) {
|
||||||
contents.executeJavaScript('if(typeof window.__onBeforeUnload === \'function\'){window.__onBeforeUnload()}', true).then(options => {
|
contents.executeJavaScript('if(typeof window.__onBeforeUnload === \'function\'){window.__onBeforeUnload()}', true).then(options => {
|
||||||
if (this.isJson(options)) {
|
if (utils.isJson(options)) {
|
||||||
let choice = dialog.showMessageBoxSync(app, options)
|
let choice = dialog.showMessageBoxSync(app, options)
|
||||||
if (choice === 1) {
|
if (choice === 1) {
|
||||||
contents.executeJavaScript('if(typeof window.__removeBeforeUnload === \'function\'){window.__removeBeforeUnload()}', true).catch(() => {});
|
contents.executeJavaScript('if(typeof window.__removeBeforeUnload === \'function\'){window.__removeBeforeUnload()}', true).catch(() => {});
|
||||||
@ -414,7 +420,7 @@ module.exports = {
|
|||||||
* electron15 后,解决跨域cookie无法携带,
|
* electron15 后,解决跨域cookie无法携带,
|
||||||
*/
|
*/
|
||||||
useCookie() {
|
useCookie() {
|
||||||
const filter = {urls: ['https://*/*']};
|
const filter = {urls: ['https://*/*', 'http://*/*']};
|
||||||
session.defaultSession.webRequest.onHeadersReceived(filter, (details, callback) => {
|
session.defaultSession.webRequest.onHeadersReceived(filter, (details, callback) => {
|
||||||
if (details.responseHeaders && details.responseHeaders['Set-Cookie']) {
|
if (details.responseHeaders && details.responseHeaders['Set-Cookie']) {
|
||||||
for (let i = 0; i < details.responseHeaders['Set-Cookie'].length; i++) {
|
for (let i = 0; i < details.responseHeaders['Set-Cookie'].length; i++) {
|
||||||
@ -436,5 +442,170 @@ module.exports = {
|
|||||||
} else {
|
} else {
|
||||||
return input.meta
|
return input.meta
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MIME类型判断
|
||||||
|
* @param filePath
|
||||||
|
* @returns {*|string}
|
||||||
|
*/
|
||||||
|
getMimeType(filePath) {
|
||||||
|
const ext = path.extname(filePath).toLowerCase()
|
||||||
|
const mimeTypes = {
|
||||||
|
'.jpg': 'image/jpeg',
|
||||||
|
'.jpeg': 'image/jpeg',
|
||||||
|
'.png': 'image/png',
|
||||||
|
'.gif': 'image/gif',
|
||||||
|
'.svg': 'image/svg+xml',
|
||||||
|
'.webp': 'image/webp'
|
||||||
|
}
|
||||||
|
return mimeTypes[ext] || 'application/octet-stream'
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 显示系统通知
|
||||||
|
* @param {Object} args - 通知参数
|
||||||
|
* @param {string} args.title - 通知标题
|
||||||
|
* @param {string} args.body - 通知内容
|
||||||
|
* @param {string} [args.icon] - 通知图标路径或URL
|
||||||
|
* @param {Electron.BrowserWindow} [window] - 主窗口实例
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
async showNotification(args, window = null) {
|
||||||
|
try {
|
||||||
|
// 如果是网络图片,进行缓存处理(仅Windows)
|
||||||
|
if (process.platform === 'win32' && args.icon && /^https?:\/\//i.test(args.icon)) {
|
||||||
|
args.icon = await utils.getCachedImage(args.icon);
|
||||||
|
}
|
||||||
|
|
||||||
|
const notifiy = new Notification(args);
|
||||||
|
notifiy.addListener('click', _ => {
|
||||||
|
if (window && window.webContents) {
|
||||||
|
window.webContents.send("clickNotification", args)
|
||||||
|
if (!window.isVisible()) {
|
||||||
|
window.show();
|
||||||
|
}
|
||||||
|
window.focus();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
notifiy.addListener('reply', (event, reply) => {
|
||||||
|
if (window && window.webContents) {
|
||||||
|
window.webContents.send("replyNotification", Object.assign(args, {reply}))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
notifiy.show()
|
||||||
|
} catch (error) {
|
||||||
|
loger.error('显示通知失败:', error);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取缓存的图片路径
|
||||||
|
* @param {string} imageUrl - 图片URL
|
||||||
|
* @returns {Promise<string>} 缓存的图片路径
|
||||||
|
*/
|
||||||
|
async getCachedImage(imageUrl) {
|
||||||
|
// 生成图片URL的唯一标识
|
||||||
|
const urlHash = crypto.createHash('md5').update(imageUrl).digest('hex');
|
||||||
|
const cacheDir = path.join(os.tmpdir(), 'dootask-cache', 'images');
|
||||||
|
const cachePath = path.join(cacheDir, `${urlHash}.png`);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 确保缓存目录存在
|
||||||
|
if (!fs.existsSync(cacheDir)) {
|
||||||
|
fs.mkdirSync(cacheDir, { recursive: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查缓存是否存在
|
||||||
|
if (!fs.existsSync(cachePath)) {
|
||||||
|
await utils.downloadImage(imageUrl, cachePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
return cachePath;
|
||||||
|
} catch (error) {
|
||||||
|
loger.error('处理缓存图片失败:', error);
|
||||||
|
return ''; // 返回空字符串,通知将使用默认图标
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 下载图片
|
||||||
|
* @param {string} url - 图片URL
|
||||||
|
* @param {string} filePath - 保存路径
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
downloadImage(url, filePath) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const file = fs.createWriteStream(filePath);
|
||||||
|
|
||||||
|
// 根据协议选择http或https
|
||||||
|
const protocol = url.startsWith('https') ? https : http;
|
||||||
|
|
||||||
|
const request = protocol.get(url, {
|
||||||
|
headers: {
|
||||||
|
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
|
||||||
|
}
|
||||||
|
}, (response) => {
|
||||||
|
// 处理重定向
|
||||||
|
if (response.statusCode === 301 || response.statusCode === 302) {
|
||||||
|
file.close();
|
||||||
|
fs.unlink(filePath, () => {});
|
||||||
|
return utils.downloadImage(response.headers.location, filePath)
|
||||||
|
.then(resolve)
|
||||||
|
.catch(reject);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查内容类型
|
||||||
|
const contentType = response.headers['content-type'];
|
||||||
|
if (!contentType || !contentType.startsWith('image/')) {
|
||||||
|
file.close();
|
||||||
|
fs.unlink(filePath, () => {});
|
||||||
|
reject(new Error(`非图片类型: ${contentType}`));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response.statusCode !== 200) {
|
||||||
|
file.close();
|
||||||
|
fs.unlink(filePath, () => {});
|
||||||
|
reject(new Error(`下载失败,状态码: ${response.statusCode}`));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let downloadedBytes = 0;
|
||||||
|
response.on('data', (chunk) => {
|
||||||
|
downloadedBytes += chunk.length;
|
||||||
|
});
|
||||||
|
|
||||||
|
response.pipe(file);
|
||||||
|
|
||||||
|
file.on('finish', () => {
|
||||||
|
// 检查文件大小
|
||||||
|
if (downloadedBytes === 0) {
|
||||||
|
file.close();
|
||||||
|
fs.unlink(filePath, () => {});
|
||||||
|
reject(new Error('下载的文件大小为0'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
file.close();
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
request.on('error', (err) => {
|
||||||
|
file.close();
|
||||||
|
fs.unlink(filePath, () => {});
|
||||||
|
reject(err);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 设置超时
|
||||||
|
request.setTimeout(30000, () => {
|
||||||
|
request.destroy();
|
||||||
|
file.close();
|
||||||
|
fs.unlink(filePath, () => {});
|
||||||
|
reject(new Error('下载超时'));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module.exports = utils;
|
||||||
|
|||||||
@ -1075,32 +1075,26 @@ export default {
|
|||||||
const body = $A.getMsgSimpleDesc(data);
|
const body = $A.getMsgSimpleDesc(data);
|
||||||
this.__notificationId = id;
|
this.__notificationId = id;
|
||||||
//
|
//
|
||||||
const notificationFuncA = (title) => {
|
const notificationFuncA = async (title) => {
|
||||||
if (dialog_type === 'group') {
|
let tempUser = this.cacheUserBasic.find(item => item.userid == userid);
|
||||||
let tempUser = this.cacheUserBasic.find(item => item.userid == userid);
|
if (!tempUser) {
|
||||||
if (tempUser) {
|
try {
|
||||||
notificationFuncB(`${title} (${tempUser.nickname})`)
|
const {data} = await this.$store.dispatch("call", {
|
||||||
} else {
|
|
||||||
this.$store.dispatch("call", {
|
|
||||||
url: 'users/basic',
|
url: 'users/basic',
|
||||||
data: {
|
data: {
|
||||||
userid: [userid]
|
userid: [userid]
|
||||||
},
|
},
|
||||||
skipAuthError: true
|
skipAuthError: true
|
||||||
}).then(({data}) => {
|
|
||||||
tempUser = data.find(item => item.userid == userid);
|
|
||||||
if (tempUser) {
|
|
||||||
notificationFuncB(`${title} (${tempUser.nickname})`)
|
|
||||||
}
|
|
||||||
}).catch(_ => {
|
|
||||||
notificationFuncB(title)
|
|
||||||
});
|
});
|
||||||
}
|
tempUser = data.find(item => item.userid == userid);
|
||||||
} else {
|
} catch (_) {}
|
||||||
notificationFuncB(title)
|
|
||||||
}
|
}
|
||||||
|
if (dialog_type === 'group' && tempUser) {
|
||||||
|
title = `${title} (${tempUser.nickname})`
|
||||||
|
}
|
||||||
|
notificationFuncB(title, tempUser?.userimg)
|
||||||
}
|
}
|
||||||
const notificationFuncB = (title) => {
|
const notificationFuncB = (title, userimg) => {
|
||||||
if (this.__notificationId === id) {
|
if (this.__notificationId === id) {
|
||||||
this.__notificationId = null
|
this.__notificationId = null
|
||||||
if (this.$isEEUiApp) {
|
if (this.$isEEUiApp) {
|
||||||
@ -1115,7 +1109,7 @@ export default {
|
|||||||
})
|
})
|
||||||
} else if (this.$Electron) {
|
} else if (this.$Electron) {
|
||||||
this.$Electron.sendMessage('openNotification', {
|
this.$Electron.sendMessage('openNotification', {
|
||||||
icon: $A.originUrl('images/logo.png'),
|
icon: userimg || $A.originUrl('images/logo.png'),
|
||||||
title,
|
title,
|
||||||
body,
|
body,
|
||||||
data,
|
data,
|
||||||
@ -1125,7 +1119,7 @@ export default {
|
|||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
this.notificationManage.replaceOptions({
|
this.notificationManage.replaceOptions({
|
||||||
icon: $A.originUrl('images/logo.png'),
|
icon: userimg || $A.originUrl('images/logo.png'),
|
||||||
body: body,
|
body: body,
|
||||||
data: data,
|
data: data,
|
||||||
tag: "dialog",
|
tag: "dialog",
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user