feat: 完成 mysql、redis 配置文件修改

This commit is contained in:
ssongliu 2022-11-02 18:30:22 +08:00 committed by ssongliu
parent b3bc8769b3
commit bfe2b95334
13 changed files with 357 additions and 206 deletions

View File

@ -1,7 +1,10 @@
package v1
import (
"bufio"
"errors"
"fmt"
"os"
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
"github.com/1Panel-dev/1Panel/backend/app/dto"
@ -61,6 +64,32 @@ func (b *BaseApi) UpdateMysqlVariables(c *gin.Context) {
helper.SuccessWithData(c, nil)
}
func (b *BaseApi) UpdateMysqlConfByFile(c *gin.Context) {
var req dto.MysqlConfUpdateByFile
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
mysqlInfo, err := mysqlService.LoadBaseInfo(req.MysqlName)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
path := fmt.Sprintf("/opt/1Panel/data/apps/%s/%s/conf/my.cnf", mysqlInfo.MysqlKey, mysqlInfo.Name)
file, err := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0640)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
defer file.Close()
write := bufio.NewWriter(file)
_, _ = write.WriteString(req.File)
write.Flush()
helper.SuccessWithData(c, nil)
}
func (b *BaseApi) SearchMysql(c *gin.Context) {
var req dto.SearchDBWithPage
if err := c.ShouldBindJSON(&req); err != nil {

View File

@ -1,8 +1,10 @@
package v1
import (
"bufio"
"context"
"fmt"
"os"
"strconv"
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
@ -63,6 +65,31 @@ func (b *BaseApi) UpdateRedisConf(c *gin.Context) {
helper.SuccessWithData(c, nil)
}
func (b *BaseApi) UpdateRedisConfByFile(c *gin.Context) {
var req dto.RedisConfUpdateByFile
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
redisInfo, err := redisService.LoadConf()
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
path := fmt.Sprintf("/opt/1Panel/data/apps/redis/%s/conf/redis.conf", redisInfo.Name)
file, err := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0640)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
defer file.Close()
write := bufio.NewWriter(file)
_, _ = write.WriteString(req.File)
write.Flush()
helper.SuccessWithData(c, nil)
}
func (b *BaseApi) RedisExec(c *gin.Context) {
redisConf, err := redisService.LoadConf()
if err != nil {

View File

@ -99,6 +99,10 @@ type MysqlVariablesUpdate struct {
TableOpenCache int64 `json:"table_open_cache" validate:"required"`
MaxConnections int64 `json:"max_connections" validate:"required"`
}
type MysqlConfUpdateByFile struct {
MysqlName string `json:"mysqlName" validate:"required"`
File string `json:"file"`
}
type ChangeDBInfo struct {
ID uint `json:"id"`
@ -139,10 +143,14 @@ type RecoverDB struct {
// redis
type RedisConfUpdate struct {
RedisName string `json:"redisName" validate:"required"`
DB int `json:"db"`
ParamName string `json:"paramName" validate:"required"`
Value string `json:"value"`
Timeout string `json:"timeout"`
Maxclients string `json:"maxclients"`
Databases string `json:"databases"`
Requirepass string `json:"requirepass"`
Maxmemory string `json:"maxmemory"`
}
type RedisConfUpdateByFile struct {
File string `json:"file"`
}
type RedisConf struct {

View File

@ -1,8 +1,11 @@
package service
import (
"bufio"
"encoding/json"
"fmt"
"io"
"os"
"strings"
"github.com/1Panel-dev/1Panel/backend/app/dto"
@ -41,17 +44,44 @@ func newRedisClient() (*redis.Client, error) {
}
func (u *RedisService) UpdateConf(req dto.RedisConfUpdate) error {
client, err := newRedisClient()
redisInfo, err := mysqlRepo.LoadRedisBaseInfo()
if err != nil {
return err
}
if _, err := client.ConfigSet(req.ParamName, req.Value).Result(); err != nil {
return err
}
if _, err := client.ConfigRewrite().Result(); err != nil {
file, err := os.OpenFile(fmt.Sprintf("/opt/1Panel/data/apps/redis/%s/conf/redis.conf", redisInfo.Name), os.O_RDWR, 0666)
if err != nil {
return err
}
defer file.Close()
reader := bufio.NewReader(file)
pos := int64(0)
for {
line, err := reader.ReadString('\n')
if err != nil {
if err == io.EOF {
break
} else {
return err
}
}
if bytes := updateConfFile(line, "timeout", req.Timeout); len(bytes) != 0 {
_, _ = file.WriteAt(bytes, pos)
}
if bytes := updateConfFile(line, "maxclients", req.Maxclients); len(bytes) != 0 {
_, _ = file.WriteAt(bytes, pos)
}
if bytes := updateConfFile(line, "databases", req.Databases); len(bytes) != 0 {
_, _ = file.WriteAt(bytes, pos)
}
if bytes := updateConfFile(line, "requirepass", req.Requirepass); len(bytes) != 0 {
_, _ = file.WriteAt(bytes, pos)
}
if bytes := updateConfFile(line, "maxmemory", req.Maxmemory); len(bytes) != 0 {
_, _ = file.WriteAt(bytes, pos)
}
pos += int64(len(line))
}
return nil
}
@ -129,3 +159,16 @@ func configGetStr(client *redis.Client, param string) string {
}
return ""
}
func updateConfFile(line, param string, value string) []byte {
var bytes []byte
if strings.HasPrefix(line, param) || strings.HasPrefix(line, "# "+param) {
if len(value) == 0 || value == "0" {
bytes = []byte(fmt.Sprintf("# %s", param))
} else {
bytes = []byte(fmt.Sprintf("%s %v", param, value))
}
return bytes
}
return bytes
}

View File

@ -28,6 +28,7 @@ func (s *DatabaseRouter) InitDatabaseRouter(Router *gin.RouterGroup) {
withRecordRouter.POST("/backups/search", baseApi.SearchDBBackups)
withRecordRouter.POST("/del", baseApi.DeleteMysql)
withRecordRouter.POST("/variables/update", baseApi.UpdateMysqlVariables)
withRecordRouter.POST("/conf/update/byfile", baseApi.UpdateMysqlConfByFile)
cmdRouter.POST("/search", baseApi.SearchMysql)
cmdRouter.GET("/variables/:name", baseApi.LoadVariables)
cmdRouter.GET("/status/:name", baseApi.LoadStatus)
@ -39,5 +40,7 @@ func (s *DatabaseRouter) InitDatabaseRouter(Router *gin.RouterGroup) {
cmdRouter.GET("/redis/status", baseApi.LoadRedisStatus)
cmdRouter.GET("/redis/conf", baseApi.LoadRedisConf)
cmdRouter.GET("/redis/exec", baseApi.RedisExec)
cmdRouter.POST("/redis/conf/update", baseApi.UpdateRedisConf)
cmdRouter.POST("/redis/conf/update/byfile", baseApi.UpdateRedisConfByFile)
}
}

View File

@ -34,6 +34,10 @@ export namespace Database {
remoteConn: boolean;
mysqlKey: string;
}
export interface MysqlConfUpdateByFile {
mysqlName: string;
file: string;
}
export interface MysqlDBCreate {
name: string;
mysqlName: string;
@ -106,10 +110,14 @@ export namespace Database {
// redis
export interface RedisConfUpdate {
redisName: string;
db: number;
paramName: string;
value: string;
timeout: string;
maxclients: string;
databases: string;
requirepass: string;
maxmemory: string;
}
export interface RedisConfUpdateByFile {
file: string;
}
export interface RedisStatus {
tcp_port: string;

View File

@ -29,6 +29,9 @@ export const updateMysqlDBInfo = (params: Database.ChangeInfo) => {
export const updateMysqlVariables = (params: Database.MysqlVariables) => {
return http.post(`/databases/variables/update`, params);
};
export const updateMysqlConfByFile = (params: Database.MysqlConfUpdateByFile) => {
return http.post(`/databases/conf/update/byfile`, params);
};
export const deleteMysqlDB = (params: { ids: number[] }) => {
return http.post(`/databases/del`, params);
};
@ -57,5 +60,8 @@ export const RedisPersistenceConf = () => {
return http.get<Database.RedisPersistenceConf>(`/databases/redis/persistence/conf`);
};
export const updateRedisConf = (params: Database.RedisConfUpdate) => {
return http.get(`/databases/redis/conf/update`, params);
return http.post(`/databases/redis/conf/update`, params);
};
export const updateRedisConfByFile = (params: Database.RedisConfUpdateByFile) => {
return http.post(`/databases/redis/conf/update/byfile`, params);
};

View File

@ -65,11 +65,7 @@
v-model="mysqlConf"
:readOnly="true"
/>
<el-button
type="primary"
style="width: 120px; margin-top: 10px"
@click="onSave(panelFormRef, 'remoteAccess', baseInfo.port)"
>
<el-button type="primary" style="width: 120px; margin-top: 10px" @click="onSaveFile()">
{{ $t('commons.button.save') }}
</el-button>
</el-collapse-item>
@ -324,6 +320,7 @@ import {
loadMysqlBaseInfo,
loadMysqlStatus,
loadMysqlVariables,
updateMysqlConfByFile,
updateMysqlDBInfo,
updateMysqlVariables,
} from '@/api/modules/database';
@ -447,6 +444,15 @@ function callback(error: any) {
}
}
const onSaveFile = async () => {
let param = {
mysqlName: mysqlName.value,
file: mysqlConf.value,
};
await updateMysqlConfByFile(param);
ElMessage.success(i18n.global.t('commons.msg.operationSuccess'));
};
const loadBaseInfo = async () => {
const res = await loadMysqlBaseInfo(mysqlName.value);
baseInfo.name = res.data?.name;

View File

@ -14,11 +14,10 @@
{{ $t('database.terminal') }}
</el-button>
<el-card style="height: calc(100vh - 178px); margin-top: 5px">
<Status ref="statusRef"></Status>
<Setting ref="settingRef"></Setting>
<Terminal ref="terminalRef"></Terminal>
</el-card>
<Status ref="statusRef"></Status>
<Setting ref="settingRef"></Setting>
<Persistence ref="persistenceRef"></Persistence>
<Terminal ref="terminalRef"></Terminal>
</div>
</template>
@ -26,11 +25,13 @@
import Submenu from '@/views/database/index.vue';
import Status from '@/views/database/redis/status/index.vue';
import Setting from '@/views/database/redis/setting/index.vue';
import Persistence from '@/views/database/redis/persistence/index.vue';
import Terminal from '@/views/database/redis/terminal/index.vue';
import { onMounted, ref } from 'vue';
const statusRef = ref();
const settingRef = ref();
const persistenceRef = ref();
const terminalRef = ref();
const changeView = async (params: string) => {
@ -38,16 +39,25 @@ const changeView = async (params: string) => {
case 'status':
settingRef.value!.onClose();
terminalRef.value!.onClose();
persistenceRef.value!.onClose();
statusRef.value!.acceptParams(params);
break;
case 'setting':
statusRef.value!.onClose();
terminalRef.value!.onClose();
persistenceRef.value!.onClose();
settingRef.value!.acceptParams(params);
break;
case 'persistence':
statusRef.value!.onClose();
settingRef.value!.onClose();
terminalRef.value!.onClose();
persistenceRef.value!.acceptParams(params);
break;
case 'terminal':
statusRef.value!.onClose();
settingRef.value!.onClose();
persistenceRef.value!.onClose();
terminalRef.value!.acceptParams(params);
break;
}

View File

@ -1,24 +1,26 @@
<template>
<div v-if="persistenceShow">
<el-form :model="form" ref="formRef" :rules="rules" label-width="120px">
<el-row>
<el-col :span="1"><br /></el-col>
<el-col :span="10">
<el-form>
<el-form-item label="appendonly" prop="appendonly">
<el-switch v-model="form.appendonly"></el-switch>
</el-form-item>
<el-form-item label="appendfsync" prop="appendfsync">
<el-radio-group v-model="form.appendfsync">
<el-radio label="always">always</el-radio>
<el-radio label="everysec">everysec</el-radio>
<el-radio label="no">no</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
</el-col>
</el-row>
</el-form>
<el-card style="margin-top: 5px">
<el-form :model="form" ref="formRef" :rules="rules" label-width="120px">
<el-row>
<el-col :span="1"><br /></el-col>
<el-col :span="10">
<el-form>
<el-form-item label="appendonly" prop="appendonly">
<el-switch v-model="form.appendonly"></el-switch>
</el-form-item>
<el-form-item label="appendfsync" prop="appendfsync">
<el-radio-group v-model="form.appendfsync">
<el-radio label="always">always</el-radio>
<el-radio label="everysec">everysec</el-radio>
<el-radio label="no">no</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
</el-col>
</el-row>
</el-form>
</el-card>
</div>
</template>

View File

@ -1,79 +1,81 @@
<template>
<div v-if="settingShow">
<el-radio-group v-model="confShowType">
<el-radio-button label="base">基础配置</el-radio-button>
<el-radio-button label="all">全部配置</el-radio-button>
</el-radio-group>
<el-form v-if="confShowType === 'base'" :model="baseInfo" ref="panelFormRef" :rules="rules" label-width="120px">
<el-row style="margin-top: 20px">
<el-col :span="1"><br /></el-col>
<el-col :span="10">
<el-form-item :label="$t('setting.port')" prop="port">
<el-input clearable type="number" v-model.number="baseInfo.port" />
</el-form-item>
<el-form-item :label="$t('setting.password')" prop="requirepass">
<el-input type="password" show-password clearable v-model="baseInfo.requirepass" />
<span class="input-help">{{ $t('database.requirepassHelper') }}</span>
</el-form-item>
<el-form-item :label="$t('database.timeout')" prop="timeout">
<el-input clearable type="number" v-model.number="baseInfo.timeout" />
<span class="input-help">{{ $t('database.timeoutHelper') }}</span>
</el-form-item>
<el-form-item :label="$t('database.maxclients')" prop="maxclients">
<el-input clearable type="number" v-model.number="baseInfo.maxclients" />
</el-form-item>
<el-form-item :label="$t('database.databases')" prop="databases">
<el-input clearable type="number" v-model.number="baseInfo.databases" />
</el-form-item>
<el-form-item :label="$t('database.maxmemory')" prop="maxmemory">
<el-input clearable type="number" v-model.number="baseInfo.maxmemory" />
<span class="input-help">{{ $t('database.maxmemoryHelper') }}</span>
</el-form-item>
<el-form-item>
<el-button type="primary" size="default" style="width: 90px">
{{ $t('commons.button.save') }}
</el-button>
</el-form-item>
</el-col>
</el-row>
</el-form>
<div v-if="confShowType === 'all'">
<codemirror
:autofocus="true"
placeholder="None data"
:indent-with-tab="true"
:tabSize="4"
style="margin-top: 10px; height: calc(100vh - 280px)"
:lineWrapping="true"
:matchBrackets="true"
theme="cobalt"
:styleActiveLine="true"
:extensions="extensions"
v-model="mysqlConf"
:readOnly="true"
/>
<el-button type="primary" size="default" style="width: 90px; margin-top: 5px">
{{ $t('commons.button.save') }}
</el-button>
</div>
<el-card style="margin-top: 5px">
<el-radio-group v-model="confShowType">
<el-radio-button label="base">基础配置</el-radio-button>
<el-radio-button label="all">全部配置</el-radio-button>
</el-radio-group>
<el-form v-if="confShowType === 'base'" :model="form" ref="formRef" :rules="rules" label-width="120px">
<el-row style="margin-top: 20px">
<el-col :span="1"><br /></el-col>
<el-col :span="10">
<el-form-item :label="$t('setting.port')" prop="port">
<el-input clearable type="number" v-model.number="form.port" />
</el-form-item>
<el-form-item :label="$t('setting.password')" prop="requirepass">
<el-input type="password" show-password clearable v-model="form.requirepass" />
<span class="input-help">{{ $t('database.requirepassHelper') }}</span>
</el-form-item>
<el-form-item :label="$t('database.timeout')" prop="timeout">
<el-input clearable type="number" v-model.number="form.timeout" />
<span class="input-help">{{ $t('database.timeoutHelper') }}</span>
</el-form-item>
<el-form-item :label="$t('database.maxclients')" prop="maxclients">
<el-input clearable type="number" v-model.number="form.maxclients" />
</el-form-item>
<el-form-item :label="$t('database.databases')" prop="databases">
<el-input clearable type="number" v-model.number="form.databases" />
</el-form-item>
<el-form-item :label="$t('database.maxmemory')" prop="maxmemory">
<el-input clearable type="number" v-model.number="form.maxmemory" />
<span class="input-help">{{ $t('database.maxmemoryHelper') }}</span>
</el-form-item>
<el-form-item>
<el-button type="primary" size="default" @click="onSave(formRef)" style="width: 90px">
{{ $t('commons.button.save') }}
</el-button>
</el-form-item>
</el-col>
</el-row>
</el-form>
<div v-if="confShowType === 'all'">
<codemirror
:autofocus="true"
placeholder="None data"
:indent-with-tab="true"
:tabSize="4"
style="margin-top: 10px; height: calc(100vh - 280px)"
:lineWrapping="true"
:matchBrackets="true"
theme="cobalt"
:styleActiveLine="true"
:extensions="extensions"
v-model="mysqlConf"
:readOnly="true"
/>
<el-button type="primary" size="default" @click="onSaveFile" style="width: 90px; margin-top: 5px">
{{ $t('commons.button.save') }}
</el-button>
</div>
</el-card>
</div>
</template>
<script lang="ts" setup>
import { FormInstance } from 'element-plus';
import { ElMessage, FormInstance } from 'element-plus';
import { reactive, ref } from 'vue';
import { Codemirror } from 'vue-codemirror';
import { javascript } from '@codemirror/lang-javascript';
import { oneDark } from '@codemirror/theme-one-dark';
import { LoadFile } from '@/api/modules/files';
import { loadRedisConf } from '@/api/modules/database';
// import i18n from '@/lang';
import { loadRedisConf, updateRedisConf, updateRedisConfByFile } from '@/api/modules/database';
import i18n from '@/lang';
import { Rules } from '@/global/form-rules';
const extensions = [javascript(), oneDark];
const confShowType = ref('base');
const baseInfo = reactive({
const form = reactive({
name: '',
port: 3306,
requirepass: '',
@ -90,49 +92,52 @@ const rules = reactive({
maxmemory: [Rules.number],
});
const panelFormRef = ref<FormInstance>();
const formRef = ref<FormInstance>();
const mysqlConf = ref();
const settingShow = ref<boolean>(false);
const acceptParams = (): void => {
settingShow.value = true;
loadBaseInfo();
loadform();
};
const onClose = (): void => {
settingShow.value = false;
};
// const onSave = async (formEl: FormInstance | undefined, key: string) => {
// if (!formEl) return;
// const result = await formEl.validateField(key, callback);
// if (!result) {
// return;
// }
// // let changeForm = {
// // paramName: key,
// // value: val + '',
// // };
// // await updateRedisConf(changeForm);
// ElMessage.success(i18n.global.t('commons.msg.operationSuccess'));
// };
// function callback(error: any) {
// if (error) {
// return error.message;
// } else {
// return;
// }
// }
const onSave = async (formEl: FormInstance | undefined) => {
if (!formEl) return;
formEl.validate(async (valid) => {
if (!valid) return;
let param = {
timeout: form.timeout + '',
maxclients: form.maxclients + '',
databases: form.databases + '',
requirepass: form.requirepass,
maxmemory: form.maxmemory + '',
};
await updateRedisConf(param);
ElMessage.success(i18n.global.t('commons.msg.operationSuccess'));
});
};
const loadBaseInfo = async () => {
const onSaveFile = async () => {
let param = {
file: mysqlConf.value,
};
await updateRedisConfByFile(param);
ElMessage.success(i18n.global.t('commons.msg.operationSuccess'));
};
const loadform = async () => {
const res = await loadRedisConf();
baseInfo.name = res.data?.name;
baseInfo.timeout = Number(res.data?.timeout);
baseInfo.maxclients = Number(res.data?.maxclients);
baseInfo.databases = Number(res.data?.databases);
baseInfo.requirepass = res.data?.requirepass;
baseInfo.maxmemory = Number(res.data?.maxmemory);
loadMysqlConf(`/opt/1Panel/data/apps/redis/${baseInfo.name}/conf/redis.conf`);
form.name = res.data?.name;
form.timeout = Number(res.data?.timeout);
form.maxclients = Number(res.data?.maxclients);
form.databases = Number(res.data?.databases);
form.requirepass = res.data?.requirepass;
form.maxmemory = Number(res.data?.maxmemory);
loadMysqlConf(`/opt/1Panel/data/apps/redis/${form.name}/conf/redis.conf`);
};
const loadMysqlConf = async (path: string) => {

View File

@ -1,77 +1,79 @@
<template>
<div v-if="statusShow">
<el-row>
<el-col :span="1"><br /></el-col>
<el-col :span="12">
<table style="margin-top: 20px; width: 100%" class="myTable">
<tr>
<td>uptime_in_days</td>
<td>{{ redisStatus!.uptime_in_days }}</td>
<td>{{ $t('database.uptimeInDays') }}</td>
</tr>
<tr>
<td>tcp_port</td>
<td>{{ redisStatus!.tcp_port }}</td>
<td>{{ $t('database.tcpPort') }}</td>
</tr>
<tr>
<td>connected_clients</td>
<td>{{ redisStatus!.connected_clients }}</td>
<td>{{ $t('database.connectedClients') }}</td>
</tr>
<tr>
<td>used_memory_rss</td>
<td>{{ redisStatus!.used_memory_rss }}</td>
<td>{{ $t('database.usedMemoryRss') }}</td>
</tr>
<tr>
<td>used_memory</td>
<td>{{ redisStatus!.used_memory }}</td>
<td>{{ $t('database.usedMemory') }}</td>
</tr>
<tr>
<td>mem_fragmentation_ratio</td>
<td>{{ redisStatus!.mem_fragmentation_ratio }}</td>
<td>{{ $t('database.tmpTableToDBHelper') }}</td>
</tr>
<tr>
<td>total_connections_received</td>
<td>{{ redisStatus!.total_connections_received }}</td>
<td>{{ $t('database.totalConnectionsReceived') }}</td>
</tr>
<tr>
<td>total_commands_processed</td>
<td>{{ redisStatus!.total_commands_processed }}</td>
<td>{{ $t('database.totalCommandsProcessed') }}</td>
</tr>
<tr>
<td>instantaneous_ops_per_sec</td>
<td>{{ redisStatus!.instantaneous_ops_per_sec }}</td>
<td>{{ $t('database.instantaneousOpsPerSec') }}</td>
</tr>
<tr>
<td>keyspace_hits</td>
<td>{{ redisStatus!.keyspace_hits }}</td>
<td>{{ $t('database.keyspaceHits') }}</td>
</tr>
<tr>
<td>keyspace_misses</td>
<td>{{ redisStatus!.keyspace_misses }}</td>
<td>{{ $t('database.keyspaceMisses') }}</td>
</tr>
<tr>
<td>hit</td>
<td>{{ redisStatus!.hit }}</td>
<td>{{ $t('database.hit') }}</td>
</tr>
<tr>
<td>latest_fork_usec</td>
<td>{{ redisStatus!.latest_fork_usec }}</td>
<td>{{ $t('database.latestForkUsec') }}</td>
</tr>
</table>
</el-col>
</el-row>
<el-card style="margin-top: 5px">
<el-row>
<el-col :span="1"><br /></el-col>
<el-col :span="12">
<table style="margin-top: 20px; width: 100%" class="myTable">
<tr>
<td>uptime_in_days</td>
<td>{{ redisStatus!.uptime_in_days }}</td>
<td>{{ $t('database.uptimeInDays') }}</td>
</tr>
<tr>
<td>tcp_port</td>
<td>{{ redisStatus!.tcp_port }}</td>
<td>{{ $t('database.tcpPort') }}</td>
</tr>
<tr>
<td>connected_clients</td>
<td>{{ redisStatus!.connected_clients }}</td>
<td>{{ $t('database.connectedClients') }}</td>
</tr>
<tr>
<td>used_memory_rss</td>
<td>{{ redisStatus!.used_memory_rss }}</td>
<td>{{ $t('database.usedMemoryRss') }}</td>
</tr>
<tr>
<td>used_memory</td>
<td>{{ redisStatus!.used_memory }}</td>
<td>{{ $t('database.usedMemory') }}</td>
</tr>
<tr>
<td>mem_fragmentation_ratio</td>
<td>{{ redisStatus!.mem_fragmentation_ratio }}</td>
<td>{{ $t('database.tmpTableToDBHelper') }}</td>
</tr>
<tr>
<td>total_connections_received</td>
<td>{{ redisStatus!.total_connections_received }}</td>
<td>{{ $t('database.totalConnectionsReceived') }}</td>
</tr>
<tr>
<td>total_commands_processed</td>
<td>{{ redisStatus!.total_commands_processed }}</td>
<td>{{ $t('database.totalCommandsProcessed') }}</td>
</tr>
<tr>
<td>instantaneous_ops_per_sec</td>
<td>{{ redisStatus!.instantaneous_ops_per_sec }}</td>
<td>{{ $t('database.instantaneousOpsPerSec') }}</td>
</tr>
<tr>
<td>keyspace_hits</td>
<td>{{ redisStatus!.keyspace_hits }}</td>
<td>{{ $t('database.keyspaceHits') }}</td>
</tr>
<tr>
<td>keyspace_misses</td>
<td>{{ redisStatus!.keyspace_misses }}</td>
<td>{{ $t('database.keyspaceMisses') }}</td>
</tr>
<tr>
<td>hit</td>
<td>{{ redisStatus!.hit }}</td>
<td>{{ $t('database.hit') }}</td>
</tr>
<tr>
<td>latest_fork_usec</td>
<td>{{ redisStatus!.latest_fork_usec }}</td>
<td>{{ $t('database.latestForkUsec') }}</td>
</tr>
</table>
</el-col>
</el-row>
</el-card>
</div>
</template>

View File

@ -1,6 +1,8 @@
<template>
<div v-show="terminalShow" style="height: 100%">
<div style="height: calc(100vh - 220px)" :id="'terminal-exec'"></div>
<el-card style="margin-top: 5px">
<div style="height: calc(100vh - 220px)" :id="'terminal-exec'"></div>
</el-card>
</div>
</template>