feat: add app launch log page
This commit is contained in:
parent
15c80bc9f7
commit
4879901a33
|
@ -12,13 +12,22 @@ import (
|
|||
. "tinyrdm/backend/storage"
|
||||
"tinyrdm/backend/types"
|
||||
maputil "tinyrdm/backend/utils/map"
|
||||
mathutil "tinyrdm/backend/utils/math"
|
||||
redis2 "tinyrdm/backend/utils/redis"
|
||||
)
|
||||
|
||||
type cmdHistoryItem struct {
|
||||
timestamp int64
|
||||
Time string `json:"time"`
|
||||
Server string `json:"server"`
|
||||
Cmd string `json:"cmd"`
|
||||
}
|
||||
|
||||
type connectionService struct {
|
||||
ctx context.Context
|
||||
conns *ConnectionsStorage
|
||||
connMap map[string]connectionItem
|
||||
ctx context.Context
|
||||
conns *ConnectionsStorage
|
||||
connMap map[string]connectionItem
|
||||
cmdHistory []cmdHistoryItem
|
||||
}
|
||||
|
||||
type connectionItem struct {
|
||||
|
@ -230,7 +239,7 @@ func (c *connectionService) CloseConnection(name string) (resp types.JSResp) {
|
|||
}
|
||||
|
||||
// get redis client from local cache or create a new open
|
||||
// if db >= 0, also switch to db index
|
||||
// if db >= 0, will also switch to db index
|
||||
func (c *connectionService) getRedisClient(connName string, db int) (*redis.Client, context.Context, error) {
|
||||
item, ok := c.connMap[connName]
|
||||
var rdb *redis.Client
|
||||
|
@ -249,7 +258,19 @@ func (c *connectionService) getRedisClient(connName string, db int) (*redis.Clie
|
|||
Password: selConn.Password,
|
||||
ReadTimeout: -1,
|
||||
})
|
||||
rdb.AddHook(redis2.NewHook(connName))
|
||||
rdb.AddHook(redis2.NewHook(connName, func(cmd string) {
|
||||
now := time.Now()
|
||||
last := strings.LastIndex(cmd, ":")
|
||||
if last != -1 {
|
||||
cmd = cmd[:last]
|
||||
}
|
||||
c.cmdHistory = append(c.cmdHistory, cmdHistoryItem{
|
||||
timestamp: now.UnixMilli(),
|
||||
Time: now.Format("2006-01-02 15:04:05"),
|
||||
Server: connName,
|
||||
Cmd: cmd,
|
||||
})
|
||||
}))
|
||||
|
||||
if _, err := rdb.Ping(c.ctx).Result(); err != nil && err != redis.Nil {
|
||||
return nil, nil, errors.New("can not connect to redis server:" + err.Error())
|
||||
|
@ -960,6 +981,28 @@ func (c *connectionService) RenameKey(connName string, db int, key, newKey strin
|
|||
return
|
||||
}
|
||||
|
||||
func (c *connectionService) GetCmdHistory(pageNo, pageSize int) (resp types.JSResp) {
|
||||
resp.Success = true
|
||||
if pageSize <= 0 || pageNo <= 0 {
|
||||
// return all history
|
||||
resp.Data = map[string]any{
|
||||
"list": c.cmdHistory,
|
||||
"pageNo": 1,
|
||||
"pageSize": -1,
|
||||
}
|
||||
} else {
|
||||
total := len(c.cmdHistory)
|
||||
startIndex := total / pageSize * (pageNo - 1)
|
||||
endIndex := mathutil.Min(startIndex+pageSize, total)
|
||||
resp.Data = map[string]any{
|
||||
"list": c.cmdHistory[startIndex:endIndex],
|
||||
"pageNo": pageNo,
|
||||
"pageSize": pageSize,
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// update or insert key info to database
|
||||
//func (c *connectionService) updateDBKey(connName string, db int, keys []string, separator string) {
|
||||
// dbStruct := map[string]any{}
|
||||
|
|
|
@ -102,7 +102,7 @@ func (c *ConnectionsStorage) GetConnection(name string) *types.Connection {
|
|||
return findConn(name, "", conns)
|
||||
}
|
||||
|
||||
// GetGroup get connection group by name
|
||||
// GetGroup get one connection group by name
|
||||
func (c *ConnectionsStorage) GetGroup(name string) *types.Connection {
|
||||
conns := c.getConnections()
|
||||
|
||||
|
|
|
@ -0,0 +1,93 @@
|
|||
package mathutil
|
||||
|
||||
import (
|
||||
"math"
|
||||
. "tinyrdm/backend/utils"
|
||||
)
|
||||
|
||||
// MaxWithIndex 查找所有元素中的最大值
|
||||
func MaxWithIndex[T Hashable](items ...T) (T, int) {
|
||||
selIndex := -1
|
||||
for i, t := range items {
|
||||
if selIndex < 0 {
|
||||
selIndex = i
|
||||
} else {
|
||||
if t > items[selIndex] {
|
||||
selIndex = i
|
||||
}
|
||||
}
|
||||
}
|
||||
return items[selIndex], selIndex
|
||||
}
|
||||
|
||||
func Max[T Hashable](items ...T) T {
|
||||
val, _ := MaxWithIndex(items...)
|
||||
return val
|
||||
}
|
||||
|
||||
// MinWithIndex 查找所有元素中的最小值
|
||||
func MinWithIndex[T Hashable](items ...T) (T, int) {
|
||||
selIndex := -1
|
||||
for i, t := range items {
|
||||
if selIndex < 0 {
|
||||
selIndex = i
|
||||
} else {
|
||||
if t < items[selIndex] {
|
||||
selIndex = i
|
||||
}
|
||||
}
|
||||
}
|
||||
return items[selIndex], selIndex
|
||||
}
|
||||
|
||||
func Min[T Hashable](items ...T) T {
|
||||
val, _ := MinWithIndex(items...)
|
||||
return val
|
||||
}
|
||||
|
||||
// Clamp 返回限制在minVal和maxVal范围内的value
|
||||
func Clamp[T Hashable](value T, minVal T, maxVal T) T {
|
||||
if minVal > maxVal {
|
||||
minVal, maxVal = maxVal, minVal
|
||||
}
|
||||
if value < minVal {
|
||||
value = minVal
|
||||
} else if value > maxVal {
|
||||
value = maxVal
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
// Abs 计算绝对值
|
||||
func Abs[T SignedNumber](val T) T {
|
||||
return T(math.Abs(float64(val)))
|
||||
}
|
||||
|
||||
// Floor 向下取整
|
||||
func Floor[T SignedNumber | UnsignedNumber](val T) T {
|
||||
return T(math.Floor(float64(val)))
|
||||
}
|
||||
|
||||
// Ceil 向上取整
|
||||
func Ceil[T SignedNumber | UnsignedNumber](val T) T {
|
||||
return T(math.Ceil(float64(val)))
|
||||
}
|
||||
|
||||
// Round 四舍五入取整
|
||||
func Round[T SignedNumber | UnsignedNumber](val T) T {
|
||||
return T(math.Round(float64(val)))
|
||||
}
|
||||
|
||||
// Sum 计算所有元素总和
|
||||
func Sum[T SignedNumber | UnsignedNumber](items ...T) T {
|
||||
var sum T
|
||||
for _, item := range items {
|
||||
sum += item
|
||||
}
|
||||
return sum
|
||||
}
|
||||
|
||||
// Average 计算所有元素的平均值
|
||||
func Average[T SignedNumber | UnsignedNumber](items ...T) T {
|
||||
return Sum(items...) / T(len(items))
|
||||
}
|
|
@ -7,31 +7,41 @@ import (
|
|||
"net"
|
||||
)
|
||||
|
||||
type execCallback func(string)
|
||||
|
||||
type LogHook struct {
|
||||
name string
|
||||
name string
|
||||
cmdExec execCallback
|
||||
}
|
||||
|
||||
func NewHook(name string) LogHook {
|
||||
return LogHook{
|
||||
name: name,
|
||||
func NewHook(name string, cmdExec execCallback) *LogHook {
|
||||
return &LogHook{
|
||||
name: name,
|
||||
cmdExec: cmdExec,
|
||||
}
|
||||
}
|
||||
|
||||
func (LogHook) DialHook(next redis.DialHook) redis.DialHook {
|
||||
func (l *LogHook) DialHook(next redis.DialHook) redis.DialHook {
|
||||
return func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||
return next(ctx, network, addr)
|
||||
}
|
||||
}
|
||||
func (LogHook) ProcessHook(next redis.ProcessHook) redis.ProcessHook {
|
||||
func (l *LogHook) ProcessHook(next redis.ProcessHook) redis.ProcessHook {
|
||||
return func(ctx context.Context, cmd redis.Cmder) error {
|
||||
log.Println(cmd.String())
|
||||
log.Println(cmd)
|
||||
if l.cmdExec != nil {
|
||||
l.cmdExec(cmd.String())
|
||||
}
|
||||
return next(ctx, cmd)
|
||||
}
|
||||
}
|
||||
func (LogHook) ProcessPipelineHook(next redis.ProcessPipelineHook) redis.ProcessPipelineHook {
|
||||
func (l *LogHook) ProcessPipelineHook(next redis.ProcessPipelineHook) redis.ProcessPipelineHook {
|
||||
return func(ctx context.Context, cmds []redis.Cmder) error {
|
||||
for _, cmd := range cmds {
|
||||
log.Println(cmd.String())
|
||||
log.Println("pipeline: ", cmd)
|
||||
if l.cmdExec != nil {
|
||||
l.cmdExec(cmd.String())
|
||||
}
|
||||
}
|
||||
return next(ctx, cmds)
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import ContentServerPane from './components/content/ContentServerPane.vue'
|
|||
import useTabStore from './stores/tab.js'
|
||||
import usePreferencesStore from './stores/preferences.js'
|
||||
import useConnectionStore from './stores/connections.js'
|
||||
import ContentLogPane from './components/content/ContentLogPane.vue'
|
||||
|
||||
const themeVars = useThemeVars()
|
||||
|
||||
|
@ -60,8 +61,8 @@ const dragging = computed(() => {
|
|||
<!-- app content-->
|
||||
<div id="app-content-wrapper" :class="{ dragging }" class="flex-box-h" :style="prefStore.generalFont">
|
||||
<nav-menu v-model:value="tabStore.nav" :width="data.navMenuWidth" />
|
||||
<!-- structure page-->
|
||||
<div v-show="tabStore.nav === 'structure'" class="flex-box-h flex-item-expand">
|
||||
<!-- browser page-->
|
||||
<div v-show="tabStore.nav === 'browser'" class="flex-box-h flex-item-expand">
|
||||
<div id="app-side" :style="{ width: asideWidthVal }" class="flex-box-h flex-item">
|
||||
<browser-pane
|
||||
v-for="t in tabStore.tabs"
|
||||
|
@ -102,7 +103,11 @@ const dragging = computed(() => {
|
|||
</div>
|
||||
|
||||
<!-- log page -->
|
||||
<div v-show="tabStore.nav === 'log'">display log</div>
|
||||
<div v-if="tabStore.nav === 'log'" class="flex-box-h flex-item-expand">
|
||||
<keep-alive>
|
||||
<content-log-pane class="flex-item-expand" />
|
||||
</keep-alive>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -0,0 +1,116 @@
|
|||
<script setup>
|
||||
import { computed, nextTick, onActivated, reactive, ref } from 'vue'
|
||||
import IconButton from '../common/IconButton.vue'
|
||||
import Refresh from '../icons/Refresh.vue'
|
||||
import useConnectionStore from '../../stores/connections.js'
|
||||
import { map, uniqBy } from 'lodash'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
const connectionStore = useConnectionStore()
|
||||
const i18n = useI18n()
|
||||
const data = reactive({
|
||||
loading: false,
|
||||
server: '',
|
||||
keyword: '',
|
||||
history: [],
|
||||
})
|
||||
const filterServerOption = computed(() => {
|
||||
const serverSet = uniqBy(data.history, 'server')
|
||||
const options = map(serverSet, ({ server }) => ({
|
||||
label: server,
|
||||
value: server,
|
||||
}))
|
||||
options.splice(0, 0, {
|
||||
label: i18n.t('all'),
|
||||
value: '',
|
||||
})
|
||||
return options
|
||||
})
|
||||
|
||||
const tableRef = ref(null)
|
||||
|
||||
const loadHistory = () => {
|
||||
data.loading = true
|
||||
connectionStore
|
||||
.getCmdHistory()
|
||||
.then((list) => {
|
||||
data.history = list
|
||||
})
|
||||
.finally(() => {
|
||||
data.loading = false
|
||||
tableRef.value?.scrollTo({ top: 999999 })
|
||||
})
|
||||
}
|
||||
onActivated(() => {
|
||||
nextTick().then(loadHistory)
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<n-card
|
||||
:title="$t('launch_log')"
|
||||
class="content-container flex-box-v"
|
||||
content-style="display: flex;flex-direction: column; overflow: hidden;"
|
||||
>
|
||||
<n-form inline :disabled="data.loading" class="flex-item">
|
||||
<n-form-item :label="$t('filter_server')">
|
||||
<n-select
|
||||
style="min-width: 100px"
|
||||
v-model:value="data.server"
|
||||
:options="filterServerOption"
|
||||
:consistent-menu-width="false"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item :label="$t('filter_keyword')">
|
||||
<n-input v-model:value="data.keyword" placeholder="" clearable />
|
||||
</n-form-item>
|
||||
<n-form-item>
|
||||
<icon-button :icon="Refresh" border t-tooltip="refresh" @click="loadHistory" />
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
<div class="fill-height flex-box-h" style="user-select: text">
|
||||
<n-data-table
|
||||
ref="tableRef"
|
||||
class="flex-item-expand"
|
||||
:columns="[
|
||||
{
|
||||
title: $t('exec_time'),
|
||||
key: 'time',
|
||||
defaultSortOrder: 'ascend',
|
||||
sorter: 'default',
|
||||
width: 180,
|
||||
},
|
||||
{
|
||||
title: $t('server'),
|
||||
key: 'server',
|
||||
filterOptionValue: data.server,
|
||||
filter(value, row) {
|
||||
return value === '' || row.server === value.toString()
|
||||
},
|
||||
width: 150,
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: $t('cmd'),
|
||||
key: 'cmd',
|
||||
filterOptionValue: data.keyword,
|
||||
filter(value, row) {
|
||||
return value === '' || !!~row.cmd.indexOf(value.toString())
|
||||
},
|
||||
},
|
||||
]"
|
||||
:data="data.history"
|
||||
flex-height
|
||||
/>
|
||||
</div>
|
||||
</n-card>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import 'content';
|
||||
|
||||
.content-container {
|
||||
padding: 5px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
</style>
|
|
@ -63,7 +63,7 @@ const tab = computed(() =>
|
|||
watch(
|
||||
() => tabStore.nav,
|
||||
(nav) => {
|
||||
if (nav === 'structure') {
|
||||
if (nav === 'browser') {
|
||||
refreshInfo()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
<script setup>
|
||||
import { get, map, mapValues, pickBy, split, sum, toArray, toNumber } from 'lodash'
|
||||
import { computed, reactive, ref } from 'vue'
|
||||
import { computed, ref } from 'vue'
|
||||
import Help from '../icons/Help.vue'
|
||||
import IconButton from '../common/IconButton.vue'
|
||||
import Filter from '../icons/Filter.vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import Refresh from '../icons/Refresh.vue'
|
||||
|
||||
const props = defineProps({
|
||||
|
@ -70,26 +69,7 @@ const totalKeys = computed(() => {
|
|||
return sum(toArray(nums))
|
||||
})
|
||||
const infoList = computed(() => map(props.info, (value, key) => ({ value, key })))
|
||||
|
||||
const i18n = useI18n()
|
||||
const infoColumns = [
|
||||
reactive({
|
||||
title: i18n.t('key'),
|
||||
key: 'key',
|
||||
defaultSortOrder: 'ascend',
|
||||
sorter: 'default',
|
||||
minWidth: 100,
|
||||
filterOptionValue: null,
|
||||
filter(value, row) {
|
||||
return !!~row.key.indexOf(value.toString())
|
||||
},
|
||||
}),
|
||||
{ title: i18n.t('value'), key: 'value' },
|
||||
]
|
||||
const infoFilter = ref('')
|
||||
const onFilterInfo = (val) => {
|
||||
infoColumns[0].filterOptionValue = val
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -165,13 +145,29 @@ const onFilterInfo = (val) => {
|
|||
</n-card>
|
||||
<n-card :title="$t('all_info')">
|
||||
<template #header-extra>
|
||||
<n-input v-model:value="infoFilter" @update:value="onFilterInfo" placeholder="" clearable>
|
||||
<n-input v-model:value="infoFilter" placeholder="" clearable>
|
||||
<template #prefix>
|
||||
<icon-button :icon="Filter" size="18" />
|
||||
</template>
|
||||
</n-input>
|
||||
</template>
|
||||
<n-data-table :columns="infoColumns" :data="infoList" />
|
||||
<n-data-table
|
||||
:columns="[
|
||||
{
|
||||
title: $t('key'),
|
||||
key: 'key',
|
||||
defaultSortOrder: 'ascend',
|
||||
sorter: 'default',
|
||||
minWidth: 100,
|
||||
filterOptionValue: infoFilter,
|
||||
filter(value, row) {
|
||||
return !!~row.key.indexOf(value.toString())
|
||||
},
|
||||
},
|
||||
{ title: $t('value'), key: 'value' },
|
||||
]"
|
||||
:data="infoList"
|
||||
/>
|
||||
</n-card>
|
||||
</n-space>
|
||||
</n-scrollbar>
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
import { reactive, ref, watch } from 'vue'
|
||||
import useDialog from '../../stores/dialog'
|
||||
import useTabStore from '../../stores/tab.js'
|
||||
import { useMessage } from 'naive-ui'
|
||||
import useConnectionStore from '../../stores/connections.js'
|
||||
|
||||
const ttlForm = reactive({
|
||||
|
@ -42,7 +41,6 @@ const onClose = () => {
|
|||
dialogStore.closeTTLDialog()
|
||||
}
|
||||
|
||||
const message = useMessage()
|
||||
const onConfirm = async () => {
|
||||
try {
|
||||
const tab = tabStore.currentTab
|
||||
|
|
|
@ -23,7 +23,7 @@ const props = defineProps({
|
|||
:stroke="props.fillColor"
|
||||
:stroke-width="props.strokeWidth"
|
||||
d="M41 4H7C5.34315 4 4 5.34315 4 7V41C4 42.6569 5.34315 44 7 44H41C42.6569 44 44 42.6569 44 41V7C44 5.34315 42.6569 4 41 4Z"
|
||||
fill="#dc423c"
|
||||
:fill="props.fillColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
import useDialogStore from '../../stores/dialog.js'
|
||||
import { h, nextTick, reactive, ref, watch } from 'vue'
|
||||
import useConnectionStore from '../../stores/connections.js'
|
||||
import { NIcon, useDialog, useMessage } from 'naive-ui'
|
||||
import { NIcon, useDialog, useMessage, useThemeVars } from 'naive-ui'
|
||||
import { ConnectionType } from '../../consts/connection_type.js'
|
||||
import ToggleFolder from '../icons/ToggleFolder.vue'
|
||||
import ToggleServer from '../icons/ToggleServer.vue'
|
||||
|
@ -17,6 +17,7 @@ import useTabStore from '../../stores/tab.js'
|
|||
import Edit from '../icons/Edit.vue'
|
||||
import { useConfirmDialog } from '../../utils/confirm_dialog.js'
|
||||
|
||||
const themeVars = useThemeVars()
|
||||
const i18n = useI18n()
|
||||
const openingConnection = ref(false)
|
||||
const connectionStore = useConnectionStore()
|
||||
|
|
|
@ -38,8 +38,8 @@ const i18n = useI18n()
|
|||
const menuOptions = computed(() => {
|
||||
return [
|
||||
{
|
||||
label: i18n.t('structure'),
|
||||
key: 'structure',
|
||||
label: i18n.t('browser'),
|
||||
key: 'browser',
|
||||
icon: renderIcon(ToggleDb),
|
||||
show: connectionStore.anyConnectionOpened,
|
||||
},
|
||||
|
|
|
@ -127,7 +127,7 @@
|
|||
"empty_server_content": "Connect server from left list",
|
||||
"reload_when_succ": "Reload immediately after success",
|
||||
"server": "Server",
|
||||
"structure": "Structure",
|
||||
"browser": "Browser",
|
||||
"log": "Log",
|
||||
"about": "About",
|
||||
"help": "Help",
|
||||
|
@ -141,5 +141,11 @@
|
|||
"unit_day": "D",
|
||||
"unit_hour": "H",
|
||||
"unit_minute": "M",
|
||||
"all_info": "All Info"
|
||||
"all_info": "All Info",
|
||||
"all": "All",
|
||||
"launch_log": "Launch Log",
|
||||
"filter_server": "Filter Server",
|
||||
"filter_keyword": "Filter Keyword",
|
||||
"exec_time": "Exec Time",
|
||||
"cmd": "Command"
|
||||
}
|
||||
|
|
|
@ -130,7 +130,7 @@
|
|||
"empty_server_content": "可以从左边选择并打开连接",
|
||||
"reload_when_succ": "操作成功后立即重新加载",
|
||||
"server": "服务器",
|
||||
"structure": "结构",
|
||||
"browser": "浏览器",
|
||||
"log": "日志",
|
||||
"about": "关于",
|
||||
"help": "帮助",
|
||||
|
@ -144,5 +144,11 @@
|
|||
"unit_day": "天",
|
||||
"unit_hour": "小时",
|
||||
"unit_minute": "分钟",
|
||||
"all_info": "所有信息"
|
||||
"all_info": "所有信息",
|
||||
"all": "所有",
|
||||
"launch_log": "运行日志",
|
||||
"filter_server": "筛选服务器",
|
||||
"filter_keyword": "筛选关键字",
|
||||
"exec_time": "执行时间",
|
||||
"cmd": "命令"
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import {
|
|||
DeleteConnection,
|
||||
DeleteGroup,
|
||||
DeleteKey,
|
||||
GetCmdHistory,
|
||||
GetConnection,
|
||||
GetKeyValue,
|
||||
ListConnection,
|
||||
|
@ -64,6 +65,13 @@ const useConnectionStore = defineStore('connections', {
|
|||
* @property {Object.<string, Map<string, DatabaseItem>>} nodeMap key format likes 'server#db', children key format likes 'key#type'
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} HistoryItem
|
||||
* @property {string} time
|
||||
* @property {string} server
|
||||
* @property {string} cmd
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @returns {ConnectionState}
|
||||
|
@ -1149,6 +1157,26 @@ const useConnectionStore = defineStore('connections', {
|
|||
return { success: false, msg }
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* get command history
|
||||
* @param {number} [pageNo]
|
||||
* @param {number} [pageSize]
|
||||
* @returns {Promise<HistoryItem[]>}
|
||||
*/
|
||||
async getCmdHistory(pageNo, pageSize) {
|
||||
if (pageNo === undefined || pageSize === undefined) {
|
||||
pageNo = -1
|
||||
pageSize = -1
|
||||
}
|
||||
try {
|
||||
const { success, data = { list: [] } } = await GetCmdHistory(pageNo, pageSize)
|
||||
const { list } = data
|
||||
return list
|
||||
} catch {
|
||||
return []
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
|
|
|
@ -74,7 +74,7 @@ const useTabStore = defineStore('tab', {
|
|||
_setActivatedIndex(idx, switchNav) {
|
||||
this.activatedIndex = idx
|
||||
if (switchNav === true) {
|
||||
this.nav = idx >= 0 ? 'structure' : 'server'
|
||||
this.nav = idx >= 0 ? 'browser' : 'server'
|
||||
} else {
|
||||
if (idx < 0) {
|
||||
this.nav = 'server'
|
||||
|
|
Loading…
Reference in New Issue