终端支持快捷设置

This commit is contained in:
chaos-zhu 2024-10-17 23:53:04 +08:00
parent 70e867410f
commit 53cc1628c2
6 changed files with 155 additions and 74 deletions

View File

@ -2,7 +2,7 @@ import { io } from 'socket.io-client'
import { defineStore, acceptHMRUpdate } from 'pinia' import { defineStore, acceptHMRUpdate } from 'pinia'
import $api from '@/api' import $api from '@/api'
import config from '@/config' import config from '@/config'
// import ping from '@/utils/ping' import { isHttps } from '@/utils'
const { defaultClientPort } = config const { defaultClientPort } = config
@ -34,9 +34,12 @@ const useStore = defineStore({
], ],
terminalConfig: { terminalConfig: {
...{ ...{
fontSize: 14, fontSize: 16,
themeName: localStorage.getItem('themeName') || 'Afterglow', themeName: 'Afterglow',
background: localStorage.getItem('terminalBackground') || '' background: '',
quickCopy: isHttps(),
quickPaste: isHttps(),
autoExecuteScript: false
}, },
...(localStorage.getItem('terminalConfig') ? JSON.parse(localStorage.getItem('terminalConfig')) : {}) ...(localStorage.getItem('terminalConfig') ? JSON.parse(localStorage.getItem('terminalConfig')) : {})
} }

View File

@ -128,3 +128,7 @@ export const exportFile = (data, filename, mimeType = 'application/json') =>{
document.body.removeChild(link) document.body.removeChild(link)
window.URL.revokeObjectURL(url) window.URL.revokeObjectURL(url)
} }
export const isHttps = () => {
return window.location.protocol === 'https:'
}

View File

@ -4,20 +4,13 @@
<el-tab-pane label="修改密码" lazy> <el-tab-pane label="修改密码" lazy>
<User /> <User />
</el-tab-pane> </el-tab-pane>
<!-- <el-tab-pane label="分组管理">
<Group />
</el-tab-pane> -->
<el-tab-pane label="登录日志"> <el-tab-pane label="登录日志">
<Record /> <Record />
</el-tab-pane> </el-tab-pane>
<!-- <el-tab-pane label="实例排序" lazy>
<Sort @update-list="emitUpdateList" />
</el-tab-pane> -->
<el-tab-pane label="全局通知" lazy> <el-tab-pane label="全局通知" lazy>
<GlobalNotify /> <GlobalNotify />
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="通知配置" lazy> <el-tab-pane label="通知配置" lazy>
<!-- <EmailList /> -->
<NotifyConfig /> <NotifyConfig />
</el-tab-pane> </el-tab-pane>
</el-tabs> </el-tabs>

View File

@ -3,17 +3,19 @@
v-model="visible" v-model="visible"
width="600px" width="600px"
top="120px" top="120px"
title="终端设置" title="本地设置"
:append-to-body="false" :append-to-body="false"
:close-on-click-modal="false" :close-on-click-modal="false"
> >
<el-tabs tab-position="top">
<el-tab-pane label="终端设置" lazy>
<el-form <el-form
ref="formRef" ref="formRef"
label-suffix="" label-suffix=""
label-width="60px" label-width="100px"
:show-message="false" :show-message="false"
> >
<el-form-item label="主题" prop="theme"> <el-form-item label="终端主题" prop="theme">
<el-select v-model="theme" placeholder="" style="width: 100%;"> <el-select v-model="theme" placeholder="" style="width: 100%;">
<el-option <el-option
v-for="(value, key) in themeList" v-for="(value, key) in themeList"
@ -23,7 +25,10 @@
/> />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="背景" prop="backgroundImage"> <el-form-item label="终端字体" prop="fontSize">
<el-input-number v-model="fontSize" :min="12" :max="30" />
</el-form-item>
<el-form-item label="终端背景" prop="backgroundImage">
<ul class="background_list"> <ul class="background_list">
<li :class="background ? '' : 'active'" @click="changeBackground('')"> <li :class="background ? '' : 'active'" @click="changeBackground('')">
<el-image class="image"> <el-image class="image">
@ -45,17 +50,73 @@
</ul> </ul>
<div class="custom_background"> <div class="custom_background">
<el-input <el-input
v-model="backgroundUrl" v-model="background"
clearable clearable
placeholder="自定义背景图片url" placeholder="自定义背景图片url"
autocomplete="on" autocomplete="on"
/> />
</div> </div>
</el-form-item> </el-form-item>
<el-form-item label="字体" prop="fontSize"> </el-form>
<el-input-number v-model="fontSize" :min="12" :max="30" /> </el-tab-pane>
<el-tab-pane label="快捷操作">
<el-form
ref="formRef"
label-suffix=""
label-width="100px"
:show-message="false"
>
<el-form-item label="选中复制" prop="quickCopy">
<el-tooltip
effect="dark"
content="启用后选中文本自动复制到剪贴板(需https支持)"
placement="right"
>
<el-switch
v-model="quickCopy"
class="swtich"
inline-prompt
style="--el-switch-on-color: #13ce66; --el-switch-off-color: #ff4949"
active-text="开启"
inactive-text="关闭"
/>
</el-tooltip>
</el-form-item>
<el-form-item label="快捷粘贴" prop="quickPaste">
<el-tooltip
effect="dark"
content="启用后右键粘贴剪贴板内容(需https支持)"
placement="right"
>
<el-switch
v-model="quickPaste"
class="swtich"
inline-prompt
style="--el-switch-on-color: #13ce66; --el-switch-off-color: #ff4949"
active-text="开启"
inactive-text="关闭"
/>
</el-tooltip>
</el-form-item>
<el-form-item label="脚本执行" prop="autoExecuteScript">
<el-tooltip
effect="dark"
content="启用后从脚本库选中脚本后自动执行(回车操作)"
placement="right"
>
<el-switch
v-model="autoExecuteScript"
class="swtich"
inline-prompt
style="--el-switch-on-color: #13ce66; --el-switch-off-color: #ff4949"
active-text="自动"
inactive-text="手动"
/>
</el-tooltip>
</el-form-item> </el-form-item>
</el-form> </el-form>
</el-tab-pane>
</el-tabs>
<template #footer> <template #footer>
<span class="dialog_footer"> <span class="dialog_footer">
<el-button @click="visible = false">关闭</el-button> <el-button @click="visible = false">关闭</el-button>
@ -95,6 +156,18 @@ const fontSize = computed({
get: () => $store.terminalConfig.fontSize, get: () => $store.terminalConfig.fontSize,
set: (newVal) => $store.setTerminalSetting({ fontSize: newVal }) set: (newVal) => $store.setTerminalSetting({ fontSize: newVal })
}) })
const quickCopy = computed({
get: () => $store.terminalConfig.quickCopy,
set: (newVal) => $store.setTerminalSetting({ quickCopy: newVal })
})
const quickPaste = computed({
get: () => $store.terminalConfig.quickPaste,
set: (newVal) => $store.setTerminalSetting({ quickPaste: newVal })
})
const autoExecuteScript = computed({
get: () => $store.terminalConfig.autoExecuteScript,
set: (newVal) => $store.setTerminalSetting({ autoExecuteScript: newVal })
})
const changeBackground = (url) => { const changeBackground = (url) => {
background.value = url || '' background.value = url || ''

View File

@ -3,7 +3,7 @@
<div <div
ref="terminalRef" ref="terminalRef"
class="terminal_container" class="terminal_container"
@contextmenu.prevent="handleRightClick" @contextmenu="handleRightClick"
/> />
<!-- <div class="terminal_command_history"> <!-- <div class="terminal_command_history">
<CommandHistory :list="commandHistoryList" /> <CommandHistory :list="commandHistoryList" />
@ -60,7 +60,10 @@ const background = computed(() => $store.terminalConfig.background)
const hostObj = computed(() => props.hostObj) const hostObj = computed(() => props.hostObj)
const hostId = computed(() => hostObj.value.id) const hostId = computed(() => hostObj.value.id)
const host = computed(() => hostObj.value.host) const host = computed(() => hostObj.value.host)
let menuCollapse = computed(() => $store.menuCollapse) const menuCollapse = computed(() => $store.menuCollapse)
const quickCopy = computed(() => $store.terminalConfig.quickCopy)
const quickPaste = computed(() => $store.terminalConfig.quickPaste)
const autoExecuteScript = computed(() => $store.terminalConfig.autoExecuteScript)
watch(menuCollapse, () => { watch(menuCollapse, () => {
nextTick(() => { nextTick(() => {
@ -272,6 +275,7 @@ const onFindText = () => {
const onSelectionChange = () => { const onSelectionChange = () => {
term.value.onSelectionChange(() => { term.value.onSelectionChange(() => {
if (!quickCopy.value) return
let str = term.value.getSelection() let str = term.value.getSelection()
if (!str) return if (!str) return
const text = new Blob([str,], { type: 'text/plain' }) const text = new Blob([str,], { type: 'text/plain' })
@ -323,8 +327,9 @@ const onData = () => {
term.value.onData((key) => { term.value.onData((key) => {
if (socketConnected.value === false) return if (socketConnected.value === false) return
let acsiiCode = key.codePointAt() let acsiiCode = key.codePointAt()
if (acsiiCode === 22) return handlePaste() // console.log(acsiiCode)
if (acsiiCode === 6) return searchBar.value.show() if (acsiiCode === 22) return handlePaste() // Ctrl + V
// if (acsiiCode === 6) return searchBar.value.show() // Ctrl + F
enterTimer.value = setTimeout(() => { enterTimer.value = setTimeout(() => {
if (enterTimer.value) clearTimeout(enterTimer.value) if (enterTimer.value) clearTimeout(enterTimer.value)
if (key === '\r') { // Enter if (key === '\r') { // Enter
@ -363,7 +368,9 @@ const onData = () => {
}) })
} }
const handleRightClick = async () => { const handleRightClick = async (e) => {
if (!quickPaste.value) return
e.preventDefault()
try { try {
const clipboardText = await navigator.clipboard.readText() const clipboardText = await navigator.clipboard.readText()
if (!clipboardText) return if (!clipboardText) return
@ -384,6 +391,7 @@ const handleClear = () => {
} }
const handlePaste = async () => { const handlePaste = async () => {
if (!quickPaste.value) return
let key = await navigator.clipboard.readText() let key = await navigator.clipboard.readText()
emit('inputCommand', key) emit('inputCommand', key)
socket.value.emit('input', key) socket.value.emit('input', key)
@ -398,6 +406,7 @@ const focusTab = () => {
} }
const inputCommand = (command) => { const inputCommand = (command) => {
command = command + (autoExecuteScript.value ? '\n' : '')
socket.value.emit('input', command) socket.value.emit('input', command)
} }

View File

@ -47,14 +47,14 @@
</template> </template>
</el-dropdown> --> </el-dropdown> -->
<el-dropdown trigger="click"> <el-dropdown trigger="click">
<span class="link_text">设置<el-icon><arrow-down /></el-icon></span> <span class="link_text">首选项<el-icon><arrow-down /></el-icon></span>
<template #dropdown> <template #dropdown>
<el-dropdown-menu> <el-dropdown-menu>
<el-dropdown-item @click="handleFullScreen"> <el-dropdown-item @click="handleFullScreen">
<span>启用全屏</span> <span>启用全屏</span>
</el-dropdown-item> </el-dropdown-item>
<el-dropdown-item @click="showSetting = true"> <el-dropdown-item @click="showSetting = true">
<span>终端设置</span> <span>本地设置</span>
</el-dropdown-item> </el-dropdown-item>
</el-dropdown-menu> </el-dropdown-menu>
</template> </template>
@ -247,7 +247,6 @@ const handleCloseAllTab = () => {
const handleExecScript = (scriptObj) => { const handleExecScript = (scriptObj) => {
let { command } = scriptObj let { command } = scriptObj
command += '\n'
if (!isSyncAllSession.value) return handleInputCommand(command) if (!isSyncAllSession.value) return handleInputCommand(command)
terminalRefs.value.forEach(terminalRef => { terminalRefs.value.forEach(terminalRef => {
terminalRef.inputCommand(command) terminalRef.inputCommand(command)
@ -355,7 +354,7 @@ const handleInputCommand = async (command) => {
const curTerminalRef = terminalRefs.value[activeTabIndex.value] const curTerminalRef = terminalRefs.value[activeTabIndex.value]
await $nextTick() await $nextTick()
curTerminalRef?.focusTab() curTerminalRef?.focusTab()
curTerminalRef.inputCommand(`${ command }`) // \n curTerminalRef.inputCommand(`${ command }`)
showInputCommand.value = false showInputCommand.value = false
} }
</script> </script>