mirror of
https://gitee.com/dromara/mayfly-go
synced 2025-11-03 07:50:25 +08:00
fix: 数据导出精度修复、redis数据操作优化
This commit is contained in:
@@ -6,6 +6,11 @@ export function exportCsv(filename: string, columns: string[], datas: []) {
|
||||
let dataValueArr: any = [];
|
||||
for (let column of columns) {
|
||||
let val: any = data[column];
|
||||
if (val == null || val == undefined) {
|
||||
dataValueArr.push('');
|
||||
continue;
|
||||
}
|
||||
|
||||
if (typeof val == 'string' && val) {
|
||||
// csv格式如果有逗号,整体用双引号括起来;如果里面还有双引号就替换成两个双引号,这样导出来的格式就不会有问题了
|
||||
if (val.indexOf(',') != -1) {
|
||||
@@ -16,9 +21,9 @@ export function exportCsv(filename: string, columns: string[], datas: []) {
|
||||
// 再将逗号转义
|
||||
val = `"${val}"`;
|
||||
}
|
||||
dataValueArr.push(val);
|
||||
dataValueArr.push(val + '\t');
|
||||
} else {
|
||||
dataValueArr.push(val);
|
||||
dataValueArr.push(val + '\t');
|
||||
}
|
||||
}
|
||||
cvsData.push(dataValueArr);
|
||||
|
||||
@@ -29,8 +29,8 @@
|
||||
</el-row>
|
||||
</el-col>
|
||||
|
||||
<el-col v-loading="state.loadingKeyTree" :span="7" class="el-scrollbar flex-auto" style="overflow: auto">
|
||||
<div>
|
||||
<el-col v-loading="state.loadingKeyTree" :span="7">
|
||||
<div class="key-list-vtree">
|
||||
<el-row>
|
||||
<el-col :span="2">
|
||||
<el-input v-model="state.keySeparator" placeholder="分割符" size="small" class="ml5" />
|
||||
@@ -52,7 +52,7 @@
|
||||
</el-row>
|
||||
|
||||
<el-row class="mb5 mt5">
|
||||
<el-col :span="20">
|
||||
<el-col :span="19">
|
||||
<el-button class="ml5" :disabled="!scanParam.id || !scanParam.db" @click="scan(true)" type="success" icon="more" size="small" plain
|
||||
>加载更多</el-button
|
||||
>
|
||||
@@ -79,8 +79,8 @@
|
||||
>flush</el-button
|
||||
>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<span style="display: inline-block" class="mt5">keys: {{ state.dbsize }}</span>
|
||||
<el-col :span="5">
|
||||
<span style="display: inline-block" class="mt5">keys:{{ state.dbsize }}</span>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
@@ -97,43 +97,40 @@
|
||||
@node-click="handleKeyTreeNodeClick"
|
||||
@node-expand="keyTreeNodeExpand"
|
||||
@node-collapse="keyTreeNodeCollapse"
|
||||
@node-contextmenu="rightClickNode"
|
||||
>
|
||||
<template #default="{ node, data }">
|
||||
<span class="custom-tree-node key-list-custom-node">
|
||||
<el-dropdown size="small" trigger="contextmenu">
|
||||
<span class="el-dropdown-link">
|
||||
<span v-if="data.type == 1 && !node.expanded">
|
||||
<SvgIcon :size="15" name="folder" />
|
||||
<span class="el-dropdown-link key-list-custom-node" :title="node.label">
|
||||
<span v-if="data.type == 1">
|
||||
<SvgIcon :size="15" :name="node.expanded ? 'folder-opened' : 'folder'" />
|
||||
</span>
|
||||
<span v-if="data.type == 1 && node.expanded">
|
||||
<SvgIcon :size="15" name="folder-opened" />
|
||||
</span>
|
||||
<span v-if="data.type == 1" class="ml5" style="font-weight: bold">
|
||||
{{ node.label }}
|
||||
</span>
|
||||
<span v-if="data.type == 2" class="ml5" style="color: #67c23a">
|
||||
<span :class="'ml5 ' + (data.type == 1 ? 'folder-label' : 'key-label')">
|
||||
{{ node.label }}
|
||||
</span>
|
||||
|
||||
<span v-if="!node.isLeaf" class="ml5" style="font-weight: bold"> ({{ data.keyCount }}) </span>
|
||||
</span>
|
||||
|
||||
<template #dropdown v-if="data.type == 2">
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item @click="showKeyDetail(data.key, true)">
|
||||
<el-link type="primary" icon="plus" :underline="false" style="margin-left: 2px">新tab打开</el-link>
|
||||
</el-dropdown-item>
|
||||
<span v-auth="'redis:data:del'">
|
||||
<el-dropdown-item @click="delKey(data.key)">
|
||||
<el-link type="danger" icon="delete" :underline="false" style="margin-left: 2px">删除</el-link>
|
||||
</el-dropdown-item>
|
||||
</span>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</span>
|
||||
</template>
|
||||
</el-tree>
|
||||
|
||||
<!-- right context menu -->
|
||||
<div ref="rightMenuRef" class="key-list-right-menu">
|
||||
<!-- folder right menu -->
|
||||
<div v-if="!state.rightClickNode?.isLeaf"></div>
|
||||
<!-- key right menu -->
|
||||
<div v-else>
|
||||
<el-row>
|
||||
<el-link @click="showKeyDetail(state.rightClickNode.key, true)" type="primary" icon="plus" :underline="false"
|
||||
>新tab打开</el-link
|
||||
>
|
||||
</el-row>
|
||||
<el-row class="mt5">
|
||||
<el-link @click="delKey(state.rightClickNode.key)" v-auth="'redis:data:del'" type="danger" icon="delete" :underline="false"
|
||||
>删除</el-link
|
||||
>
|
||||
</el-row>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
|
||||
@@ -204,6 +201,7 @@ const treeProps = {
|
||||
const defaultCount = 250;
|
||||
|
||||
const keyTreeRef: any = ref(null);
|
||||
const rightMenuRef: any = ref(null);
|
||||
|
||||
const state = reactive({
|
||||
tags: [],
|
||||
@@ -217,6 +215,7 @@ const state = reactive({
|
||||
keyTreeExpanded: new Set(),
|
||||
activeName: '',
|
||||
dataTabs: {} as any,
|
||||
rightClickNode: {} as any,
|
||||
scanParam: {
|
||||
id: null as any,
|
||||
mode: '',
|
||||
@@ -407,6 +406,7 @@ const expandAllKeyNode = (nodes: any) => {
|
||||
};
|
||||
|
||||
const handleKeyTreeNodeClick = async (data: any) => {
|
||||
hideAllMenus();
|
||||
// 目录则不做处理
|
||||
if (data.type == 1) {
|
||||
return;
|
||||
@@ -478,6 +478,43 @@ const keyTreeNodeCollapse = (data: any, node: any, component: any) => {
|
||||
state.keyTreeExpanded.delete(data.key);
|
||||
};
|
||||
|
||||
const rightClickNode = (event: any, data: any, node: any) => {
|
||||
hideAllMenus();
|
||||
|
||||
keyTreeRef.value.setCurrentKey(node.key);
|
||||
state.rightClickNode = node;
|
||||
|
||||
// nextTick for dom render
|
||||
nextTick(() => {
|
||||
let top = event.clientY;
|
||||
const menu = rightMenuRef.value;
|
||||
menu.style.display = 'block';
|
||||
|
||||
// position in bottom
|
||||
if (document.body.clientHeight - top < menu.clientHeight) {
|
||||
top -= menu.clientHeight;
|
||||
}
|
||||
|
||||
menu.style.left = `${event.clientX}px`;
|
||||
menu.style.top = `${top}px`;
|
||||
|
||||
document.addEventListener('click', hideAllMenus, { once: true });
|
||||
});
|
||||
};
|
||||
|
||||
const hideAllMenus = () => {
|
||||
let menus: any = document.querySelectorAll('.key-list-right-menu');
|
||||
|
||||
if (menus.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
state.rightClickNode = null;
|
||||
for (const menu of menus) {
|
||||
menu.style.display = 'none';
|
||||
}
|
||||
};
|
||||
|
||||
const searchKey = async () => {
|
||||
state.scanParam.cursor = {};
|
||||
await scan(false);
|
||||
@@ -596,6 +633,14 @@ const delKey = (key: string) => {
|
||||
height: calc(100vh - 250px);
|
||||
}
|
||||
|
||||
.key-list-vtree .folder-label {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.key-list-vtree .key-label {
|
||||
color: #67c23a;
|
||||
}
|
||||
|
||||
.key-list-vtree .key-list-custom-node {
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
@@ -604,4 +649,21 @@ const delKey = (key: string) => {
|
||||
height: 22px;
|
||||
line-height: 22px;
|
||||
}
|
||||
|
||||
/* right menu style start */
|
||||
.key-list-right-menu {
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
padding: 5px;
|
||||
z-index: 99999;
|
||||
overflow: hidden;
|
||||
border-radius: 3px;
|
||||
border: 2px solid lightgrey;
|
||||
background: #fafafa;
|
||||
}
|
||||
.dark-mode .key-list-right-menu {
|
||||
background: #263238;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user