mirror of
https://github.com/fofolee/uTools-quickcommand.git
synced 2025-07-03 22:42:45 +08:00
添加快捷命令服务的功能
This commit is contained in:
parent
7390125d7c
commit
661c6b3711
@ -9,6 +9,8 @@ const {
|
|||||||
} = require('./lib/vm2')
|
} = require('./lib/vm2')
|
||||||
const path = require("path")
|
const path = require("path")
|
||||||
const axios = require('axios');
|
const axios = require('axios');
|
||||||
|
const http = require('http');
|
||||||
|
const url = require('url')
|
||||||
|
|
||||||
window._ = require("lodash")
|
window._ = require("lodash")
|
||||||
window.yuQueClient = axios.create({
|
window.yuQueClient = axios.create({
|
||||||
@ -266,154 +268,6 @@ let getSleepCodeByShell = ms => {
|
|||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
// 屏蔽危险函数
|
|
||||||
window.getuToolsLite = () => {
|
|
||||||
var utoolsLite = Object.assign({}, utools)
|
|
||||||
if (utools.isDev()) return utoolsLite
|
|
||||||
// 数据库相关接口
|
|
||||||
delete utoolsLite.db
|
|
||||||
delete utoolsLite.dbStorage
|
|
||||||
delete utoolsLite.removeFeature
|
|
||||||
delete utoolsLite.setFeature
|
|
||||||
delete utoolsLite.onDbPull
|
|
||||||
// 支付相关接口
|
|
||||||
delete utoolsLite.fetchUserServerTemporaryToken
|
|
||||||
delete utoolsLite.getUserServerTemporaryToken
|
|
||||||
delete utoolsLite.openPayment
|
|
||||||
delete utoolsLite.fetchUserPayments
|
|
||||||
return utoolsLite
|
|
||||||
}
|
|
||||||
|
|
||||||
let getSandboxFuns = () => {
|
|
||||||
var sandbox = {
|
|
||||||
utools: getuToolsLite(),
|
|
||||||
quickcommand: quickcommand,
|
|
||||||
electron: electron,
|
|
||||||
axios: axios,
|
|
||||||
Audio: Audio,
|
|
||||||
fetch: fetch
|
|
||||||
}
|
|
||||||
shortCodes.forEach(f => {
|
|
||||||
sandbox[f.name] = f
|
|
||||||
})
|
|
||||||
return sandbox
|
|
||||||
}
|
|
||||||
|
|
||||||
let createNodeVM = () => {
|
|
||||||
var sandbox = getSandboxFuns()
|
|
||||||
const vm = new NodeVM({
|
|
||||||
require: {
|
|
||||||
external: true,
|
|
||||||
builtin: ["*"],
|
|
||||||
},
|
|
||||||
console: 'redirect',
|
|
||||||
env: process.env,
|
|
||||||
sandbox: sandbox,
|
|
||||||
});
|
|
||||||
return vm
|
|
||||||
}
|
|
||||||
|
|
||||||
let stringifyAll = item => {
|
|
||||||
var cache = [];
|
|
||||||
var string = JSON.stringify(item, (key, value) => {
|
|
||||||
if (typeof value === 'object' && value !== null) {
|
|
||||||
if (cache.indexOf(value) !== -1) return
|
|
||||||
cache.push(value);
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}, '\t')
|
|
||||||
if (string != "{}") return string
|
|
||||||
else return item.toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
let parseItem = item => {
|
|
||||||
if (typeof item == "object") {
|
|
||||||
if (Buffer.isBuffer(item)) {
|
|
||||||
var bufferString = `[Buffer ${item.slice(0, 50).toString('hex').match(/\w{1,2}/g).join(" ")}`
|
|
||||||
if (item.length > 50) bufferString += `... ${(item.length / 1000).toFixed(2)}kb`
|
|
||||||
return bufferString + ']'
|
|
||||||
} else if (item instanceof ArrayBuffer) {
|
|
||||||
return `ArrayBuffer(${item.byteLength})`
|
|
||||||
} else if (item instanceof Blob) {
|
|
||||||
return `Blob {size: ${item.size}, type: "${item.type}"}`
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
return stringifyAll(item)
|
|
||||||
} catch (error) {}
|
|
||||||
}
|
|
||||||
} else if (typeof item == "undefined") {
|
|
||||||
return "undefined"
|
|
||||||
}
|
|
||||||
return item.toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
window.convertFilePathToUtoolsPayload = files => files.map(file => {
|
|
||||||
let isFile = fs.statSync(file).isFile()
|
|
||||||
return {
|
|
||||||
isFile: isFile,
|
|
||||||
isDirectory: !isFile,
|
|
||||||
name: path.basename(file),
|
|
||||||
path: file
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
let parseStdout = stdout => stdout.map(x => parseItem(x)).join("\n")
|
|
||||||
|
|
||||||
window.VmEval = (cmd, sandbox = {}) => new VM({
|
|
||||||
sandbox: sandbox
|
|
||||||
}).run(cmd)
|
|
||||||
|
|
||||||
// The vm module of Node.js is deprecated in the renderer process and will be removed
|
|
||||||
window.runCodeInVm = (cmd, cb) => {
|
|
||||||
const vm = createNodeVM()
|
|
||||||
//重定向 console
|
|
||||||
vm.on('console.log', (...stdout) => {
|
|
||||||
console.log(stdout);
|
|
||||||
cb(parseStdout(stdout), null)
|
|
||||||
});
|
|
||||||
|
|
||||||
vm.on('console.error', stderr => {
|
|
||||||
cb(null, stderr.toString())
|
|
||||||
});
|
|
||||||
|
|
||||||
let liteErr = e => {
|
|
||||||
if (!e) return
|
|
||||||
return e.stack.replace(/([ ] +at.+)|(.+\.js:\d+)/g, '').trim()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 错误处理
|
|
||||||
try {
|
|
||||||
vm.run(cmd, path.join(__dirname, 'preload.js'));
|
|
||||||
} catch (e) {
|
|
||||||
console.log('Error: ', e)
|
|
||||||
cb(null, liteErr(e))
|
|
||||||
}
|
|
||||||
|
|
||||||
let cbUnhandledError = e => {
|
|
||||||
removeAllListener()
|
|
||||||
console.log('UnhandledError: ', e)
|
|
||||||
cb(null, liteErr(e.error))
|
|
||||||
}
|
|
||||||
|
|
||||||
let cbUnhandledRejection = e => {
|
|
||||||
removeAllListener()
|
|
||||||
console.log('UnhandledRejection: ', e)
|
|
||||||
cb(null, liteErr(e.reason))
|
|
||||||
}
|
|
||||||
|
|
||||||
let removeAllListener = () => {
|
|
||||||
window.removeEventListener('error', cbUnhandledError)
|
|
||||||
window.removeEventListener('unhandledrejection', cbUnhandledRejection)
|
|
||||||
delete window.isWatchingError
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!window.isWatchingError) {
|
|
||||||
window.addEventListener('error', cbUnhandledError)
|
|
||||||
window.addEventListener('unhandledrejection', cbUnhandledRejection)
|
|
||||||
window.isWatchingError = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
window.htmlEncode = (value) => {
|
window.htmlEncode = (value) => {
|
||||||
return String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """)
|
return String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """)
|
||||||
}
|
}
|
||||||
@ -509,16 +363,6 @@ window.getCurrentFolderPathFix = () => {
|
|||||||
return pwdFix.replace(/\\/g, '\\\\')
|
return pwdFix.replace(/\\/g, '\\\\')
|
||||||
}
|
}
|
||||||
|
|
||||||
window.getMatchedFilesFix = payload => {
|
|
||||||
let MatchedFiles = payload
|
|
||||||
let Matched = cmd.match(/\{\{MatchedFiles(\[\d+\]){0,1}(\.\w{1,11}){0,1}\}\}/g)
|
|
||||||
Matched && Matched.forEach(m => {
|
|
||||||
repl = eval(m.slice(2, -2))
|
|
||||||
typeof repl == 'object' ? (repl = JSON.stringify(repl)) : (repl = repl.replace('\\', '\\\\'))
|
|
||||||
cmd = cmd.replace(m, repl.replace('$', '$$$'))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
window.saveFile = (content, file) => {
|
window.saveFile = (content, file) => {
|
||||||
if (file instanceof Object) file = utools.showSaveDialog(file)
|
if (file instanceof Object) file = utools.showSaveDialog(file)
|
||||||
if (!file) return false
|
if (!file) return false
|
||||||
@ -559,6 +403,156 @@ window.getSelectFile = hwnd => {
|
|||||||
|
|
||||||
window.clipboardReadText = () => electron.clipboard.readText()
|
window.clipboardReadText = () => electron.clipboard.readText()
|
||||||
|
|
||||||
|
window.convertFilePathToUtoolsPayload = files => files.map(file => {
|
||||||
|
let isFile = fs.statSync(file).isFile()
|
||||||
|
return {
|
||||||
|
isFile: isFile,
|
||||||
|
isDirectory: !isFile,
|
||||||
|
name: path.basename(file),
|
||||||
|
path: file
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
let stringifyAll = item => {
|
||||||
|
var cache = [];
|
||||||
|
var string = JSON.stringify(item, (key, value) => {
|
||||||
|
if (typeof value === 'object' && value !== null) {
|
||||||
|
if (cache.indexOf(value) !== -1) return
|
||||||
|
cache.push(value);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}, '\t')
|
||||||
|
if (string != "{}") return string
|
||||||
|
else return item.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
let parseItem = item => {
|
||||||
|
if (typeof item == "object") {
|
||||||
|
if (Buffer.isBuffer(item)) {
|
||||||
|
var bufferString = `[Buffer ${item.slice(0, 50).toString('hex').match(/\w{1,2}/g).join(" ")}`
|
||||||
|
if (item.length > 50) bufferString += `... ${(item.length / 1000).toFixed(2)}kb`
|
||||||
|
return bufferString + ']'
|
||||||
|
} else if (item instanceof ArrayBuffer) {
|
||||||
|
return `ArrayBuffer(${item.byteLength})`
|
||||||
|
} else if (item instanceof Blob) {
|
||||||
|
return `Blob {size: ${item.size}, type: "${item.type}"}`
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
return stringifyAll(item)
|
||||||
|
} catch (error) {}
|
||||||
|
}
|
||||||
|
} else if (typeof item == "undefined") {
|
||||||
|
return "undefined"
|
||||||
|
}
|
||||||
|
return item.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
let parseStdout = stdout => stdout.map(x => parseItem(x)).join("\n")
|
||||||
|
|
||||||
|
// 屏蔽危险函数
|
||||||
|
window.getuToolsLite = () => {
|
||||||
|
var utoolsLite = Object.assign({}, utools)
|
||||||
|
if (utools.isDev()) return utoolsLite
|
||||||
|
// 数据库相关接口
|
||||||
|
delete utoolsLite.db
|
||||||
|
delete utoolsLite.dbStorage
|
||||||
|
delete utoolsLite.removeFeature
|
||||||
|
delete utoolsLite.setFeature
|
||||||
|
delete utoolsLite.onDbPull
|
||||||
|
// 支付相关接口
|
||||||
|
delete utoolsLite.fetchUserServerTemporaryToken
|
||||||
|
delete utoolsLite.getUserServerTemporaryToken
|
||||||
|
delete utoolsLite.openPayment
|
||||||
|
delete utoolsLite.fetchUserPayments
|
||||||
|
return utoolsLite
|
||||||
|
}
|
||||||
|
|
||||||
|
let getSandboxFuns = () => {
|
||||||
|
var sandbox = {
|
||||||
|
utools: getuToolsLite(),
|
||||||
|
quickcommand: quickcommand,
|
||||||
|
electron: electron,
|
||||||
|
axios: axios,
|
||||||
|
Audio: Audio,
|
||||||
|
fetch: fetch
|
||||||
|
}
|
||||||
|
shortCodes.forEach(f => {
|
||||||
|
sandbox[f.name] = f
|
||||||
|
})
|
||||||
|
return sandbox
|
||||||
|
}
|
||||||
|
|
||||||
|
let createNodeVM = (userVars) => {
|
||||||
|
var sandbox = getSandboxFuns()
|
||||||
|
Object.assign(userVars, sandbox)
|
||||||
|
const vm = new NodeVM({
|
||||||
|
require: {
|
||||||
|
external: true,
|
||||||
|
builtin: ["*"],
|
||||||
|
},
|
||||||
|
console: 'redirect',
|
||||||
|
env: process.env,
|
||||||
|
sandbox: userVars,
|
||||||
|
});
|
||||||
|
return vm
|
||||||
|
}
|
||||||
|
|
||||||
|
window.VmEval = (cmd, sandbox = {}) => new VM({
|
||||||
|
sandbox: sandbox
|
||||||
|
}).run(cmd)
|
||||||
|
|
||||||
|
let isWatchingError = false
|
||||||
|
// The vm module of Node.js is deprecated in the renderer process and will be removed
|
||||||
|
window.runCodeInVm = (cmd, callback, userVars = {}) => {
|
||||||
|
const vm = createNodeVM(userVars)
|
||||||
|
//重定向 console
|
||||||
|
vm.on('console.log', (...stdout) => {
|
||||||
|
console.log(stdout);
|
||||||
|
callback(parseStdout(stdout), null)
|
||||||
|
});
|
||||||
|
|
||||||
|
vm.on('console.error', stderr => {
|
||||||
|
callback(null, stderr.toString())
|
||||||
|
});
|
||||||
|
|
||||||
|
let liteErr = e => {
|
||||||
|
if (!e) return
|
||||||
|
return e.stack.replace(/([ ] +at.+)|(.+\.js:\d+)/g, '').trim()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 错误处理
|
||||||
|
try {
|
||||||
|
vm.run(cmd, path.join(__dirname, 'preload.js'));
|
||||||
|
} catch (e) {
|
||||||
|
console.log('Error: ', e)
|
||||||
|
callback(null, liteErr(e))
|
||||||
|
}
|
||||||
|
|
||||||
|
let cbUnhandledError = e => {
|
||||||
|
removeAllListener()
|
||||||
|
console.log('UnhandledError: ', e)
|
||||||
|
callback(null, liteErr(e.error))
|
||||||
|
}
|
||||||
|
|
||||||
|
let cbUnhandledRejection = e => {
|
||||||
|
removeAllListener()
|
||||||
|
console.log('UnhandledRejection: ', e)
|
||||||
|
callback(null, liteErr(e.reason))
|
||||||
|
}
|
||||||
|
|
||||||
|
let removeAllListener = () => {
|
||||||
|
window.removeEventListener('error', cbUnhandledError)
|
||||||
|
window.removeEventListener('unhandledrejection', cbUnhandledRejection)
|
||||||
|
isWatchingError = false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isWatchingError) {
|
||||||
|
window.addEventListener('error', cbUnhandledError)
|
||||||
|
window.addEventListener('unhandledrejection', cbUnhandledRejection)
|
||||||
|
isWatchingError = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
window.runCodeFile = (cmd, option, terminal, callback) => {
|
window.runCodeFile = (cmd, option, terminal, callback) => {
|
||||||
var bin = option.bin,
|
var bin = option.bin,
|
||||||
argv = option.argv,
|
argv = option.argv,
|
||||||
@ -610,3 +604,60 @@ window.runCodeFile = (cmd, option, terminal, callback) => {
|
|||||||
// callback(stdout, stderr)
|
// callback(stdout, stderr)
|
||||||
// })
|
// })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let httpServer
|
||||||
|
window.quickcommandHttpServer = () => {
|
||||||
|
let run = (cmd = '', port = 33442) => {
|
||||||
|
let httpResponse = (res, code, result) => {
|
||||||
|
// 因为无法判断 vm2 是否执行完毕,故只收受一次 console.log,接收后就关闭连接
|
||||||
|
if (res.finished) return
|
||||||
|
res.writeHead(code, {
|
||||||
|
'Content-Type': 'text/html'
|
||||||
|
});
|
||||||
|
if (result) res.write(result);
|
||||||
|
res.end();
|
||||||
|
}
|
||||||
|
let runUserCode = (res, cmd, userVars) => {
|
||||||
|
// 不需要返回输出的提前关闭连接
|
||||||
|
if (!cmd.includes('console.log')) httpResponse(res, 200)
|
||||||
|
window.runCodeInVm(cmd, (stdout, stderr) => {
|
||||||
|
// 错误返回 500
|
||||||
|
if (stderr) return httpResponse(res, 500, stderr)
|
||||||
|
return httpResponse(res, 200, stdout)
|
||||||
|
}, userVars)
|
||||||
|
}
|
||||||
|
httpServer = http.createServer()
|
||||||
|
httpServer.on('request', (req, res) => {
|
||||||
|
if (req.method === 'GET') {
|
||||||
|
let parsedParams = _.cloneDeep(url.parse(req.url, true).query)
|
||||||
|
runUserCode(res, cmd, parsedParams)
|
||||||
|
} else if (req.method === 'POST') {
|
||||||
|
let data = []
|
||||||
|
req.on('data', (chunk) => {
|
||||||
|
data.push(chunk)
|
||||||
|
})
|
||||||
|
req.on('end', () => {
|
||||||
|
let parsedParams
|
||||||
|
let params = data.join("").toString()
|
||||||
|
// 先尝试作为 json 解析
|
||||||
|
try {
|
||||||
|
parsedParams = JSON.parse(params)
|
||||||
|
} catch (error) {
|
||||||
|
parsedParams = _.cloneDeep(url.parse('?' + params, true).query)
|
||||||
|
}
|
||||||
|
runUserCode(res, cmd, parsedParams)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
httpResponse(res, 405)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
httpServer.listen(port, 'localhost');
|
||||||
|
}
|
||||||
|
let stop = () => {
|
||||||
|
httpServer.close()
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
run,
|
||||||
|
stop
|
||||||
|
}
|
||||||
|
}
|
10
src/App.vue
10
src/App.vue
@ -33,6 +33,16 @@ export default defineComponent({
|
|||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// 如果配置了后台服务则开启监听
|
||||||
|
if (this.$profile.quickFeatures.apiServer.serverStatus) {
|
||||||
|
window
|
||||||
|
.quickcommandHttpServer()
|
||||||
|
.run(
|
||||||
|
this.$profile.quickFeatures.apiServer.cmd,
|
||||||
|
this.$profile.quickFeatures.apiServer.port
|
||||||
|
);
|
||||||
|
console.log("Server Start...");
|
||||||
|
}
|
||||||
// 默认主题色
|
// 默认主题色
|
||||||
this.setCssVar("primary", this.$profile.primaryColor);
|
this.setCssVar("primary", this.$profile.primaryColor);
|
||||||
// 进入插件
|
// 进入插件
|
||||||
|
BIN
src/assets/feature/api.png
Normal file
BIN
src/assets/feature/api.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.5 KiB |
BIN
src/assets/feature/crontab.png
Normal file
BIN
src/assets/feature/crontab.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.7 KiB |
@ -10,7 +10,7 @@ import Cron from "croner"
|
|||||||
let userProfile = UTOOLS.getDB(
|
let userProfile = UTOOLS.getDB(
|
||||||
UTOOLS.DBPRE.CFG + "preferences"
|
UTOOLS.DBPRE.CFG + "preferences"
|
||||||
);
|
);
|
||||||
Object.assign(defaultProfile, userProfile)
|
_.merge(defaultProfile, _.cloneDeep(userProfile))
|
||||||
|
|
||||||
// "async" is optional;
|
// "async" is optional;
|
||||||
// more info on params: https://v2.quasar.dev/quasar-cli/boot-files
|
// more info on params: https://v2.quasar.dev/quasar-cli/boot-files
|
||||||
|
@ -143,6 +143,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<MonacoEditor
|
<MonacoEditor
|
||||||
class="absolute-bottom"
|
class="absolute-bottom"
|
||||||
|
:placeholder="true"
|
||||||
ref="editor"
|
ref="editor"
|
||||||
@typing="(val) => (quickcommandInfo.cmd = val)"
|
@typing="(val) => (quickcommandInfo.cmd = val)"
|
||||||
:style="{
|
:style="{
|
||||||
|
@ -12,6 +12,176 @@
|
|||||||
/>
|
/>
|
||||||
<!-- 菜单 -->
|
<!-- 菜单 -->
|
||||||
<q-list>
|
<q-list>
|
||||||
|
<!-- 实用功能 -->
|
||||||
|
<q-item clickable>
|
||||||
|
<q-item-section side>
|
||||||
|
<q-icon name="keyboard_arrow_left" />
|
||||||
|
</q-item-section>
|
||||||
|
<q-item-section>实用功能</q-item-section>
|
||||||
|
<q-menu anchor="top end" self="top start">
|
||||||
|
<q-list>
|
||||||
|
<q-item>
|
||||||
|
<q-item-section side>
|
||||||
|
<q-icon name="folder_special" />
|
||||||
|
</q-item-section>
|
||||||
|
<q-input
|
||||||
|
dense
|
||||||
|
prefix="快速收藏文件至"
|
||||||
|
suffix="标签"
|
||||||
|
outlined
|
||||||
|
input-class="text-center"
|
||||||
|
style="width: 280px"
|
||||||
|
autofocus
|
||||||
|
v-model="quickFeatures.favFile.tag"
|
||||||
|
type="text"
|
||||||
|
>
|
||||||
|
<template v-slot:append>
|
||||||
|
<q-toggle
|
||||||
|
@click="toggleFeature('favFile')"
|
||||||
|
v-model="quickFeatures.favFile.enable"
|
||||||
|
checked-icon="check"
|
||||||
|
color="primary"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<q-tooltip
|
||||||
|
>启用后,选中文件可以通过超级面板快速将文件收藏到「{{
|
||||||
|
quickFeatures.favFile.tag
|
||||||
|
}}」标签
|
||||||
|
</q-tooltip>
|
||||||
|
</q-input>
|
||||||
|
</q-item>
|
||||||
|
<q-item>
|
||||||
|
<q-item-section side>
|
||||||
|
<q-icon name="bookmarks" />
|
||||||
|
</q-item-section>
|
||||||
|
<q-input
|
||||||
|
dense
|
||||||
|
prefix="快速收藏网址至"
|
||||||
|
suffix="标签"
|
||||||
|
outlined
|
||||||
|
input-class="text-center"
|
||||||
|
style="width: 280px"
|
||||||
|
v-model="quickFeatures.favUrl.tag"
|
||||||
|
type="text"
|
||||||
|
>
|
||||||
|
<template v-slot:append>
|
||||||
|
<q-toggle
|
||||||
|
@click="toggleFeature('favUrl')"
|
||||||
|
v-model="quickFeatures.favUrl.enable"
|
||||||
|
checked-icon="check"
|
||||||
|
color="primary"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<q-tooltip
|
||||||
|
>启用后,在浏览器界面可以通过超级面板快速将网址收藏到「{{
|
||||||
|
quickFeatures.favUrl.tag
|
||||||
|
}}」标签
|
||||||
|
</q-tooltip>
|
||||||
|
</q-input>
|
||||||
|
</q-item>
|
||||||
|
<q-item>
|
||||||
|
<q-item-section side>
|
||||||
|
<q-icon name="drive_file_rename_outline" />
|
||||||
|
</q-item-section>
|
||||||
|
<q-input
|
||||||
|
dense
|
||||||
|
prefix="新建插件别名至"
|
||||||
|
suffix="标签"
|
||||||
|
outlined
|
||||||
|
input-class="text-center"
|
||||||
|
style="width: 280px"
|
||||||
|
autofocus
|
||||||
|
v-model="quickFeatures.pluNickName.tag"
|
||||||
|
type="text"
|
||||||
|
>
|
||||||
|
<template v-slot:append>
|
||||||
|
<q-toggle
|
||||||
|
@click="toggleFeature('pluNickName')"
|
||||||
|
v-model="quickFeatures.pluNickName.enable"
|
||||||
|
checked-icon="check"
|
||||||
|
color="primary"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<q-tooltip
|
||||||
|
>启用后,在主输入框输入「插件别名」可以快速设置插件别名<br />
|
||||||
|
并将所有设置的别名保存至「{{
|
||||||
|
quickFeatures.pluNickName.tag
|
||||||
|
}}」标签
|
||||||
|
</q-tooltip>
|
||||||
|
</q-input>
|
||||||
|
</q-item>
|
||||||
|
<q-item>
|
||||||
|
<q-item-section side>
|
||||||
|
<q-icon name="timer" />
|
||||||
|
</q-item-section>
|
||||||
|
<q-input
|
||||||
|
dense
|
||||||
|
prefix="新建计划任务至"
|
||||||
|
suffix="标签"
|
||||||
|
outlined
|
||||||
|
input-class="text-center"
|
||||||
|
style="width: 280px"
|
||||||
|
v-model="quickFeatures.crontab.tag"
|
||||||
|
type="text"
|
||||||
|
>
|
||||||
|
<template v-slot:append>
|
||||||
|
<q-toggle
|
||||||
|
@click="toggleFeature('crontab')"
|
||||||
|
v-model="quickFeatures.crontab.enable"
|
||||||
|
checked-icon="check"
|
||||||
|
color="primary"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<q-tooltip
|
||||||
|
>启用后,在主输入框输入「计划任务」可以配置计划任务,定制执行指定或新建的快捷命令<br />
|
||||||
|
如果是直接新建,则新建的任务会保存在「{{
|
||||||
|
quickFeatures.crontab.tag
|
||||||
|
}}」标签<br />
|
||||||
|
注意此功能并没有使用系统自带的计划任务,需要配置插件跟随
|
||||||
|
utools 启动和保留后台<br />
|
||||||
|
本功能比系统自带的更为强大,因为你可以在计划任务中任意使用
|
||||||
|
utools 或 quickcommand 的 api
|
||||||
|
</q-tooltip>
|
||||||
|
</q-input>
|
||||||
|
</q-item>
|
||||||
|
<q-item>
|
||||||
|
<q-item-section side>
|
||||||
|
<q-icon name="api" />
|
||||||
|
</q-item-section>
|
||||||
|
<q-input
|
||||||
|
dense
|
||||||
|
prefix="开启快捷命令服务"
|
||||||
|
suffix="端口"
|
||||||
|
outlined
|
||||||
|
v-model="quickFeatures.apiServer.port"
|
||||||
|
input-class="text-center"
|
||||||
|
style="width: 280px"
|
||||||
|
type="text"
|
||||||
|
>
|
||||||
|
<template v-slot:append>
|
||||||
|
<q-toggle
|
||||||
|
@click="toggleFeature('apiServer')"
|
||||||
|
v-model="quickFeatures.apiServer.enable"
|
||||||
|
checked-icon="check"
|
||||||
|
color="primary"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<q-tooltip
|
||||||
|
>启用后,在主输入框输入「快捷命令服务」可以进入配置一个后台服务<br />
|
||||||
|
通过本地监听{{
|
||||||
|
quickFeatures.apiServer.port
|
||||||
|
}}端口的形式,接收用户传送过来的参数,然后根据参数执行不同的操作
|
||||||
|
<br />
|
||||||
|
本功能的意义在于,将 utools
|
||||||
|
的接口暴露出来,可以通过命令行等外部途径 <br />
|
||||||
|
直接启用 ubrowser 或者直接redirect 到相应的插件<br />
|
||||||
|
需要配置插件跟随 utools 启动和保留后台
|
||||||
|
</q-tooltip>
|
||||||
|
</q-input>
|
||||||
|
</q-item>
|
||||||
|
</q-list>
|
||||||
|
</q-menu>
|
||||||
|
</q-item>
|
||||||
<!-- 导入 -->
|
<!-- 导入 -->
|
||||||
<q-item clickable>
|
<q-item clickable>
|
||||||
<q-item-section side>
|
<q-item-section side>
|
||||||
@ -77,108 +247,6 @@
|
|||||||
</q-list>
|
</q-list>
|
||||||
</q-menu>
|
</q-menu>
|
||||||
</q-item>
|
</q-item>
|
||||||
<!-- 实用功能 -->
|
|
||||||
<q-item clickable>
|
|
||||||
<q-item-section side>
|
|
||||||
<q-icon name="keyboard_arrow_left" />
|
|
||||||
</q-item-section>
|
|
||||||
<q-item-section>实用功能</q-item-section>
|
|
||||||
<q-menu anchor="top end" self="top start">
|
|
||||||
<q-list>
|
|
||||||
<q-item>
|
|
||||||
<q-item-section side>
|
|
||||||
<q-icon name="folder_special" />
|
|
||||||
</q-item-section>
|
|
||||||
<q-input
|
|
||||||
dense
|
|
||||||
prefix="快速收藏文件至"
|
|
||||||
suffix="标签"
|
|
||||||
outlined
|
|
||||||
input-class="text-center"
|
|
||||||
style="width: 280px"
|
|
||||||
autofocus
|
|
||||||
v-model="quickFeatures.favFile.tag"
|
|
||||||
type="text"
|
|
||||||
>
|
|
||||||
<template v-slot:append>
|
|
||||||
<q-toggle
|
|
||||||
@click="toggleFeature('favFile')"
|
|
||||||
v-model="quickFeatures.favFile.enable"
|
|
||||||
checked-icon="check"
|
|
||||||
color="primary"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
<q-tooltip
|
|
||||||
>启用后,选中文件可以通过超级面板快速将文件收藏到「{{
|
|
||||||
quickFeatures.favFile.tag
|
|
||||||
}}」标签
|
|
||||||
</q-tooltip>
|
|
||||||
</q-input>
|
|
||||||
</q-item>
|
|
||||||
<q-item>
|
|
||||||
<q-item-section side>
|
|
||||||
<q-icon name="bookmarks" />
|
|
||||||
</q-item-section>
|
|
||||||
<q-input
|
|
||||||
dense
|
|
||||||
prefix="快速收藏网址至"
|
|
||||||
suffix="标签"
|
|
||||||
outlined
|
|
||||||
input-class="text-center"
|
|
||||||
style="width: 280px"
|
|
||||||
autofocus
|
|
||||||
v-model="quickFeatures.favUrl.tag"
|
|
||||||
type="text"
|
|
||||||
>
|
|
||||||
<template v-slot:append>
|
|
||||||
<q-toggle
|
|
||||||
@click="toggleFeature('favUrl')"
|
|
||||||
v-model="quickFeatures.favUrl.enable"
|
|
||||||
checked-icon="check"
|
|
||||||
color="primary"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
<q-tooltip
|
|
||||||
>启用后,在浏览器界面可以通过超级面板快速将网址收藏到「{{
|
|
||||||
quickFeatures.favUrl.tag
|
|
||||||
}}」标签
|
|
||||||
</q-tooltip>
|
|
||||||
</q-input>
|
|
||||||
</q-item>
|
|
||||||
<q-item>
|
|
||||||
<q-item-section side>
|
|
||||||
<q-icon name="drive_file_rename_outline" />
|
|
||||||
</q-item-section>
|
|
||||||
<q-input
|
|
||||||
dense
|
|
||||||
prefix="新建插件别名至"
|
|
||||||
suffix="标签"
|
|
||||||
outlined
|
|
||||||
input-class="text-center"
|
|
||||||
style="width: 280px"
|
|
||||||
autofocus
|
|
||||||
v-model="quickFeatures.pluNickName.tag"
|
|
||||||
type="text"
|
|
||||||
>
|
|
||||||
<template v-slot:append>
|
|
||||||
<q-toggle
|
|
||||||
@click="toggleFeature('pluNickName')"
|
|
||||||
v-model="quickFeatures.pluNickName.enable"
|
|
||||||
checked-icon="check"
|
|
||||||
color="primary"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
<q-tooltip
|
|
||||||
>启用后,在主输入框输入「插件别名」可以快速设置插件别名<br />
|
|
||||||
并将所有设置的别名保存至「{{
|
|
||||||
quickFeatures.pluNickName.tag
|
|
||||||
}}」标签
|
|
||||||
</q-tooltip>
|
|
||||||
</q-input>
|
|
||||||
</q-item>
|
|
||||||
</q-list>
|
|
||||||
</q-menu>
|
|
||||||
</q-item>
|
|
||||||
<!-- 选项 -->
|
<!-- 选项 -->
|
||||||
<q-item clickable>
|
<q-item clickable>
|
||||||
<q-item-section side>
|
<q-item-section side>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div id="monacoEditor" style="width: 100%; height: 100%"></div>
|
<div id="monacoEditor" style="width: 100%; height: 100%"></div>
|
||||||
<div class="absolute-center flex" v-show="!value">
|
<div class="absolute-center flex" v-show="!value && placeholder">
|
||||||
<div class="placeholder text-center q-gutter-md">
|
<div class="placeholder text-center q-gutter-md">
|
||||||
<div v-for="shortCut in shortCuts" :key="shortCut">
|
<div v-for="shortCut in shortCuts" :key="shortCut">
|
||||||
<span>{{ shortCut[0] }}</span
|
<span>{{ shortCut[0] }}</span
|
||||||
@ -56,6 +56,9 @@ export default {
|
|||||||
return this.$q.dark.isActive;
|
return this.$q.dark.isActive;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
props: {
|
||||||
|
placeholder: Boolean,
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
initEditor() {
|
initEditor() {
|
||||||
let monacoEditorPreferences = {
|
let monacoEditorPreferences = {
|
||||||
|
127
src/components/quickFeatures/ApiServer.vue
Normal file
127
src/components/quickFeatures/ApiServer.vue
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<MonacoEditor
|
||||||
|
:placeholder="false"
|
||||||
|
class="absolute-top"
|
||||||
|
ref="editor"
|
||||||
|
@typing="
|
||||||
|
(val) => {
|
||||||
|
$profile.quickFeatures.apiServer.cmd = val;
|
||||||
|
serverStatus && (needRestart = true);
|
||||||
|
}
|
||||||
|
"
|
||||||
|
:style="{
|
||||||
|
bottom: bottomHeight + 'px',
|
||||||
|
}"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="
|
||||||
|
absolute-bottom
|
||||||
|
flex
|
||||||
|
items-center
|
||||||
|
justify-between
|
||||||
|
q-px-md
|
||||||
|
shadow-10
|
||||||
|
"
|
||||||
|
:style="{
|
||||||
|
height: bottomHeight + 'px',
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<div class="q-gutter-xs">
|
||||||
|
<q-badge color="primary" dense square>POST</q-badge
|
||||||
|
><q-badge color="primary" dense square>GET</q-badge>
|
||||||
|
<span>
|
||||||
|
http://127.0.0.1:{{ $profile.quickFeatures.apiServer.port }}
|
||||||
|
</span>
|
||||||
|
<span>的参数,均会作为本脚本里的变量 </span>
|
||||||
|
</div>
|
||||||
|
<q-btn-group unelevated>
|
||||||
|
<q-btn flat color="primary" icon="help" />
|
||||||
|
<q-separator inset vertical />
|
||||||
|
<q-btn
|
||||||
|
flat
|
||||||
|
color="negative"
|
||||||
|
icon="stop"
|
||||||
|
v-if="serverStatus && !needRestart"
|
||||||
|
@click="stopServer"
|
||||||
|
label="停止服务"
|
||||||
|
/>
|
||||||
|
<q-btn
|
||||||
|
flat
|
||||||
|
color="warning"
|
||||||
|
icon="restart_alt"
|
||||||
|
v-else-if="serverStatus && needRestart"
|
||||||
|
@click="restartServer"
|
||||||
|
label="重启服务"
|
||||||
|
/>
|
||||||
|
<q-btn
|
||||||
|
flat
|
||||||
|
color="primary"
|
||||||
|
icon="play_arrow"
|
||||||
|
v-else
|
||||||
|
label="开启服务"
|
||||||
|
@click="enableServer"
|
||||||
|
>
|
||||||
|
</q-btn>
|
||||||
|
</q-btn-group>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import MonacoEditor from "components/MonacoEditor";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: { MonacoEditor },
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
bottomHeight: 40,
|
||||||
|
serverStatus: this.$profile.quickFeatures.apiServer.serverStatus,
|
||||||
|
needRestart: null,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.$refs.editor.setEditorValue(this.$profile.quickFeatures.apiServer.cmd);
|
||||||
|
this.$refs.editor.setEditorLanguage("javascript");
|
||||||
|
this.needRestart = false;
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
enableServer() {
|
||||||
|
quickcommand
|
||||||
|
.showConfirmBox(
|
||||||
|
"请注意,该接口未做任何权限鉴定,千万不要试图将本端口转发出去,否则无异于将本机的 shell 权限暴露在公网!",
|
||||||
|
"FBI WARNING"
|
||||||
|
)
|
||||||
|
.then((ok) => {
|
||||||
|
if (!ok) return;
|
||||||
|
this.$profile.quickFeatures.apiServer.serverStatus =
|
||||||
|
this.serverStatus = true;
|
||||||
|
window
|
||||||
|
.quickcommandHttpServer()
|
||||||
|
.run(
|
||||||
|
this.$profile.quickFeatures.apiServer.cmd,
|
||||||
|
this.$profile.quickFeatures.apiServer.port
|
||||||
|
);
|
||||||
|
quickcommand.showMessageBox("启动服务成功!");
|
||||||
|
});
|
||||||
|
},
|
||||||
|
stopServer() {
|
||||||
|
window.quickcommandHttpServer().stop();
|
||||||
|
this.$profile.quickFeatures.apiServer.serverStatus =
|
||||||
|
this.serverStatus = false;
|
||||||
|
quickcommand.showMessageBox("关闭服务成功!");
|
||||||
|
},
|
||||||
|
restartServer() {
|
||||||
|
window.quickcommandHttpServer().stop();
|
||||||
|
window
|
||||||
|
.quickcommandHttpServer()
|
||||||
|
.run(
|
||||||
|
this.$profile.quickFeatures.apiServer.cmd,
|
||||||
|
this.$profile.quickFeatures.apiServer.port
|
||||||
|
);
|
||||||
|
this.needRestart = false;
|
||||||
|
quickcommand.showMessageBox("重启服务成功!");
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
55
src/components/quickFeatures/CrontabCmd.vue
Normal file
55
src/components/quickFeatures/CrontabCmd.vue
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
<template>
|
||||||
|
<q-card>
|
||||||
|
<q-card-section class="text-h5 text-center">定时执行</q-card-section>
|
||||||
|
<q-card-section class="q-gutter-md">
|
||||||
|
<q-input
|
||||||
|
v-model="crontab"
|
||||||
|
type="text"
|
||||||
|
standout="bg-primary text-white"
|
||||||
|
label="请输入 Crontab 表达式"
|
||||||
|
mask="# # # # # #"
|
||||||
|
>
|
||||||
|
<template v-slot:append>
|
||||||
|
<q-btn flat icon="help"></q-btn>
|
||||||
|
</template>
|
||||||
|
</q-input>
|
||||||
|
<pre class="explain">
|
||||||
|
{{ explain }}
|
||||||
|
</pre>
|
||||||
|
<div>当前状态:</div>
|
||||||
|
<div>下次执行时间:</div>
|
||||||
|
</q-card-section>
|
||||||
|
<q-card-actions align="right">
|
||||||
|
<q-btn flat color="negative" v-close-popup>禁用</q-btn>
|
||||||
|
<q-btn flat color="primary" v-close-popup>启用</q-btn>
|
||||||
|
</q-card-actions>
|
||||||
|
</q-card>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const explain = `
|
||||||
|
┌──────────────── (可选) 秒 (0 - 59)
|
||||||
|
│ ┌────────────── 分钟 (0 - 59)
|
||||||
|
│ │ ┌──────────── 小时 (0 - 23)
|
||||||
|
│ │ │ ┌────────── 日 (1 - 31)
|
||||||
|
│ │ │ │ ┌──────── 月 (1 - 12, 一月-十二月)
|
||||||
|
│ │ │ │ │ ┌────── 星期 (0 - 6, 周日-周六)
|
||||||
|
* * * * * *`;
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
crontab: "",
|
||||||
|
explain: explain,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.explain {
|
||||||
|
background: #ffffff18;
|
||||||
|
padding: 0 10px;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
</style>
|
40
src/components/quickFeatures/FavFile.vue
Normal file
40
src/components/quickFeatures/FavFile.vue
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
mounted() {
|
||||||
|
utools.setExpendHeight(0);
|
||||||
|
quickcommand.enterData.payload.forEach((file) => {
|
||||||
|
let uid = this.getUid();
|
||||||
|
let fileInfo = window.getFileInfo({
|
||||||
|
type: "file",
|
||||||
|
argvs: file.path,
|
||||||
|
readfile: false,
|
||||||
|
});
|
||||||
|
let fileName = fileInfo.name.replace(fileInfo.ext, "");
|
||||||
|
let command = {
|
||||||
|
features: {
|
||||||
|
cmds: [fileName],
|
||||||
|
explain: `打开${fileName}`,
|
||||||
|
icon: utools.getFileIcon(file.path),
|
||||||
|
platform: [window.processPlatform],
|
||||||
|
code: `key_${uid}`,
|
||||||
|
},
|
||||||
|
program: "quickcommand",
|
||||||
|
cmd: `open(\"${file.path.replace(/\\/g, "\\\\")}\")`,
|
||||||
|
output: "ignore",
|
||||||
|
tags: [this.$profile.quickFeatures.favFile.tag],
|
||||||
|
};
|
||||||
|
this.importCommand(command);
|
||||||
|
});
|
||||||
|
utools.showNotification("操作成功!");
|
||||||
|
utools.outPlugin();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getUid() {
|
||||||
|
return this.$parent.getUid();
|
||||||
|
},
|
||||||
|
importCommand(command) {
|
||||||
|
this.$parent.importCommand(command);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
76
src/components/quickFeatures/FavUrl.vue
Normal file
76
src/components/quickFeatures/FavUrl.vue
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
cmdCtrlKey: window.processPlatform === "darwin" ? "command" : "control",
|
||||||
|
};
|
||||||
|
},
|
||||||
|
async mounted() {
|
||||||
|
utools.setExpendHeight(0);
|
||||||
|
utools.hideMainWindow();
|
||||||
|
// getCurrentBrowserUrl 似乎失效了
|
||||||
|
// let url = utools.getCurrentBrowserUrl();
|
||||||
|
utools.simulateKeyboardTap("l", this.cmdCtrlKey);
|
||||||
|
await this.wait(50);
|
||||||
|
utools.simulateKeyboardTap("c", this.cmdCtrlKey);
|
||||||
|
await this.wait(50);
|
||||||
|
let url = window.clipboardReadText();
|
||||||
|
if (!/^http/.test(url)) {
|
||||||
|
utools.showMainWindow();
|
||||||
|
utools.setExpendHeight(550);
|
||||||
|
let choise = await quickcommand.showButtonBox(
|
||||||
|
["http", "https"],
|
||||||
|
"当前浏览器网址显示不完整,请问访问的页面是哪一种?"
|
||||||
|
);
|
||||||
|
url = choise.text + "://" + url;
|
||||||
|
}
|
||||||
|
let title = quickcommand.enterData.payload.title
|
||||||
|
.replace(/和另外 \d+ 个页面.*/, "")
|
||||||
|
.replace(/[-|—] .*?[Edge|Firefox|Chrome].*/, "")
|
||||||
|
.trim();
|
||||||
|
// let req = await axios(url)
|
||||||
|
// let title = quickcommand.htmlParse(req.data).querySelector('title').innerText
|
||||||
|
let base = /(http(s){0,1}:\/\/.*?(:\d+){0,1})(\/|$).*/.exec(url)[1];
|
||||||
|
let iconUrl = base + "/favicon.ico";
|
||||||
|
let iconPath = window.joinPath(
|
||||||
|
utools.getPath("temp"),
|
||||||
|
"quickcommandfavicon.ico"
|
||||||
|
);
|
||||||
|
let uid = this.getUid();
|
||||||
|
let command = {
|
||||||
|
features: {
|
||||||
|
explain: `访问${title}`,
|
||||||
|
cmds: [title],
|
||||||
|
platform: ["linux", "win32", "darwin"],
|
||||||
|
code: `key_${uid}`,
|
||||||
|
},
|
||||||
|
program: "quickcommand",
|
||||||
|
cmd: `visit(\"${url}\")\n`,
|
||||||
|
output: "ignore",
|
||||||
|
tags: [this.$profile.quickFeatures.favUrl.tag],
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
let res = await quickcommand.downloadFile(iconUrl, iconPath);
|
||||||
|
if (res) command.features.icon = iconPath;
|
||||||
|
} catch (e) {}
|
||||||
|
this.importCommand(command);
|
||||||
|
utools.showNotification("操作成功!");
|
||||||
|
utools.outPlugin();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
wait(ms) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
resolve();
|
||||||
|
}, ms);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
getUid() {
|
||||||
|
return this.$parent.getUid();
|
||||||
|
},
|
||||||
|
importCommand(command) {
|
||||||
|
this.$parent.importCommand(command);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
144
src/components/quickFeatures/PluginNickName.vue
Normal file
144
src/components/quickFeatures/PluginNickName.vue
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
<template>
|
||||||
|
<div class="flex justify-center content-center" style="height: 500px">
|
||||||
|
<div class="q-gutter-lg q-pa-lg" style="width: 600px">
|
||||||
|
<div class="text-center text-h2 q-ma-none">插件别名设置</div>
|
||||||
|
<q-select
|
||||||
|
outlined
|
||||||
|
transition-show="jump-down"
|
||||||
|
transition-hide="jump-up"
|
||||||
|
v-model="plugin"
|
||||||
|
:options="plugins"
|
||||||
|
type="text"
|
||||||
|
class="full-width"
|
||||||
|
:display-value="plugin.pluginName"
|
||||||
|
@update:model-value="feature = features[0]"
|
||||||
|
label="请选择插件"
|
||||||
|
>
|
||||||
|
<template v-slot:prepend>
|
||||||
|
<q-icon name="extension" />
|
||||||
|
</template>
|
||||||
|
<template v-slot:option="scope">
|
||||||
|
<q-item v-bind="scope.itemProps">
|
||||||
|
<q-item-section avatar>
|
||||||
|
<q-img :src="`file:///${scope.opt.logoPath}`" />
|
||||||
|
</q-item-section>
|
||||||
|
<q-item-section>
|
||||||
|
<q-item-label v-html="scope.opt.pluginName" />
|
||||||
|
<q-item-label caption>{{ scope.opt.description }}</q-item-label>
|
||||||
|
</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
</template>
|
||||||
|
</q-select>
|
||||||
|
<q-select
|
||||||
|
outlined
|
||||||
|
transition-show="jump-down"
|
||||||
|
transition-hide="jump-up"
|
||||||
|
v-model="feature"
|
||||||
|
:options="features"
|
||||||
|
type="text"
|
||||||
|
:display-value="feature.cmd || ''"
|
||||||
|
class="full-width"
|
||||||
|
label="请选择功能关键字"
|
||||||
|
>
|
||||||
|
<template v-slot:prepend>
|
||||||
|
<q-icon name="font_download" />
|
||||||
|
</template>
|
||||||
|
<template v-slot:option="scope">
|
||||||
|
<q-item v-bind="scope.itemProps">
|
||||||
|
<q-item-section avatar>
|
||||||
|
<q-img :src="`file:///${plugin.logoPath}`" />
|
||||||
|
</q-item-section>
|
||||||
|
<q-item-section>
|
||||||
|
<q-item-label v-html="scope.opt.cmd" />
|
||||||
|
<q-item-label caption>{{ scope.opt.explain }}</q-item-label>
|
||||||
|
</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
</template>
|
||||||
|
</q-select>
|
||||||
|
<q-select
|
||||||
|
class="full-width"
|
||||||
|
max-values="3"
|
||||||
|
type="text"
|
||||||
|
placeholder="键入后回车"
|
||||||
|
use-input
|
||||||
|
hide-dropdown-icon
|
||||||
|
use-chips
|
||||||
|
multiple
|
||||||
|
new-value-mode="add-unique"
|
||||||
|
input-debounce="0"
|
||||||
|
outlined
|
||||||
|
v-model="nickName"
|
||||||
|
label="要设置的别名"
|
||||||
|
>
|
||||||
|
<template v-slot:prepend>
|
||||||
|
<q-icon name="drive_file_rename_outline" />
|
||||||
|
</template>
|
||||||
|
</q-select>
|
||||||
|
<q-btn
|
||||||
|
class="full-width"
|
||||||
|
color="primary"
|
||||||
|
label="确定"
|
||||||
|
@click="addPluNickName()"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
plugins: [],
|
||||||
|
plugin: {},
|
||||||
|
feature: {},
|
||||||
|
nickName: [],
|
||||||
|
};
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.plugins = _.values(window.getUtoolsPlugins());
|
||||||
|
this.plugin = this.plugins[0];
|
||||||
|
this.feature = this.features[0];
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
features() {
|
||||||
|
return this.plugin?.features
|
||||||
|
?.map((x) => {
|
||||||
|
return {
|
||||||
|
explain: x.explain,
|
||||||
|
cmd: x.cmds.filter((y) => y.length)[0],
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.filter((x) => x.cmd);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
addPluNickName() {
|
||||||
|
if (!this.nickName.length)
|
||||||
|
return quickcommand.showMessageBox("请填写别名", "warning");
|
||||||
|
let uid = this.getUid();
|
||||||
|
let command = {
|
||||||
|
features: {
|
||||||
|
cmds: this.nickName,
|
||||||
|
explain: this.feature.explain,
|
||||||
|
icon: window.getBase64Ico(this.plugin.logoPath),
|
||||||
|
platform: this.plugin.platform || ["darwin", "win32", "linux"],
|
||||||
|
code: `key_${uid}`,
|
||||||
|
},
|
||||||
|
program: "quickcommand",
|
||||||
|
cmd: `utools.redirect("${this.feature.cmd}");utools.showMainWindow()`,
|
||||||
|
output: "ignore",
|
||||||
|
tags: [this.$profile.quickFeatures.pluNickName.tag],
|
||||||
|
};
|
||||||
|
this.importCommand(command);
|
||||||
|
this.nickName = [];
|
||||||
|
quickcommand.showMessageBox("添加成功!");
|
||||||
|
},
|
||||||
|
getUid() {
|
||||||
|
return this.$parent.getUid();
|
||||||
|
},
|
||||||
|
importCommand(command) {
|
||||||
|
this.$parent.importCommand(command);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
@ -17,5 +17,15 @@ export default {
|
|||||||
enable: false,
|
enable: false,
|
||||||
tag: "别名"
|
tag: "别名"
|
||||||
},
|
},
|
||||||
|
crontab: {
|
||||||
|
enable: false,
|
||||||
|
tag: "任务"
|
||||||
|
},
|
||||||
|
apiServer: {
|
||||||
|
enable: false,
|
||||||
|
port: 33442,
|
||||||
|
cmd: "",
|
||||||
|
serverStatus: false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -42,6 +42,20 @@ const quickFeatures = {
|
|||||||
cmds: ["插件别名"],
|
cmds: ["插件别名"],
|
||||||
icon: require("../../assets/feature/plugin.png"),
|
icon: require("../../assets/feature/plugin.png"),
|
||||||
platform: ["win32", "darwin", "linux"],
|
platform: ["win32", "darwin", "linux"],
|
||||||
|
},
|
||||||
|
crontab: {
|
||||||
|
code: "feature_crontab",
|
||||||
|
explain: "为快捷命令添加计划任务",
|
||||||
|
cmds: ["计划任务", "crontab"],
|
||||||
|
icon: require("../../assets/feature/crontab.png"),
|
||||||
|
platform: ["win32", "darwin", "linux"],
|
||||||
|
},
|
||||||
|
apiServer: {
|
||||||
|
code: "feature_apiServer",
|
||||||
|
explain: "配置快捷命令后台服务",
|
||||||
|
cmds: ["快捷命令服务配置", "quickcommandServer"],
|
||||||
|
icon: require("../../assets/feature/api.png"),
|
||||||
|
platform: ["win32", "darwin", "linux"],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,244 +1,29 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<component :is="currentComponent" :ref="currentComponent" />
|
||||||
class="flex justify-center content-center"
|
|
||||||
style="height: 500px"
|
|
||||||
v-show="showPluNickNameSetting"
|
|
||||||
>
|
|
||||||
<div class="q-gutter-lg q-pa-lg" style="width: 600px">
|
|
||||||
<div class="text-center text-h2 q-ma-none">插件别名设置</div>
|
|
||||||
<q-select
|
|
||||||
outlined
|
|
||||||
transition-show="jump-down"
|
|
||||||
transition-hide="jump-up"
|
|
||||||
v-model="plugin"
|
|
||||||
:options="plugins"
|
|
||||||
type="text"
|
|
||||||
class="full-width"
|
|
||||||
:display-value="plugin.pluginName"
|
|
||||||
@update:model-value="feature = features[0]"
|
|
||||||
label="请选择插件"
|
|
||||||
>
|
|
||||||
<template v-slot:prepend>
|
|
||||||
<q-icon name="extension" />
|
|
||||||
</template>
|
|
||||||
<template v-slot:option="scope">
|
|
||||||
<q-item v-bind="scope.itemProps">
|
|
||||||
<q-item-section avatar>
|
|
||||||
<q-img :src="`file:///${scope.opt.logoPath}`" />
|
|
||||||
</q-item-section>
|
|
||||||
<q-item-section>
|
|
||||||
<q-item-label v-html="scope.opt.pluginName" />
|
|
||||||
<q-item-label caption>{{ scope.opt.description }}</q-item-label>
|
|
||||||
</q-item-section>
|
|
||||||
</q-item>
|
|
||||||
</template>
|
|
||||||
</q-select>
|
|
||||||
<q-select
|
|
||||||
outlined
|
|
||||||
transition-show="jump-down"
|
|
||||||
transition-hide="jump-up"
|
|
||||||
v-model="feature"
|
|
||||||
:options="features"
|
|
||||||
type="text"
|
|
||||||
:display-value="feature.cmd || ''"
|
|
||||||
class="full-width"
|
|
||||||
label="请选择功能关键字"
|
|
||||||
>
|
|
||||||
<template v-slot:prepend>
|
|
||||||
<q-icon name="font_download" />
|
|
||||||
</template>
|
|
||||||
<template v-slot:option="scope">
|
|
||||||
<q-item v-bind="scope.itemProps">
|
|
||||||
<q-item-section avatar>
|
|
||||||
<q-img :src="`file:///${plugin.logoPath}`" />
|
|
||||||
</q-item-section>
|
|
||||||
<q-item-section>
|
|
||||||
<q-item-label v-html="scope.opt.cmd" />
|
|
||||||
<q-item-label caption>{{ scope.opt.explain }}</q-item-label>
|
|
||||||
</q-item-section>
|
|
||||||
</q-item>
|
|
||||||
</template>
|
|
||||||
</q-select>
|
|
||||||
<q-select
|
|
||||||
class="full-width"
|
|
||||||
max-values="3"
|
|
||||||
type="text"
|
|
||||||
placeholder="键入后回车"
|
|
||||||
use-input
|
|
||||||
hide-dropdown-icon
|
|
||||||
use-chips
|
|
||||||
multiple
|
|
||||||
new-value-mode="add-unique"
|
|
||||||
input-debounce="0"
|
|
||||||
outlined
|
|
||||||
v-model="nickName"
|
|
||||||
label="要设置的别名"
|
|
||||||
>
|
|
||||||
<template v-slot:prepend>
|
|
||||||
<q-icon name="drive_file_rename_outline" />
|
|
||||||
</template>
|
|
||||||
</q-select>
|
|
||||||
<q-btn
|
|
||||||
class="full-width"
|
|
||||||
color="primary"
|
|
||||||
label="确定"
|
|
||||||
@click="addPluNickName()"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import PluginNickName from "components/quickFeatures/PluginNickName";
|
||||||
|
import CrontabCmd from "components/quickFeatures/CrontabCmd";
|
||||||
|
import ApiServer from "components/quickFeatures/ApiServer";
|
||||||
|
import FavFile from "components/quickFeatures/FavFile";
|
||||||
|
import FavUrl from "components/quickFeatures/FavUrl";
|
||||||
|
import { markRaw } from "vue";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
components: {
|
||||||
|
pluNickName: markRaw(PluginNickName),
|
||||||
|
crontab: markRaw(CrontabCmd),
|
||||||
|
apiServer: markRaw(ApiServer),
|
||||||
|
favFile: markRaw(FavFile),
|
||||||
|
favUrl: markRaw(FavUrl),
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
featureType: this.$route.params.featuretype,
|
currentComponent: this.$route.params.featuretype,
|
||||||
cmdCtrlKey: window.processPlatform === "darwin" ? "command" : "control",
|
|
||||||
plugins: [],
|
|
||||||
plugin: {},
|
|
||||||
feature: {},
|
|
||||||
nickName: [],
|
|
||||||
showPluNickNameSetting: false,
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
|
||||||
features() {
|
|
||||||
return this.plugin?.features
|
|
||||||
?.map((x) => {
|
|
||||||
return {
|
|
||||||
explain: x.explain,
|
|
||||||
cmd: x.cmds.filter((y) => y.length)[0],
|
|
||||||
};
|
|
||||||
})
|
|
||||||
.filter((x) => x.cmd);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
switch (this.featureType) {
|
|
||||||
case "pluNickName":
|
|
||||||
this.showPluNickNameSetting = true;
|
|
||||||
this.plugins = _.values(window.getUtoolsPlugins());
|
|
||||||
this.plugin = this.plugins[0];
|
|
||||||
this.feature = this.features[0];
|
|
||||||
break;
|
|
||||||
case "favFile":
|
|
||||||
this.addFavFile();
|
|
||||||
break;
|
|
||||||
case "favUrl":
|
|
||||||
this.addFavUrl();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
methods: {
|
||||||
wait(ms) {
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
setTimeout(() => {
|
|
||||||
resolve();
|
|
||||||
}, ms);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
getPlugins() {},
|
|
||||||
addPluNickName() {
|
|
||||||
if (!this.nickName.length)
|
|
||||||
return quickcommand.showMessageBox("请填写别名", "warning");
|
|
||||||
let uid = this.getUid();
|
|
||||||
let command = {
|
|
||||||
features: {
|
|
||||||
cmds: this.nickName,
|
|
||||||
explain: this.feature.explain,
|
|
||||||
icon: window.getBase64Ico(this.plugin.logoPath),
|
|
||||||
platform: this.plugin.platform || ["darwin", "win32", "linux"],
|
|
||||||
code: `key_${uid}`,
|
|
||||||
},
|
|
||||||
program: "quickcommand",
|
|
||||||
cmd: `utools.redirect("${this.feature.cmd}");utools.showMainWindow()`,
|
|
||||||
output: "ignore",
|
|
||||||
tags: [this.$profile.quickFeatures.pluNickName.tag],
|
|
||||||
};
|
|
||||||
this.importCommand(command);
|
|
||||||
this.nickName = [];
|
|
||||||
quickcommand.showMessageBox("添加成功!");
|
|
||||||
},
|
|
||||||
addFavFile() {
|
|
||||||
utools.setExpendHeight(0);
|
|
||||||
quickcommand.enterData.payload.forEach((file) => {
|
|
||||||
let uid = this.getUid();
|
|
||||||
let fileInfo = window.getFileInfo({
|
|
||||||
type: "file",
|
|
||||||
argvs: file.path,
|
|
||||||
readfile: false,
|
|
||||||
});
|
|
||||||
let fileName = fileInfo.name.replace(fileInfo.ext, "");
|
|
||||||
let command = {
|
|
||||||
features: {
|
|
||||||
cmds: [fileName],
|
|
||||||
explain: `打开${fileName}`,
|
|
||||||
icon: utools.getFileIcon(file.path),
|
|
||||||
platform: [window.processPlatform],
|
|
||||||
code: `key_${uid}`,
|
|
||||||
},
|
|
||||||
program: "quickcommand",
|
|
||||||
cmd: `open(\"${file.path.replace(/\\/g, "\\\\")}\")`,
|
|
||||||
output: "ignore",
|
|
||||||
tags: [this.$profile.quickFeatures.favFile.tag],
|
|
||||||
};
|
|
||||||
this.importCommand(command);
|
|
||||||
});
|
|
||||||
this.showMsg();
|
|
||||||
},
|
|
||||||
async addFavUrl() {
|
|
||||||
utools.setExpendHeight(0);
|
|
||||||
utools.hideMainWindow();
|
|
||||||
// getCurrentBrowserUrl 似乎失效了
|
|
||||||
// let url = utools.getCurrentBrowserUrl();
|
|
||||||
utools.simulateKeyboardTap("l", this.cmdCtrlKey);
|
|
||||||
await this.wait(50);
|
|
||||||
utools.simulateKeyboardTap("c", this.cmdCtrlKey);
|
|
||||||
await this.wait(50);
|
|
||||||
let url = window.clipboardReadText();
|
|
||||||
if (!/^http/.test(url)) {
|
|
||||||
utools.showMainWindow();
|
|
||||||
utools.setExpendHeight(550);
|
|
||||||
let choise = await quickcommand.showButtonBox(
|
|
||||||
["http", "https"],
|
|
||||||
"当前浏览器网址显示不完整,请问访问的页面是哪一种?"
|
|
||||||
);
|
|
||||||
url = choise.text + "://" + url;
|
|
||||||
}
|
|
||||||
let title = quickcommand.enterData.payload.title
|
|
||||||
.replace(/和另外 \d+ 个页面.*/, "")
|
|
||||||
.replace(/[-|—] .*?[Edge|Firefox|Chrome].*/, "")
|
|
||||||
.trim();
|
|
||||||
// let req = await axios(url)
|
|
||||||
// let title = quickcommand.htmlParse(req.data).querySelector('title').innerText
|
|
||||||
let base = /(http(s){0,1}:\/\/.*?(:\d+){0,1})(\/|$).*/.exec(url)[1];
|
|
||||||
let iconUrl = base + "/favicon.ico";
|
|
||||||
let iconPath = window.joinPath(
|
|
||||||
utools.getPath("temp"),
|
|
||||||
"quickcommandfavicon.ico"
|
|
||||||
);
|
|
||||||
let uid = this.getUid();
|
|
||||||
let command = {
|
|
||||||
features: {
|
|
||||||
explain: `访问${title}`,
|
|
||||||
cmds: [title],
|
|
||||||
platform: ["linux", "win32", "darwin"],
|
|
||||||
code: `key_${uid}`,
|
|
||||||
},
|
|
||||||
program: "quickcommand",
|
|
||||||
cmd: `visit(\"${url}\")\n`,
|
|
||||||
output: "ignore",
|
|
||||||
tags: [this.$profile.quickFeatures.favUrl.tag],
|
|
||||||
};
|
|
||||||
try {
|
|
||||||
let res = await quickcommand.downloadFile(iconUrl, iconPath);
|
|
||||||
if (res) command.features.icon = iconPath;
|
|
||||||
} catch (e) {}
|
|
||||||
this.importCommand(command);
|
|
||||||
this.showMsg();
|
|
||||||
},
|
|
||||||
importCommand(command) {
|
importCommand(command) {
|
||||||
command = _.cloneDeep(command);
|
command = _.cloneDeep(command);
|
||||||
this.$utools.putDB(
|
this.$utools.putDB(
|
||||||
@ -252,10 +37,6 @@ export default {
|
|||||||
Math.random().toString().substr(3, 3) + Date.now()
|
Math.random().toString().substr(3, 3) + Date.now()
|
||||||
).toString(36);
|
).toString(36);
|
||||||
},
|
},
|
||||||
showMsg() {
|
|
||||||
utools.showNotification("操作成功!");
|
|
||||||
utools.outPlugin();
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user