mirror of
				https://gitee.com/dromara/mayfly-go
				synced 2025-11-04 00:10:25 +08:00 
			
		
		
		
	feat: redis新增实例树
This commit is contained in:
		@@ -1,88 +1,71 @@
 | 
				
			|||||||
<template>
 | 
					<template>
 | 
				
			||||||
    <div>
 | 
					    <div>
 | 
				
			||||||
        <el-card>
 | 
					        <el-card>
 | 
				
			||||||
            <div style="float: left">
 | 
					          <el-row>
 | 
				
			||||||
                <el-row type="flex" justify="space-between">
 | 
					            <el-col :span="3">
 | 
				
			||||||
                    <el-col :span="24">
 | 
					              <redis-instance-tree 
 | 
				
			||||||
                        <el-form class="search-form" label-position="right" :inline="true">
 | 
					                  @init-load-instances="initLoadInstances"
 | 
				
			||||||
                            <el-form-item label="标签">
 | 
					                  @change-instance="changeInstance"
 | 
				
			||||||
                                <el-select @change="changeTag" @focus="getTags" v-model="query.tagPath"
 | 
					                  @change-schema="loadInitSchema"
 | 
				
			||||||
                                    placeholder="请选择标签" filterable style="width: 250px">
 | 
					                  :instances="state.instances"
 | 
				
			||||||
                                    <el-option v-for="item in tags" :key="item" :label="item" :value="item">
 | 
					              />
 | 
				
			||||||
                                    </el-option>
 | 
					            </el-col>
 | 
				
			||||||
                                </el-select>
 | 
					            <el-col :span="19" style="border-left: 1px solid var(--el-card-border-color)">
 | 
				
			||||||
                            </el-form-item>
 | 
					              <el-col class="mt10">
 | 
				
			||||||
                            <el-form-item label="redis" label-width="40px">
 | 
					                <el-form class="search-form" label-position="right" :inline="true" label-width="60px">
 | 
				
			||||||
                                <el-select v-model="scanParam.id" placeholder="请选择redis" @change="changeRedis"
 | 
					                  <el-form-item label="key" label-width="40px">
 | 
				
			||||||
                                    @clear="clearRedis" clearable style="width: 250px">
 | 
					                    <el-input placeholder="match 支持*模糊key" style="width: 250px" v-model="scanParam.match"
 | 
				
			||||||
                                    <el-option v-for="item in redisList" :key="item.id"
 | 
					                              @clear="clear()" clearable></el-input>
 | 
				
			||||||
                                        :label="`${item.name ? item.name : ''} [${item.host}]`" :value="item.id">
 | 
					                  </el-form-item>
 | 
				
			||||||
                                    </el-option>
 | 
					                  <el-form-item label="count" label-width="40px">
 | 
				
			||||||
                                </el-select>
 | 
					                    <el-input placeholder="count" style="width: 70px" v-model.number="scanParam.count">
 | 
				
			||||||
                            </el-form-item>
 | 
					                    </el-input>
 | 
				
			||||||
                            <el-form-item label="库" label-width="20px">
 | 
					                  </el-form-item>
 | 
				
			||||||
                                <el-select v-model="scanParam.db" @change="changeDb" placeholder="库"
 | 
					                  <el-form-item>
 | 
				
			||||||
                                    style="width: 85px">
 | 
					                    <el-button @click="searchKey()" type="success" icon="search" plain></el-button>
 | 
				
			||||||
                                    <el-option v-for="db in dbList" :key="db" :label="db" :value="db"> </el-option>
 | 
					                    <el-button @click="scan()" icon="bottom" plain>scan</el-button>
 | 
				
			||||||
                                </el-select>
 | 
					                    <el-popover placement="right" :width="200" trigger="click">
 | 
				
			||||||
                            </el-form-item>
 | 
					                      <template #reference>
 | 
				
			||||||
                        </el-form>
 | 
					                        <el-button type="primary" icon="plus" plain></el-button>
 | 
				
			||||||
                    </el-col>
 | 
					                      </template>
 | 
				
			||||||
                    <el-col class="mt10">
 | 
					                      <el-tag @click="onAddData('string')" :color="getTypeColor('string')"
 | 
				
			||||||
                        <el-form class="search-form" label-position="right" :inline="true" label-width="60px">
 | 
					                              style="cursor: pointer">string</el-tag>
 | 
				
			||||||
                            <el-form-item label="key" label-width="40px">
 | 
					                      <el-tag @click="onAddData('hash')" :color="getTypeColor('hash')" class="ml5"
 | 
				
			||||||
                                <el-input placeholder="match 支持*模糊key" style="width: 250px" v-model="scanParam.match"
 | 
					                              style="cursor: pointer">hash</el-tag>
 | 
				
			||||||
                                    @clear="clear()" clearable></el-input>
 | 
					                      <el-tag @click="onAddData('set')" :color="getTypeColor('set')" class="ml5"
 | 
				
			||||||
                            </el-form-item>
 | 
					                              style="cursor: pointer">set</el-tag>
 | 
				
			||||||
                            <el-form-item label="count" label-width="40px">
 | 
					                      <!-- <el-tag @click="onAddData('list')" :color="getTypeColor('list')" class="ml5" style="cursor: pointer">list</el-tag> -->
 | 
				
			||||||
                                <el-input placeholder="count" style="width: 70px" v-model.number="scanParam.count">
 | 
					                    </el-popover>
 | 
				
			||||||
                                </el-input>
 | 
					                  </el-form-item>
 | 
				
			||||||
                            </el-form-item>
 | 
					                  <div style="float: right">
 | 
				
			||||||
                            <el-form-item>
 | 
					                    <span>keys: {{ state.dbsize }}</span>
 | 
				
			||||||
                                <el-button @click="searchKey()" type="success" icon="search" plain></el-button>
 | 
					                  </div>
 | 
				
			||||||
                                <el-button @click="scan()" icon="bottom" plain>scan</el-button>
 | 
					                </el-form>
 | 
				
			||||||
                                <el-popover placement="right" :width="200" trigger="click">
 | 
					              </el-col>
 | 
				
			||||||
                                    <template #reference>
 | 
					              <el-table v-loading="state.loading" :data="state.keys" stripe :highlight-current-row="true" style="cursor: pointer">
 | 
				
			||||||
                                        <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-tag @click="onAddData('list')" :color="getTypeColor('list')" class="ml5" style="cursor: pointer">list</el-tag> -->
 | 
					 | 
				
			||||||
                                </el-popover>
 | 
					 | 
				
			||||||
                            </el-form-item>
 | 
					 | 
				
			||||||
                            <div style="float: right">
 | 
					 | 
				
			||||||
                                <span>keys: {{ dbsize }}</span>
 | 
					 | 
				
			||||||
                            </div>
 | 
					 | 
				
			||||||
                        </el-form>
 | 
					 | 
				
			||||||
                    </el-col>
 | 
					 | 
				
			||||||
                </el-row>
 | 
					 | 
				
			||||||
            </div>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            <el-table v-loading="loading" :data="keys" stripe :highlight-current-row="true" style="cursor: pointer">
 | 
					 | 
				
			||||||
                <el-table-column show-overflow-tooltip prop="key" label="key"></el-table-column>
 | 
					                <el-table-column show-overflow-tooltip prop="key" label="key"></el-table-column>
 | 
				
			||||||
                <el-table-column prop="type" label="type" width="80">
 | 
					                <el-table-column prop="type" label="type" width="80">
 | 
				
			||||||
                    <template #default="scope">
 | 
					                  <template #default="scope">
 | 
				
			||||||
                        <el-tag :color="getTypeColor(scope.row.type)" size="small">{{ scope.row.type }}</el-tag>
 | 
					                    <el-tag :color="getTypeColor(scope.row.type)" size="small">{{ scope.row.type }}</el-tag>
 | 
				
			||||||
                    </template>
 | 
					                  </template>
 | 
				
			||||||
                </el-table-column>
 | 
					                </el-table-column>
 | 
				
			||||||
                <el-table-column prop="ttl" label="ttl(过期时间)" width="140">
 | 
					                <el-table-column prop="ttl" label="ttl(过期时间)" width="140">
 | 
				
			||||||
                    <template #default="scope">
 | 
					                  <template #default="scope">
 | 
				
			||||||
                        {{ ttlConveter(scope.row.ttl) }}
 | 
					                    {{ ttlConveter(scope.row.ttl) }}
 | 
				
			||||||
                    </template>
 | 
					                  </template>
 | 
				
			||||||
                </el-table-column>
 | 
					                </el-table-column>
 | 
				
			||||||
                <el-table-column label="操作">
 | 
					                <el-table-column label="操作">
 | 
				
			||||||
                    <template #default="scope">
 | 
					                  <template #default="scope">
 | 
				
			||||||
                        <el-button @click="getValue(scope.row)" type="success" icon="search" plain size="small">查看
 | 
					                    <el-button @click="getValue(scope.row)" type="success" icon="search" plain size="small">查看
 | 
				
			||||||
                        </el-button>
 | 
					                    </el-button>
 | 
				
			||||||
                        <el-button @click="del(scope.row.key)" type="danger" icon="delete" plain size="small">删除
 | 
					                    <el-button @click="del(scope.row.key)" type="danger" icon="delete" plain size="small">删除
 | 
				
			||||||
                        </el-button>
 | 
					                    </el-button>
 | 
				
			||||||
                    </template>
 | 
					                  </template>
 | 
				
			||||||
                </el-table-column>
 | 
					                </el-table-column>
 | 
				
			||||||
            </el-table>
 | 
					              </el-table>
 | 
				
			||||||
 | 
					            </el-col>
 | 
				
			||||||
 | 
					          </el-row>
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
        </el-card>
 | 
					        </el-card>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <div style="text-align: center; margin-top: 10px"></div>
 | 
					        <div style="text-align: center; margin-top: 10px"></div>
 | 
				
			||||||
@@ -107,7 +90,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
<script lang="ts" setup>
 | 
					<script lang="ts" setup>
 | 
				
			||||||
import { redisApi } from './api';
 | 
					import { redisApi } from './api';
 | 
				
			||||||
import { toRefs, reactive, watch } from 'vue';
 | 
					import { toRefs, reactive } from 'vue';
 | 
				
			||||||
import { ElMessage, ElMessageBox } from 'element-plus';
 | 
					import { ElMessage, ElMessageBox } from 'element-plus';
 | 
				
			||||||
import HashValue from './HashValue.vue';
 | 
					import HashValue from './HashValue.vue';
 | 
				
			||||||
import StringValue from './StringValue.vue';
 | 
					import StringValue from './StringValue.vue';
 | 
				
			||||||
@@ -116,7 +99,7 @@ import ListValue from './ListValue.vue';
 | 
				
			|||||||
import { isTrue, notBlank, notNull } from '@/common/assert';
 | 
					import { isTrue, notBlank, notNull } from '@/common/assert';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { useStore } from '@/store/index.ts';
 | 
					import { useStore } from '@/store/index.ts';
 | 
				
			||||||
import { tagApi } from '../tag/api.ts';
 | 
					import RedisInstanceTree from '@/views/ops/redis/RedisInstanceTree.vue';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let store = useStore();
 | 
					let store = useStore();
 | 
				
			||||||
const state = reactive({
 | 
					const state = reactive({
 | 
				
			||||||
@@ -159,64 +142,18 @@ const state = reactive({
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
    keys: [],
 | 
					    keys: [],
 | 
				
			||||||
    dbsize: 0,
 | 
					    dbsize: 0,
 | 
				
			||||||
 | 
					    instances:{tags:{}, tree:{}, dbs:{}, tables:{}}
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const {
 | 
					const {
 | 
				
			||||||
    loading,
 | 
					 | 
				
			||||||
    tags,
 | 
					 | 
				
			||||||
    redisList,
 | 
					 | 
				
			||||||
    dbList,
 | 
					 | 
				
			||||||
    query,
 | 
					 | 
				
			||||||
    scanParam,
 | 
					    scanParam,
 | 
				
			||||||
    dataEdit,
 | 
					    dataEdit,
 | 
				
			||||||
    hashValueDialog,
 | 
					    hashValueDialog,
 | 
				
			||||||
    stringValueDialog,
 | 
					    stringValueDialog,
 | 
				
			||||||
    setValueDialog,
 | 
					    setValueDialog,
 | 
				
			||||||
    listValueDialog,
 | 
					    listValueDialog,
 | 
				
			||||||
    keys,
 | 
					 | 
				
			||||||
    dbsize,
 | 
					 | 
				
			||||||
} = toRefs(state)
 | 
					} = toRefs(state)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const searchRedis = async () => {
 | 
					 | 
				
			||||||
    notBlank(state.query.tagPath, '请先选择标签');
 | 
					 | 
				
			||||||
    const res = await redisApi.redisList.request(state.query);
 | 
					 | 
				
			||||||
    state.redisList = res.list;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const changeTag = (tagPath: string) => {
 | 
					 | 
				
			||||||
    clearRedis();
 | 
					 | 
				
			||||||
    if (tagPath != null) {
 | 
					 | 
				
			||||||
        searchRedis();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const getTags = async () => {
 | 
					 | 
				
			||||||
    state.tags = await tagApi.getAccountTags.request(null);
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const changeRedis = (id: number) => {
 | 
					 | 
				
			||||||
    resetScanParam();
 | 
					 | 
				
			||||||
    if (id != 0) {
 | 
					 | 
				
			||||||
        const redis: any = state.redisList.find((x: any) => x.id == id);
 | 
					 | 
				
			||||||
        if (redis) {
 | 
					 | 
				
			||||||
            state.dbList = (state.redisList.find((x: any) => x.id == id) as any).db.split(',');
 | 
					 | 
				
			||||||
            state.scanParam.mode = redis.mode;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // 默认选中配置的第一个库
 | 
					 | 
				
			||||||
    state.scanParam.db = state.dbList[0];
 | 
					 | 
				
			||||||
    state.keys = [];
 | 
					 | 
				
			||||||
    state.dbsize = 0;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const changeDb = () => {
 | 
					 | 
				
			||||||
    resetScanParam();
 | 
					 | 
				
			||||||
    state.keys = [];
 | 
					 | 
				
			||||||
    state.dbsize = 0;
 | 
					 | 
				
			||||||
    searchKey();
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const scan = async () => {
 | 
					const scan = async () => {
 | 
				
			||||||
    isTrue(state.scanParam.id != null, '请先选择redis');
 | 
					    isTrue(state.scanParam.id != null, '请先选择redis');
 | 
				
			||||||
    notBlank(state.scanParam.count, 'count不能为空');
 | 
					    notBlank(state.scanParam.count, 'count不能为空');
 | 
				
			||||||
@@ -256,15 +193,6 @@ const searchKey = async () => {
 | 
				
			|||||||
    await scan();
 | 
					    await scan();
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const clearRedis = () => {
 | 
					 | 
				
			||||||
    state.redisList = [];
 | 
					 | 
				
			||||||
    state.scanParam.id = null;
 | 
					 | 
				
			||||||
    resetScanParam();
 | 
					 | 
				
			||||||
    state.scanParam.db = '';
 | 
					 | 
				
			||||||
    state.keys = [];
 | 
					 | 
				
			||||||
    state.dbsize = 0;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const clear = () => {
 | 
					const clear = () => {
 | 
				
			||||||
    resetScanParam();
 | 
					    resetScanParam();
 | 
				
			||||||
    if (state.scanParam.id) {
 | 
					    if (state.scanParam.id) {
 | 
				
			||||||
@@ -328,20 +256,18 @@ const del = (key: string) => {
 | 
				
			|||||||
        confirmButtonText: '确定',
 | 
					        confirmButtonText: '确定',
 | 
				
			||||||
        cancelButtonText: '取消',
 | 
					        cancelButtonText: '取消',
 | 
				
			||||||
        type: 'warning',
 | 
					        type: 'warning',
 | 
				
			||||||
    })
 | 
					    }).then(() => {
 | 
				
			||||||
        .then(() => {
 | 
					      redisApi.delKey
 | 
				
			||||||
            redisApi.delKey
 | 
					          .request({
 | 
				
			||||||
                .request({
 | 
					            key,
 | 
				
			||||||
                    key,
 | 
					            id: state.scanParam.id,
 | 
				
			||||||
                    id: state.scanParam.id,
 | 
					            db: state.scanParam.db,
 | 
				
			||||||
                    db: state.scanParam.db,
 | 
					          })
 | 
				
			||||||
                })
 | 
					          .then(() => {
 | 
				
			||||||
                .then(() => {
 | 
					            ElMessage.success('删除成功!');
 | 
				
			||||||
                    ElMessage.success('删除成功!');
 | 
					            searchKey();
 | 
				
			||||||
                    searchKey();
 | 
					          });
 | 
				
			||||||
                });
 | 
					    }).catch(() => { });
 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
        .catch(() => { });
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const ttlConveter = (ttl: any) => {
 | 
					const ttlConveter = (ttl: any) => {
 | 
				
			||||||
@@ -392,27 +318,46 @@ const getTypeColor = (type: string) => {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 加载选中的db
 | 
					 | 
				
			||||||
const setSelects = async (redisDbOptInfo: any) => {
 | 
					 | 
				
			||||||
    // 设置标签路径等
 | 
					 | 
				
			||||||
    const { tagPath, dbId } = redisDbOptInfo.dbOptInfo;
 | 
					 | 
				
			||||||
    state.query.tagPath = tagPath;
 | 
					 | 
				
			||||||
    await searchRedis();
 | 
					 | 
				
			||||||
    state.scanParam.id = dbId;
 | 
					 | 
				
			||||||
    changeRedis(dbId);
 | 
					 | 
				
			||||||
    changeDb();
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 判断如果有数据则加载下拉选项
 | 
					const initLoadInstances = async ()=>{
 | 
				
			||||||
let redisDbOptInfo = store.state.redisDbOptInfo;
 | 
					  const res = await redisApi.redisList.request({});
 | 
				
			||||||
if (redisDbOptInfo.dbOptInfo.tagPath) {
 | 
					  if(!res.total) return
 | 
				
			||||||
    setSelects(redisDbOptInfo);
 | 
					  state.instances = {tags:{}, tree:{}, dbs:{}, tables:{}} ; // 初始化变量
 | 
				
			||||||
 | 
					  for (const db of res.list) {
 | 
				
			||||||
 | 
					    let arr = state.instances.tree[db.tagId] || []
 | 
				
			||||||
 | 
					    const {tagId, tagPath} = db
 | 
				
			||||||
 | 
					    // tags
 | 
				
			||||||
 | 
					    state.instances.tags[db.tagId]={tagId, tagPath}
 | 
				
			||||||
 | 
					    // 实例
 | 
				
			||||||
 | 
					    arr.push(db)
 | 
				
			||||||
 | 
					    state.instances.tree[db.tagId] = arr;
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 监听选中操作的db变化,并加载下拉选项
 | 
					const changeInstance = async (inst: any) => {
 | 
				
			||||||
watch(store.state.redisDbOptInfo, async (newValue) => {
 | 
					  let dbs = state.instances.dbs[inst.id] || []
 | 
				
			||||||
    await setSelects(newValue);
 | 
					  if(dbs.length <=0 ){
 | 
				
			||||||
});
 | 
					    const res = await redisApi.redisInfo.request({ id: inst.id, host:inst.host });
 | 
				
			||||||
 | 
					    for (let db in res.Keyspace){
 | 
				
			||||||
 | 
					      dbs.push({
 | 
				
			||||||
 | 
					        name: db,
 | 
				
			||||||
 | 
					        keys: res.Keyspace[db]?.split(',')[0]?.split('=')[1] || 0
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  state.instances.dbs[inst.id] = dbs
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** 初始化加载db数据 */
 | 
				
			||||||
 | 
					const loadInitSchema = (inst: any, schema: string)=>{
 | 
				
			||||||
 | 
					  state.scanParam.id = inst.id
 | 
				
			||||||
 | 
					  state.scanParam.db = schema.replace('db','')
 | 
				
			||||||
 | 
					  scan()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -134,7 +134,6 @@ watch(
 | 
				
			|||||||
            for (let k in info['Keyspace']) {
 | 
					            for (let k in info['Keyspace']) {
 | 
				
			||||||
                let data = { db: k }
 | 
					                let data = { db: k }
 | 
				
			||||||
                let d = info['Keyspace'][k].split(',')
 | 
					                let d = info['Keyspace'][k].split(',')
 | 
				
			||||||
                debugger
 | 
					 | 
				
			||||||
                for (let f of d) {
 | 
					                for (let f of d) {
 | 
				
			||||||
                    let v = f.split('=')
 | 
					                    let v = f.split('=')
 | 
				
			||||||
                    data[v[0]] = v[1]
 | 
					                    data[v[0]] = v[1]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -32,13 +32,6 @@
 | 
				
			|||||||
                            </el-popover>
 | 
					                            </el-popover>
 | 
				
			||||||
                        </template></el-input>
 | 
					                        </template></el-input>
 | 
				
			||||||
                </el-form-item>
 | 
					                </el-form-item>
 | 
				
			||||||
                <el-form-item prop="db" label="库号:" required>
 | 
					 | 
				
			||||||
                    <el-select @change="changeDb" v-model="dbList" multiple allow-create filterable
 | 
					 | 
				
			||||||
                        placeholder="请选择可操作库号" style="width: 100%">
 | 
					 | 
				
			||||||
                        <el-option v-for="db in [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]" :key="db"
 | 
					 | 
				
			||||||
                            :label="db" :value="db" />
 | 
					 | 
				
			||||||
                    </el-select>
 | 
					 | 
				
			||||||
                </el-form-item>
 | 
					 | 
				
			||||||
                <el-form-item prop="remark" label="备注:">
 | 
					                <el-form-item prop="remark" label="备注:">
 | 
				
			||||||
                    <el-input v-model.trim="form.remark" auto-complete="off" type="textarea"></el-input>
 | 
					                    <el-input v-model.trim="form.remark" auto-complete="off" type="textarea"></el-input>
 | 
				
			||||||
                </el-form-item>
 | 
					                </el-form-item>
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										156
									
								
								mayfly_go_web/src/views/ops/redis/RedisInstanceTree.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										156
									
								
								mayfly_go_web/src/views/ops/redis/RedisInstanceTree.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,156 @@
 | 
				
			|||||||
 | 
					<template>
 | 
				
			||||||
 | 
					  <div class="instances-box layout-aside">
 | 
				
			||||||
 | 
					    <el-row type="flex" justify="space-between">
 | 
				
			||||||
 | 
					      <el-col :span="24" :style="{
 | 
				
			||||||
 | 
					        maxHeight: state.instanceMenuMaxHeight,
 | 
				
			||||||
 | 
					        height: state.instanceMenuMaxHeight, 
 | 
				
			||||||
 | 
					        overflow:'auto'
 | 
				
			||||||
 | 
					      }" class="el-scrollbar flex-auto">
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        <el-menu background-color="transparent" :collapse-transition="false">
 | 
				
			||||||
 | 
					          <!-- 第一级:tag -->
 | 
				
			||||||
 | 
					          <el-sub-menu v-for="tag of instances.tags" :index="tag.tagPath" :key="tag.tagPath">
 | 
				
			||||||
 | 
					            <template #title>
 | 
				
			||||||
 | 
					              <el-icon><FolderOpened color="#e6a23c"/></el-icon>
 | 
				
			||||||
 | 
					              <span>{{ tag.tagPath }}</span>
 | 
				
			||||||
 | 
					            </template>
 | 
				
			||||||
 | 
					            <!-- 第二级:数据库实例 -->
 | 
				
			||||||
 | 
					            <el-sub-menu v-for="inst in instances.tree[tag.tagId]"
 | 
				
			||||||
 | 
					                         :index="'mongo-instance-' + inst.id"
 | 
				
			||||||
 | 
					                         :key="'mongo-instance-' + inst.id"
 | 
				
			||||||
 | 
					                         @click.prevent="changeInstance(inst)"
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					              <template #title>
 | 
				
			||||||
 | 
					                <el-popover
 | 
				
			||||||
 | 
					                    placement="right-start"
 | 
				
			||||||
 | 
					                    title="mongo数据库实例信息"
 | 
				
			||||||
 | 
					                    trigger="hover"
 | 
				
			||||||
 | 
					                    :width="210"
 | 
				
			||||||
 | 
					                >
 | 
				
			||||||
 | 
					                  <template #reference>
 | 
				
			||||||
 | 
					                    <span>  <el-icon><MostlyCloudy color="#409eff"/></el-icon>{{ inst.name }}</span>
 | 
				
			||||||
 | 
					                  </template>
 | 
				
			||||||
 | 
					                  <template #default>
 | 
				
			||||||
 | 
					                    <el-form class="instances-pop-form" label-width="55px" :size="'small'">
 | 
				
			||||||
 | 
					                      <el-form-item label="名称:">{{inst.name}}</el-form-item>
 | 
				
			||||||
 | 
					                      <el-form-item label="链接:">{{inst.host}}</el-form-item>
 | 
				
			||||||
 | 
					                    </el-form>
 | 
				
			||||||
 | 
					                  </template>
 | 
				
			||||||
 | 
					                </el-popover>
 | 
				
			||||||
 | 
					              </template>
 | 
				
			||||||
 | 
					              <!-- 第三级:数据库 -->
 | 
				
			||||||
 | 
					              <el-sub-menu v-for="db in instances.dbs[inst.id]" 
 | 
				
			||||||
 | 
					                           :index="inst.id + db.name" 
 | 
				
			||||||
 | 
					                           :key="inst.id + db.name"
 | 
				
			||||||
 | 
					                           :class="state.nowSchema === (inst.id+db.name) && 'checked'"
 | 
				
			||||||
 | 
					                           @click.prevent="changeSchema(inst, db.name)"
 | 
				
			||||||
 | 
					              >
 | 
				
			||||||
 | 
					                <template #title>
 | 
				
			||||||
 | 
					                      <el-icon><Coin color="#67c23a"/></el-icon>
 | 
				
			||||||
 | 
					                  <span class="checked-schema">
 | 
				
			||||||
 | 
					                    {{ db.name  }} [{{db.keys}}]
 | 
				
			||||||
 | 
					                  </span>
 | 
				
			||||||
 | 
					                </template>
 | 
				
			||||||
 | 
					              </el-sub-menu>
 | 
				
			||||||
 | 
					            </el-sub-menu>
 | 
				
			||||||
 | 
					          </el-sub-menu>
 | 
				
			||||||
 | 
					        </el-menu>
 | 
				
			||||||
 | 
					      </el-col>
 | 
				
			||||||
 | 
					    </el-row>
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script lang="ts" setup>
 | 
				
			||||||
 | 
					import {onBeforeMount, reactive} from 'vue';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					defineProps({
 | 
				
			||||||
 | 
					  instances: {
 | 
				
			||||||
 | 
					    type: Object, required: true
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const emits = defineEmits(['initLoadInstances','changeInstance','changeSchema'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					onBeforeMount(async ()=>{
 | 
				
			||||||
 | 
					  await initLoadInstances()
 | 
				
			||||||
 | 
					  setHeight()
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const setHeight = () => {
 | 
				
			||||||
 | 
					  state.instanceMenuMaxHeight = window.innerHeight - 140 + 'px';
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const state = reactive({
 | 
				
			||||||
 | 
					  instanceMenuMaxHeight: '800px',
 | 
				
			||||||
 | 
					  nowSchema: '',
 | 
				
			||||||
 | 
					  filterParam: {},
 | 
				
			||||||
 | 
					  loading: {},
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 初始化加载实例数据
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					const initLoadInstances = () => {
 | 
				
			||||||
 | 
					  emits('initLoadInstances')
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 改变选中的数据库实例
 | 
				
			||||||
 | 
					 * @param inst 选中的实例对象
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					const changeInstance = (inst : any) => {
 | 
				
			||||||
 | 
					  emits('changeInstance', inst)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 改变选中的数据库schema
 | 
				
			||||||
 | 
					 * @param inst 选中的实例对象
 | 
				
			||||||
 | 
					 * @param schema 选中的数据库schema
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					const changeSchema = (inst : any, schema: string) => {
 | 
				
			||||||
 | 
					  state.nowSchema = inst.id + schema
 | 
				
			||||||
 | 
					  emits('changeSchema', inst, schema)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<style lang="scss">
 | 
				
			||||||
 | 
					.instances-box {
 | 
				
			||||||
 | 
					  .el-menu{
 | 
				
			||||||
 | 
					    width: 275px;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  .el-sub-menu{
 | 
				
			||||||
 | 
					    .checked{
 | 
				
			||||||
 | 
					      .checked-schema{
 | 
				
			||||||
 | 
					        color: var(--el-color-primary);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  .el-sub-menu__title{
 | 
				
			||||||
 | 
					    padding-left: 0 !important;
 | 
				
			||||||
 | 
					    height: 30px !important;
 | 
				
			||||||
 | 
					    line-height: 30px !important;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  .el-menu--vertical:not(.el-menu--collapse):not(.el-menu--popup-container) .el-sub-menu__title{
 | 
				
			||||||
 | 
					    padding-right: 10px;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  .el-menu-item{
 | 
				
			||||||
 | 
					    padding-left: 0 !important;
 | 
				
			||||||
 | 
					    height: 20px !important;
 | 
				
			||||||
 | 
					    line-height: 20px !important;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  .el-icon{
 | 
				
			||||||
 | 
					    margin: 0;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  .el-sub-menu__icon-arrow{
 | 
				
			||||||
 | 
					    top:inherit;
 | 
				
			||||||
 | 
					    right: 10px;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.instances-pop-form{
 | 
				
			||||||
 | 
					  .el-form-item{
 | 
				
			||||||
 | 
					    margin-bottom: unset;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</style>
 | 
				
			||||||
		Reference in New Issue
	
	Block a user