refactor: 样式调整

This commit is contained in:
meilin.huang
2023-12-14 13:05:21 +08:00
parent 5c72b1de57
commit 18cf2e54c4
17 changed files with 391 additions and 337 deletions

View File

@@ -2,7 +2,7 @@
<div>
<transition name="el-zoom-in-top">
<!-- 查询表单 -->
<SearchForm v-show="isShowSearch" :items="searchItems" v-model="queryForm_" :search="queryData" :reset="reset" :search-col="searchCol">
<SearchForm v-if="isShowSearch" :items="searchItems" v-model="queryForm_" :search="queryData" :reset="reset" :search-col="searchCol">
<!-- 遍历父组件传入的 solts 透传给子组件 -->
<template v-for="(_, key) in useSlots()" v-slot:[key]>
<slot :name="key"></slot>
@@ -10,7 +10,7 @@
</SearchForm>
</transition>
<el-card>
<div class="card">
<div class="table-main">
<!-- 表格头部 操作按钮 -->
<div class="table-header">
@@ -121,7 +121,7 @@
:page-sizes="pageSizes"
/>
</el-row>
</el-card>
</div>
</div>
</template>

View File

@@ -190,6 +190,18 @@ body,
}
}
.flex-justify-between {
display: flex;
align-items: center; // 垂直方向水平居中
justify-content: space-between; // 使第一个子元素靠近父容器的起始位置,最后一个子元素靠近终止位置,而其他子元素均匀分布在它们之间
}
.flex-align-center {
display: flex;
align-items: center;
}
/* 宽高 100%
------------------------------- */
.w100 {
@@ -276,6 +288,10 @@ body,
.pl#{$i} {
padding-left: #{$i}px !important;
}
.pd#{$i} {
padding: #{$i}px !important;
}
}
@@ -335,12 +351,15 @@ body,
user-select: none;
}
.toolbar {
width: 100%;
padding: 4px;
overflow: hidden;
line-height: 24px;
border: 1px solid var(--el-border-color-light, #ebeef5);
/* custom card */
.card {
box-sizing: border-box;
padding: 20px;
overflow-x: hidden;
background-color: var(--el-bg-color);
border: 1px solid var(--el-border-color-light);
border-radius: 6px;
box-shadow: 0 0 12px rgb(0 0 0 / 5%);
}
.fl {
@@ -361,10 +380,6 @@ body,
z-index: inherit !important;
}
.f12 {
font-size: 12px
}
.pointer {
cursor: pointer;
}
@@ -396,6 +411,7 @@ body,
.default-theme.splitpanes--horizontal>.splitpanes__splitter {
border-top: 1px solid var(--bg-main-color);
}
// 竖线样式
.splitpanes.default-theme .splitpanes__splitter::before,
.splitpanes.default-theme .splitpanes__splitter::after {

View File

@@ -1,7 +1,7 @@
<template>
<div class="tag-tree">
<el-input v-model="filterText" placeholder="输入关键字->搜索已展开节点信息" clearable size="small" class="mb5" />
<el-scrollbar :style="{ height: state.height, maxHeight: state.height, backgroundColor: 'var(--el-fill-color-blank)' }">
<div class="tag-tree card pd5">
<el-scrollbar>
<el-input v-model="filterText" placeholder="输入关键字->搜索已展开节点信息" clearable size="small" class="mb5 w100" />
<el-tree
ref="treeRef"
:highlight-current="true"
@@ -32,8 +32,9 @@
</span>
</template>
</el-tree>
<contextmenu :dropdown="state.dropdown" :items="state.contextmenuItems" ref="contextmenuRef" @currentContextmenuClick="onCurrentContextmenuClick" />
</el-scrollbar>
<contextmenu :dropdown="state.dropdown" :items="state.contextmenuItems" ref="contextmenuRef" @currentContextmenuClick="onCurrentContextmenuClick" />
</div>
</template>
@@ -43,7 +44,6 @@ import { NodeType, TagTreeNode } from './tag';
import TagInfo from './TagInfo.vue';
import { Contextmenu } from '@/components/contextmenu';
import { tagApi } from '../tag/api';
import { useEventListener, useWindowSize } from '@vueuse/core';
const props = defineProps({
resourceType: {
@@ -74,8 +74,6 @@ const emit = defineEmits(['nodeClick', 'currentContextmenuClick']);
const treeRef: any = ref(null);
const contextmenuRef = ref();
const { height: vh } = useWindowSize();
const state = reactive({
height: 600 as any,
filterText: '',
@@ -88,14 +86,7 @@ const state = reactive({
});
const { filterText } = toRefs(state);
onMounted(async () => {
setHeight();
useEventListener(window, 'resize', setHeight);
});
const setHeight = () => {
state.height = vh.value - 138 + 'px';
};
onMounted(async () => {});
watch(filterText, (val) => {
treeRef.value?.filter(val);
@@ -195,8 +186,7 @@ defineExpose({
<style lang="scss" scoped>
.tag-tree {
border-radius: var(--el-input-border-radius, var(--el-border-radius-base));
border: 1px solid var(--el-border-color-light, #ebeef5);
height: calc(100vh - 108px);
.el-tree {
display: inline-block;

View File

@@ -21,7 +21,7 @@
</el-col>
<el-col style="text-align: center" :span="1">:</el-col>
<el-col :span="5">
<el-input type="number" v-model.number="form.port" placeholder="请输入端口"></el-input>
<el-input type="number" v-model.number="form.port" placeholder="端口"></el-input>
</el-col>
</el-form-item>
<el-form-item prop="username" label="用户名" required>
@@ -49,7 +49,7 @@
<el-tab-pane label="其他配置" name="other">
<el-form-item prop="params" label="连接参数">
<el-input v-model.trim="form.params" placeholder="其他连接参数,形如: key1=value1&key2=value2">
<template #suffix>
<!-- <template #suffix>
<el-link
target="_blank"
href="https://github.com/go-sql-driver/mysql#parameters"
@@ -58,7 +58,7 @@
class="mr5"
>参数参考</el-link
>
</template>
</template> -->
</el-input>
</el-form-item>

View File

@@ -47,101 +47,103 @@
</Pane>
<Pane>
<el-row>
<el-col :span="24" v-if="state.db">
<el-descriptions :column="4" size="small" border class="ml5">
<el-descriptions-item label-align="right" label="操作"
><el-button
:disabled="!state.db || !nowDbInst.id"
type="primary"
icon="Search"
@click="addQueryTab({ id: nowDbInst.id, dbs: nowDbInst.databases }, state.db)"
size="small"
>新建查询</el-button
></el-descriptions-item
>
<div class="card db-op pd5">
<el-row>
<el-col :span="24" v-if="state.db">
<el-descriptions :column="4" size="small" border>
<el-descriptions-item label-align="right" label="操作"
><el-button
:disabled="!state.db || !nowDbInst.id"
type="primary"
icon="Search"
@click="addQueryTab({ id: nowDbInst.id, dbs: nowDbInst.databases }, state.db)"
size="small"
>新建查询</el-button
></el-descriptions-item
>
<el-descriptions-item label-align="right" label="tag">{{ nowDbInst.tagPath }}</el-descriptions-item>
<el-descriptions-item label-align="right" label="tag">{{ nowDbInst.tagPath }}</el-descriptions-item>
<el-descriptions-item label-align="right">
<template #label>
<div>
<SvgIcon :name="getDbDialect(nowDbInst.type).getInfo().icon" :size="18" />
实例
</div>
</template>
{{ nowDbInst.id }}
<el-divider direction="vertical" border-style="dashed" />
{{ nowDbInst.name }}
<el-divider direction="vertical" border-style="dashed" />
{{ nowDbInst.host }}
</el-descriptions-item>
<el-descriptions-item label="库名" label-align="right">{{ state.db }}</el-descriptions-item>
</el-descriptions>
</el-col>
</el-row>
<div id="data-exec" class="mt5 ml5">
<el-tabs
v-if="state.tabs.size > 0"
type="card"
@tab-remove="onRemoveTab"
@tab-change="onTabChange"
style="width: 100%"
v-model="state.activeName"
class="h100"
>
<el-tab-pane class="h100" closable v-for="dt in state.tabs.values()" :label="dt.label" :name="dt.key" :key="dt.key">
<template #label>
<el-popover :show-after="1000" placement="bottom-start" trigger="hover" :width="250">
<template #reference> {{ dt.label }} </template>
<template #default>
<el-descriptions :column="1" size="small">
<el-descriptions-item label="tagPath">
{{ dt.params.tagPath }}
</el-descriptions-item>
<el-descriptions-item label="名称">
{{ dt.params.name }}
</el-descriptions-item>
<el-descriptions-item label="host">
<SvgIcon :name="getDbDialect(dt.params.type).getInfo().icon" :size="18" />
{{ dt.params.host }}
</el-descriptions-item>
<el-descriptions-item label="库名">
{{ dt.params.dbName }}
</el-descriptions-item>
</el-descriptions>
<el-descriptions-item label-align="right">
<template #label>
<div>
<SvgIcon :name="getDbDialect(nowDbInst.type).getInfo().icon" :size="18" />
实例
</div>
</template>
</el-popover>
</template>
{{ nowDbInst.id }}
<el-divider direction="vertical" border-style="dashed" />
{{ nowDbInst.name }}
<el-divider direction="vertical" border-style="dashed" />
{{ nowDbInst.host }}
</el-descriptions-item>
<db-table-data-op
v-if="dt.type === TabType.TableData"
:db-id="dt.dbId"
:db-name="dt.db"
:table-name="dt.params.table"
:table-height="state.dataTabsTableHeight"
></db-table-data-op>
<el-descriptions-item label="库名" label-align="right">{{ state.db }}</el-descriptions-item>
</el-descriptions>
</el-col>
</el-row>
<db-sql-editor
v-if="dt.type === TabType.Query"
:db-id="dt.dbId"
:db-name="dt.db"
:sql-name="dt.params.sqlName"
@save-sql-success="reloadSqls"
>
</db-sql-editor>
<div id="data-exec" class="mt5">
<el-tabs
v-if="state.tabs.size > 0"
type="card"
@tab-remove="onRemoveTab"
@tab-change="onTabChange"
style="width: 100%"
v-model="state.activeName"
class="h100"
>
<el-tab-pane class="h100" closable v-for="dt in state.tabs.values()" :label="dt.label" :name="dt.key" :key="dt.key">
<template #label>
<el-popover :show-after="1000" placement="bottom-start" trigger="hover" :width="250">
<template #reference> {{ dt.label }} </template>
<template #default>
<el-descriptions :column="1" size="small">
<el-descriptions-item label="tagPath">
{{ dt.params.tagPath }}
</el-descriptions-item>
<el-descriptions-item label="名称">
{{ dt.params.name }}
</el-descriptions-item>
<el-descriptions-item label="host">
<SvgIcon :name="getDbDialect(dt.params.type).getInfo().icon" :size="18" />
{{ dt.params.host }}
</el-descriptions-item>
<el-descriptions-item label="库名">
{{ dt.params.dbName }}
</el-descriptions-item>
</el-descriptions>
</template>
</el-popover>
</template>
<db-tables-op
v-if="dt.type == TabType.TablesOp"
:db-id="dt.params.id"
:db="dt.params.db"
:db-type="dt.params.type"
:height="state.tablesOpHeight"
/>
</el-tab-pane>
</el-tabs>
<db-table-data-op
v-if="dt.type === TabType.TableData"
:db-id="dt.dbId"
:db-name="dt.db"
:table-name="dt.params.table"
:table-height="state.dataTabsTableHeight"
></db-table-data-op>
<db-sql-editor
v-if="dt.type === TabType.Query"
:db-id="dt.dbId"
:db-name="dt.db"
:sql-name="dt.params.sqlName"
@save-sql-success="reloadSqls"
>
</db-sql-editor>
<db-tables-op
v-if="dt.type == TabType.TablesOp"
:db-id="dt.params.id"
:db="dt.params.db"
:db-type="dt.params.type"
:height="state.tablesOpHeight"
/>
</el-tab-pane>
</el-tabs>
</div>
</div>
</Pane>
</Splitpanes>
@@ -397,8 +399,8 @@ onBeforeUnmount(() => {
* 设置editor高度和数据表高度
*/
const setHeight = () => {
state.dataTabsTableHeight = window.innerHeight - 255 + 'px';
state.tablesOpHeight = window.innerHeight - 212 + 'px';
state.dataTabsTableHeight = window.innerHeight - 270 + 'px';
state.tablesOpHeight = window.innerHeight - 225 + 'px';
};
// 选择数据库,改变当前正在操作的数据库信息
@@ -607,6 +609,10 @@ const getNowDbInfo = () => {
font-size: 9px;
}
.db-op {
height: calc(100vh - 108px);
}
#data-exec {
.el-tabs {
--el-tabs-header-height: 30px;

View File

@@ -1,8 +1,8 @@
<template>
<div>
<div>
<div class="toolbar">
<div class="fl">
<div class="card pd5 flex-justify-between">
<div>
<el-link @click="onRunSql()" :underline="false" class="ml15" icon="VideoPlay"> </el-link>
<el-divider direction="vertical" border-style="dashed" />
@@ -33,7 +33,7 @@
</el-upload>
</div>
<div class="fr">
<div>
<el-button @click="saveSql()" type="primary" icon="document-add" plain size="small">保存SQL</el-button>
</div>
</div>
@@ -44,7 +44,7 @@
@resize="resizeTableHeight"
horizontal
class="default-theme"
style="height: calc(100vh - 220px)"
style="height: calc(100vh - 233px)"
>
<Pane :size="state.editorSize" max-size="80">
<MonacoEditor ref="monacoEditorRef" class="mt5" v-model="state.sql" language="sql" height="100%" :id="'MonacoTextarea-' + getKey()" />
@@ -128,7 +128,7 @@
</template>
<script lang="ts" setup>
import { h, nextTick, onMounted, reactive, toRefs, ref } from 'vue';
import { h, nextTick, onMounted, reactive, toRefs, ref, unref } from 'vue';
import { getToken } from '@/common/utils/storage';
import { notBlank } from '@/common/assert';
import { format as sqlFormatter } from 'sql-formatter';
@@ -276,7 +276,7 @@ const onRemoveTab = (targetId: number) => {
const resizeTableHeight = (e: any) => {
const vh = window.innerHeight;
state.editorSize = e[0].size;
const plitpaneHeight = vh - 210;
const plitpaneHeight = vh - 223;
const editorHeight = plitpaneHeight * (state.editorSize / 100);
state.tableDataHeight = plitpaneHeight - editorHeight - 40 + 'px';
};
@@ -336,7 +336,7 @@ const onRunSql = async (newTab = false) => {
// 不是新建tab执行则在当前激活的tab上执行sql
i = state.execResTabs.findIndex((x) => x.id == state.activeTab);
execRes = state.execResTabs[i];
if (execRes.loading?.value) {
if (unref(execRes.loading)) {
ElMessage.error('当前结果集tab正在执行, 请使用新标签执行');
return;
}

View File

@@ -47,11 +47,11 @@
<el-divider direction="vertical" border-style="dashed" />
<el-tooltip :show-after="500" v-if="hasUpdatedFileds" class="box-item" effect="dark" content="提交修改" placement="top">
<el-link @click="submitUpdateFields()" type="success" :underline="false" class="f12">提交</el-link>
<el-link @click="submitUpdateFields()" type="success" :underline="false" class="font12">提交</el-link>
</el-tooltip>
<el-divider v-if="hasUpdatedFileds" direction="vertical" border-style="dashed" />
<el-tooltip :show-after="500" v-if="hasUpdatedFileds" class="box-item" effect="dark" content="取消修改" placement="top">
<el-link @click="cancelUpdateFields" type="warning" :underline="false" class="f12">取消</el-link>
<el-link @click="cancelUpdateFields" type="warning" :underline="false" class="font12">取消</el-link>
</el-tooltip>
</div>
</el-col>

View File

@@ -1,19 +1,19 @@
<template>
<div class="file-manage">
<el-dialog title="进程信息" v-model="dialogVisible" :destroy-on-close="true" :show-close="true" :before-close="handleClose" width="65%">
<div class="toolbar">
<div class="card pd5">
<el-row>
<el-col :span="4">
<el-input size="small" placeholder="进程名" v-model="params.name" plain clearable></el-input>
</el-col>
<el-col :span="4" class="ml5">
<el-select @change="getProcess" size="small" v-model="params.sortType" placeholder="请选择排序类型">
<el-select class="w100" @change="getProcess" size="small" v-model="params.sortType" placeholder="请选择排序类型">
<el-option key="cpu" label="cpu降序" value="1"> </el-option>
<el-option key="cpu" label="mem降序" value="2"> </el-option>
</el-select>
</el-col>
<el-col :span="4" class="ml5">
<el-select @change="getProcess" size="small" v-model="params.count" placeholder="请选择进程个数">
<el-select class="w100" @change="getProcess" size="small" v-model="params.count" placeholder="请选择进程个数">
<el-option key="10" label="10" value="10"> </el-option>
<el-option key="15" label="15" value="15"> </el-option>
<el-option key="20" label="20" value="20"> </el-option>

View File

@@ -44,9 +44,9 @@
</Pane>
<Pane>
<div id="mongo-tab" class="ml5" style="border: 1px solid var(--el-border-color-light, #ebeef5); margin-top: 1px">
<div class="mongo-data-tab card pd5">
<el-row v-if="nowColl">
<el-descriptions :column="10" size="small" border>
<el-descriptions class="w100" :column="10" size="small" border>
<!-- <el-descriptions-item label-align="right" label="tag">xxx</el-descriptions-item> -->
<el-descriptions-item label="ns" label-align="right">
@@ -74,7 +74,7 @@
</el-row>
<el-row type="flex">
<el-tabs @tab-remove="removeDataTab" style="width: 100%; margin-left: 5px" v-model="state.activeName">
<el-tabs @tab-remove="removeDataTab" class="w100 ml5" v-model="state.activeName">
<el-tab-pane closable v-for="dt in state.dataTabs" :key="dt.key" :label="dt.label" :name="dt.key">
<el-row>
<el-col :span="2">
@@ -96,27 +96,29 @@
</el-input>
</el-col>
</el-row>
<el-row :style="`height: ${dataHeight}; overflow: auto;`">
<el-col :span="6" v-for="item in dt.datas" :key="item">
<el-card :body-style="{ padding: '0px', position: 'relative' }">
<el-input type="textarea" v-model="item.value" :rows="10" />
<div style="padding: 3px; float: right" class="mr5 mongo-doc-btns">
<div>
<el-link @click="onEditDoc(item)" :underline="false" type="success" icon="MagicStick"></el-link>
<el-scrollbar class="mongo-data-tab-data">
<el-row>
<el-col :span="6" v-for="item in dt.datas" :key="item">
<el-card :body-style="{ padding: '0px', position: 'relative' }">
<el-input type="textarea" v-model="item.value" :rows="10" />
<div style="padding: 3px; float: right" class="mr5 mongo-doc-btns">
<div>
<el-link @click="onEditDoc(item)" :underline="false" type="success" icon="MagicStick"></el-link>
<el-divider direction="vertical" border-style="dashed" />
<el-divider direction="vertical" border-style="dashed" />
<el-popconfirm @confirm="onDeleteDoc(item.value)" title="确定删除该文档?" width="160">
<template #reference>
<el-link v-auth="perms.delData" :underline="false" type="danger" icon="DocumentDelete">
</el-link>
</template>
</el-popconfirm>
<el-popconfirm @confirm="onDeleteDoc(item.value)" title="确定删除该文档?" width="160">
<template #reference>
<el-link v-auth="perms.delData" :underline="false" type="danger" icon="DocumentDelete">
</el-link>
</template>
</el-popconfirm>
</div>
</div>
</div>
</el-card>
</el-col>
</el-row>
</el-card>
</el-col>
</el-row>
</el-scrollbar>
</el-tab-pane>
</el-tabs>
</el-row>
@@ -253,7 +255,6 @@ const NodeTypeColl = new NodeType(MongoNodeType.Coll).withNodeClickFunc((nodeDat
const findParamInputRef: any = ref(null);
const state = reactive({
tags: [],
dataHeight: `${window.innerHeight - 220}px`,
mongoList: [] as any,
activeName: '', // 当前操作的tab
dataTabs: {} as any, // 数据tabs
@@ -282,7 +283,7 @@ const state = reactive({
},
});
const { dataHeight, findDialog, docEditDialog } = toRefs(state);
const { findDialog, docEditDialog } = toRefs(state);
const nowColl = computed(() => {
return getNowDataTab();
@@ -506,7 +507,17 @@ const getNowDataTab = () => {
max-width: 120px;
}
#mongo-tab {
.mongo-data-tab {
height: calc(100vh - 108px);
}
.mongo-data-tab {
margin-top: 1px;
.mongo-data-tab-data {
height: calc(100vh - 230px);
}
.el-tabs__header {
margin: 0 0 5px;

View File

@@ -1,5 +1,5 @@
<template>
<div>
<div class="redis-data-op">
<Splitpanes class="default-theme">
<Pane size="20" max-size="30">
<tag-tree :resource-type="TagResourceTypeEnum.Redis.value" :tag-path-node-type="NodeTypeTagPath">
@@ -34,68 +34,68 @@
</Pane>
<Pane min-size="20" size="30">
<div class="key-list-vtree">
<el-row>
<el-col :span="2">
<el-input v-model="state.keySeparator" placeholder="分割符" size="small" class="ml5" />
</el-col>
<el-col :span="18">
<el-input @clear="clear" v-model="scanParam.match" placeholder="match 支持*模糊key" clearable size="small" class="ml10" />
</el-col>
<el-col :span="4">
<el-button
class="ml15"
:disabled="!scanParam.id || !scanParam.db"
@click="searchKey()"
type="success"
icon="search"
size="small"
plain
></el-button>
</el-col>
</el-row>
<div class="key-list-vtree card pd5">
<el-scrollbar>
<el-row>
<el-col :span="2">
<el-input v-model="state.keySeparator" placeholder="分割符" size="small" class="ml5" />
</el-col>
<el-col :span="18">
<el-input @clear="clear" v-model="scanParam.match" placeholder="match 支持*模糊key" clearable size="small" class="ml10" />
</el-col>
<el-col :span="4">
<el-button
class="ml15"
:disabled="!scanParam.id || !scanParam.db"
@click="searchKey()"
type="success"
icon="search"
size="small"
plain
></el-button>
</el-col>
</el-row>
<el-row class="mb5 mt5">
<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
>
<el-row class="mb5 mt5">
<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
>
<el-button
v-auth="'redis:data:save'"
:disabled="!scanParam.id || !scanParam.db"
@click="showNewKeyDialog"
type="primary"
icon="plus"
size="small"
plain
>新增key</el-button
>
<el-button
v-auth="'redis:data:save'"
:disabled="!scanParam.id || !scanParam.db"
@click="showNewKeyDialog"
type="primary"
icon="plus"
size="small"
plain
>新增key</el-button
>
<el-button
:disabled="!scanParam.id || !scanParam.db"
@click="flushDb"
type="danger"
plain
v-auth="'redis:data:del'"
size="small"
icon="delete"
>flush</el-button
>
</el-col>
<el-col :span="5">
<span style="display: inline-block" class="mt5">keys:{{ state.dbsize }}</span>
</el-col>
</el-row>
<el-button
:disabled="!scanParam.id || !scanParam.db"
@click="flushDb"
type="danger"
plain
v-auth="'redis:data:del'"
size="small"
icon="delete"
>flush</el-button
>
</el-col>
<el-col :span="5">
<span style="display: inline-block" class="mt5">keys:{{ state.dbsize }}</span>
</el-col>
</el-row>
<el-scrollbar
:style="{
maxHeight: state.keyTreeHeight,
height: state.keyTreeHeight,
backgroundColor: 'var(--el-fill-color-blank)',
border: '1px solid var(--el-border-color-light, #ebeef5)',
}"
>
<el-tree
ref="keyTreeRef"
:highlight-current="true"
@@ -130,7 +130,7 @@
</Pane>
<Pane min-size="40">
<div class="">
<div class="key-detail card pd5">
<el-tabs @tab-remove="removeDataTab" v-model="state.activeName">
<el-tab-pane closable v-for="dt in state.dataTabs" :key="dt.key" :label="dt.label" :name="dt.key">
<key-detail :redisId="scanParam.id" :db="scanParam.db" :key-info="dt.keyInfo" @change-key="searchKey()" @del-key="delKey" />
@@ -178,10 +178,9 @@ import { TagTreeNode, NodeType } from '../component/tag';
import TagTree from '../component/TagTree.vue';
import { keysToTree, sortByTreeNodes, keysToList } from './utils';
import { Contextmenu, ContextmenuItem } from '@/components/contextmenu';
import { sleep } from '../../../common/utils/loading';
import { sleep } from '@/common/utils/loading';
import { TagResourceTypeEnum } from '@/common/commonEnum';
import { Splitpanes, Pane } from 'splitpanes';
import { useEventListener } from '@vueuse/core';
const KeyDetail = defineAsyncComponent(() => import('./KeyDetail.vue'));
@@ -316,15 +315,7 @@ const state = reactive({
const { scanParam, keyTreeData, newKeyDialog } = toRefs(state);
onMounted(async () => {
setHeight();
// 监听浏览器窗口大小变化,更新对应组件高度
useEventListener(window, 'resize', setHeight);
});
const setHeight = () => {
state.keyTreeHeight = window.innerHeight - 165 + 'px';
};
onMounted(async () => {});
const scan = async (appendKey = false) => {
isTrue(state.scanParam.id != null, '请先选择redis');
@@ -581,24 +572,27 @@ const delKey = (key: string) => {
</script>
<style lang="scss">
.key-list-vtree {
height: 100%;
}
.redis-data-op {
.key-list-vtree,
.key-detail {
height: calc(100vh - 108px);
}
.key-list-vtree .folder-label {
font-weight: bold;
}
.key-list-vtree .folder-label {
font-weight: bold;
}
.key-list-vtree .key-label {
color: #67c23a;
}
.key-list-vtree .key-label {
color: #67c23a;
}
.key-list-vtree .key-list-custom-node {
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
/*note the following 2 items should be same value, may not consist with itemSize*/
height: 22px;
line-height: 22px;
.key-list-vtree .key-list-custom-node {
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
/*note the following 2 items should be same value, may not consist with itemSize*/
height: 22px;
line-height: 22px;
}
}
</style>

View File

@@ -107,10 +107,10 @@ defineExpose({ getContent });
.format-viewer-container .el-textarea textarea {
font-size: 14px;
height: calc(100vh - 536px + v-bind(height));
height: calc(100vh - 546px + v-bind(height));
}
.format-viewer-container .monaco-editor-content {
height: calc(100vh - 550px + v-bind(height)) !important;
height: calc(100vh - 560px + v-bind(height)) !important;
}
</style>

View File

@@ -1,8 +1,10 @@
<template>
<div class="menu">
<div class="toolbar">
<el-input v-model="filterTag" placeholder="输入关键字过滤(右击进行操作)" style="width: 220px; margin-right: 10px" />
<el-button v-auth="'tag:save'" type="primary" icon="plus" @click="showSaveTagDialog(null)">添加</el-button>
<div class="tag-tree-list card">
<div class="card pd10">
<el-input v-model="filterTag" clearable placeholder="输入关键字过滤(右击进行操作)" style="width: 220px; margin-right: 10px" />
<el-button v-if="useUserInfo().userInfo.username == 'admin'" v-auth="'tag:save'" type="primary" icon="plus" @click="showSaveTagDialog(null)"
>添加</el-button
>
<div style="float: right">
<el-tooltip placement="top">
<template #content>
@@ -17,33 +19,34 @@
</el-tooltip>
</div>
</div>
<el-tree
ref="tagTreeRef"
class="none-select"
:indent="38"
node-key="id"
:props="props"
:data="data"
@node-expand="handleNodeExpand"
@node-collapse="handleNodeCollapse"
@node-contextmenu="nodeContextmenu"
@node-click="treeNodeClick"
:default-expanded-keys="defaultExpandedKeys"
:expand-on-click-node="true"
:filter-node-method="filterNode"
>
<template #default="{ data }">
<span class="custom-tree-node">
<span style="font-size: 13px">
{{ data.code }}
<span style="color: #3c8dbc"></span>
{{ data.name }}
<span style="color: #3c8dbc"></span>
<el-tag v-if="data.children !== null" size="small">{{ data.children.length }}</el-tag>
<el-scrollbar class="tag-tree-data">
<el-tree
ref="tagTreeRef"
class="none-select"
node-key="id"
:props="props"
:data="data"
@node-expand="handleNodeExpand"
@node-collapse="handleNodeCollapse"
@node-contextmenu="nodeContextmenu"
@node-click="treeNodeClick"
:default-expanded-keys="defaultExpandedKeys"
:expand-on-click-node="true"
:filter-node-method="filterNode"
>
<template #default="{ data }">
<span class="custom-tree-node">
<span style="font-size: 13px">
{{ data.code }}
<span style="color: #3c8dbc"></span>
{{ data.name }}
<span style="color: #3c8dbc"></span>
<el-tag v-if="data.children !== null" size="small">{{ data.children.length }}</el-tag>
</span>
</span>
</span>
</template>
</el-tree>
</template>
</el-tree>
</el-scrollbar>
<el-dialog width="500px" :title="saveTabDialog.title" :before-close="cancelSaveTag" v-model="saveTabDialog.visible">
<el-form ref="tagForm" :rules="rules" :model="saveTabDialog.form" label-width="auto">
@@ -113,6 +116,7 @@ import { TagResourceTypeEnum } from '../../../common/commonEnum';
import EnumValue from '@/common/Enum';
import { useRouter } from 'vue-router';
import { hasPerm } from '@/components/auth/auth';
import { useUserInfo } from '@/store/userInfo';
interface Tree {
id: number;
@@ -390,12 +394,14 @@ const removeDeafultExpandId = (id: any) => {
};
</script>
<style lang="scss">
.menu {
height: 100%;
.tag-tree-list {
.tag-tree-data {
height: calc(100vh - 200px);
.el-tree-node__content {
height: 40px;
line-height: 40px;
.el-tree-node__content {
height: 40px;
line-height: 40px;
}
}
}

View File

@@ -1,8 +1,8 @@
<template>
<div class="account-dialog">
<el-dialog :title="account == null ? '' : '分配“' + account.username + '”的角色'" v-model="dialogVisible" :before-close="cancel" :show-close="false">
<div class="toolbar">
<div style="float: left">
<div class="card pd5">
<div>
<el-input placeholder="请输入角色名" style="width: 150px" v-model="query.name" @clear="clear()" clearable> </el-input>
<el-button class="ml5" @click="search" type="success" icon="search"></el-button>
</div>
@@ -17,15 +17,17 @@
</template>
</el-table-column>
</el-table>
<el-pagination
@current-change="handlePageChange"
style="text-align: center; margin-top: 20px"
background
layout="prev, pager, next, total, jumper"
:total="total"
v-model:current-page="query.pageNum"
:page-size="query.pageSize"
></el-pagination>
<el-row type="flex" justify="end">
<el-pagination
@current-change="handlePageChange"
style="text-align: center; margin-top: 20px"
background
layout="prev, pager, next, total, jumper"
:total="total"
v-model:current-page="query.pageNum"
:page-size="query.pageSize"
></el-pagination>
</el-row>
<template #footer>
<div class="dialog-footer">

View File

@@ -1,44 +1,52 @@
<template>
<div class="menu">
<div class="toolbar">
<div class="card system-resouce-list">
<div class="card pd10 flex-justify-between">
<div>
<span style="font-size: 14px"> <SvgIcon name="info-filled" />红色橙色字体表示禁用状态 (右击资源进行操作) </span>
<el-input v-model="filterResource" clearable placeholder="输入关键字过滤(右击进行操作)" style="width: 220px; margin-right: 10px" />
<el-button v-auth="perms.addResource" type="primary" icon="plus" @click="addResource(false)">添加</el-button>
</div>
<div>
<span> <SvgIcon name="info-filled" />红色橙色字体表示禁用状态 (右击资源进行操作) </span>
</div>
<el-button v-auth="perms.addResource" type="primary" icon="plus" @click="addResource(false)">添加</el-button>
</div>
<el-tree
class="none-select"
:indent="38"
node-key="id"
:props="props"
:data="data"
@node-expand="handleNodeExpand"
@node-collapse="handleNodeCollapse"
@node-contextmenu="nodeContextmenu"
@node-click="treeNodeClick"
:default-expanded-keys="defaultExpandedKeys"
:expand-on-click-node="true"
draggable
:allow-drop="allowDrop"
@node-drop="handleDrop"
>
<template #default="{ data }">
<span class="custom-tree-node">
<span style="font-size: 13px" v-if="data.type === menuTypeValue">
<span style="color: #3c8dbc"></span>
<span v-if="data.status == 1">{{ data.name }}</span>
<span v-if="data.status == -1" style="color: #e6a23c">{{ data.name }}</span>
<span style="color: #3c8dbc"></span>
<el-tag v-if="data.children !== null" size="small">{{ data.children.length }}</el-tag>
<el-scrollbar class="tree-data">
<el-tree
ref="resourceTreeRef"
class="none-select"
:indent="38"
node-key="id"
:props="props"
:data="data"
@node-expand="handleNodeExpand"
@node-collapse="handleNodeCollapse"
@node-contextmenu="nodeContextmenu"
@node-click="treeNodeClick"
:default-expanded-keys="defaultExpandedKeys"
:expand-on-click-node="true"
draggable
:allow-drop="allowDrop"
@node-drop="handleDrop"
:filter-node-method="filterNode"
>
<template #default="{ data }">
<span class="custom-tree-node">
<span style="font-size: 13px" v-if="data.type === menuTypeValue">
<span style="color: #3c8dbc"></span>
<span v-if="data.status == 1">{{ data.name }}</span>
<span v-if="data.status == -1" style="color: #e6a23c">{{ data.name }}</span>
<span style="color: #3c8dbc"></span>
<el-tag v-if="data.children !== null" size="small">{{ data.children.length }}</el-tag>
</span>
<span style="font-size: 13px" v-if="data.type === permissionTypeValue">
<span style="color: #3c8dbc"></span>
<span :style="data.status == 1 ? 'color: #67c23a;' : 'color: #f67c6c;'">{{ data.name }}</span>
<span style="color: #3c8dbc"></span>
</span>
</span>
<span style="font-size: 13px" v-if="data.type === permissionTypeValue">
<span style="color: #3c8dbc"></span>
<span :style="data.status == 1 ? 'color: #67c23a;' : 'color: #f67c6c;'">{{ data.name }}</span>
<span style="color: #3c8dbc"></span>
</span>
</span>
</template>
</el-tree>
</template>
</el-tree>
</el-scrollbar>
<ResourceEdit
:title="dialogForm.title"
@@ -94,7 +102,7 @@
</template>
<script lang="ts" setup>
import { ref, toRefs, reactive, onMounted } from 'vue';
import { ref, toRefs, reactive, onMounted, watch } from 'vue';
import { ElMessage, ElMessageBox } from 'element-plus';
import ResourceEdit from './ResourceEdit.vue';
import { ResourceTypeEnum } from '../enums';
@@ -119,6 +127,8 @@ const props = {
};
const contextmenuRef = ref();
const filterResource = ref();
const resourceTreeRef = ref();
const contextmenuInfo = new ContextmenuItem('info', '详情').withIcon('View').withOnClick((data: any) => info(data));
@@ -195,6 +205,17 @@ onMounted(() => {
search();
});
watch(filterResource, (val) => {
resourceTreeRef.value!.filter(val);
});
const filterNode = (value: string, data: any) => {
if (!value) {
return true;
}
return data.name.includes(value);
};
const search = async () => {
let res = await resourceApi.list.request(null);
state.data = res;
@@ -380,11 +401,15 @@ const info = async (data: any) => {
};
</script>
<style lang="scss">
.menu {
.system-resouce-list {
.el-tree-node__content {
height: 40px;
line-height: 40px;
}
.tree-data {
height: calc(100vh - 200px);
}
}
.none-select {

View File

@@ -18,7 +18,7 @@ require (
github.com/gorilla/websocket v1.5.1
github.com/kanzihuang/vitess/go/vt/sqlparser v0.0.0-20231018071450-ac8d9f0167e9
github.com/lionsoul2014/ip2region/binding/golang v0.0.0-20230712084735-068dc2aee82d
github.com/mojocn/base64Captcha v1.3.5 //
github.com/mojocn/base64Captcha v1.3.6 //
github.com/pkg/errors v0.9.1
github.com/pkg/sftp v1.13.6
github.com/pquerna/otp v1.4.0
@@ -78,7 +78,7 @@ require (
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect
golang.org/x/arch v0.3.0 // indirect
golang.org/x/exp v0.0.0-20230519143937-03e91628a987
golang.org/x/image v0.0.0-20220302094943-723b81ca9867 // indirect
golang.org/x/image v0.13.0 // indirect
golang.org/x/net v0.18.0 // indirect
golang.org/x/sync v0.1.0 // indirect
golang.org/x/sys v0.15.0 // indirect

View File

@@ -88,9 +88,12 @@ func (p *tagTreeAppImpl) Save(ctx context.Context, tag *entity.TagTree) error {
tag.CodePath = parentTag.CodePath + tag.Code + entity.CodePathSeparator
} else {
if accountId != consts.AdminId {
return errorx.NewBiz("非管理员无法添加根标签")
}
tag.CodePath = tag.Code + entity.CodePathSeparator
}
if err := p.CanAccess(accountId, tag.CodePath); err != nil {
if p.CanAccess(accountId, tag.CodePath) != nil {
return errorx.NewBiz("无权添加该标签")
}

View File

@@ -22,7 +22,8 @@ func Generate() (string, string, error) {
c := base64Captcha.NewCaptcha(driver, store)
// 获取
return c.Generate()
id, b64s, _, err := c.Generate()
return id, b64s, err
}
// 验证验证码