NEZ-2495 feat:terminal支持查看历史记录页面开发
This commit is contained in:
@@ -135,14 +135,103 @@
|
|||||||
font-size: 6px;
|
font-size: 6px;
|
||||||
}
|
}
|
||||||
.shell-input{
|
.shell-input{
|
||||||
|
position: relative;
|
||||||
input {
|
input {
|
||||||
background: #1E1E1E !important;
|
background: #1E1E1E !important;
|
||||||
border: none;
|
border: none;
|
||||||
color: white;
|
color: white;
|
||||||
|
padding-right: 53px;
|
||||||
}
|
}
|
||||||
input::input-placeholder{
|
input::input-placeholder{
|
||||||
color: #7C7C7C;
|
color: #7C7C7C;
|
||||||
}
|
}
|
||||||
|
.el-input__suffix{
|
||||||
|
right: 20px;
|
||||||
|
.el-input__suffix-inner{
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
i{
|
||||||
|
color: $--color-text-regular;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
i.active{
|
||||||
|
color: $--color-primary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.web-terminal-history{
|
||||||
|
position: absolute;
|
||||||
|
bottom: 32px;
|
||||||
|
z-index: 9;
|
||||||
|
width: 100%;
|
||||||
|
background: #1E1E1E;
|
||||||
|
border-bottom: 1px solid rgba(0,0,0,0.50);
|
||||||
|
.terminal-history-header{
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 0 20px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #B7B7B7;
|
||||||
|
height: 36px;
|
||||||
|
border-bottom: 1px solid #2F2F2F;
|
||||||
|
i{
|
||||||
|
font-size: 14px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.terminal-history-list-wrap{
|
||||||
|
padding: 10px 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
.terminal-history-list{
|
||||||
|
max-height: 160px;
|
||||||
|
overflow-y: auto;
|
||||||
|
line-height:normal;
|
||||||
|
&::-webkit-scrollbar-thumb{
|
||||||
|
background-color:#404040;
|
||||||
|
border:2px solid #222329;
|
||||||
|
}
|
||||||
|
.terminal-history-item{
|
||||||
|
padding: 0px 20px;
|
||||||
|
height: 20px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
cursor: pointer;
|
||||||
|
&:hover{
|
||||||
|
background: #18171D;
|
||||||
|
}
|
||||||
|
.terminal-history-num{
|
||||||
|
width: 28px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #B7B7B7;
|
||||||
|
font-weight: 400;
|
||||||
|
flex-shrink: 0;
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
.terminal-history-text{
|
||||||
|
font-size: 14px;
|
||||||
|
color: #FFFFFF;
|
||||||
|
font-weight: 400;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.terminal-history-empty{
|
||||||
|
line-height: 50px;
|
||||||
|
color: #B7B7B7;
|
||||||
|
font-size: 14px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -5,6 +5,20 @@
|
|||||||
"css_prefix_text": "nz-icon-",
|
"css_prefix_text": "nz-icon-",
|
||||||
"description": "",
|
"description": "",
|
||||||
"glyphs": [
|
"glyphs": [
|
||||||
|
{
|
||||||
|
"icon_id": "16639137",
|
||||||
|
"name": "history",
|
||||||
|
"font_class": "history",
|
||||||
|
"unicode": "e663",
|
||||||
|
"unicode_decimal": 58979
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "33610702",
|
||||||
|
"name": "关闭2",
|
||||||
|
"font_class": "guanbi2",
|
||||||
|
"unicode": "e7be",
|
||||||
|
"unicode_decimal": 59326
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"icon_id": "32096202",
|
"icon_id": "32096202",
|
||||||
"name": "定位",
|
"name": "定位",
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
@@ -133,9 +133,11 @@ export default {
|
|||||||
this.host = res.data.host
|
this.host = res.data.host
|
||||||
this.create()
|
this.create()
|
||||||
} else {
|
} else {
|
||||||
this.terminal.uuid = res.data.uuid
|
if (res.data) {
|
||||||
this.terminal.userName = res.data.authUsername + '@' + res.data.host
|
this.terminal.uuid = res.data.uuid
|
||||||
this.host = res.data.host
|
this.terminal.userName = res.data.authUsername + '@' + res.data.host
|
||||||
|
this.host = res.data.host
|
||||||
|
}
|
||||||
params.name = this.terminal.name
|
params.name = this.terminal.name
|
||||||
this.$emit('loginFail', params)
|
this.$emit('loginFail', params)
|
||||||
this.$message.error(res.msg)
|
this.$message.error(res.msg)
|
||||||
@@ -311,7 +313,12 @@ export default {
|
|||||||
this.terminalSocket.send(message)
|
this.terminalSocket.send(message)
|
||||||
this.terminalSocket.send('\n')
|
this.terminalSocket.send('\n')
|
||||||
this.term.scrollToBottom()
|
this.term.scrollToBottom()
|
||||||
|
this.historyChange(message)
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
// 新增历史记录
|
||||||
|
historyChange (message) {
|
||||||
|
this.$emit('historyChange', message)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted () {
|
mounted () {
|
||||||
@@ -324,6 +331,3 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style scoped lang="scss">
|
|
||||||
|
|
||||||
</style>
|
|
||||||
|
|||||||
@@ -11,7 +11,29 @@
|
|||||||
</div>
|
</div>
|
||||||
<fileListState v-clickoutside="hideFileState" ref="fileListState"/>
|
<fileListState v-clickoutside="hideFileState" ref="fileListState"/>
|
||||||
<webSSHNew ref="websshNew" />
|
<webSSHNew ref="websshNew" />
|
||||||
<el-input :placeholder="placeholder" size="small" class="shell-input" v-model="message" @keyup.enter.native="sendMessage" @focus="placeholderChange('focus')" @blur="placeholderChange('blur')"/>
|
<div class="shell-input">
|
||||||
|
<el-input ref="shellInput" :placeholder="placeholder" size="small" v-model="message" @keyup.enter.native="sendMessage" @focus="placeholderChange('focus')" @blur="placeholderChange('blur')">
|
||||||
|
<i slot="suffix" class="nz-icon nz-icon-history" :class="{'active':visible}" :title="$t('terminal.history')" @click="toggleHistory"></i>
|
||||||
|
</el-input>
|
||||||
|
<transition name="el-zoom-in-bottom">
|
||||||
|
<div class="web-terminal-history" v-show="visible">
|
||||||
|
<div class="terminal-history-header">
|
||||||
|
<span>{{$t('terminal.history')}}</span>
|
||||||
|
<i class="nz-icon nz-icon-close" @click="visible=false"></i>
|
||||||
|
</div>
|
||||||
|
<div class="terminal-history-list-wrap" v-if="historyArr.length">
|
||||||
|
<!-- 历史命令记录 -->
|
||||||
|
<ul class="terminal-history-list">
|
||||||
|
<li class="terminal-history-item" v-for="(item,index) in historyArr" :key="index" @click="historyClick(item)">
|
||||||
|
<span class="terminal-history-num">{{index+1}}</span>
|
||||||
|
<span class="terminal-history-text">{{item}}</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div v-else class="terminal-history-empty">{{$t('terminal.noHistoricalRecord')}}</div>
|
||||||
|
</div>
|
||||||
|
</transition>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -19,6 +41,7 @@
|
|||||||
import webSSHNew from '@/components/cli/webSSHNew'
|
import webSSHNew from '@/components/cli/webSSHNew'
|
||||||
import fileListState from './fileListState'
|
import fileListState from './fileListState'
|
||||||
import imageUrl from '@/assets/img/logo1-2.png'
|
import imageUrl from '@/assets/img/logo1-2.png'
|
||||||
|
import bus from '@/libs/bus'
|
||||||
export default {
|
export default {
|
||||||
name: 'terminal',
|
name: 'terminal',
|
||||||
components: {
|
components: {
|
||||||
@@ -32,7 +55,10 @@ export default {
|
|||||||
fileListStateType: '',
|
fileListStateType: '',
|
||||||
message: '',
|
message: '',
|
||||||
name: '',
|
name: '',
|
||||||
placeholder: this.$t('terminal.placeholder')
|
placeholder: this.$t('terminal.placeholder'),
|
||||||
|
visible: false,
|
||||||
|
// 历史命令记录
|
||||||
|
historyArr: []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@@ -49,6 +75,7 @@ export default {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
this.logo = localStorage.getItem('nz-sys-logo')
|
this.logo = localStorage.getItem('nz-sys-logo')
|
||||||
|
this.getHistory()
|
||||||
},
|
},
|
||||||
mounted () {
|
mounted () {
|
||||||
const self = this
|
const self = this
|
||||||
@@ -70,7 +97,7 @@ export default {
|
|||||||
self.$refs.websshNew.addConsole(asset.id, asset.manageIp, '', '', 'asset')
|
self.$refs.websshNew.addConsole(asset.id, asset.manageIp, '', '', 'asset')
|
||||||
})
|
})
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e)
|
// console.log(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -87,7 +114,7 @@ export default {
|
|||||||
placeholderChange (type) {
|
placeholderChange (type) {
|
||||||
if (type == 'focus') {
|
if (type == 'focus') {
|
||||||
this.placeholder = ''
|
this.placeholder = ''
|
||||||
}else {
|
} else {
|
||||||
this.placeholder = this.$t('terminal.placeholder')
|
this.placeholder = this.$t('terminal.placeholder')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -96,14 +123,33 @@ export default {
|
|||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.message = ''
|
this.message = ''
|
||||||
})
|
})
|
||||||
}
|
},
|
||||||
},
|
// 获取历史输入命令
|
||||||
beforeDestroy () {
|
getHistory () {
|
||||||
|
const length = localStorage.getItem('nz-history-size') || 100
|
||||||
|
const historyArr = JSON.parse(localStorage.getItem('nz-history-terminal') || '[]')
|
||||||
|
historyArr.splice(length)
|
||||||
|
this.historyArr = historyArr
|
||||||
|
},
|
||||||
|
// 切换历史记录显示隐藏
|
||||||
|
toggleHistory () {
|
||||||
|
this.visible = !this.visible
|
||||||
|
},
|
||||||
|
// 点击历史记录
|
||||||
|
historyClick (value) {
|
||||||
|
this.visible = false
|
||||||
|
this.message = value
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.$refs.shellInput.focus()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 新增历史记录
|
||||||
|
historyChange: bus.debounce(function (message) {
|
||||||
|
const historyArr = JSON.parse(localStorage.getItem('nz-history-terminal') || '[]')
|
||||||
|
historyArr.unshift(message)
|
||||||
|
localStorage.setItem('nz-history-terminal', JSON.stringify(historyArr))
|
||||||
|
this.getHistory()
|
||||||
|
}, 100)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
|
||||||
|
|
||||||
</style>
|
|
||||||
|
|||||||
@@ -1,15 +1,18 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="ani-webSHH-height web-terminal-new" id="web-terminal-new">
|
<div class="ani-webSHH-height web-terminal-new" id="web-terminal-new">
|
||||||
<el-tabs :before-leave="beforeLeave"
|
<el-tabs
|
||||||
@tab-click="handleClick"
|
:before-leave="beforeLeave"
|
||||||
@tab-remove="removeTab"
|
@tab-click="handleClick"
|
||||||
type="border-card"
|
@tab-remove="removeTab"
|
||||||
v-model="editableTabsValue" >
|
type="border-card"
|
||||||
<el-tab-pane :key="item.name"
|
v-model="editableTabsValue"
|
||||||
:label="item.title"
|
>
|
||||||
:name="item.name"
|
<el-tab-pane
|
||||||
closable
|
:key="item.name"
|
||||||
v-for="(item, index) in editableTabs"
|
:label="item.title"
|
||||||
|
:name="item.name"
|
||||||
|
closable
|
||||||
|
v-for="(item, index) in editableTabs"
|
||||||
>
|
>
|
||||||
<!-- tab显示的内容 1 grey,2 green, 3 red-->
|
<!-- tab显示的内容 1 grey,2 green, 3 red-->
|
||||||
<span slot="label" class="el-tabs__item-label">
|
<span slot="label" class="el-tabs__item-label">
|
||||||
@@ -64,6 +67,7 @@
|
|||||||
@loginFail="loginFail"
|
@loginFail="loginFail"
|
||||||
@closeConsole="removeTab"
|
@closeConsole="removeTab"
|
||||||
@refreshConsoleTitle="refreshTabTitle"
|
@refreshConsoleTitle="refreshTabTitle"
|
||||||
|
@historyChange="(message)=>{$parent.historyChange(message)}"
|
||||||
></terminal>
|
></terminal>
|
||||||
|
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
@@ -77,13 +81,13 @@
|
|||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<div class="popover-webshell-item" @click="assetShowChange"><i class="nz-icon nz-icon-menu-assets" />{{$t('webshell.selAsset')}}</div>
|
<div class="popover-webshell-item" @click="assetShowChange"><i class="nz-icon nz-icon-menu-assets" />{{$t('webshell.selAsset')}}</div>
|
||||||
<div class="popover-webshell-item" @click="customShow=true"><i class="nz-icon nz-icon-edit" />{{$t('webshell.custom')}}</div>
|
<div class="popover-webshell-item" @click="customShow=true"><i class="nz-icon nz-icon-edit" />{{$t('webshell.custom')}}</div>
|
||||||
</div>
|
</div>
|
||||||
<span slot="reference" style="padding:8px;font-size:20px;font-weight:bold;">+</span>
|
<span slot="reference" style="padding:8px;font-size:20px;font-weight:bold;">+</span>
|
||||||
</el-popover>
|
</el-popover>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
<!--弹窗-->
|
<!--弹窗-->
|
||||||
<el-dialog :modal-append-to-body='false' :show-close="true" :visible.sync="assetShow" @close="closeAssetCustom" class="nz-dialog" width="620px">
|
<el-dialog :modal-append-to-body='false' :show-close="true" :visible.sync="assetShow" @close="closeAssetCustom" class="nz-dialog" width="620px">
|
||||||
<div slot="title">{{$t('webshell.connect')}}</div>
|
<div slot="title">{{$t('webshell.connect')}}</div>
|
||||||
<div >
|
<div >
|
||||||
@@ -121,7 +125,7 @@
|
|||||||
</el-form>
|
</el-form>
|
||||||
</div>
|
</div>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
<el-dialog :modal-append-to-body='false' :show-close="true" :visible.sync="customShow" @close="closeAssetCustom" class="nz-dialog" width="620px"destroy-on-close >
|
<el-dialog :modal-append-to-body='false' :show-close="true" :visible.sync="customShow" @close="closeAssetCustom" class="nz-dialog" width="620px" destroy-on-close>
|
||||||
<div slot="title">{{$t('webshell.connect')}}</div>
|
<div slot="title">{{$t('webshell.connect')}}</div>
|
||||||
<div >
|
<div >
|
||||||
<el-form label-width="120px" size="small" :model="customConnect" label-position = "top" :rules=" customConnect.authProtocol ===2 ? rulesCustom2: rulesCustom" ref="customConnect" v-my-loading="assetLoading" class="custom">
|
<el-form label-width="120px" size="small" :model="customConnect" label-position = "top" :rules=" customConnect.authProtocol ===2 ? rulesCustom2: rulesCustom" ref="customConnect" v-my-loading="assetLoading" class="custom">
|
||||||
@@ -151,10 +155,10 @@
|
|||||||
>
|
>
|
||||||
<el-input v-model="customConnect.authPriKey" size="small" autocomplete="new-password"/>
|
<el-input v-model="customConnect.authPriKey" size="small" autocomplete="new-password"/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item :label='$t("login.pin")' prop="authPin"
|
<el-form-item
|
||||||
:rules="[
|
:label='$t("login.pin")' prop="authPin"
|
||||||
{ required: customConnect.authType ===1, message:$t('validate.required'), trigger: 'change'},
|
:rules="[{ required: customConnect.authType ===1, message:$t('validate.required'), trigger: 'change'},]"
|
||||||
]">
|
>
|
||||||
<el-input v-model="customConnect.authPin" size="small" type="password" autocomplete="new-password"/>
|
<el-input v-model="customConnect.authPin" size="small" type="password" autocomplete="new-password"/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item
|
<el-form-item
|
||||||
|
|||||||
@@ -227,12 +227,12 @@ export default {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
// 使用防抖是因为,防止标签输入框失去焦点校验和开始任务校验重复(连续两次message提示)
|
// 防止标签输入框失去焦点校验和开始任务校验重复(连续两次message提示)
|
||||||
validateHost: bus.debounce(function () {
|
validateHost: bus.debounce(function () {
|
||||||
this.$message.error(this.$t('validate.host'))
|
this.$message.error(this.$t('validate.host'))
|
||||||
},
|
},
|
||||||
50),
|
50),
|
||||||
// 使用防抖是因为,防止标签输入框失去焦点校验和开始任务校验重复(连续两次message提示)
|
// 防止标签输入框失去焦点校验和开始任务校验重复(连续两次message提示)
|
||||||
validateDuplicate: bus.debounce(function () {
|
validateDuplicate: bus.debounce(function () {
|
||||||
this.$message.error(this.$t('ping.duplicate') + ' IP')
|
this.$message.error(this.$t('ping.duplicate') + ' IP')
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -218,12 +218,12 @@ export default {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
// 使用防抖是因为,防止标签输入框失去焦点校验和开始任务校验重复(连续两次message提示)
|
// 防止标签输入框失去焦点校验和开始任务校验重复(连续两次message提示)
|
||||||
validateHost: bus.debounce(function () {
|
validateHost: bus.debounce(function () {
|
||||||
this.$message.error(this.$t('validate.host'))
|
this.$message.error(this.$t('validate.host'))
|
||||||
},
|
},
|
||||||
50),
|
50),
|
||||||
// 使用防抖是因为,防止标签输入框失去焦点校验和开始任务校验重复(连续两次message提示)
|
// 防止标签输入框失去焦点校验和开始任务校验重复(连续两次message提示)
|
||||||
validateDuplicate: bus.debounce(function () {
|
validateDuplicate: bus.debounce(function () {
|
||||||
this.$message.error(this.$t('ping.duplicate') + ' IP')
|
this.$message.error(this.$t('ping.duplicate') + ' IP')
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -93,13 +93,14 @@ const user = {
|
|||||||
localStorage.setItem(`nz-user-${res.data.user.id}-theme`, currentTheme)
|
localStorage.setItem(`nz-user-${res.data.user.id}-theme`, currentTheme)
|
||||||
const body = document.getElementsByTagName('body')[0]
|
const body = document.getElementsByTagName('body')[0]
|
||||||
body.setAttribute('class', `theme-${currentTheme}`)
|
body.setAttribute('class', `theme-${currentTheme}`)
|
||||||
|
console.log(res)
|
||||||
localStorage.setItem('timezoneOffset', moment.tz(res.data.timezone || defaultAppearance.timezone).format('Z'))
|
localStorage.setItem('timezoneOffset', moment.tz(res.data.timezone || defaultAppearance.timezone).format('Z'))
|
||||||
localStorage.setItem('nz-sys-default-cabinet-usize', res.data.defaultCabinetUsize)
|
localStorage.setItem('nz-sys-default-cabinet-usize', res.data.defaultCabinetUsize)
|
||||||
localStorage.setItem('nz-sys-max-terminal-num', res.data.maxTerminalNum)
|
localStorage.setItem('nz-sys-max-terminal-num', res.data.maxTerminalNum)
|
||||||
localStorage.setItem('nz-sys-asset-ping-switch', res.data.assetPingSwitch)
|
localStorage.setItem('nz-sys-asset-ping-switch', res.data.assetPingSwitch)
|
||||||
localStorage.setItem('nz-unnsaved-change', res.data.unsavedChange)
|
localStorage.setItem('nz-unnsaved-change', res.data.unsavedChange)
|
||||||
localStorage.setItem('nz-mfa-enable', Number(res.data.mfaAuthEnable) ? 1 : 0)
|
localStorage.setItem('nz-mfa-enable', Number(res.data.mfaAuthEnable) ? 1 : 0)
|
||||||
|
localStorage.setItem('nz-history-size', res.data.history_size ? res.data.history_size : 100)
|
||||||
store.commit('setLanguage', res.data.user.lang || defaultAppearance.language)
|
store.commit('setLanguage', res.data.user.lang || defaultAppearance.language)
|
||||||
store.commit('setTimeFormatMain', localStorage.getItem('nz-default-dateFormat') || 'YYYY-MM-DD HH:mm:ss')
|
store.commit('setTimeFormatMain', localStorage.getItem('nz-default-dateFormat') || 'YYYY-MM-DD HH:mm:ss')
|
||||||
// 获取可选语言
|
// 获取可选语言
|
||||||
|
|||||||
Reference in New Issue
Block a user