mirror of
https://gitee.com/dromara/mayfly-go
synced 2025-11-03 16:00:25 +08:00
refactor: redis hash类型使用hscan获取数据
This commit is contained in:
@@ -107,11 +107,11 @@ const themeConfigModule: Module<ThemeConfigState, RootStateTypes> = {
|
||||
layout: 'classic',
|
||||
|
||||
// ssh终端字体颜色
|
||||
terminalForeground: '#d0d0d0',
|
||||
terminalForeground: '#c5c8c6',
|
||||
// ssh终端背景色
|
||||
terminalBackground: '#1c1c1c',
|
||||
terminalBackground: '#121212',
|
||||
// ssh终端cursor色
|
||||
terminalCursor: '#e4c9af',
|
||||
terminalCursor: '#f0cc09',
|
||||
terminalFontSize: 15,
|
||||
|
||||
|
||||
|
||||
@@ -65,9 +65,9 @@ export default defineComponent({
|
||||
// cursorStyle: 'underline', //光标样式
|
||||
disableStdin: false,
|
||||
theme: {
|
||||
foreground: getThemeConfig.value.terminalForeground || '#d0d0d0', //字体
|
||||
background: getThemeConfig.value.terminalBackground || '#1c1c1c', //背景色
|
||||
cursor: getThemeConfig.value.terminalCursor || '#e4c9af', //设置光标
|
||||
foreground: getThemeConfig.value.terminalForeground || '#c5c8c6', //字体
|
||||
background: getThemeConfig.value.terminalBackground || '#121212', //背景色
|
||||
cursor: getThemeConfig.value.terminalCursor || '#f0cc09', //设置光标
|
||||
} as any,
|
||||
});
|
||||
const fitAddon = new FitAddon();
|
||||
|
||||
@@ -1,313 +0,0 @@
|
||||
<template>
|
||||
<el-dialog :title="title" v-model="dialogVisible" :before-close="cancel" :show-close="false" width="750px" :destroy-on-close="true">
|
||||
<el-form label-width="85px">
|
||||
<el-form-item prop="key" label="key:">
|
||||
<el-input :disabled="operationType == 2" v-model="key.key"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="timed" label="过期时间:">
|
||||
<el-input v-model.number="key.timed" type="number"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="dataType" label="数据类型:">
|
||||
<el-select :disabled="operationType == 2" style="width: 100%" v-model="key.type" placeholder="请选择数据类型">
|
||||
<el-option key="string" label="string" value="string"> </el-option>
|
||||
<el-option key="hash" label="hash" value="hash"> </el-option>
|
||||
<el-option key="set" label="set" value="set"> </el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item v-if="key.type == 'string'" prop="value" label="内容:">
|
||||
<div id="string-value-text" style="width: 100%">
|
||||
<el-input class="json-text" v-model="string.value" type="textarea" :autosize="{ minRows: 10, maxRows: 20 }"></el-input>
|
||||
<el-select class="text-type-select" @change="onChangeTextType" v-model="string.type">
|
||||
<el-option key="text" label="text" value="text"> </el-option>
|
||||
<el-option key="json" label="json" value="json"> </el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
</el-form-item>
|
||||
|
||||
<span v-if="key.type == 'hash'">
|
||||
<el-button @click="onAddHashValue" icon="plus" size="small" plain class="mt10">添加</el-button>
|
||||
<el-table :data="hash.value" stripe style="width: 100%">
|
||||
<el-table-column prop="key" label="key" width>
|
||||
<template #default="scope">
|
||||
<el-input v-model="scope.row.key" clearable size="small"></el-input>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="value" label="value" min-width="200">
|
||||
<template #default="scope">
|
||||
<el-input
|
||||
v-model="scope.row.value"
|
||||
clearable
|
||||
type="textarea"
|
||||
:autosize="{ minRows: 2, maxRows: 10 }"
|
||||
size="small"
|
||||
></el-input>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="90">
|
||||
<template #default="scope">
|
||||
<el-button type="danger" @click="hash.value.splice(scope.$index, 1)" icon="delete" size="small" plain>删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</span>
|
||||
|
||||
<span v-if="key.type == 'set'">
|
||||
<el-button @click="onAddSetValue" icon="plus" size="small" plain class="mt10">添加</el-button>
|
||||
<el-table :data="set.value" stripe style="width: 100%">
|
||||
<el-table-column prop="value" label="value" min-width="200">
|
||||
<template #default="scope">
|
||||
<el-input
|
||||
v-model="scope.row.value"
|
||||
clearable
|
||||
type="textarea"
|
||||
:autosize="{ minRows: 2, maxRows: 10 }"
|
||||
size="small"
|
||||
></el-input>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="90">
|
||||
<template #default="scope">
|
||||
<el-button type="danger" @click="set.value.splice(scope.$index, 1)" icon="delete" size="small" plain>删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</span>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="cancel()">取 消</el-button>
|
||||
<el-button @click="saveValue" type="primary" v-auth="'redis:data:save'">确 定</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, reactive, watch, toRefs } from 'vue';
|
||||
import { redisApi } from './api';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { isTrue, notEmpty } from '@/common/assert';
|
||||
import { formatJsonString } from '@/common/utils/format';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'DateEdit',
|
||||
components: {},
|
||||
props: {
|
||||
visible: {
|
||||
type: Boolean,
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
},
|
||||
redisId: {
|
||||
type: [Number],
|
||||
require: true,
|
||||
},
|
||||
keyInfo: {
|
||||
type: [Object],
|
||||
},
|
||||
// 操作类型,1:新增,2:修改
|
||||
operationType: {
|
||||
type: [Number],
|
||||
},
|
||||
stringValue: {
|
||||
type: [String],
|
||||
},
|
||||
setValue: {
|
||||
type: [Array, Object],
|
||||
},
|
||||
hashValue: {
|
||||
type: [Array, Object],
|
||||
},
|
||||
},
|
||||
emits: ['valChange', 'cancel', 'update:visible'],
|
||||
setup(props: any, { emit }) {
|
||||
const state = reactive({
|
||||
dialogVisible: false,
|
||||
operationType: 1,
|
||||
redisId: '',
|
||||
key: {
|
||||
key: '',
|
||||
type: 'string',
|
||||
timed: -1,
|
||||
},
|
||||
string: {
|
||||
type: 'text',
|
||||
value: '',
|
||||
},
|
||||
hash: {
|
||||
value: [
|
||||
{
|
||||
key: '',
|
||||
value: '',
|
||||
},
|
||||
],
|
||||
},
|
||||
set: {
|
||||
value: [{ value: '' }],
|
||||
},
|
||||
});
|
||||
|
||||
const cancel = () => {
|
||||
emit('update:visible', false);
|
||||
emit('cancel');
|
||||
setTimeout(() => {
|
||||
state.key = {
|
||||
key: '',
|
||||
type: 'string',
|
||||
timed: -1,
|
||||
};
|
||||
state.string.value = '';
|
||||
state.string.type = 'text';
|
||||
state.hash.value = [
|
||||
{
|
||||
key: '',
|
||||
value: '',
|
||||
},
|
||||
];
|
||||
}, 500);
|
||||
};
|
||||
|
||||
watch(
|
||||
() => props.visible,
|
||||
(val) => {
|
||||
state.dialogVisible = val;
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => props.redisId,
|
||||
(val) => {
|
||||
state.redisId = val;
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => props.operationType,
|
||||
(val) => {
|
||||
state.operationType = val;
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => props.keyInfo,
|
||||
(val) => {
|
||||
if (val) {
|
||||
state.key = { ...val };
|
||||
}
|
||||
},
|
||||
{
|
||||
deep: true, // 深度监听的参数
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => props.stringValue,
|
||||
(val) => {
|
||||
if (val) {
|
||||
state.string.value = val;
|
||||
}
|
||||
},
|
||||
{
|
||||
deep: true, // 深度监听的参数
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => props.setValue,
|
||||
(val) => {
|
||||
if (val) {
|
||||
state.set.value = val;
|
||||
}
|
||||
},
|
||||
{
|
||||
deep: true, // 深度监听的参数
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => props.hashValue,
|
||||
(val) => {
|
||||
if (val) {
|
||||
state.hash.value = val;
|
||||
}
|
||||
},
|
||||
{
|
||||
deep: true, // 深度监听的参数
|
||||
}
|
||||
);
|
||||
|
||||
const saveValue = async () => {
|
||||
notEmpty(state.key.key, 'key不能为空');
|
||||
|
||||
if (state.key.type == 'string') {
|
||||
notEmpty(state.string.value, 'value不能为空');
|
||||
const sv = { value: formatJsonString(state.string.value, true), id: state.redisId };
|
||||
Object.assign(sv, state.key);
|
||||
await redisApi.saveStringValue.request(sv);
|
||||
}
|
||||
|
||||
if (state.key.type == 'hash') {
|
||||
isTrue(state.hash.value.length > 0, 'hash内容不能为空');
|
||||
const sv = { value: state.hash.value, id: state.redisId };
|
||||
Object.assign(sv, state.key);
|
||||
await redisApi.saveHashValue.request(sv);
|
||||
}
|
||||
|
||||
if (state.key.type == 'set') {
|
||||
isTrue(state.set.value.length > 0, 'set内容不能为空');
|
||||
const sv = { value: state.set.value.map((x) => x.value), id: state.redisId };
|
||||
Object.assign(sv, state.key);
|
||||
await redisApi.saveSetValue.request(sv);
|
||||
}
|
||||
|
||||
ElMessage.success('数据保存成功');
|
||||
cancel();
|
||||
emit('valChange');
|
||||
};
|
||||
|
||||
const onAddHashValue = () => {
|
||||
state.hash.value.push({ key: '', value: '' });
|
||||
};
|
||||
|
||||
const onAddSetValue = () => {
|
||||
state.set.value.push({ value: '' });
|
||||
};
|
||||
|
||||
// 更改文本类型
|
||||
const onChangeTextType = (val: string) => {
|
||||
if (val == 'json') {
|
||||
state.string.value = formatJsonString(state.string.value, false);
|
||||
return;
|
||||
}
|
||||
if (val == 'text') {
|
||||
state.string.value = formatJsonString(state.string.value, true);
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
...toRefs(state),
|
||||
saveValue,
|
||||
cancel,
|
||||
onAddHashValue,
|
||||
onAddSetValue,
|
||||
onChangeTextType,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<style lang="scss">
|
||||
#string-value-text {
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
position: relative;
|
||||
|
||||
.text-type-select {
|
||||
position: absolute;
|
||||
z-index: 2;
|
||||
right: 10px;
|
||||
top: 10px;
|
||||
max-width: 70px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -23,7 +23,7 @@
|
||||
<el-form class="search-form" label-position="right" :inline="true" label-width="60px">
|
||||
<el-form-item label="key" label-width="40px">
|
||||
<el-input
|
||||
placeholder="支持*模糊key"
|
||||
placeholder="match 支持*模糊key"
|
||||
style="width: 240px"
|
||||
v-model="scanParam.match"
|
||||
@clear="clear()"
|
||||
@@ -36,7 +36,14 @@
|
||||
<el-form-item>
|
||||
<el-button @click="searchKey()" type="success" icon="search" plain></el-button>
|
||||
<el-button @click="scan()" icon="bottom" plain>scan</el-button>
|
||||
<el-button type="primary" icon="plus" @click="onAddData(false)" plain></el-button>
|
||||
<el-popover placement="right" :width="200" trigger="click">
|
||||
<template #reference>
|
||||
<el-button type="primary" icon="plus" plain></el-button>
|
||||
</template>
|
||||
<el-tag @click="onAddData('string')" :color="getTypeColor('string')" style="cursor: pointer">string</el-tag>
|
||||
<el-tag @click="onAddData('hash')" :color="getTypeColor('hash')" class="ml5" style="cursor: pointer">hash</el-tag>
|
||||
<el-tag @click="onAddData('set')" :color="getTypeColor('set')" class="ml5" style="cursor: pointer">set</el-tag>
|
||||
</el-popover>
|
||||
</el-form-item>
|
||||
<div style="float: right">
|
||||
<span>keys: {{ dbsize }}</span>
|
||||
@@ -69,17 +76,32 @@
|
||||
|
||||
<div style="text-align: center; margin-top: 10px"></div>
|
||||
|
||||
<!-- <value-dialog v-model:visible="valueDialog.visible" :keyValue="valueDialog.value" /> -->
|
||||
<hash-value
|
||||
v-model:visible="hashValueDialog.visible"
|
||||
:operationType="dataEdit.operationType"
|
||||
:title="dataEdit.title"
|
||||
:keyInfo="dataEdit.keyInfo"
|
||||
:redisId="scanParam.id"
|
||||
@cancel="onCancelDataEdit"
|
||||
@valChange="searchKey"
|
||||
/>
|
||||
|
||||
<data-edit
|
||||
v-model:visible="dataEdit.visible"
|
||||
<string-value
|
||||
v-model:visible="stringValueDialog.visible"
|
||||
:operationType="dataEdit.operationType"
|
||||
:title="dataEdit.title"
|
||||
:keyInfo="dataEdit.keyInfo"
|
||||
:redisId="scanParam.id"
|
||||
@cancel="onCancelDataEdit"
|
||||
@valChange="searchKey"
|
||||
/>
|
||||
|
||||
<set-value
|
||||
v-model:visible="setValueDialog.visible"
|
||||
:title="dataEdit.title"
|
||||
:keyInfo="dataEdit.keyInfo"
|
||||
:redisId="scanParam.id"
|
||||
:operationType="dataEdit.operationType"
|
||||
:stringValue="dataEdit.stringValue"
|
||||
:setValue="dataEdit.setValue"
|
||||
:hashValue="dataEdit.hashValue"
|
||||
@valChange="searchKey"
|
||||
@cancel="onCancelDataEdit"
|
||||
/>
|
||||
@@ -91,13 +113,17 @@ import { redisApi } from './api';
|
||||
import { toRefs, reactive, defineComponent } from 'vue';
|
||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||
import ProjectEnvSelect from '../component/ProjectEnvSelect.vue';
|
||||
import DataEdit from './DataEdit.vue';
|
||||
import HashValue from './HashValue.vue';
|
||||
import StringValue from './StringValue.vue';
|
||||
import SetValue from './SetValue.vue';
|
||||
import { isTrue, notBlank, notNull } from '@/common/assert';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'DataOperation',
|
||||
components: {
|
||||
DataEdit,
|
||||
StringValue,
|
||||
HashValue,
|
||||
SetValue,
|
||||
ProjectEnvSelect,
|
||||
},
|
||||
setup() {
|
||||
@@ -113,10 +139,6 @@ export default defineComponent({
|
||||
count: 10,
|
||||
cursor: {},
|
||||
},
|
||||
valueDialog: {
|
||||
visible: false,
|
||||
value: {},
|
||||
},
|
||||
dataEdit: {
|
||||
visible: false,
|
||||
title: '新增数据',
|
||||
@@ -126,9 +148,15 @@ export default defineComponent({
|
||||
timed: -1,
|
||||
key: '',
|
||||
},
|
||||
stringValue: '',
|
||||
hashValue: [{ key: '', value: '' }],
|
||||
setValue: [{ value: '' }],
|
||||
},
|
||||
hashValueDialog: {
|
||||
visible: false,
|
||||
},
|
||||
stringValueDialog: {
|
||||
visible: false,
|
||||
},
|
||||
setValueDialog: {
|
||||
visible: false,
|
||||
},
|
||||
keys: [],
|
||||
dbsize: 0,
|
||||
@@ -158,10 +186,15 @@ export default defineComponent({
|
||||
const scan = async () => {
|
||||
isTrue(state.scanParam.id != null, '请先选择redis');
|
||||
notBlank(state.scanParam.count, 'count不能为空');
|
||||
isTrue(state.scanParam.count < 20001, 'count不能超过20000');
|
||||
|
||||
const match = state.scanParam.match;
|
||||
if (!match || match == '*') {
|
||||
isTrue(state.scanParam.count <= 200, 'match为空或者*时, count不能超过200');
|
||||
} else {
|
||||
isTrue(state.scanParam.count <= 20000, 'count不能超过20000');
|
||||
}
|
||||
|
||||
state.loading = true;
|
||||
|
||||
try {
|
||||
const res = await redisApi.scan.request(state.scanParam);
|
||||
state.keys = res.keys;
|
||||
@@ -207,60 +240,43 @@ export default defineComponent({
|
||||
|
||||
const getValue = async (row: any) => {
|
||||
const type = row.type;
|
||||
const key = row.key;
|
||||
|
||||
let res: any;
|
||||
const reqParam = {
|
||||
key: row.key,
|
||||
id: state.scanParam.id,
|
||||
};
|
||||
switch (type) {
|
||||
case 'string':
|
||||
res = await redisApi.getStringValue.request(reqParam);
|
||||
break;
|
||||
case 'hash':
|
||||
res = await redisApi.getHashValue.request(reqParam);
|
||||
break;
|
||||
case 'set':
|
||||
res = await redisApi.getSetValue.request(reqParam);
|
||||
break;
|
||||
default:
|
||||
res = null;
|
||||
break;
|
||||
}
|
||||
notNull(res, '暂不支持该类型数据查看');
|
||||
|
||||
if (type == 'string') {
|
||||
state.dataEdit.stringValue = res;
|
||||
}
|
||||
if (type == 'set') {
|
||||
state.dataEdit.setValue = res.map((x: any) => {
|
||||
return {
|
||||
value: x,
|
||||
};
|
||||
});
|
||||
}
|
||||
if (type == 'hash') {
|
||||
const hash = [];
|
||||
//遍历key和value
|
||||
const keys = Object.keys(res);
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
const key = keys[i];
|
||||
const value = res[key];
|
||||
hash.push({
|
||||
key,
|
||||
value,
|
||||
});
|
||||
}
|
||||
state.dataEdit.hashValue = hash;
|
||||
}
|
||||
|
||||
state.dataEdit.keyInfo.type = type;
|
||||
state.dataEdit.keyInfo.timed = row.ttl;
|
||||
state.dataEdit.keyInfo.key = key;
|
||||
state.dataEdit.keyInfo.key = row.key;
|
||||
state.dataEdit.operationType = 2;
|
||||
state.dataEdit.title = '修改数据';
|
||||
state.dataEdit.visible = true;
|
||||
state.dataEdit.title = '查看数据';
|
||||
|
||||
if (type == 'hash') {
|
||||
state.hashValueDialog.visible = true;
|
||||
} else if (type == 'string') {
|
||||
state.stringValueDialog.visible = true;
|
||||
} else if (type == 'set') {
|
||||
state.setValueDialog.visible = true;
|
||||
} else {
|
||||
ElMessage.warning('暂不支持该类型');
|
||||
}
|
||||
};
|
||||
|
||||
const onAddData = (type: string) => {
|
||||
notNull(state.scanParam.id, '请先选择redis');
|
||||
state.dataEdit.operationType = 1;
|
||||
state.dataEdit.title = '新增数据';
|
||||
state.dataEdit.keyInfo.type = type;
|
||||
state.dataEdit.keyInfo.timed = -1;
|
||||
if (type == 'hash') {
|
||||
state.hashValueDialog.visible = true;
|
||||
} else if (type == 'string') {
|
||||
state.stringValueDialog.visible = true;
|
||||
} else if (type == 'set') {
|
||||
state.setValueDialog.visible = true;
|
||||
} else {
|
||||
ElMessage.warning('暂不支持该类型');
|
||||
}
|
||||
};
|
||||
|
||||
const onCancelDataEdit = () => {
|
||||
state.dataEdit.keyInfo = {} as any;
|
||||
};
|
||||
|
||||
const del = (key: string) => {
|
||||
@@ -331,20 +347,6 @@ export default defineComponent({
|
||||
}
|
||||
};
|
||||
|
||||
const onAddData = () => {
|
||||
notNull(state.scanParam.id, '请先选择redis');
|
||||
state.dataEdit.operationType = 1;
|
||||
state.dataEdit.title = '新增数据';
|
||||
state.dataEdit.visible = true;
|
||||
};
|
||||
|
||||
const onCancelDataEdit = () => {
|
||||
state.dataEdit.keyInfo = {} as any;
|
||||
state.dataEdit.stringValue = '';
|
||||
state.dataEdit.setValue = [];
|
||||
state.dataEdit.hashValue = [];
|
||||
};
|
||||
|
||||
return {
|
||||
...toRefs(state),
|
||||
changeProjectEnv,
|
||||
|
||||
254
mayfly_go_web/src/views/ops/redis/HashValue.vue
Normal file
254
mayfly_go_web/src/views/ops/redis/HashValue.vue
Normal file
@@ -0,0 +1,254 @@
|
||||
<template>
|
||||
<el-dialog :title="title" v-model="dialogVisible" :before-close="cancel" width="800px" :destroy-on-close="true">
|
||||
<el-form label-width="85px">
|
||||
<el-form-item prop="key" label="key:">
|
||||
<el-input :disabled="operationType == 2" v-model="key.key"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="timed" label="过期时间:">
|
||||
<el-input v-model.number="key.timed" type="number"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="dataType" label="数据类型:">
|
||||
<el-input v-model="key.type" disabled></el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-row class="mt10">
|
||||
<el-form label-position="right" :inline="true">
|
||||
<el-form-item label="field" label-width="40px" v-if="operationType == 2">
|
||||
<el-input placeholder="支持*模糊field" style="width: 140px" v-model="scanParam.match" clearable size="small"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="count" v-if="operationType == 2">
|
||||
<el-input placeholder="count" style="width: 62px" v-model.number="scanParam.count" size="small"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button v-if="operationType == 2" @click="reHscan()" type="success" icon="search" plain size="small"></el-button>
|
||||
<el-button v-if="operationType == 2" @click="hscan()" icon="bottom" plain size="small">scan</el-button>
|
||||
<el-button @click="onAddHashValue" icon="plus" size="small" plain>添加</el-button>
|
||||
</el-form-item>
|
||||
<div v-if="operationType == 2" class="mt10" style="float: right">
|
||||
<span>fieldSize: {{ keySize }}</span>
|
||||
</div>
|
||||
</el-form>
|
||||
</el-row>
|
||||
<el-table :data="hashValues" stripe style="width: 100%">
|
||||
<el-table-column prop="field" label="field" width>
|
||||
<template #default="scope">
|
||||
<el-input v-model="scope.row.field" clearable size="small"></el-input>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="value" label="value" min-width="200">
|
||||
<template #default="scope">
|
||||
<el-input v-model="scope.row.value" clearable type="textarea" :autosize="{ minRows: 2, maxRows: 10 }" size="small"></el-input>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="120">
|
||||
<template #default="scope">
|
||||
<el-button v-if="operationType == 2" type="success" @click="hset(scope.row)" icon="check" size="small" plain></el-button>
|
||||
<el-button type="danger" @click="hdel(scope.row.field, scope.$index)" icon="delete" size="small" plain></el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-form>
|
||||
<template #footer v-if="operationType == 1">
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="cancel()">取 消</el-button>
|
||||
<el-button @click="saveValue" type="primary" v-auth="'redis:data:save'">确 定</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, reactive, watch, toRefs } from 'vue';
|
||||
import { redisApi } from './api';
|
||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||
import { isTrue, notEmpty } from '@/common/assert';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'HashValue',
|
||||
components: {},
|
||||
props: {
|
||||
visible: {
|
||||
type: Boolean,
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
},
|
||||
// 操作类型,1:新增,2:修改
|
||||
operationType: {
|
||||
type: [Number],
|
||||
require: true,
|
||||
},
|
||||
redisId: {
|
||||
type: [Number],
|
||||
require: true,
|
||||
},
|
||||
keyInfo: {
|
||||
type: [Object],
|
||||
},
|
||||
hashValue: {
|
||||
type: [Array, Object],
|
||||
},
|
||||
},
|
||||
emits: ['valChange', 'cancel', 'update:visible'],
|
||||
setup(props: any, { emit }) {
|
||||
const state = reactive({
|
||||
dialogVisible: false,
|
||||
operationType: 1,
|
||||
redisId: 0,
|
||||
key: {
|
||||
key: '',
|
||||
type: 'hash',
|
||||
timed: -1,
|
||||
},
|
||||
scanParam: {
|
||||
key: '',
|
||||
id: 0,
|
||||
cursor: 0,
|
||||
match: '',
|
||||
count: 10,
|
||||
},
|
||||
keySize: 0,
|
||||
hashValues: [
|
||||
{
|
||||
field: '',
|
||||
value: '',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const cancel = () => {
|
||||
emit('update:visible', false);
|
||||
emit('cancel');
|
||||
setTimeout(() => {
|
||||
state.hashValues = [];
|
||||
state.key = {} as any;
|
||||
}, 500);
|
||||
};
|
||||
|
||||
watch(props, async (newValue) => {
|
||||
const visible = newValue.visible;
|
||||
state.redisId = newValue.redisId;
|
||||
state.key = newValue.keyInfo;
|
||||
state.operationType = newValue.operationType;
|
||||
|
||||
if (visible && state.operationType == 2) {
|
||||
state.scanParam.id = props.redisId;
|
||||
state.scanParam.key = state.key.key;
|
||||
await reHscan();
|
||||
}
|
||||
|
||||
state.dialogVisible = visible;
|
||||
});
|
||||
|
||||
const reHscan = async () => {
|
||||
state.scanParam.id = state.redisId;
|
||||
state.scanParam.cursor = 0;
|
||||
hscan();
|
||||
};
|
||||
|
||||
const hscan = async () => {
|
||||
const match = state.scanParam.match;
|
||||
if (!match || match == '' || match == '*') {
|
||||
if (state.scanParam.count > 100) {
|
||||
ElMessage.error('match为空或者*时, count不能超过100');
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (state.scanParam.count > 1000) {
|
||||
ElMessage.error('count不能超过1000');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const scanRes = await redisApi.hscan.request(state.scanParam);
|
||||
state.scanParam.cursor = scanRes.cursor;
|
||||
state.keySize = scanRes.keySize;
|
||||
|
||||
const keys = scanRes.keys;
|
||||
const hashValue = [];
|
||||
const fieldCount = keys.length / 2;
|
||||
let nextFieldIndex = 0;
|
||||
for (let i = 0; i < fieldCount; i++) {
|
||||
hashValue.push({ field: keys[nextFieldIndex++], value: keys[nextFieldIndex++] });
|
||||
}
|
||||
state.hashValues = hashValue;
|
||||
};
|
||||
|
||||
const hdel = async (field: any, index: any) => {
|
||||
// 如果是新增操作,则直接数组移除即可
|
||||
if (state.operationType == 1) {
|
||||
state.hashValues.splice(index, 1);
|
||||
return;
|
||||
}
|
||||
await ElMessageBox.confirm(`确定删除[${field}]?`, '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
});
|
||||
await redisApi.hdel.request({
|
||||
id: state.redisId,
|
||||
key: state.key.key,
|
||||
field,
|
||||
});
|
||||
ElMessage.success('删除成功');
|
||||
reHscan();
|
||||
};
|
||||
|
||||
const hset = async (row: any) => {
|
||||
await redisApi.saveHashValue.request({
|
||||
id: state.redisId,
|
||||
key: state.key.key,
|
||||
timed: state.key.timed,
|
||||
value: [
|
||||
{
|
||||
field: row.field,
|
||||
value: row.value,
|
||||
},
|
||||
],
|
||||
});
|
||||
ElMessage.success('保存成功');
|
||||
};
|
||||
|
||||
const onAddHashValue = () => {
|
||||
state.hashValues.push({ field: '', value: '' });
|
||||
};
|
||||
|
||||
const saveValue = async () => {
|
||||
notEmpty(state.key.key, 'key不能为空');
|
||||
isTrue(state.hashValues.length > 0, 'hash内容不能为空');
|
||||
const sv = { value: state.hashValues, id: state.redisId };
|
||||
Object.assign(sv, state.key);
|
||||
await redisApi.saveHashValue.request(sv);
|
||||
ElMessage.success('保存成功');
|
||||
|
||||
cancel();
|
||||
emit('valChange');
|
||||
};
|
||||
|
||||
return {
|
||||
...toRefs(state),
|
||||
reHscan,
|
||||
hscan,
|
||||
cancel,
|
||||
hdel,
|
||||
hset,
|
||||
onAddHashValue,
|
||||
saveValue,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<style lang="scss">
|
||||
#string-value-text {
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
position: relative;
|
||||
|
||||
.text-type-select {
|
||||
position: absolute;
|
||||
z-index: 2;
|
||||
right: 10px;
|
||||
top: 10px;
|
||||
max-width: 70px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
157
mayfly_go_web/src/views/ops/redis/SetValue.vue
Normal file
157
mayfly_go_web/src/views/ops/redis/SetValue.vue
Normal file
@@ -0,0 +1,157 @@
|
||||
<template>
|
||||
<el-dialog :title="title" v-model="dialogVisible" :before-close="cancel" width="800px" :destroy-on-close="true">
|
||||
<el-form label-width="85px">
|
||||
<el-form-item prop="key" label="key:">
|
||||
<el-input :disabled="operationType == 2" v-model="key.key"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="timed" label="过期时间:">
|
||||
<el-input v-model.number="key.timed" type="number"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="dataType" label="数据类型:">
|
||||
<el-input v-model="key.type" disabled></el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-button @click="onAddSetValue" icon="plus" size="small" plain class="mt10">添加</el-button>
|
||||
<el-table :data="value" stripe style="width: 100%">
|
||||
<el-table-column prop="value" label="value" min-width="200">
|
||||
<template #default="scope">
|
||||
<el-input v-model="scope.row.value" clearable type="textarea" :autosize="{ minRows: 2, maxRows: 10 }" size="small"></el-input>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="90">
|
||||
<template #default="scope">
|
||||
<el-button type="danger" @click="set.value.splice(scope.$index, 1)" icon="delete" size="small" plain>删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="cancel()">取 消</el-button>
|
||||
<el-button @click="saveValue" type="primary" v-auth="'redis:data:save'">确 定</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, reactive, watch, toRefs } from 'vue';
|
||||
import { redisApi } from './api';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { isTrue, notEmpty } from '@/common/assert';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'SetValue',
|
||||
components: {},
|
||||
props: {
|
||||
visible: {
|
||||
type: Boolean,
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
},
|
||||
redisId: {
|
||||
type: [Number],
|
||||
require: true,
|
||||
},
|
||||
keyInfo: {
|
||||
type: [Object],
|
||||
},
|
||||
// 操作类型,1:新增,2:修改
|
||||
operationType: {
|
||||
type: [Number],
|
||||
},
|
||||
setValue: {
|
||||
type: [Array, Object],
|
||||
},
|
||||
},
|
||||
emits: ['valChange', 'cancel', 'update:visible'],
|
||||
setup(props: any, { emit }) {
|
||||
const state = reactive({
|
||||
dialogVisible: false,
|
||||
operationType: 1,
|
||||
redisId: '',
|
||||
key: {
|
||||
key: '',
|
||||
type: 'string',
|
||||
timed: -1,
|
||||
},
|
||||
value: [{ value: '' }],
|
||||
});
|
||||
|
||||
const cancel = () => {
|
||||
emit('update:visible', false);
|
||||
emit('cancel');
|
||||
setTimeout(() => {
|
||||
state.key = {
|
||||
key: '',
|
||||
type: 'string',
|
||||
timed: -1,
|
||||
};
|
||||
state.value = [];
|
||||
}, 500);
|
||||
};
|
||||
|
||||
watch(props, async (newValue) => {
|
||||
state.dialogVisible = newValue.visible;
|
||||
state.key = newValue.key;
|
||||
state.redisId = newValue.redisId;
|
||||
state.key = newValue.keyInfo;
|
||||
state.operationType = newValue.operationType;
|
||||
// 如果是查看编辑操作,则获取值
|
||||
if (state.dialogVisible && state.operationType == 2) {
|
||||
getSetValue();
|
||||
}
|
||||
});
|
||||
|
||||
const getSetValue = async () => {
|
||||
const res = await redisApi.getSetValue.request({
|
||||
id: state.redisId,
|
||||
key: state.key.key,
|
||||
});
|
||||
state.value = res.map((x: any) => {
|
||||
return {
|
||||
value: x,
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
const saveValue = async () => {
|
||||
notEmpty(state.key.key, 'key不能为空');
|
||||
isTrue(state.value.length > 0, 'set内容不能为空');
|
||||
const sv = { value: state.value.map((x) => x.value), id: state.redisId };
|
||||
Object.assign(sv, state.key);
|
||||
await redisApi.saveSetValue.request(sv);
|
||||
|
||||
ElMessage.success('数据保存成功');
|
||||
cancel();
|
||||
emit('valChange');
|
||||
};
|
||||
|
||||
const onAddSetValue = () => {
|
||||
state.value.push({ value: '' });
|
||||
};
|
||||
|
||||
return {
|
||||
...toRefs(state),
|
||||
saveValue,
|
||||
cancel,
|
||||
onAddSetValue,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<style lang="scss">
|
||||
#string-value-text {
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
position: relative;
|
||||
|
||||
.text-type-select {
|
||||
position: absolute;
|
||||
z-index: 2;
|
||||
right: 10px;
|
||||
top: 10px;
|
||||
max-width: 70px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
169
mayfly_go_web/src/views/ops/redis/StringValue.vue
Normal file
169
mayfly_go_web/src/views/ops/redis/StringValue.vue
Normal file
@@ -0,0 +1,169 @@
|
||||
<template>
|
||||
<el-dialog :title="title" v-model="dialogVisible" :before-close="cancel" width="800px" :destroy-on-close="true">
|
||||
<el-form label-width="85px">
|
||||
<el-form-item prop="key" label="key:">
|
||||
<el-input :disabled="operationType == 2" v-model="key.key"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="timed" label="过期时间:">
|
||||
<el-input v-model.number="key.timed" type="number"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="dataType" label="数据类型:">
|
||||
<el-input v-model="key.type" disabled></el-input>
|
||||
</el-form-item>
|
||||
|
||||
<div id="string-value-text" style="width: 100%">
|
||||
<el-input class="json-text" v-model="string.value" type="textarea" :autosize="{ minRows: 10, maxRows: 20 }"></el-input>
|
||||
<el-select class="text-type-select" @change="onChangeTextType" v-model="string.type">
|
||||
<el-option key="text" label="text" value="text"> </el-option>
|
||||
<el-option key="json" label="json" value="json"> </el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="cancel()">取 消</el-button>
|
||||
<el-button @click="saveValue" type="primary" v-auth="'redis:data:save'">确 定</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, reactive, watch, toRefs } from 'vue';
|
||||
import { redisApi } from './api';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { notEmpty } from '@/common/assert';
|
||||
import { formatJsonString } from '@/common/utils/format';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'StringValue',
|
||||
components: {},
|
||||
props: {
|
||||
visible: {
|
||||
type: Boolean,
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
},
|
||||
redisId: {
|
||||
type: [Number],
|
||||
require: true,
|
||||
},
|
||||
keyInfo: {
|
||||
type: [Object],
|
||||
},
|
||||
// 操作类型,1:新增,2:修改
|
||||
operationType: {
|
||||
type: [Number],
|
||||
},
|
||||
},
|
||||
emits: ['valChange', 'cancel', 'update:visible'],
|
||||
setup(props: any, { emit }) {
|
||||
const state = reactive({
|
||||
dialogVisible: false,
|
||||
operationType: 1,
|
||||
redisId: '',
|
||||
key: {
|
||||
key: '',
|
||||
type: 'string',
|
||||
timed: -1,
|
||||
},
|
||||
string: {
|
||||
type: 'text',
|
||||
value: '',
|
||||
},
|
||||
});
|
||||
|
||||
const cancel = () => {
|
||||
emit('update:visible', false);
|
||||
emit('cancel');
|
||||
setTimeout(() => {
|
||||
state.key = {
|
||||
key: '',
|
||||
type: 'string',
|
||||
timed: -1,
|
||||
};
|
||||
state.string.value = '';
|
||||
state.string.type = 'text';
|
||||
}, 500);
|
||||
};
|
||||
|
||||
watch(
|
||||
() => props.visible,
|
||||
(val) => {
|
||||
state.dialogVisible = val;
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => props.redisId,
|
||||
(val) => {
|
||||
state.redisId = val;
|
||||
}
|
||||
);
|
||||
|
||||
watch(props, async (newValue) => {
|
||||
state.dialogVisible = newValue.visible;
|
||||
state.key = newValue.key;
|
||||
state.redisId = newValue.redisId;
|
||||
state.key = newValue.keyInfo;
|
||||
state.operationType = newValue.operationType
|
||||
// 如果是查看编辑操作,则获取值
|
||||
if (state.dialogVisible && state.operationType == 2) {
|
||||
getStringValue();
|
||||
}
|
||||
});
|
||||
|
||||
const getStringValue = async () => {
|
||||
state.string.value = await redisApi.getStringValue.request({
|
||||
id: state.redisId,
|
||||
key: state.key.key,
|
||||
});
|
||||
};
|
||||
|
||||
const saveValue = async () => {
|
||||
notEmpty(state.key.key, 'key不能为空');
|
||||
|
||||
notEmpty(state.string.value, 'value不能为空');
|
||||
const sv = { value: formatJsonString(state.string.value, true), id: state.redisId };
|
||||
Object.assign(sv, state.key);
|
||||
await redisApi.saveStringValue.request(sv);
|
||||
ElMessage.success('数据保存成功');
|
||||
cancel();
|
||||
emit('valChange');
|
||||
};
|
||||
|
||||
// 更改文本类型
|
||||
const onChangeTextType = (val: string) => {
|
||||
if (val == 'json') {
|
||||
state.string.value = formatJsonString(state.string.value, false);
|
||||
return;
|
||||
}
|
||||
if (val == 'text') {
|
||||
state.string.value = formatJsonString(state.string.value, true);
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
...toRefs(state),
|
||||
saveValue,
|
||||
cancel,
|
||||
onChangeTextType,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<style lang="scss">
|
||||
#string-value-text {
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
position: relative;
|
||||
|
||||
.text-type-select {
|
||||
position: absolute;
|
||||
z-index: 2;
|
||||
right: 10px;
|
||||
top: 10px;
|
||||
max-width: 70px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -12,6 +12,9 @@ export const redisApi = {
|
||||
getStringValue: Api.create("/redis/{id}/string-value", 'get'),
|
||||
saveStringValue: Api.create("/redis/{id}/string-value", 'post'),
|
||||
getHashValue: Api.create("/redis/{id}/hash-value", 'get'),
|
||||
hscan: Api.create("/redis/{id}/hscan", 'get'),
|
||||
hget: Api.create("/redis/{id}/hget", 'get'),
|
||||
hdel: Api.create("/redis/{id}/hdel", 'delete'),
|
||||
saveHashValue: Api.create("/redis/{id}/hash-value", 'post'),
|
||||
getSetValue: Api.create("/redis/{id}/set-value", 'get'),
|
||||
saveSetValue: Api.create("/redis/{id}/set-value", 'post'),
|
||||
|
||||
Reference in New Issue
Block a user