feat: 1.前端组件升级 2.redis数据操作支持string,hash,set的新增修改

This commit is contained in:
meilin.huang
2022-01-12 16:00:31 +08:00
parent 468ecb5623
commit 1216ce3b52
52 changed files with 1808 additions and 645 deletions

View File

@@ -54,18 +54,9 @@ func (l *LogFormatter) Format(entry *logrus.Entry) ([]byte, error) {
timestamp := time.Now().Local().Format("2006-01-02 15:04:05.000")
level := entry.Level
logMsg := fmt.Sprintf("%s [%s]", timestamp, strings.ToUpper(level.String()))
// 如果存在调用信息,且为error级别以上记录文件及行号
// 如果存在调用信息,记录方法信息及行号
if caller := entry.Caller; caller != nil {
var fp string
// 全路径切割,只获取项目相关路径,
// 即/Users/hml/Desktop/project/go/mayfly-go/server/test.go只获取/server/test.go
ps := strings.Split(caller.File, "mayfly-go/")
if len(ps) >= 2 {
fp = ps[1]
} else {
fp = ps[0]
}
logMsg = logMsg + fmt.Sprintf(" [%s:%d]", fp, caller.Line)
logMsg = logMsg + fmt.Sprintf(" [%s:%d]", caller.Function, caller.Line)
}
for k, v := range entry.Data {
logMsg = logMsg + fmt.Sprintf(" [%s=%v]", k, v)

View File

@@ -7,29 +7,29 @@
"lint-fix": "eslint --fix --ext .js --ext .jsx --ext .vue src/"
},
"dependencies": {
"@types/lodash": "^4.14.178",
"axios": "^0.21.1",
"axios": "^0.24.0",
"codemirror": "^5.61.0",
"core-js": "^3.6.5",
"countup.js": "^2.0.7",
"cropperjs": "^1.5.11",
"echarts": "^5.1.1",
"echarts-wordcloud": "^2.0.0",
"element-plus": "^1.0.2-beta.44",
"element-plus": "^1.3.0-beta.2",
"@element-plus/icons-vue": "^0.2.4",
"jsonlint": "^1.6.3",
"lodash": "^4.17.21",
"mitt": "^2.1.0",
"mitt": "^3.0.0",
"nprogress": "^0.2.0",
"screenfull": "^5.1.0",
"sortablejs": "^1.13.0",
"sql-formatter": "^2.3.3",
"vue": "^3.0.5",
"vue-router": "^4.0.2",
"vuex": "^4.0.0-rc.2",
"xterm": "^4.9.0",
"xterm-addon-fit": "^0.4.0"
"sql-formatter": "^4.0.2",
"vue": "^3.2.20",
"vue-router": "^4.0.12",
"vuex": "^4.0.2",
"xterm": "^4.16.0",
"xterm-addon-fit": "^0.5.0"
},
"devDependencies": {
"@types/lodash": "^4.14.178",
"@types/axios": "^0.14.0",
"@types/clipboard": "^2.0.1",
"@types/node": "^15.6.0",
@@ -40,14 +40,14 @@
"@vitejs/plugin-vue": "^1.2.2",
"@vue/compiler-sfc": "^3.0.11",
"dotenv": "^10.0.0",
"eslint": "^7.27.0",
"eslint-plugin-vue": "^7.9.0",
"eslint": "^8.5.0",
"eslint-plugin-vue": "^8.2.0",
"prettier": "^2.3.0",
"sass": "^1.34.0",
"sass-loader": "^11.1.1",
"sass": "^1.45.1",
"sass-loader": "^12.4.0",
"typescript": "^4.2.4",
"vite": "^2.3.2",
"vue-eslint-parser": "^7.6.0"
"vite": "^2.7.4",
"vue-eslint-parser": "^8.0.1"
},
"browserslist": [
"> 1%",

View File

@@ -1,4 +1,5 @@
import { nextTick } from 'vue';
import * as svg from '@element-plus/icons-vue';
// 获取阿里字体图标
const getAlicdnIconfont = () => {
@@ -31,16 +32,10 @@ const getAlicdnIconfont = () => {
const elementPlusIconfont = () => {
return new Promise((resolve, reject) => {
nextTick(() => {
const styles: any = document.styleSheets;
let sheetsIconList = [];
for (let i = 0; i < styles.length; i++) {
for (let j = 0; j < styles[i].cssRules.length; j++) {
if (styles[i].cssRules[j].selectorText && styles[i].cssRules[j].selectorText.indexOf('.el-icon-') === 0) {
sheetsIconList.push(
`${styles[i].cssRules[j].selectorText.substring(1, styles[i].cssRules[j].selectorText.length).replace(/\:\:before/gi, '')}`
);
}
}
const icons = svg as any;
const sheetsIconList = [];
for (const i in icons) {
sheetsIconList.push(`${icons[i].name}`);
}
if (sheetsIconList.length > 0) resolve(sheetsIconList);
else reject('未获取到值,请刷新重试');

View File

@@ -1,57 +1,71 @@
<template>
<div class="icon-selector">
<el-popover :placement="placement" :width="650" v-model:visible="fontIconVisible" popper-class="icon-selector-popper">
<el-popover placement="bottom" :width="450" v-model:visible="fontIconVisible" popper-class="icon-selector-popper">
<template #reference>
<el-input
v-model="modelValue"
placeholder="请点击选择图标"
clearable
size="small"
v-model="fontIconSearch"
:placeholder="fontIconPlaceholder"
:clearable="clearable"
:disabled="disabled"
:size="size"
ref="inputWidthRef"
:prefix-icon="modelValue"
@clear="onClearFontIcon"
></el-input>
@focus="onIconFocus"
@blur="onIconBlur"
>
<template #prepend>
<SvgIcon :name="prepend" class="font14" />
</template>
</el-input>
</template>
<transition name="el-zoom-in-top">
<div class="icon-selector-warp" v-show="fontIconVisible">
<div class="icon-selector-warp-title">请选择一个图标</div>
<div v-if="isAllOn" class="icon-selector-all">
<el-input v-model="fontIconSearch" placeholder="请输入内容进行搜索" size="small"></el-input>
<div class="icon-selector-all-tabs">
<div
class="icon-selector-all-tabs-item"
v-for="(v, k) in fontIconTabsList"
:key="k"
@click="onFontIconTabsClick(v, k)"
:class="{ 'icon-selector-all-tabs-active': fontIconTabsIndex === k }"
<div class="icon-selector-warp-title flex">
<div class="flex-auto">{{ title }}</div>
<div class="icon-selector-warp-title-tab" v-if="type === 'all'">
<span :class="{ 'span-active': fontIconType === 'ali' }" @click="onIconChange('ali')" class="ml10" title="iconfont 图标"
>ali</span
>
<span
:class="{ 'span-active': fontIconType === 'ele' }"
@click="onIconChange('ele')"
class="ml10"
title="elementPlus 图标"
>ele</span
>
<span
:class="{ 'span-active': fontIconType === 'awe' }"
@click="onIconChange('awe')"
class="ml10"
title="fontawesome 图标"
>awe</span
>
<div class="label">{{ v.label }}</div>
</div>
</div>
</div>
<div class="icon-selector-warp-row">
<el-row :gutter="10">
<el-scrollbar ref="selectorScrollbarRef">
<el-row :gutter="10" v-if="fontIconSheetsFilterList.length > 0">
<el-col
:xs="4"
:xs="6"
:sm="4"
:md="2"
:lg="2"
:xl="1"
:class="`${fontIconTabsIcon}-col`"
@click="onColClick(v, k)"
:md="4"
:lg="4"
:xl="4"
@click="onColClick(v)"
v-for="(v, k) in fontIconSheetsFilterList"
:key="k"
>
<div class="icon-selector-warp-item" :class="{ 'icon-selector-active': fontIconIndex === k }">
<div class="icon-selector-warp-item" :class="{ 'icon-selector-active': fontIconPrefix === v }">
<div class="flex-margin">
<div class="icon-selector-warp-item-value">
<i :class="[fontIconTabsIcon, v]"></i>
<SvgIcon :name="v" />
</div>
</div>
</div>
</el-col>
</el-row>
<el-empty :image-size="100" v-if="fontIconSheetsFilterList.length <= 0"></el-empty>
<el-empty :image-size="100" v-if="fontIconSheetsFilterList.length <= 0" :description="emptyDescription"></el-empty>
</el-scrollbar>
</div>
</div>
</transition>
@@ -60,43 +74,92 @@
</template>
<script lang="ts">
import { ref, toRefs, reactive, onMounted, computed } from 'vue';
import initIconfont from '@/common/utils/getStyleSheets.ts';
import { ref, toRefs, reactive, onMounted, nextTick, computed, watch } from 'vue';
import initIconfont from '@/common/utils/getStyleSheets';
export default {
name: 'iconSelector',
emits: ['update:modelValue', 'get', 'clear'],
props: {
// 是否开启高级功能
isAllOn: {
// 输入框前置内容
prepend: {
type: String,
default: () => 'Pointer',
},
// 输入框占位文本
placeholder: {
type: String,
default: () => '请输入内容搜索图标或者选择图标',
},
// 输入框占位文本
size: {
type: String,
default: () => 'default',
},
// 弹窗标题
title: {
type: String,
default: () => '请选择图标',
},
// icon 图标类型
type: {
type: String,
default: () => 'ele',
},
// 禁用
disabled: {
type: Boolean,
default: () => false,
},
// 出现位置
placement: {
type: String,
default: () => 'bottom',
// 是否可清空
clearable: {
type: Boolean,
default: () => true,
},
modelValue: {
// 自定义空状态描述文字
emptyDescription: {
type: String,
default: () => '无相关图标',
},
// 双向绑定值,字段名为固定,改了之后将不生效
// 参考https://v3.cn.vuejs.org/guide/migration/v-model.html#%E8%BF%81%E7%A7%BB%E7%AD%96%E7%95%A5
modelValue: String,
},
setup(props, { emit }) {
const inputWidthRef = ref();
const selectorScrollbarRef = ref();
const state: any = reactive({
// fontIcon: '',
// fontIconPrefix: '',
fontIconPrefix: '',
fontIconVisible: false,
fontIconWidth: 0,
fontIconIndex: '',
fontIconSearch: '',
fontIconTabsIndex: 0,
fontIconTabsIcon: 'iconfont ali',
fontIconTabsList: [{ label: 'element' }, { label: 'iconfont' }],
fontIconSheetsList: [],
fontIconSheetsListAli: [],
fontIconSheetsListEle: [],
fontIconSheetsListAwe: [],
fontIconPlaceholder: '',
fontIconType: 'ali',
fontIconShow: true,
});
// 设置无数据时的空状态
// 处理 input 获取焦点时modelValue 有值时,改变 input 的 placeholder 值
const onIconFocus = () => {
state.fontIconVisible = true;
if (!props.modelValue) return false;
state.fontIconSearch = '';
state.fontIconPlaceholder = props.modelValue;
};
// 处理 input 失去焦点时,为空将清空 input 值,为点击选中图标时,将取原先值
const onIconBlur = () => {
state.fontIconVisible = false;
setTimeout(() => {
const icon = state.fontIconSheetsList.filter((icon: string) => icon === state.fontIconSearch);
if (icon.length <= 0) state.fontIconSearch = '';
}, 300);
};
// 处理 icon 双向绑定数值回显
const initModeValueEcho = () => {
if (props.modelValue === '') return false;
state.fontIconPlaceholder = props.modelValue;
state.fontIconPrefix = props.modelValue;
};
// 图标搜索及图标数据显示
const fontIconSheetsFilterList = computed(() => {
if (!state.fontIconSearch) return state.fontIconSheetsList;
let search = state.fontIconSearch.trim().toLowerCase();
@@ -104,65 +167,93 @@ export default {
if (item.toLowerCase().indexOf(search) !== -1) return item;
});
});
// 获取 input 的宽度
// const getInputWidth = () => {
// nextTick(() => {
// state.fontIconWidth = inputWidthRef.value.$el.offsetWidth;
// });
// };
const getInputWidth = () => {
nextTick(() => {
state.fontIconWidth = inputWidthRef.value.$el.offsetWidth;
});
};
// 监听页面宽度改变
// const initResize = () => {
// window.addEventListener('resize', () => {
// getInputWidth();
// });
// };
const initResize = () => {
window.addEventListener('resize', () => {
getInputWidth();
});
};
// 初始化数据
const initFontIconData = () => {
initIconfont.ele().then((res: any) => {
state.fontIconSheetsListEle = res;
const initFontIconData = async (type: string) => {
state.fontIconSheetsList = [];
if (type === 'ali') {
// await initIconfont.ali().then((res: any) => {
// // 阿里字体图标使用 `iconfont xxx`
// state.fontIconSheetsList = res.map((i) => `iconfont ${i}`);
// });
} else if (type === 'ele') {
await initIconfont.ele().then((res: any) => {
state.fontIconSheetsList = res;
});
// initIconfont.ali().then((res: any) => {
// state.fontIconSheetsListAli = res;
} else if (type === 'awe') {
// await initIconfont.awe().then((res: any) => {
// // fontawesome字体图标使用 `fa xxx`
// state.fontIconSheetsList = res.map((i) => `fa ${i}`);
// });
}
// 初始化 input 的 placeholder
// 参考单项数据流https://cn.vuejs.org/v2/guide/components-props.html?#%E5%8D%95%E5%90%91%E6%95%B0%E6%8D%AE%E6%B5%81
state.fontIconPlaceholder = props.placeholder;
// 初始化双向绑定回显
initModeValueEcho();
// 切换时,滚动条置顶。感兴趣可以使用 keep-alive <component :is="xxx"/> 进行缓存
selectorScrollbarRef.value.wrap$.scrollTop = 0;
};
// 当前项点击
const onColClick = (v: any, k: number) => {
state.fontIconIndex = k;
// state.fontIcon = v;
// 图标点击切换
const onIconChange = (type: string) => {
state.fontIconType = type;
initFontIconData(type);
};
// 获取当前点击的 icon 图标
const onColClick = (v: any) => {
state.fontIconPlaceholder = v;
state.fontIconVisible = false;
// if (state.fontIconTabsIndex === 0) state.fontIconPrefix = `iconfont ali ${v}`;
// else if (state.fontIconTabsIndex === 1) state.fontIconPrefix = `${v}`;
emit('update:modelValue', v);
};
// input 点击清除按钮时
const onClearFontIcon = () => {
state.fontIconIndex = '';
// state.fontIconPrefix = '';
state.fontIconPrefix = v;
emit('get', state.fontIconPrefix);
emit('update:modelValue', state.fontIconPrefix);
};
// tabs 点击
const onFontIconTabsClick = (v: any, k: number) => {
state.fontIconTabsIndex = k;
if (v.label === 'iconfont') state.fontIconSheetsList = state.fontIconSheetsListAli;
else if (v.label === 'element') state.fontIconSheetsList = state.fontIconSheetsListEle;
if (k === 0) state.fontIconTabsIcon = `iconfont ali`;
else if (k === 1) state.fontIconTabsIcon = `ele`;
// 清空当前点击的 icon 图标
const onClearFontIcon = () => {
state.fontIconPrefix = '';
emit('clear', state.fontIconPrefix);
emit('update:modelValue', state.fontIconPrefix);
};
// 页面加载时
onMounted(() => {
initFontIconData();
// initResize();
// getInputWidth();
// 判断默认进来是什么类型图标,进行 tab 回显
if (props.type === 'all') {
// if (props.modelValue?.indexOf('iconfont') > -1) onIconChange('ali');
// else if (props.modelValue?.indexOf('element') > -1) onIconChange('ele');
// else if (props.modelValue?.indexOf('fa') > -1) onIconChange('awe');
// else onIconChange('ali');
} else {
onIconChange(props.type);
}
initResize();
getInputWidth();
});
// 监听双向绑定 modelValue 的变化
watch(
() => props.modelValue,
() => {
initModeValueEcho();
}
);
return {
inputWidthRef,
selectorScrollbarRef,
fontIconSheetsFilterList,
onColClick,
onIconChange,
onClearFontIcon,
onFontIconTabsClick,
onIconFocus,
onIconBlur,
...toRefs(state),
};
},

View File

@@ -0,0 +1,24 @@
<script lang="ts">
// 渲染函数https://v3.cn.vuejs.org/guide/render-function.html
import { h, resolveComponent, defineComponent } from 'vue';
export default defineComponent({
name: 'svgIcon',
props: {
// svg 图标组件名字
name: {
type: String,
},
// svg 大小
size: {
type: Number,
},
// svg 颜色
color: {
type: String,
},
},
setup(props: any) {
return () => h('i', { class: 'el-icon', style: `--font-size: ${props.size};--color: ${props.color}` }, [h(resolveComponent(`${props.name}`))]);
},
});
</script>

View File

@@ -7,14 +7,33 @@ import { globalComponentSize } from '@/common/utils/componentSize.ts';
import { dateStrFormat } from '@/common/utils/date.ts'
import ElementPlus from 'element-plus';
import 'element-plus/lib/theme-chalk/index.css';
import 'element-plus/dist/index.css';
import '@/theme/index.scss';
import mitt from 'mitt';
import { ElMessage } from 'element-plus';
import locale from 'element-plus/lib/locale/lang/zh-cn'
import * as svg from '@element-plus/icons-vue';
import SvgIcon from '@/components/svgIcon/index.vue';
const app = createApp(App);
/**
* 导出全局注册 element plus svg 图标
* @param app vue 实例
* @description 使用https://element-plus.gitee.io/zh-CN/component/icon.html
*/
function elSvg(app: any) {
const icons = svg as any;
for (const i in icons) {
app.component(`${icons[i].name}`, icons[i]);
}
app.component('SvgIcon', SvgIcon);
}
elSvg(app)
directive(app);
app.use(router)
.use(store, key)
.use(ElementPlus, { size: globalComponentSize, locale: locale })
@@ -42,5 +61,3 @@ app.config.errorHandler = function (err: any, vm, info) {
}
app.config.globalProperties.mittBus = mitt();
directive(app);

View File

@@ -119,7 +119,7 @@ const themeConfigModule: Module<ThemeConfigState, RootStateTypes> = {
globalViceTitle: 'mayfly',
// 默认初始语言,可选值"<zh-cn|en|zh-tw>",默认 zh-cn
globalI18n: 'zh-cn',
// 默认全局组件大小,可选值"<|medium|small|mini>",默认 ''
// 默认全局组件大小,可选值"<|large|default|small>",默认 ''
globalComponentSize: '',
},
},

View File

@@ -1,12 +1,10 @@
@import 'mixins/function.scss';
@import 'mixins/element-mixins.scss';
@import 'mixins/mixins.scss';
/* Button 按钮
------------------------------- */
// text
.el-button {
font-weight: 500;
}
.el-button--text {
color: set-color(primary);
&:focus,
@@ -749,9 +747,14 @@
// 默认样式修改
.el-menu {
border-right: none !important;
width: 220px;
}
// 修复点击左侧菜单折叠再展开时,宽度不跟随问题
.el-menu--collapse {
width: 64px !important;
}
.el-menu-item,
.el-submenu__title {
.el-sub-menu__title {
height: 50px !important;
line-height: 50px !important;
color: var(--bg-menuBarColor);
@@ -759,31 +762,31 @@
}
// horizontal 水平方向时
.el-menu--horizontal > .el-menu-item.is-active,
.el-menu--horizontal > .el-submenu.is-active .el-submenu__title {
.el-menu--horizontal > .el-sub-menu.is-active .el-sub-menu__title {
border-bottom: 3px solid !important;
border-bottom-color: set-color(primary);
color: set-color(primary);
color: set-color(primary) !important;
}
.el-menu--horizontal .el-menu-item:not(.is-disabled):focus,
.el-menu--horizontal .el-menu-item:not(.is-disabled):hover,
.el-menu--horizontal > .el-submenu:focus .el-submenu__title,
.el-menu--horizontal > .el-submenu:hover .el-submenu__title,
.el-menu--horizontal > .el-sub-menu:focus .el-sub-menu__title,
.el-menu--horizontal > .el-sub-menu:hover .el-sub-menu__title,
.el-menu--horizontal .el-menu .el-menu-item.is-active,
.el-menu--horizontal .el-menu .el-submenu.is-active > .el-submenu__title {
color: set-color(primary);
.el-menu--horizontal .el-menu .el-sub-menu.is-active > .el-sub-menu__title {
color: set-color(primary) !important;
}
.el-menu.el-menu--horizontal {
border-bottom: none !important;
}
.el-menu--horizontal > .el-menu-item,
.el-menu--horizontal > .el-submenu .el-submenu__title {
.el-menu--horizontal > .el-sub-menu .el-sub-menu__title {
color: var(--bg-topBarColor);
}
// 外部链接时
.el-menu-item a,
.el-menu-item a:hover,
.el-menu-item i,
.el-submenu__title i {
.el-sub-menu__title i {
color: inherit;
text-decoration: none;
}
@@ -793,22 +796,23 @@
}
// 默认 hover 时
.el-menu-item:hover,
.el-submenu__title:hover {
.el-sub-menu__title:hover {
color: set-color(primary) !important;
background-color: transparent !important;
i {
color: set-color(primary);
}
}
// 高亮时
.el-menu-item.is-active {
// 高亮时/菜单收起时
.el-menu-item.is-active,
.el-menu--collapse .el-sub-menu.is-active i {
color: set-color(primary);
}
.el-active-extend {
color: #ffffff !important;
color: var(--color-whites) !important;
background-color: set-color(primary) !important;
i {
color: #ffffff !important;
color: var(--color-whites) !important;
}
}
#add-is-active {
@@ -819,34 +823,37 @@
}
// 菜单收起时且是a链接
.el-popper.is-dark a {
color: #ffffff !important;
color: var(--color-whites) !important;
text-decoration: none;
}
// 菜单收起时鼠标经过背景颜色/字体颜色
.el-popper.is-light {
.el-menu--vertical {
.el-menu {
background: var(--bg-menuBar);
}
}
.el-menu--horizontal {
background: var(--bg-topBar);
.el-menu,
.el-menu-item,
.el-submenu__title {
.el-sub-menu__title {
color: var(--bg-topBarColor);
background: var(--bg-topBar);
}
}
}
// 第三方图标字体间距/大小设置
.el-menu-item .iconfont,
.el-submenu .iconfont {
font-size: 14px !important;
display: inline-block;
vertical-align: middle;
margin-right: 5px;
width: 24px;
text-align: center;
}
// .el-menu-item .iconfont,
// .el-sub-menu .iconfont {
// @include generalIcon;
// }
// .el-menu-item .fa,
// .el-sub-menu .fa {
// @include generalIcon;
// }
// element plus 本身字体图标
.el-submenu [class^='el-icon-'] {
.el-sub-menu .el-icon {
font-size: 14px !important;
}
// 去掉离开浏览器时,菜单的默认高亮
@@ -888,6 +895,9 @@
color: set-color(primary);
background-color: set-color(primary-light-9);
}
.el-dropdown-menu .el-dropdown-menu__item {
white-space: nowrap;
}
/* Steps 步骤条
------------------------------- */
@@ -931,18 +941,25 @@
color: set-color(primary);
}
.el-overlay {
overflow: hidden;
.el-overlay-dialog {
display: flex;
align-items: center;
justify-content: center;
position: unset !important;
width: 100%;
height: 100%;
.el-dialog {
margin: 0 auto !important;
position: absolute;
.el-dialog__body {
padding: 20px !important;
}
}
}
}
.el-dialog__body {
max-height: 70vh !important;
max-height: calc(90vh - 111px) !important;
overflow-y: auto;
overflow-x: hidden;
}
@@ -998,6 +1015,9 @@
/* scrollbar
------------------------------- */
.el-scrollbar__bar {
z-index: 4;
}
.el-scrollbar__wrap {
overflow-x: hidden !important;
max-height: 100%; /*防止页面切换时,滚动条高度不变的问题(滚动条高度非滚动条滚动高度)*/
@@ -1008,13 +1028,27 @@
.el-select-dropdown__wrap {
max-height: 274px !important; /*修复Select 选择器高度问题*/
}
.el-cascader-menu__wrap.el-scrollbar__wrap {
height: 204px !important; /*修复Cascader 级联选择器高度问题*/
}
/* Drawer 抽屉
------------------------------- */
.el-drawer__body {
.el-drawer {
--el-drawer-padding-primary: unset !important;
.el-drawer__header {
padding: 0 15px !important;
height: 50px;
display: flex;
align-items: center;
margin-bottom: 0 !important;
border-bottom: 1px solid rgb(230, 230, 230);
}
.el-drawer__body {
width: 100%;
height: 100%;
overflow: auto;
}
}
.el-drawer-fade-enter-active .el-drawer.rtl {
animation: rtl-drawer-animation 0.3s ease-in reverse !important;

View File

@@ -0,0 +1,15 @@
import Api from '@/common/Api';
export const serviceApi = {
services: Api.create("/gw/services", 'get'),
saveService: Api.create("/gw/services", 'post'),
syncService: Api.create("/gw/services/{id}/sync", 'post'),
// 获取服务下的api信息
serviceApis: Api.create("/gw/services/{serviceId}/apis", 'get'),
saveServiceApi: Api.create("/gw/services/{serviceId}/apis", 'post'),
syncServiceApi: Api.create("/gw/services/{id}/apis/{apiId}/sync", 'post'),
// 获取项目下的成员信息
projectMems: Api.create("/gw/projects/{projectId}/members", 'get'),
saveProjectMem: Api.create("/gw/projects/{projectId}/members", 'post'),
deleteProjectMem: Api.create("/gw/projects/{projectId}/members/{accountId}", 'delete'),
}

View File

@@ -0,0 +1,192 @@
<template>
<div>
<el-dialog :title="title" v-model="dialogVisible" :show-close="false" :before-close="cancel" width="65%">
<el-form :model="form" ref="apiForm" :rules="rules" label-width="85px" size="small">
<el-form-item prop="serviceId" label="服务:" required>
<el-select style="width: 100%" v-model="form.serviceId" placeholder="请选择服务" @change="changeService" filterable>
<el-option v-for="item in services" :key="item.id" :label="`${item.name}`" :value="item.id"> </el-option>
</el-select>
</el-form-item>
<el-form-item prop="name" label="名称:" required>
<el-input v-model.trim="form.name" placeholder="请输入api名称" auto-complete="off"></el-input>
</el-form-item>
<el-form-item prop="code" label="code:" required>
<el-input :disabled="form.id" v-model.trim="form.code" placeholder="请输入code" auto-complete="off"></el-input>
</el-form-item>
<el-form-item prop="method" label="method:" required>
<el-select style="width: 100%" v-model="form.method" placeholder="请选择请求方法" @change="changeService" filterable>
<el-option key="get" label="GET" value="GET"> </el-option>
<el-option key="post" label="POST" value="POST"> </el-option>
<el-option key="put" label="PUT" value="PUT"> </el-option>
<el-option key="delete" label="DELETE" value="DELETE"> </el-option>
</el-select>
</el-form-item>
<el-form-item prop="uri" label="uri:" required>
<el-input v-model.trim="form.uri" placeholder="请输入method:uri格式"></el-input>
</el-form-item>
<el-form-item label="schema:">
<!-- <vue3-json-editor v-model="jsonschema" @json-change="schemaChange" :show-btns="false" :expandedOnStart="true" /> -->
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" :loading="btnLoading" @click="btnOk" size="mini"> </el-button>
<el-button @click="cancel()" size="mini"> </el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script lang="ts">
import { toRefs, reactive, watch, defineComponent, ref } from 'vue';
import { serviceApi } from '../api';
import { ElMessage } from 'element-plus';
// import { Vue3JsonEditor } from 'vue3-json-editor';
export default defineComponent({
name: 'RedisEdit',
components: {
// Vue3JsonEditor,
},
props: {
visible: {
type: Boolean,
},
services: {
type: Array,
},
api: {
type: [Boolean, Object],
},
title: {
type: String,
},
},
setup(props: any, { emit }) {
const apiForm: any = ref(null);
const state = reactive({
dialogVisible: false,
services: [],
form: {
id: null,
name: null,
code: null,
uri: null,
serviceName: null,
serviceId: null,
schema: null,
},
jsonschema: {},
btnLoading: false,
rules: {
serviceId: [
{
required: true,
message: '请选择服务',
trigger: ['change', 'blur'],
},
],
name: [
{
required: true,
message: '请输入api名称',
trigger: ['change', 'blur'],
},
],
method: [
{
required: true,
message: '请输入请求method',
trigger: ['change', 'blur'],
},
],
uri: [
{
required: true,
message: '请输入请求uri',
trigger: ['change', 'blur'],
},
],
code: [
{
required: true,
message: '请输入code',
trigger: ['change', 'blur'],
},
],
},
});
watch(props, async (newValue) => {
state.services = newValue.services;
if (newValue.api) {
state.form = { ...newValue.api };
console.log(state.form)
if (state.form.schema) {
state.jsonschema = JSON.parse(state.form.schema as any);
}
} else {
state.form = { } as any;
}
state.dialogVisible = newValue.visible;
});
const changeService = (serviceId: number) => {
for (let p of state.services as any) {
if (p.id == serviceId) {
state.form.serviceName = p.name;
}
}
};
const schemaChange = (jsonValue: any) => {
state.form.schema = JSON.stringify(jsonValue) as any;
};
const btnOk = async () => {
apiForm.value.validate((valid: boolean) => {
if (valid) {
serviceApi.saveServiceApi.request(state.form).then(() => {
ElMessage.success('保存成功');
emit('val-change', state.form);
state.btnLoading = true;
setTimeout(() => {
state.btnLoading = false;
}, 1000);
cancel();
});
} else {
ElMessage.error('请正确填写信息');
return false;
}
});
};
const cancel = () => {
emit('update:visible', false);
emit('cancel');
setTimeout(() => {
apiForm.value.resetFields();
// 重置对象属性为null
state.form = {} as any;
state.jsonschema = {};
}, 200);
};
return {
...toRefs(state),
schemaChange,
apiForm,
changeService,
btnOk,
cancel,
};
},
});
</script>
<style lang="scss">
</style>

View File

@@ -0,0 +1,239 @@
<template>
<div>
<div class="toolbar">
<el-button @click="showSaveApiDialog" v-auth="permissions.saveProject" type="primary" icon="el-icon-plus" size="mini">添加</el-button>
<el-button
@click="showSaveApiDialog(chooseData)"
v-auth="permissions.saveProject"
:disabled="chooseId == null"
type="primary"
icon="el-icon-edit"
size="mini"
>编辑</el-button
>
<el-button v-auth="'role:del'" :disabled="chooseId == null" type="danger" icon="el-icon-delete" size="mini">删除</el-button>
<div style="float: right">
<el-select v-model="query.serviceId" @change="changeService" placeholder="请选择服务" filterable size="small">
<el-option v-for="item in services" :key="item.id" :label="`${item.name}`" :value="item.id"> </el-option>
</el-select>
<el-input
class="mr2 ml2"
placeholder="请输入服务名!"
size="small"
style="width: 140px"
v-model="query.name"
@clear="search"
clearable
></el-input>
<el-button @click="search" type="success" icon="el-icon-search" size="mini"></el-button>
</div>
</div>
<el-table :data="apis" @current-change="choose" border ref="table" style="width: 100%">
<el-table-column label="选择" width="50px">
<template #default="scope">
<el-radio v-model="chooseId" :label="scope.row.id">
<i></i>
</el-radio>
</template>
</el-table-column>
<el-table-column prop="serviceName" label="服务"></el-table-column>
<el-table-column prop="name" label="名称" show-overflow-tooltip></el-table-column>
<el-table-column prop="code" label="code" show-overflow-tooltip> </el-table-column>
<el-table-column prop="method" label="method" min-width="45" show-overflow-tooltip> </el-table-column>
<el-table-column prop="uri" label="uri" show-overflow-tooltip> </el-table-column>
<el-table-column prop="createTime" label="创建时间">
<template #default="scope">
{{ $filters.dateFormat(scope.row.createTime) }}
</template>
</el-table-column>
<el-table-column prop="creator" label="创建者" min-width="50"> </el-table-column>
<el-table-column label="操作" min-width="50">
<template #default="scope">
<el-button
@click="syncServiceApi(scope.row)"
type="success"
icom="el-icon-tickets"
size="mini"
plain
:disabled="scope.row.canSync == -1"
>同步</el-button
>
</template>
</el-table-column>
<!-- <el-table-column label="查看更多" min-width="80px">
<template #default="scope">
<el-link @click.prevent="showMembers(scope.row)" type="success">成员</el-link>
<el-link class="ml5" @click.prevent="showEnv(scope.row)" type="info">环境</el-link>
</template>
</el-table-column> -->
</el-table>
<el-pagination
@current-change="handlePageChange"
style="text-align: center"
background
layout="prev, pager, next, total, jumper"
:total="total"
v-model:current-page="query.pageNum"
:page-size="query.pageSize"
/>
<api-edit :services="services" v-model:visible="saveApiDialog.visible" :api="saveApiDialog.form" @val-change="valChange"/>
<!-- <el-dialog width="400px" title="服务编辑" :before-close="cancelAddService" v-model="addServiceDialog.visible">
<el-form :model="addServiceDialog.form" size="small" label-width="70px">
<el-form-item label="服务名:" required>
<el-input :disabled="addServiceDialog.form.id ? true : false" v-model="addServiceDialog.form.name" auto-complete="off"></el-input>
</el-form-item>
<el-form-item label="描述:" required>
<el-input v-model="addServiceDialog.form.remark" auto-complete="off"></el-input>
</el-form-item>
<el-form-item label="地址:">
<el-input v-model="addServiceDialog.form.urls" auto-complete="off" placeholder="不填则注册中心获取"></el-input>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="saveService" type="primary" size="small"> </el-button>
<el-button @click="cancelAddService()" size="small"> </el-button>
</div>
</template>
</el-dialog> -->
</div>
</template>
<script lang="ts">
import { toRefs, reactive, onMounted, defineComponent } from 'vue';
import { serviceApi } from '../api';
import { ElMessage } from 'element-plus';
import { notEmpty } from '@/common/assert';
import ApiEdit from './ApiEdit.vue'
export default defineComponent({
name: 'ServiceList',
components: {
ApiEdit
},
setup() {
const state = reactive({
permissions: {
saveProject: 'project:save',
saveMember: 'project:member:add',
delMember: 'project:member:del',
saveEnv: 'project:env:add',
},
query: {
pageNum: 1,
pageSize: 10,
name: null,
},
total: 0,
apis: [],
services: [],
btnLoading: false,
chooseId: null as any,
chooseData: null as any,
saveApiDialog: {
title: '新增api',
visible: false,
form: { name: '', remark: '' },
},
});
onMounted(() => {
getServices();
// search();
});
const search = async () => {
let res = await serviceApi.serviceApis.request(state.query);
state.apis = res.list;
state.total = res.total;
};
const getServices = async () => {
let res = await serviceApi.services.request({ pateNum: 1, pageSize: 100 });
state.services = res.list;
};
const changeService = async () => {
search()
}
const handlePageChange = (curPage: number) => {
state.query.pageNum = curPage;
search();
};
const showSaveApiDialog = (data: any) => {
if (data) {
state.saveApiDialog.form = { ...data };
} else {
state.saveApiDialog.form = {} as any;
}
state.saveApiDialog.visible = true;
};
const cancelAddApi = () => {
state.saveApiDialog.visible = false;
state.saveApiDialog.form = {} as any;
};
const saveService = async () => {
const form = state.saveApiDialog.form as any;
notEmpty(form.name, '服务名不能为空');
notEmpty(form.remark, '服务描述不能为空');
await serviceApi.saveService.request(form);
ElMessage.success('保存成功');
search();
cancelAddApi();
};
const choose = (item: any) => {
if (!item) {
return;
}
state.chooseId = item.id;
state.chooseData = item;
};
const syncServiceApi = async (item: any) => {
await serviceApi.syncServiceApi.request({apiId: item.id, id: item.serviceId})
ElMessage.success("同步成功")
item.canSync = -1
}
const valChange = () => {
search();
}
// const addEnv = async () => {
// const envForm = state.showEnvDialog.envForm;
// envForm.projectId = state.chooseData.id;
// await projectApi.saveProjectEnv.request(envForm);
// ElMessage.success('保存成功');
// state.showEnvDialog.envs = await projectApi.projectEnvs.request({ projectId: envForm.projectId });
// cancelAddEnv();
// };
return {
...toRefs(state),
search,
changeService,
handlePageChange,
choose,
showSaveApiDialog,
saveService,
syncServiceApi,
cancelAddApi,
valChange,
};
},
});
</script>
<style lang="scss">
</style>

View File

@@ -0,0 +1,223 @@
<template>
<div>
<div class="toolbar">
<el-button @click="showAddServiceDialog" v-auth="permissions.saveProject" type="primary" icon="el-icon-plus" size="mini">添加</el-button>
<el-button
@click="showAddServiceDialog(chooseData)"
v-auth="permissions.saveProject"
:disabled="chooseId == null"
type="primary"
icon="el-icon-edit"
size="mini"
>编辑</el-button
>
<el-button v-auth="'role:del'" :disabled="chooseId == null" type="danger" icon="el-icon-delete" size="mini">删除</el-button>
<div style="float: right">
<el-input
class="mr2"
placeholder="请输入项目名!"
size="small"
style="width: 140px"
v-model="query.name"
@clear="search"
clearable
></el-input>
<el-button @click="search" type="success" icon="el-icon-search" size="mini"></el-button>
</div>
</div>
<el-table :data="services" @current-change="choose" border ref="table" style="width: 100%">
<el-table-column label="选择" width="50px">
<template #default="scope">
<el-radio v-model="chooseId" :label="scope.row.id">
<i></i>
</el-radio>
</template>
</el-table-column>
<el-table-column prop="name" label="服务名"></el-table-column>
<el-table-column prop="routePath" label="路由路径"></el-table-column>
<el-table-column prop="urls" label="服务地址">
<template #default="scope">
{{ scope.row.urls ? scope.row.urls : '注册中心' }}
</template>
</el-table-column>
<el-table-column prop="remark" label="描述" min-width="80px" show-overflow-tooltip></el-table-column>
<el-table-column prop="createTime" label="创建时间">
<template #default="scope">
{{ $filters.dateFormat(scope.row.createTime) }}
</template>
</el-table-column>
<el-table-column prop="creator" label="创建者"> </el-table-column>
<!-- <el-table-column label="查看更多" min-width="80px">
<template #default="scope">
<el-link @click.prevent="showMembers(scope.row)" type="success">成员</el-link>
<el-link class="ml5" @click.prevent="showEnv(scope.row)" type="info">环境</el-link>
</template>
</el-table-column> -->
<el-table-column label="操作" min-width="80px">
<template #default="scope">
<el-button
@click="syncService(scope.row)"
type="success"
icom="el-icon-tickets"
size="mini"
plain
:disabled="scope.row.canSync == -1"
>同步</el-button
>
</template>
</el-table-column>
</el-table>
<el-pagination
@current-change="handlePageChange"
style="text-align: center"
background
layout="prev, pager, next, total, jumper"
:total="total"
v-model:current-page="query.pageNum"
:page-size="query.pageSize"
/>
<el-dialog width="400px" title="服务编辑" :before-close="cancelAddService" v-model="addServiceDialog.visible">
<el-form :model="addServiceDialog.form" size="small" label-width="85px">
<el-form-item label="服务名:" required>
<el-input :disabled="addServiceDialog.form.id ? true : false" v-model="addServiceDialog.form.name" auto-complete="off"></el-input>
</el-form-item>
<el-form-item label="路由路径:" required>
<el-input v-model="addServiceDialog.form.routePath" auto-complete="off"></el-input>
</el-form-item>
<el-form-item label="描述:" required>
<el-input v-model="addServiceDialog.form.remark" auto-complete="off"></el-input>
</el-form-item>
<el-form-item label="地址:">
<el-input v-model="addServiceDialog.form.urls" auto-complete="off" placeholder="不填则注册中心获取"></el-input>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="saveService" type="primary" size="small"> </el-button>
<el-button @click="cancelAddService()" size="small"> </el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script lang="ts">
import { toRefs, reactive, onMounted, defineComponent } from 'vue';
import { serviceApi } from '../api';
import { ElMessage } from 'element-plus';
import { notEmpty } from '@/common/assert';
export default defineComponent({
name: 'ServiceList',
components: {},
setup() {
const state = reactive({
permissions: {
saveProject: 'project:save',
saveMember: 'project:member:add',
delMember: 'project:member:del',
saveEnv: 'project:env:add',
},
query: {
pageNum: 1,
pageSize: 10,
name: null,
},
total: 0,
services: [],
btnLoading: false,
chooseId: null as any,
chooseData: null as any,
addServiceDialog: {
title: '新增服务',
visible: false,
form: { name: '', remark: '' },
},
});
onMounted(() => {
search();
});
const search = async () => {
let res = await serviceApi.services.request(state.query);
state.services = res.list;
state.total = res.total;
};
const handlePageChange = (curPage: number) => {
state.query.pageNum = curPage;
search();
};
const showAddServiceDialog = (data: any) => {
if (data) {
state.addServiceDialog.form = {...data};
} else {
state.addServiceDialog.form = {} as any;
}
state.addServiceDialog.visible = true;
};
const cancelAddService = () => {
state.addServiceDialog.visible = false;
state.addServiceDialog.form = {} as any;
};
const saveService = async () => {
const form = state.addServiceDialog.form as any;
notEmpty(form.name, '服务名不能为空');
notEmpty(form.remark, '服务描述不能为空');
await serviceApi.saveService.request(form);
ElMessage.success('保存成功');
search();
cancelAddService();
};
const syncService = async (item: any) => {
await serviceApi.syncService.request({id: item.id})
ElMessage.success("同步成功")
item.canSync = -1
}
const choose = (item: any) => {
if (!item) {
return;
}
state.chooseId = item.id;
state.chooseData = item;
};
// const addEnv = async () => {
// const envForm = state.showEnvDialog.envForm;
// envForm.projectId = state.chooseData.id;
// await projectApi.saveProjectEnv.request(envForm);
// ElMessage.success('保存成功');
// state.showEnvDialog.envs = await projectApi.projectEnvs.request({ projectId: envForm.projectId });
// cancelAddEnv();
// };
// const roleEditChange = (data: any) => {
// ElMessage.success('修改成功!');
// search();
// };
return {
...toRefs(state),
search,
handlePageChange,
choose,
showAddServiceDialog,
saveService,
syncService,
cancelAddService,
};
},
});
</script>
<style lang="scss">
</style>

View File

@@ -83,7 +83,7 @@ export default defineComponent({
() => route.path,
() => {
initCurrentRouteMeta(route.meta);
proxy.$refs.layoutScrollbarRef.wrap.scrollTop = 0;
proxy.$refs.layoutScrollbarRef.wrap$.scrollTop = 0;
}
);
return {

View File

@@ -33,7 +33,7 @@ export default {
watch(
() => route.path,
() => {
proxy.$refs.layoutDefaultsScrollbarRef.wrap.scrollTop = 0;
proxy.$refs.layoutDefaultsScrollbarRef.wrap$.scrollTop = 0;
}
);
return {

View File

@@ -1,20 +1,16 @@
<template>
<div class="layout-navbars-breadcrumb" v-show="getThemeConfig.isBreadcrumb">
<i
class="layout-navbars-breadcrumb-icon"
:class="getThemeConfig.isCollapse ? 'el-icon-s-unfold' : 'el-icon-s-fold'"
@click="onThemeConfigChange"
></i>
<SvgIcon class="layout-navbars-breadcrumb-icon" :name="getThemeConfig.isCollapse ? 'expand' : 'fold'" @click="onThemeConfigChange" />
<el-breadcrumb class="layout-navbars-breadcrumb-hide">
<transition-group name="breadcrumb" mode="out-in">
<el-breadcrumb-item v-for="(v, k) in breadcrumbList" :key="v.meta.title">
<span v-if="k === breadcrumbList.length - 1" class="layout-navbars-breadcrumb-span">
<i :class="v.meta.icon" class="layout-navbars-breadcrumb-iconfont" v-if="getThemeConfig.isBreadcrumbIcon"></i
>{{ v.meta.title }}
<SvgIcon :name="v.meta.icon" class="layout-navbars-breadcrumb-iconfont" v-if="getThemeConfig.isBreadcrumbIcon" />
{{ v.meta.title }}
</span>
<a v-else @click.prevent="onBreadcrumbClick(v)">
<i :class="v.meta.icon" class="layout-navbars-breadcrumb-iconfont" v-if="getThemeConfig.isBreadcrumbIcon"></i
>{{ v.meta.title }}
<SvgIcon :name="v.meta.icon" class="layout-navbars-breadcrumb-iconfont" v-if="getThemeConfig.isBreadcrumbIcon" />
{{ v.meta.title }}
</a>
</el-breadcrumb-item>
</transition-group>

View File

@@ -10,8 +10,13 @@
@select="onHandleSelect"
@blur="onSearchBlur"
>
<template #prefix>
<el-icon class="el-input__icon">
<search />
</el-icon>
</template>
<template #default="{ item }">
<div><i :class="item.meta.icon" class="mr10"></i>{{ item.meta.title }}</div>
<div><SvgIcon :name="item.meta.icon" class="mr5" />{{ item.meta.title }}</div>
</template>
</el-autocomplete>
</el-dialog>

View File

@@ -2,22 +2,27 @@
<div class="layout-navbars-breadcrumb-user" :style="{ flex: layoutUserFlexNum }">
<el-dropdown :show-timeout="70" :hide-timeout="50" trigger="click" @command="onComponentSizeChange">
<div class="layout-navbars-breadcrumb-user-icon">
<i class="el-icon-plus" title="组件大小"></i>
<el-icon title="组件大小">
<plus />
</el-icon>
</div>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item command="" :disabled="disabledSize === ''">默认</el-dropdown-item>
<el-dropdown-item command="medium" :disabled="disabledSize === 'medium'">中等</el-dropdown-item>
<el-dropdown-item command="large" :disabled="disabledSize === 'large'">大型</el-dropdown-item>
<el-dropdown-item command="small" :disabled="disabledSize === 'small'">小型</el-dropdown-item>
<el-dropdown-item command="mini" :disabled="disabledSize === 'mini'">超小</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
<div class="layout-navbars-breadcrumb-user-icon" @click="onSearchClick">
<i class="el-icon-search" title="菜单搜索"></i>
<el-icon title="菜单搜索">
<search />
</el-icon>
</div>
<div class="layout-navbars-breadcrumb-user-icon" @click="onLayoutSetingClick">
<i class="el-icon-setting" title="布局设置"></i>
<el-icon title="布局设置">
<setting />
</el-icon>
</div>
<div class="layout-navbars-breadcrumb-user-icon">
<el-popover
@@ -29,7 +34,9 @@
>
<template #reference>
<el-badge :is-dot="true" @click="isShowUserNewsPopover = !isShowUserNewsPopover">
<i class="el-icon-bell" title="消息"></i>
<el-icon title="消息">
<bell />
</el-icon>
</el-badge>
</template>
<transition name="el-zoom-in-top">
@@ -38,7 +45,12 @@
</el-popover>
</div>
<div class="layout-navbars-breadcrumb-user-icon mr10" @click="onScreenfullClick">
<i class="iconfont" :title="isScreenfull ? '开全屏' : '关全屏'" :class="!isScreenfull ? 'el-icon-full-screen' : 'el-icon-crop'"></i>
<el-icon v-if="!isScreenfull" title="关全屏">
<full-screen />
</el-icon>
<el-icon v-else title="开全屏">
<crop />
</el-icon>
</div>
<el-dropdown :show-timeout="70" :hide-timeout="50" @command="onHandleCommandClick">
<span class="layout-navbars-breadcrumb-user-link" style="cursor: pointer">
@@ -54,7 +66,7 @@
</el-dropdown-menu>
</template>
</el-dropdown>
<Search ref="searchRef" />
<SearchMenu ref="searchRef" />
</div>
</template>
@@ -70,7 +82,7 @@ import UserNews from '@/views/layout/navBars/breadcrumb/userNews.vue';
import Search from '@/views/layout/navBars/breadcrumb/search.vue';
export default {
name: 'layoutBreadcrumbUser',
components: { UserNews, Search },
components: { UserNews, SearchMenu: Search },
setup() {
const { proxy } = getCurrentInstance() as any;
const router = useRouter();
@@ -159,7 +171,7 @@ export default {
removeLocal('themeConfig');
getThemeConfig.value.globalComponentSize = size;
setLocal('themeConfig', getThemeConfig.value);
proxy.$ELEMENT.size = size;
// proxy.$ELEMENT.size = size;
initComponentSize();
window.location.reload();
};
@@ -169,14 +181,14 @@ export default {
case '':
state.disabledSize = '';
break;
case 'medium':
state.disabledSize = 'medium';
case 'default':
state.disabledSize = 'default';
break;
case 'small':
state.disabledSize = 'small';
break;
case 'mini':
state.disabledSize = 'mini';
case 'large':
state.disabledSize = 'large';
break;
}
};

View File

@@ -17,21 +17,31 @@
"
>
<i class="iconfont icon-webicon318 layout-navbars-tagsview-ul-li-iconfont font14" v-if="isActive(v)"></i>
<i class="layout-navbars-tagsview-ul-li-iconfont" :class="v.meta.icon" v-if="!isActive(v) && getThemeConfig.isTagsviewIcon"></i>
<SvgIcon
:name="v.meta.icon"
class="layout-navbars-tagsview-ul-li-iconfont"
v-if="!isActive(v) && getThemeConfig.isTagsviewIcon"
/>
<span>{{ v.meta.title }}</span>
<template v-if="isActive(v)">
<i class="el-icon-refresh-right ml5" @click.stop="refreshCurrentTagsView(v.fullPath)"></i>
<i
class="el-icon-close layout-navbars-tagsview-ul-li-icon layout-icon-active"
<SvgIcon
name="RefreshRight"
class="ml5 layout-navbars-tagsview-ul-li-refresh"
@click.stop="refreshCurrentTagsView($route.fullPath)"
/>
<SvgIcon
name="Close"
class="layout-navbars-tagsview-ul-li-icon layout-icon-active"
v-if="!v.meta.isAffix"
@click.stop="closeCurrentTagsView(v.fullPath)"
></i>
@click.stop="closeCurrentTagsView(getThemeConfig.isShareTagsView ? v.path : v.url)"
/>
</template>
<i
class="el-icon-close layout-navbars-tagsview-ul-li-icon layout-icon-three"
<SvgIcon
name="Close"
class="layout-navbars-tagsview-ul-li-icon layout-icon-three"
v-if="!v.meta.isAffix"
@click.stop="closeCurrentTagsView(v.fullPath)"
></i>
@click.stop="closeCurrentTagsView(getThemeConfig.isShareTagsView ? v.path : v.url)"
/>
</li>
</ul>
</el-scrollbar>
@@ -240,7 +250,7 @@ export default {
// 最后 li
let liLast: any = tagsRefs.value[tagsRefs.value.length - 1];
// 当前滚动条的值
let scrollRefs = proxy.$refs.scrollbarRef.$refs.wrap;
let scrollRefs = proxy.$refs.scrollbarRef.$refs.wrap$;
// 当前滚动条滚动宽度
let scrollS = scrollRefs.scrollWidth;
// 当前滚动条偏移宽度

View File

@@ -1,20 +1,20 @@
<template>
<template v-for="val in chils">
<el-submenu :index="val.path" :key="val.path" v-if="val.children && val.children.length > 0">
<el-sub-menu :index="val.path" :key="val.path" v-if="val.children && val.children.length > 0">
<template #title>
<i :class="val.meta.icon"></i>
<SvgIcon :name="val.meta.icon" />
<span>{{ val.meta.title }}</span>
</template>
<sub-item :chil="val.children" />
</el-submenu>
</el-sub-menu>
<el-menu-item :index="val.path" :key="val.path" v-else>
<template v-if="!val.meta.link || (val.meta.link && val.meta.isIframe)">
<i :class="val.meta.icon ? val.meta.icon : ''"></i>
<SvgIcon :name="val.meta.icon" />
<span>{{ val.meta.title }}</span>
</template>
<template v-else>
<a :href="val.meta.link" target="_blank">
<i :class="val.meta.icon ? val.meta.icon : ''"></i>
<SvgIcon :name="val.meta.icon" />
{{ val.meta.title }}
</a>
</template>

View File

@@ -8,15 +8,15 @@
:collapse-transition="false"
>
<template v-for="val in menuLists">
<el-submenu :index="val.path" v-if="val.children && val.children.length > 0" :key="val.path">
<el-sub-menu :index="val.path" v-if="val.children && val.children.length > 0" :key="val.path">
<template #title>
<i :class="val.meta.icon ? val.meta.icon : ''"></i>
<SvgIcon :name="val.meta.icon" />
<span>{{ val.meta.title }}</span>
</template>
<SubItem :chil="val.children" />
</el-submenu>
</el-sub-menu>
<el-menu-item :index="val.path" :key="val.path" v-else>
<i :class="val.meta.icon ? val.meta.icon : ''"></i>
<SvgIcon :name="val.meta.icon" />
<template #title v-if="!val.meta.link || (val.meta.link && val.meta.isIframe)">
<span>{{ val.meta.title }}</span>
</template>

View File

@@ -1,14 +1,14 @@
<template>
<el-form ref="loginFormRef" :model="loginForm" :rules="rules" class="login-content-form">
<el-form ref="loginFormRef" :model="loginForm" :rules="rules" class="login-content-form" size="large">
<el-form-item prop="username">
<el-input type="text" placeholder="请输入用户名" prefix-icon="el-icon-user" v-model="loginForm.username" clearable autocomplete="off">
<el-input type="text" placeholder="请输入用户名" prefix-icon="user" v-model="loginForm.username" clearable autocomplete="off">
</el-input>
</el-form-item>
<el-form-item prop="password">
<el-input
type="password"
placeholder="请输入密码"
prefix-icon="el-icon-lock"
prefix-icon="lock"
v-model="loginForm.password"
autocomplete="off"
show-password
@@ -22,7 +22,7 @@
type="text"
maxlength="6"
placeholder="请输入验证码"
prefix-icon="el-icon-position"
prefix-icon="position"
v-model="loginForm.captcha"
clearable
autocomplete="off"

View File

@@ -1,6 +1,6 @@
<template>
<div>
<el-form class="search-form" label-position="right" :inline="true" label-width="60px" size="small">
<el-form class="search-form" label-position="right" :inline="true" label-width="60px">
<el-form-item prop="project" label="项目" label-width="40px">
<el-select v-model="projectId" placeholder="请选择项目" @change="changeProject" filterable>
<el-option v-for="item in projects" :key="item.id" :label="`${item.name} [${item.remark}]`" :value="item.id"></el-option>

View File

@@ -1,7 +1,7 @@
<template>
<div>
<el-dialog :title="title" v-model="dialogVisible" :show-close="false" :before-close="cancel" width="35%">
<el-form :model="form" ref="dbForm" :rules="rules" label-width="85px" size="small">
<el-form :model="form" ref="dbForm" :rules="rules" label-width="85px">
<el-form-item prop="projectId" label="项目:" required>
<el-select style="width: 100%" v-model="form.projectId" placeholder="请选择项目" @change="changeProject" filterable>
<el-option v-for="item in projects" :key="item.id" :label="`${item.name} [${item.remark}]`" :value="item.id"> </el-option>
@@ -46,8 +46,8 @@
<template #footer>
<div class="dialog-footer">
<el-button type="primary" :loading="btnLoading" @click="btnOk" size="mini"> </el-button>
<el-button @click="cancel()" size="mini"> </el-button>
<el-button type="primary" :loading="btnLoading" @click="btnOk"> </el-button>
<el-button @click="cancel()"> </el-button>
</div>
</template>
</el-dialog>
@@ -198,7 +198,7 @@ export default defineComponent({
const btnOk = async () => {
dbForm.value.validate((valid: boolean) => {
if (valid) {
state.form.port = Number.parseInt(state.form.port as any)
state.form.port = Number.parseInt(state.form.port as any);
dbApi.saveDb.request(state.form).then(() => {
ElMessage.success('保存成功');
emit('val-change', state.form);

View File

@@ -1,21 +1,13 @@
<template>
<div class="db-list">
<el-card>
<el-button v-auth="permissions.saveDb" type="primary" icon="el-icon-plus" size="mini" @click="editDb(true)">添加</el-button>
<el-button v-auth="permissions.saveDb" :disabled="chooseId == null" @click="editDb(false)" type="primary" icon="el-icon-edit" size="mini"
>编辑</el-button
>
<el-button
v-auth="permissions.delDb"
:disabled="chooseId == null"
@click="deleteDb(chooseId)"
type="danger"
icon="el-icon-delete"
size="mini"
<el-button v-auth="permissions.saveDb" type="primary" icon="plus" @click="editDb(true)">添加</el-button>
<el-button v-auth="permissions.saveDb" :disabled="chooseId == null" @click="editDb(false)" type="primary" icon="edit">编辑</el-button>
<el-button v-auth="permissions.delDb" :disabled="chooseId == null" @click="deleteDb(chooseId)" type="danger" icon="delete"
>删除</el-button
>
<div style="float: right">
<el-form class="search-form" label-position="right" :inline="true" label-width="60px" size="small">
<el-form class="search-form" label-position="right" :inline="true" label-width="60px">
<el-form-item prop="project">
<el-select v-model="query.projectId" placeholder="请选择项目" filterable clearable>
<el-option v-for="item in projects" :key="item.id" :label="`${item.name} [${item.remark}]`" :value="item.id"> </el-option>
@@ -25,11 +17,13 @@
<el-form-item>
<el-input v-model="query.database" placeholder="请输入数据库" auto-complete="off" clearable></el-input>
</el-form-item>
<el-button v-waves type="primary" icon="el-icon-search" size="mini" @click="search()">查询</el-button>
<el-form-item>
<el-button v-waves type="primary" icon="search" @click="search()">查询</el-button>
</el-form-item>
</el-form>
</div>
<el-table :data="datas" ref="table" @current-change="choose" show-overflow-tooltip>
<el-table-column label="选择" width="50px">
<el-table-column label="选择" width="60px">
<template #default="scope">
<el-radio v-model="chooseId" :label="scope.row.id">
<i></i>
@@ -121,7 +115,7 @@
</el-dialog>
<el-dialog width="40%" :title="`${chooseTableName} 字段信息`" v-model="columnDialog.visible">
<el-table border :data="columnDialog.columns" size="mini">
<el-table border :data="columnDialog.columns">
<el-table-column prop="columnName" label="名称" show-overflow-tooltip> </el-table-column>
<el-table-column prop="columnComment" label="备注" show-overflow-tooltip> </el-table-column>
<el-table-column width="120" prop="columnType" label="类型" show-overflow-tooltip> </el-table-column>
@@ -129,7 +123,7 @@
</el-dialog>
<el-dialog width="40%" :title="`${chooseTableName} 索引信息`" v-model="indexDialog.visible">
<el-table border :data="indexDialog.indexs" size="mini">
<el-table border :data="indexDialog.indexs">
<el-table-column prop="indexName" label="索引名" show-overflow-tooltip> </el-table-column>
<el-table-column prop="columnName" label="列名" show-overflow-tooltip> </el-table-column>
<el-table-column prop="seqInIndex" label="列序列号" show-overflow-tooltip> </el-table-column>

View File

@@ -25,9 +25,9 @@
<el-aside id="sqlcontent" width="65%" style="background-color: rgb(238, 241, 246)">
<div class="toolbar">
<div class="fl">
<!-- <el-button v-waves @click="runSql" type="success" icon="el-icon-video-play" size="mini" plain>执行</el-button>
<!-- <el-button v-waves @click="runSql" type="success" icon="video-play" plain>执行</el-button>
<el-button v-waves @click="formatSql" type="primary" icon="el-icon-magic-stick" size="mini" plain>格式化</el-button> -->
<el-button v-waves @click="formatSql" type="primary" icon="magic-stick" plain>格式化</el-button> -->
<el-upload
style="display: inline-block; margin-left: 10px"
@@ -43,7 +43,7 @@
multiple
:limit="100"
>
<el-button v-waves type="success" icon="el-icon-video-play" size="mini" plain>sql脚本执行</el-button>
<el-button v-waves type="success" icon="video-play" plain>sql脚本执行</el-button>
</el-upload>
</div>
@@ -55,7 +55,6 @@
filterable
allow-create
default-first-option
size="mini"
class="mr10"
>
<el-option v-for="item in sqlNames" :key="item" :label="item.database" :value="item">
@@ -63,8 +62,8 @@
</el-option>
</el-select>
<el-button v-waves @click="saveSql" type="primary" icon="el-icon-document-add" size="mini" plain>保存</el-button>
<el-button v-waves @click="deleteSql" type="danger" icon="el-icon-delete" size="mini" plain>删除</el-button>
<el-button v-waves @click="saveSql" type="primary" icon="document-add" plain>保存</el-button>
<el-button v-waves @click="deleteSql" type="danger" icon="delete" plain>删除</el-button>
</div>
</div>
<codemirror
@@ -77,13 +76,13 @@
:options="cmOptions"
/>
<el-button-group :style="btnStyle">
<el-button v-waves @click="runSql" type="success" icon="el-icon-video-play" size="small" plain>执行</el-button>
<el-button v-waves @click="formatSql" type="primary" icon="el-icon-magic-stick" size="small" plain>格式化</el-button>
<el-button v-waves @click="runSql" type="success" icon="video-play" size="small" plain>执行</el-button>
<el-button v-waves @click="formatSql" type="primary" icon="magic-stick" size="small" plain>格式化</el-button>
</el-button-group>
</el-aside>
<el-container style="margin-left: 2px">
<el-header style="text-align: left; height: 45px; font-size: 12px; padding: 0px">
<el-header style="text-align: left; height: 35px; font-size: 12px; padding: 0px">
<el-select v-model="tableName" placeholder="请选择表" @change="changeTable" filterable style="width: 99%">
<el-option
v-for="item in tableMetadata"
@@ -96,7 +95,7 @@
</el-header>
<el-main style="padding: 0px; overflow: hidden">
<el-table :data="columnMetadata" height="100%" size="mini">
<el-table :data="columnMetadata" height="100%">
<el-table-column prop="columnName" label="名称" show-overflow-tooltip> </el-table-column>
<el-table-column prop="columnComment" label="备注" show-overflow-tooltip> </el-table-column>
<el-table-column width="120" prop="columnType" label="类型" show-overflow-tooltip> </el-table-column>
@@ -105,7 +104,7 @@
</el-container>
</el-container>
<el-table style="margin-top: 1px" :data="execRes.data" size="mini" max-height="300" :empty-text="execRes.emptyResText" stripe border>
<el-table style="margin-top: 1px" :data="execRes.data" max-height="300" :empty-text="execRes.emptyResText" stripe border size="small">
<el-table-column
min-width="100"
:width="flexColumnWidth(item, execRes.data)"
@@ -514,8 +513,8 @@ export default defineComponent({
if (temp) {
state.btnStyle.display = 'block';
if (!state.btnStyle.left) {
state.btnStyle.left = e.target.getBoundingClientRect().left - 100 + 'px';
state.btnStyle.top = e.target.getBoundingClientRect().top - 20 + 'px';
state.btnStyle.left = e.target.getBoundingClientRect().left - 150 + 'px';
state.btnStyle.top = e.target.getBoundingClientRect().top - 60 + 'px';
}
} else {
state.btnStyle.display = 'none';
@@ -553,6 +552,7 @@ export default defineComponent({
<style scoped lang="scss">
.codesql {
font-size: 10pt;
font-weight: 600;
font-family: Consolas, Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace, serif;
}
#sqlcontent {

View File

@@ -3,7 +3,7 @@
<el-dialog :title="title" v-model="dialogVisible" :show-close="true" :before-close="handleClose" width="800px">
<div class="toolbar">
<div style="float: right">
<el-button v-auth="'machine:file:add'" type="primary" @click="add" icon="el-icon-plus" size="mini" plain>添加</el-button>
<el-button v-auth="'machine:file:add'" type="primary" @click="add" icon="plus" size="small" plain>添加</el-button>
</div>
</div>
<!-- <div style="float: right;">
@@ -12,35 +12,35 @@
<el-table :data="fileTable" stripe style="width: 100%">
<el-table-column prop="name" label="名称" width>
<template #default="scope">
<el-input v-model="scope.row.name" size="mini" :disabled="scope.row.id != null" clearable></el-input>
<el-input v-model="scope.row.name" size="small" :disabled="scope.row.id != null" clearable></el-input>
</template>
</el-table-column>
<el-table-column prop="name" label="类型" min-width="50px">
<template #default="scope">
<el-select :disabled="scope.row.id != null" size="mini" v-model="scope.row.type" style="width: 100px" placeholder="请选择">
<el-select :disabled="scope.row.id != null" size="small" v-model="scope.row.type" style="width: 100px" placeholder="请选择">
<el-option v-for="item in enums.FileTypeEnum" :key="item.value" :label="item.label" :value="item.value"></el-option>
</el-select>
</template>
</el-table-column>
<el-table-column prop="path" label="路径" width>
<template #default="scope">
<el-input v-model="scope.row.path" :disabled="scope.row.id != null" size="mini" clearable></el-input>
<el-input v-model="scope.row.path" :disabled="scope.row.id != null" size="small" clearable></el-input>
</template>
</el-table-column>
<el-table-column label="操作" width>
<template #default="scope">
<el-button v-if="scope.row.id == null" @click="addFiles(scope.row)" type="success" icon="el-icon-success" size="mini" plain
<el-button v-if="scope.row.id == null" @click="addFiles(scope.row)" type="success" icon="success" size="small" plain
>确定</el-button
>
<el-button v-if="scope.row.id != null" @click="getConf(scope.row)" type="primary" icon="el-icon-tickets" size="mini" plain
<el-button v-if="scope.row.id != null" @click="getConf(scope.row)" type="primary" icon="tickets" size="small" plain
>查看</el-button
>
<el-button
v-auth="'machine:file:del'"
type="danger"
@click="deleteRow(scope.$index, scope.row)"
icon="el-icon-delete"
size="mini"
icon="delete"
size="small"
plain
>删除</el-button
>
@@ -57,13 +57,13 @@
<el-dropdown size="small" trigger="contextmenu">
<span class="el-dropdown-link">
<span v-if="data.type == 'd' && !node.expanded">
<i class="el-icon-folder"></i>
<SvgIcon name="folder"/>
</span>
<span v-if="data.type == 'd' && node.expanded">
<i class="el-icon-folder-opened"></i>
<SvgIcon name="folder-opened"/>
</span>
<span v-if="data.type == '-'">
<i class="el-icon-document"></i>
<SvgIcon name="document"/>
</span>
<span style="display: inline-block">
@@ -79,7 +79,7 @@
@click.prevent="getFileContent(tree.folder.id, data.path)"
v-if="data.type == '-' && data.size < 1 * 1024 * 1024"
type="info"
icon="el-icon-view"
icon="view"
:underline="false"
>
查看
@@ -102,7 +102,7 @@
:limit="100"
style="display: inline-block; margin-left: 2px"
>
<el-link v-auth="'machine:file:upload'" @click.prevent icon="el-icon-upload" :underline="false">
<el-link v-auth="'machine:file:upload'" @click.prevent icon="upload" :underline="false">
上传
</el-link>
</el-upload>
@@ -113,7 +113,7 @@
v-if="data.type == '-'"
@click.prevent="downloadFile(node, data)"
type="primary"
icon="el-icon-download"
icon="download"
:underline="false"
style="margin-left: 2px"
>下载</el-link
@@ -125,7 +125,7 @@
v-if="!dontOperate(data)"
@click.prevent="deleteFile(node, data)"
type="danger"
icon="el-icon-delete"
icon="delete"
:underline="false"
style="margin-left: 2px"
>删除
@@ -154,8 +154,8 @@
<template #footer>
<div class="dialog-footer">
<el-button v-auth="'machine:file:write'" type="primary" @click="updateContent" size="mini"> </el-button>
<el-button @click="fileContent.contentVisible = false" size="mini"> </el-button>
<el-button v-auth="'machine:file:write'" type="primary" @click="updateContent"> </el-button>
<el-button @click="fileContent.contentVisible = false"> </el-button>
</div>
</template>
</el-dialog>
@@ -171,6 +171,7 @@ import { codemirror } from '@/components/codemirror';
import { getSession } from '@/common/utils/storage';
import enums from './enums';
import config from '@/common/config';
import SvgIcon from '@/components/svgIcon/index.vue';
export default defineComponent({
name: 'FileManage',

View File

@@ -1,7 +1,7 @@
<template>
<div>
<el-dialog :title="title" v-model="dialogVisible" :show-close="false" :before-close="cancel" width="35%">
<el-form :model="form" ref="machineForm" :rules="rules" label-width="85px" size="small">
<el-form :model="form" ref="machineForm" :rules="rules" label-width="85px" >
<el-form-item prop="projectId" label="项目:" required>
<el-select style="width: 100%" v-model="form.projectId" placeholder="请选择项目" @change="changeProject" filterable>
<el-option v-for="item in projects" :key="item.id" :label="`${item.name} [${item.remark}]`" :value="item.id"> </el-option>

View File

@@ -2,51 +2,28 @@
<div>
<el-card>
<div>
<el-button v-auth="'machine:add'" type="primary" icon="el-icon-plus" size="mini" @click="openFormDialog(false)" plain>添加</el-button>
<el-button v-auth="'machine:add'" type="primary" icon="plus" @click="openFormDialog(false)" plain>添加</el-button>
<el-button
v-auth="'machine:update'"
type="primary"
icon="el-icon-edit"
size="mini"
icon="edit"
:disabled="currentId == null"
@click="openFormDialog(currentData)"
plain
>编辑</el-button
>
<el-button
v-auth="'machine:del'"
:disabled="currentId == null"
@click="deleteMachine(currentId)"
type="danger"
icon="el-icon-delete"
size="mini"
<el-button v-auth="'machine:del'" :disabled="currentId == null" @click="deleteMachine(currentId)" type="danger" icon="delete"
>删除</el-button
>
<el-button
v-auth="'machine:file'"
type="success"
icon="el-icon-files"
:disabled="currentId == null"
@click="fileManage(currentData)"
size="mini"
plain
<el-button v-auth="'machine:file'" type="success" icon="files" :disabled="currentId == null" @click="fileManage(currentData)" plain
>文件</el-button
>
<div style="float: right">
<el-select size="small" v-model="params.projectId" placeholder="请选择项目" @clear="search" filterable clearable>
<el-select v-model="params.projectId" placeholder="请选择项目" @clear="search" filterable clearable>
<el-option v-for="item in projects" :key="item.id" :label="`${item.name} [${item.remark}]`" :value="item.id"> </el-option>
</el-select>
<el-input
class="ml5"
placeholder="请输入ip"
size="small"
style="width: 300px"
v-model="params.ip"
@clear="search"
plain
clearable
></el-input>
<el-button class="ml5" @click="search" type="success" icon="el-icon-search" size="small"></el-button>
<el-input class="ml5" placeholder="请输入ip" style="width: 200px" v-model="params.ip" @clear="search" plain clearable></el-input>
<el-button class="ml5" @click="search" type="success" icon="search"></el-button>
</div>
</div>
@@ -85,9 +62,9 @@
<el-table-column prop="modifier" label="修改者" :min-width="55"></el-table-column> -->
<el-table-column label="操作" min-width="260" fixed="right">
<template #default="scope">
<el-button type="success" @click="serviceManager(scope.row)" size="mini" plain>脚本</el-button>
<el-button v-auth="'machine:terminal'" type="primary" @click="showTerminal(scope.row)" size="mini" plain>终端</el-button>
<el-button :disabled="!scope.row.hasCli" type="danger" @click="closeCli(scope.row)" size="mini" plain>关闭连接</el-button>
<el-button type="success" @click="serviceManager(scope.row)" plain size="small">脚本</el-button>
<el-button v-auth="'machine:terminal'" type="primary" @click="showTerminal(scope.row)" plain size="small">终端</el-button>
<el-button :disabled="!scope.row.hasCli" type="danger" @click="closeCli(scope.row)" plain size="small">关闭连接</el-button>
</template>
</el-table-column>
</el-table>

View File

@@ -9,7 +9,7 @@
:destroy-on-close="true"
width="800px"
>
<el-form :model="form" ref="mockDataForm" label-width="70px" size="small">
<el-form :model="form" ref="mockDataForm" label-width="70px">
<el-form-item prop="method" label="名称">
<el-input v-model.trim="form.name" placeholder="请输入名称"></el-input>
</el-form-item>

View File

@@ -3,16 +3,16 @@
<el-dialog :title="title" v-model="dialogVisible" :destroy-on-close="true" :show-close="true" :before-close="handleClose" width="60%">
<div class="toolbar">
<div style="float: left">
<el-select v-model="type" @change="getScripts" size="mini" placeholder="请选择">
<el-select v-model="type" @change="getScripts" size="small" placeholder="请选择">
<el-option :key="0" label="私有" :value="0"> </el-option>
<el-option :key="1" label="公共" :value="1"> </el-option>
</el-select>
</div>
<div style="float: right">
<el-button @click="editScript(currentData)" :disabled="currentId == null" type="primary" icon="el-icon-tickets" size="mini" plain
<el-button @click="editScript(currentData)" :disabled="currentId == null" type="primary" icon="tickets" size="small" plain
>查看</el-button
>
<el-button v-auth="'machine:script:save'" type="primary" @click="editScript(null)" icon="el-icon-plus" size="mini" plain
<el-button v-auth="'machine:script:save'" type="primary" @click="editScript(null)" icon="plus" size="small" plain
>添加</el-button
>
<el-button
@@ -20,15 +20,15 @@
:disabled="currentId == null"
type="danger"
@click="deleteRow(currentData)"
icon="el-icon-delete"
size="mini"
icon="delete"
size="small"
plain
>删除</el-button
>
</div>
</div>
<el-table :data="scriptTable" @current-change="choose" stripe border size="mini" style="width: 100%">
<el-table :data="scriptTable" @current-change="choose" stripe border size="small" style="width: 100%">
<el-table-column label="选择" width="55px">
<template #default="scope">
<el-radio v-model="currentId" :label="scope.row.id">
@@ -45,7 +45,7 @@
</el-table-column>
<el-table-column label="操作">
<template #default="scope">
<el-button v-if="scope.row.id == null" @click="addFiles(scope.row)" type="success" icon="el-icon-success" size="mini" plain
<el-button v-if="scope.row.id == null" @click="addFiles(scope.row)" type="success" icon="el-icon-success" size="small" plain
>确定</el-button
>
@@ -54,8 +54,8 @@
v-if="scope.row.id != null"
@click="runScript(scope.row)"
type="primary"
icon="el-icon-tickets"
size="mini"
icon="video-play"
size="small"
plain
>执行</el-button
>
@@ -65,14 +65,14 @@
</el-dialog>
<el-dialog title="脚本参数" v-model="scriptParamsDialog.visible" width="400px">
<el-form ref="paramsForm" :model="scriptParamsDialog.params" label-width="70px" size="mini">
<el-form ref="paramsForm" :model="scriptParamsDialog.params" label-width="70px" size="small">
<el-form-item v-for="item in scriptParamsDialog.paramsFormItem" :key="item.name" :prop="item.model" :label="item.name" required>
<el-input v-model="scriptParamsDialog.params[item.model]" :placeholder="item.placeholder" autocomplete="off"></el-input>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button type="primary" @click="hasParamsRun(currentData)" size="mini"> </el-button>
<el-button type="primary" @click="hasParamsRun(currentData)" size="small"> </el-button>
</span>
</template>
</el-dialog>

View File

@@ -2,47 +2,26 @@
<div class="project-list">
<el-card>
<div>
<el-button @click="showAddProjectDialog" v-auth="permissions.saveProject" type="primary" icon="el-icon-plus" size="mini"
>添加</el-button
>
<el-button @click="showAddProjectDialog" v-auth="permissions.saveProject" type="primary" icon="plus">添加</el-button>
<el-button
@click="showAddProjectDialog(chooseData)"
v-auth="permissions.saveProject"
:disabled="chooseId == null"
type="primary"
icon="el-icon-edit"
size="mini"
icon="edit"
>编辑</el-button
>
<el-button @click="showMembers(chooseData)" :disabled="chooseId == null" type="success" icon="el-icon-setting" size="mini"
>成员管理</el-button
>
<el-button @click="showMembers(chooseData)" :disabled="chooseId == null" type="success" icon="setting">成员管理</el-button>
<el-button @click="showEnv(chooseData)" :disabled="chooseId == null" type="info" icon="el-icon-setting" size="mini"
>环境管理</el-button
>
<el-button @click="showEnv(chooseData)" :disabled="chooseId == null" type="info" icon="setting">环境管理</el-button>
<el-button
v-auth="permissions.delProject"
@click="delProject"
:disabled="chooseId == null"
type="danger"
icon="el-icon-delete"
size="mini"
<el-button v-auth="permissions.delProject" @click="delProject" :disabled="chooseId == null" type="danger" icon="delete"
>删除</el-button
>
<div style="float: right">
<el-input
class="mr2"
placeholder="请输入项目名!"
size="small"
style="width: 300px"
v-model="query.name"
@clear="search"
clearable
></el-input>
<el-button @click="search" type="success" icon="el-icon-search" size="small"></el-button>
<el-input class="mr2" placeholder="请输入项目名!" style="width: 200px" v-model="query.name" @clear="search" clearable></el-input>
<el-button @click="search" type="success" icon="search"></el-button>
</div>
</div>
<el-table :data="projects" @current-change="choose" ref="table" style="width: 100%">
@@ -82,7 +61,7 @@
</el-card>
<el-dialog width="400px" title="项目编辑" :before-close="cancelAddProject" v-model="addProjectDialog.visible">
<el-form :model="addProjectDialog.form" size="small" label-width="70px">
<el-form :model="addProjectDialog.form" label-width="70px">
<el-form-item label="项目名:" required>
<el-input :disabled="addProjectDialog.form.id ? true : false" v-model="addProjectDialog.form.name" auto-complete="off"></el-input>
</el-form-item>
@@ -92,18 +71,18 @@
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="addProject" type="primary" size="small"> </el-button>
<el-button @click="cancelAddProject()" size="small"> </el-button>
<el-button @click="addProject" type="primary"> </el-button>
<el-button @click="cancelAddProject()"> </el-button>
</div>
</template>
</el-dialog>
<el-dialog width="500px" :title="showEnvDialog.title" v-model="showEnvDialog.visible">
<div class="toolbar">
<el-button @click="showAddEnvDialog" v-auth="permissions.saveMember" type="primary" icon="el-icon-plus" size="mini">添加</el-button>
<!-- <el-button v-auth="'role:update'" :disabled="chooseId == null" type="danger" icon="el-icon-delete" size="mini">删除</el-button> -->
<el-button @click="showAddEnvDialog" v-auth="permissions.saveMember" type="primary" icon="plus">添加</el-button>
<!-- <el-button v-auth="'role:update'" :disabled="chooseId == null" type="danger" icon="delete">删除</el-button> -->
</div>
<el-table border :data="showEnvDialog.envs" size="small">
<el-table border :data="showEnvDialog.envs">
<el-table-column property="name" label="环境名" width="125"></el-table-column>
<el-table-column property="remark" label="描述" width="125"></el-table-column>
<el-table-column property="createTime" label="创建时间">
@@ -114,7 +93,7 @@
</el-table>
<el-dialog width="400px" title="添加环境" :before-close="cancelAddEnv" v-model="showEnvDialog.addVisible">
<el-form :model="showEnvDialog.envForm" size="small" label-width="70px">
<el-form :model="showEnvDialog.envForm" label-width="70px">
<el-form-item label="环境名:" required>
<el-input v-model="showEnvDialog.envForm.name" auto-complete="off"></el-input>
</el-form-item>
@@ -124,8 +103,8 @@
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button v-auth="permissions.saveEnv" @click="addEnv" type="primary" :loading="btnLoading" size="small"> </el-button>
<el-button @click="cancelAddEnv()" size="small"> </el-button>
<el-button v-auth="permissions.saveEnv" @click="addEnv" type="primary" :loading="btnLoading"> </el-button>
<el-button @click="cancelAddEnv()"> </el-button>
</div>
</template>
</el-dialog>
@@ -133,20 +112,12 @@
<el-dialog width="500px" :title="showMemDialog.title" v-model="showMemDialog.visible">
<div class="toolbar">
<el-button v-auth="permissions.saveMember" @click="showAddMemberDialog()" type="primary" icon="el-icon-plus" size="mini"
>添加</el-button
>
<el-button
v-auth="permissions.delMember"
@click="deleteMember"
:disabled="showMemDialog.chooseId == null"
type="danger"
icon="el-icon-delete"
size="mini"
<el-button v-auth="permissions.saveMember" @click="showAddMemberDialog()" type="primary" icon="plus">添加</el-button>
<el-button v-auth="permissions.delMember" @click="deleteMember" :disabled="showMemDialog.chooseId == null" type="danger" icon="delete"
>移除</el-button
>
</div>
<el-table @current-change="chooseMember" border :data="showMemDialog.members.list" size="small">
<el-table @current-change="chooseMember" border :data="showMemDialog.members.list">
<el-table-column label="选择" width="50px">
<template #default="scope">
<el-radio v-model="showMemDialog.chooseId" :label="scope.row.id">
@@ -173,7 +144,7 @@
/>
<el-dialog width="400px" title="添加成员" :before-close="cancelAddMember" v-model="showMemDialog.addVisible">
<el-form :model="showMemDialog.memForm" size="small" label-width="70px">
<el-form :model="showMemDialog.memForm" label-width="70px">
<el-form-item label="账号:">
<el-select
style="width: 100%"
@@ -192,10 +163,8 @@
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button v-auth="permissions.saveMember" @click="addMember" type="primary" :loading="btnLoading" size="small"
> </el-button
>
<el-button @click="cancelAddMember()" size="small"> </el-button>
<el-button v-auth="permissions.saveMember" @click="addMember" type="primary" :loading="btnLoading"> </el-button>
<el-button @click="cancelAddMember()"> </el-button>
</div>
</template>
</el-dialog>

View File

@@ -0,0 +1,271 @@
<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="keyInfo.key"></el-input>
</el-form-item>
<el-form-item prop="timed" label="过期时间:">
<el-input v-model.number="keyInfo.timed" type="number"></el-input>
</el-form-item>
<el-form-item prop="dataType" label="数据类型:">
<el-select :disabled="operationType == 2" style="width: 100%" v-model="keyInfo.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="keyInfo.type == 'string'" prop="value" label="内容:">
<el-input class="json-text" v-model="stringValue" type="textarea" :autosize="{ minRows: 10, maxRows: 20 }"></el-input>
</el-form-item>
<span v-if="keyInfo.type == 'hash'">
<el-button @click="onAddHashValue" icon="plus" size="small" plain class="mt10">添加</el-button>
<el-table :data="hashValue" 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="hashValue.splice(scope.$index, 1)" icon="delete" size="small" plain>删除</el-button>
</template>
</el-table-column>
</el-table>
</span>
<span v-if="keyInfo.type == 'set'">
<el-button @click="onAddSetValue" icon="plus" size="small" plain class="mt10">添加</el-button>
<el-table :data="setValue" stripe style="width: 100%">
<el-table-column prop="value" label="value" width>
<template #default="scope" min-width="200">
<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="setValue.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="saveValue" type="primary" v-auth="'redis:data:save'"> </el-button>
<el-button @click="cancel()"> </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: '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: '',
keyInfo: {
key: '',
type: 'string',
timed: -1,
},
stringValue: '',
hashValue: [
{
key: '',
value: '',
},
],
setValue: [{ value: '' }],
});
const cancel = () => {
emit('update:visible', false);
emit('cancel');
setTimeout(() => {
state.keyInfo = {
key: '',
type: 'string',
timed: -1,
};
state.stringValue = '';
state.hashValue = [
{
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.keyInfo = { ...val };
}
},
{
deep: true, // 深度监听的参数
}
);
watch(
() => props.stringValue,
(val) => {
if (val) {
state.stringValue = val;
}
},
{
deep: true, // 深度监听的参数
}
);
watch(
() => props.setValue,
(val) => {
if (val) {
state.setValue = val;
}
},
{
deep: true, // 深度监听的参数
}
);
watch(
() => props.hashValue,
(val) => {
if (val) {
state.hashValue = val;
}
},
{
deep: true, // 深度监听的参数
}
);
const saveValue = async () => {
notEmpty(state.keyInfo.key, 'key不能为空');
if (state.keyInfo.type == 'string') {
notEmpty(state.stringValue, 'value不能为空');
const sv = { value: state.stringValue, id: state.redisId };
Object.assign(sv, state.keyInfo);
await redisApi.saveStringValue.request(sv);
}
if (state.keyInfo.type == 'hash') {
isTrue(state.hashValue.length > 0, 'hash内容不能为空');
const sv = { value: state.hashValue, id: state.redisId };
Object.assign(sv, state.keyInfo);
await redisApi.saveHashValue.request(sv);
}
if (state.keyInfo.type == 'set') {
isTrue(state.setValue.length > 0, 'set内容不能为空');
const sv = { value: state.setValue.map((x) => x.value), id: state.redisId };
Object.assign(sv, state.keyInfo);
await redisApi.saveSetValue.request(sv);
}
ElMessage.success('数据保存成功');
cancel();
emit('valChange');
};
const onAddHashValue = () => {
state.hashValue.push({ key: '', value: '' });
};
const onAddSetValue = () => {
state.setValue.push({ value: '' });
};
return {
...toRefs(state),
saveValue,
cancel,
onAddHashValue,
onAddSetValue,
};
},
});
</script>

View File

@@ -16,31 +16,36 @@
</el-option>
</el-select>
</el-form-item>
</template>
</project-env-select>
</el-col>
<el-col class="mt10">
<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"
style="width: 180px"
v-model="scanParam.match"
size="mini"
@clear="clear()"
clearable
></el-input>
</el-form-item>
<el-form-item label-width="40px">
<el-input placeholder="count" style="width: 62px" v-model="scanParam.count" size="mini"></el-input>
<el-form-item label="count" label-width="60px">
<el-input placeholder="count" style="width: 62px" v-model="scanParam.count"></el-input>
</el-form-item>
<el-button @click="searchKey()" type="success" icon="el-icon-search" size="mini" plain></el-button>
<el-button @click="scan()" icon="el-icon-bottom" size="mini" plain>scan</el-button>
<el-button type="primary" icon="el-icon-plus" size="mini" @click="save(false)" plain></el-button>
</template>
</project-env-select>
<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-form-item>
<div style="float: right">
<span>keys: {{ dbsize }}</span>
</div>
</el-form>
</el-col>
</el-row>
</div>
<div style="float: right">
<!-- <el-button @click="scan()" icon="el-icon-refresh" size="small" plain>刷新</el-button> -->
<span>keys: {{ dbsize }}</span>
</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 prop="type" label="type" width="80"> </el-table-column>
@@ -51,8 +56,8 @@
</el-table-column>
<el-table-column label="操作">
<template #default="scope">
<el-button @click="getValue(scope.row)" type="success" icon="el-icon-search" size="mini" plain>查看</el-button>
<el-button @click="del(scope.row.key)" type="danger" size="mini" icon="el-icon-delete" plain>删除</el-button>
<el-button @click="getValue(scope.row)" type="success" icon="search" plain size="small">查看</el-button>
<el-button @click="del(scope.row.key)" type="danger" icon="delete" plain size="small">删除</el-button>
</template>
</el-table-column>
</el-table>
@@ -60,7 +65,20 @@
<div style="text-align: center; margin-top: 10px"></div>
<value-dialog v-model:visible="valueDialog.visible" :keyValue="valueDialog.value" />
<!-- <value-dialog v-model:visible="valueDialog.visible" :keyValue="valueDialog.value" /> -->
<data-edit
v-model:visible="dataEdit.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"
/>
</div>
</template>
@@ -70,12 +88,15 @@ 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 { isTrue, notNull } from '@/common/assert';
import { key } from '../../../store/index';
export default defineComponent({
name: 'DataOperation',
components: {
ValueDialog,
DataEdit,
ProjectEnvSelect,
},
setup() {
@@ -103,6 +124,19 @@ export default defineComponent({
visible: false,
value: {},
},
dataEdit: {
visible: false,
title: '新增数据',
operationType: 1,
keyInfo: {
type: 'string',
timed: -1,
key: '',
},
stringValue: '',
hashValue: [{ key: '', value: '' }],
setValue: [{ value: '' }],
},
keys: [],
dbsize: 0,
});
@@ -170,39 +204,64 @@ export default defineComponent({
};
const getValue = async (row: any) => {
let api: any;
switch (row.type) {
case 'string':
api = redisApi.getStringValue;
break;
case 'hash':
api = redisApi.getHashValue;
break;
case 'set':
api = redisApi.getSetValue;
break;
default:
api = redisApi.getStringValue;
break;
}
const type = row.type;
const key = row.key;
let res: any;
const id = state.cluster == 0 ? state.scanParam.id : state.cluster;
const res = await api.request({
const reqParam = {
cluster: state.cluster,
key: row.key,
id,
});
let timed = row.ttl == 18446744073709552000 ? 0 : row.ttl;
state.valueDialog.value = { id: state.scanParam.id, key: row.key, value: res, timed: timed, type: row.type };
state.valueDialog.visible = true;
};
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, '暂不支持该类型数据查看');
// closeValueDialog() {
// this.valueDialog.visible = false
// this.valueDialog.value = {}
// }
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;
}
// const update = (key: string) => {};
state.dataEdit.keyInfo.type = type;
state.dataEdit.keyInfo.timed = row.ttl;
state.dataEdit.keyInfo.key = key;
state.dataEdit.operationType = 2;
state.dataEdit.title = '修改数据';
state.dataEdit.visible = true;
};
const del = (key: string) => {
ElMessageBox.confirm(`此操作将删除对应的key , 是否继续?`, '提示', {
@@ -227,7 +286,7 @@ export default defineComponent({
};
const ttlConveter = (ttl: any) => {
if (ttl == 18446744073709552000) {
if (ttl == -1) {
return '永久';
}
if (!ttl) {
@@ -262,6 +321,20 @@ export default defineComponent({
return result;
};
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,
@@ -273,6 +346,8 @@ export default defineComponent({
getValue,
del,
ttlConveter,
onAddData,
onCancelDataEdit,
};
},
});

View File

@@ -1,7 +1,7 @@
<template>
<div>
<el-dialog :title="title" v-model="dialogVisible" :show-close="false" :before-close="cancel" width="35%">
<el-form :model="form" ref="redisForm" :rules="rules" label-width="85px" size="small">
<el-form :model="form" ref="redisForm" :rules="rules" label-width="85px">
<el-form-item prop="projectId" label="项目:" required>
<el-select style="width: 100%" v-model="form.projectId" placeholder="请选择项目" @change="changeProject" filterable>
<el-option v-for="item in projects" :key="item.id" :label="`${item.name} [${item.remark}]`" :value="item.id"> </el-option>
@@ -32,8 +32,8 @@
<template #footer>
<div class="dialog-footer">
<el-button type="primary" :loading="btnLoading" @click="btnOk" size="mini"> </el-button>
<el-button @click="cancel()" size="mini"> </el-button>
<el-button type="primary" :loading="btnLoading" @click="btnOk"> </el-button>
<el-button @click="cancel()"> </el-button>
</div>
</template>
</el-dialog>

View File

@@ -1,18 +1,18 @@
<template>
<div>
<el-card>
<el-button type="primary" icon="el-icon-plus" size="mini" @click="editRedis(true)" plain>添加</el-button>
<el-button type="primary" icon="el-icon-edit" :disabled="currentId == null" size="mini" @click="editRedis(false)" plain>编辑</el-button>
<el-button type="danger" icon="el-icon-delete" :disabled="currentId == null" size="mini" @click="deleteRedis" plain>删除</el-button>
<el-button type="primary" icon="plus" @click="editRedis(true)" plain>添加</el-button>
<el-button type="primary" icon="edit" :disabled="currentId == null" @click="editRedis(false)" plain>编辑</el-button>
<el-button type="danger" icon="delete" :disabled="currentId == null" @click="deleteRedis" plain>删除</el-button>
<div style="float: right">
<!-- <el-input placeholder="host" size="mini" style="width: 140px" v-model="query.host" @clear="search" plain clearable></el-input>
<el-select v-model="params.clusterId" size="mini" clearable placeholder="集群选择">
<!-- <el-input placeholder="host" style="width: 140px" v-model="query.host" @clear="search" plain clearable></el-input>
<el-select v-model="params.clusterId" clearable placeholder="集群选择">
<el-option v-for="item in clusters" :key="item.id" :value="item.id" :label="item.name"></el-option>
</el-select> -->
<el-select v-model="query.projectId" placeholder="请选择项目" filterable clearable size="small">
<el-select v-model="query.projectId" placeholder="请选择项目" filterable clearable>
<el-option v-for="item in projects" :key="item.id" :label="`${item.name} [${item.remark}]`" :value="item.id"> </el-option>
</el-select>
<el-button class="ml5" @click="search" type="success" icon="el-icon-search" size="small"></el-button>
<el-button class="ml5" @click="search" type="success" icon="search"></el-button>
</div>
<el-table :data="redisTable" style="width: 100%" @current-change="choose">
<el-table-column label="选择" width="50px">
@@ -33,8 +33,8 @@
<el-table-column prop="creator" label="创建人"></el-table-column>
<el-table-column label="操作" width>
<template #default="scope">
<el-button type="primary" @click="info(scope.row)" icon="el-icon-tickets" size="mini" plain>info</el-button>
<!-- <el-button type="success" @click="manage(scope.row)" :ref="scope.row" size="mini" plain>数据管理</el-button> -->
<el-button type="primary" @click="info(scope.row)" icon="tickets" plain size="small">info</el-button>
<!-- <el-button type="success" @click="manage(scope.row)" :ref="scope.row" plain>数据管理</el-button> -->
</template>
</el-table-column>
</el-table>

View File

@@ -8,8 +8,8 @@
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="saveValue" type="primary" size="mini"> </el-button>
<el-button @click="cancel()" size="mini"> </el-button>
<el-button @click="saveValue" type="primary"> </el-button>
<el-button @click="cancel()"> </el-button>
</div>
</template>
</el-dialog>

View File

@@ -10,8 +10,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'),
getSetValue: Api.create("/redis/{id}/set-value", 'get'),
saveHashValue: Api.create("/redis/{id}/hash-value", 'post'),
getSetValue: Api.create("/redis/{id}/set-value", 'get'),
saveSetValue: Api.create("/redis/{id}/set-value", 'post'),
del: Api.create("/redis/{id}/scan/{cursor}/{count}", 'delete'),
delKey: Api.create("/redis/{id}/key", 'delete'),
}

View File

@@ -1,7 +1,7 @@
<template>
<div class="account-dialog">
<el-dialog :title="title" v-model="dialogVisible" :before-close="cancel" :show-close="false" width="35%">
<el-form :model="form" ref="accountForm" :rules="rules" label-width="85px" size="small">
<el-form :model="form" ref="accountForm" :rules="rules" label-width="85px">
<el-form-item prop="username" label="用户名:" required>
<el-input :disabled="edit" v-model.trim="form.username" placeholder="请输入账号用户名" auto-complete="off"></el-input>
</el-form-item>
@@ -15,8 +15,8 @@
<template #footer>
<div class="dialog-footer">
<el-button @click="cancel()" size="mini"> </el-button>
<el-button type="primary" :loading="btnLoading" @click="btnOk" size="small"> </el-button>
<el-button @click="cancel()"> </el-button>
<el-button type="primary" :loading="btnLoading" @click="btnOk"> </el-button>
</div>
</template>
</el-dialog>

View File

@@ -1,22 +1,12 @@
<template>
<div class="role-list">
<el-card>
<el-button v-auth="'account:add'" type="primary" icon="el-icon-plus" size="mini" @click="editAccount(true)">添加</el-button>
<el-button
v-auth="'account:update'"
:disabled="chooseId == null"
@click="editAccount(false)"
type="primary"
icon="el-icon-edit"
size="mini"
>编辑</el-button
>
<el-button v-auth="'account:saveRoles'" :disabled="chooseId == null" @click="roleEdit()" type="success" icon="el-icon-setting" size="mini"
<el-button v-auth="'account:add'" type="primary" icon="plus" @click="editAccount(true)">添加</el-button>
<el-button v-auth="'account:update'" :disabled="chooseId == null" @click="editAccount(false)" type="primary" icon="edit">编辑</el-button>
<el-button v-auth="'account:saveRoles'" :disabled="chooseId == null" @click="roleEdit()" type="success" icon="setting"
>角色分配</el-button
>
<el-button v-auth="'account:del'" :disabled="chooseId == null" @click="deleteAccount()" type="danger" icon="el-icon-delete" size="mini"
>删除</el-button
>
<el-button v-auth="'account:del'" :disabled="chooseId == null" @click="deleteAccount()" type="danger" icon="delete">删除</el-button>
<div style="float: right">
<el-input
class="mr2"
@@ -27,7 +17,7 @@
@clear="search()"
clearable
></el-input>
<el-button @click="search()" type="success" icon="el-icon-search" size="small"></el-button>
<el-button @click="search()" type="success" icon="search" size="small"></el-button>
</div>
<el-table :data="datas" ref="table" @current-change="choose" show-overflow-tooltip>
<el-table-column label="选择" width="50px">
@@ -41,8 +31,8 @@
<el-table-column align="center" prop="status" label="状态" min-width="63">
<template #default="scope">
<el-tag v-if="scope.row.status == 1" type="success" size="mini">正常</el-tag>
<el-tag v-if="scope.row.status == -1" type="danger" size="mini">禁用</el-tag>
<el-tag v-if="scope.row.status == 1" type="success">正常</el-tag>
<el-tag v-if="scope.row.status == -1" type="danger">禁用</el-tag>
</template>
</el-table-column>
<el-table-column min-width="160" prop="lastLoginTime" label="最后登录时间">
@@ -80,8 +70,8 @@
@click="changeStatus(scope.row)"
v-if="scope.row.status == 1"
type="danger"
icom="el-icon-tickets"
size="mini"
icom="tickets"
size="small"
plain
>禁用</el-button
>
@@ -90,7 +80,7 @@
v-if="scope.row.status == -1"
type="success"
@click="changeStatus(scope.row)"
size="mini"
size="small"
plain
>启用</el-button
>

View File

@@ -8,8 +8,8 @@
>
<div class="toolbar">
<div style="float: left">
<el-input placeholder="请输入角色名" size="small" style="width: 150px" v-model="query.name" @clear="clear()" clearable></el-input>
<el-button @click="search" type="success" icon="el-icon-search" size="small"></el-button>
<el-input placeholder="请输入角色名" style="width: 150px" v-model="query.name" @clear="clear()" clearable></el-input>
<el-button @click="search" type="success" icon="search"></el-button>
</div>
</div>
<el-table :data="allRole" border ref="roleTable" @select="select" style="width: 100%">
@@ -34,8 +34,8 @@
<template #footer>
<div class="dialog-footer">
<el-button @click="cancel()" size="small"> </el-button>
<el-button type="primary" :loading="btnLoading" @click="btnOk" size="small"> </el-button>
<el-button @click="cancel()"> </el-button>
<el-button type="primary" :loading="btnLoading" @click="btnOk"> </el-button>
</div>
</template>
</el-dialog>

View File

@@ -1,9 +1,9 @@
<template>
<div class="menu-dialog">
<el-dialog :title="title" :destroy-on-close="true" v-model="dialogVisible" width="850px">
<el-form :model="form" :inline="true" ref="menuForm" :rules="rules" label-width="95px" size="small">
<el-dialog :title="title" :destroy-on-close="true" v-model="dialogVisible" width="769px">
<el-form :model="form" :inline="true" ref="menuForm" :rules="rules" label-width="95px">
<el-row :gutter="10">
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb10">
<el-form-item prop="type" label="类型" required>
<el-select v-model="form.type" :disabled="typeDisabled" placeholder="请选择" width="w100">
<el-option v-for="item in enums.ResourceTypeEnum" :key="item.value" :label="item.label" :value="item.value">
@@ -11,65 +11,65 @@
</el-select>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb10">
<el-form-item prop="name" label="名称" required>
<el-input v-model.trim="form.name" placeholder="资源名[菜单名]" auto-complete="off"></el-input>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb10">
<el-form-item prop="code" label="path|code">
<el-input v-model.trim="form.code" placeholder="菜单不带/自动拼接父路径"></el-input>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb10">
<el-form-item label="序号" prop="weight" required>
<el-input v-model.trim="form.weight" type="number" placeholder="请输入序号"></el-input>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb10">
<el-form-item v-if="form.type === enums.ResourceTypeEnum.MENU.value" label="图标">
<icon-selector v-model="form.meta.icon" :isAllOn="true" />
<icon-selector v-model="form.meta.icon" type="ele" />
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb10">
<el-form-item v-if="form.type === enums.ResourceTypeEnum.MENU.value" prop="code" label="路由名">
<el-input v-model.trim="form.meta.routeName" placeholder="请输入路由名称"></el-input>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb10">
<el-form-item v-if="form.type === enums.ResourceTypeEnum.MENU.value" prop="code" label="组件">
<el-input v-model.trim="form.meta.component" placeholder="请输入组件名"></el-input>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb10">
<el-form-item v-if="form.type === enums.ResourceTypeEnum.MENU.value" prop="code" label="是否缓存">
<el-select v-model="form.meta.isKeepAlive" placeholder="请选择" width="w100">
<el-option v-for="item in trueFalseOption" :key="item.value" :label="item.label" :value="item.value"> </el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb10">
<el-form-item v-if="form.type === enums.ResourceTypeEnum.MENU.value" prop="code" label="是否隐藏">
<el-select v-model="form.meta.isHide" placeholder="请选择" width="w100">
<el-option v-for="item in trueFalseOption" :key="item.value" :label="item.label" :value="item.value"> </el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb10">
<el-form-item v-if="form.type === enums.ResourceTypeEnum.MENU.value" prop="code" label="tag不可删除">
<el-select v-model="form.meta.isAffix" placeholder="请选择" width="w100">
<el-option v-for="item in trueFalseOption" :key="item.value" :label="item.label" :value="item.value"> </el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb10">
<el-form-item v-if="form.type === enums.ResourceTypeEnum.MENU.value" prop="code" label="是否iframe">
<el-select @change="changeIsIframe" v-model="form.meta.isIframe" placeholder="请选择" width="w100">
<el-option v-for="item in trueFalseOption" :key="item.value" :label="item.label" :value="item.value"> </el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb10">
<el-form-item
v-if="form.type === enums.ResourceTypeEnum.MENU.value && form.meta.isIframe"
prop="code"
@@ -83,8 +83,8 @@
</el-form>
<div style="text-align: center" class="dialog-footer mt10">
<el-button type="primary" :loading="btnLoading" @click="btnOk" size="mini"> </el-button>
<el-button @click="cancel()" size="mini"> </el-button>
<el-button type="primary" :loading="btnLoading" @click="btnOk"> </el-button>
<el-button @click="cancel()"> </el-button>
</div>
</el-dialog>
</div>
@@ -122,7 +122,7 @@ export default defineComponent({
const defaultMeta = {
routeName: '',
icon: 'el-icon-menu',
icon: 'Menu',
redirect: '',
component: '',
isKeepAlive: true,

View File

@@ -2,9 +2,9 @@
<div class="menu">
<div class="toolbar">
<div>
<span style="font-size: 14px"> <i class="el-icon-info"></i>红色字体表示禁用状态,右击鼠标显示操作 </span>
<span style="font-size: 14px"><SvgIcon name="info-filled"/>红色字体表示禁用状态</span>
</div>
<el-button v-auth="'resource:add'" type="primary" icon="el-icon-plus" size="mini" @click="addResource(false)">添加</el-button>
<el-button v-auth="'resource:add'" type="primary" icon="plus" @click="addResource(false)">添加</el-button>
</div>
<el-tree
class="none-select"
@@ -15,93 +15,74 @@
@node-expand="handleNodeExpand"
@node-collapse="handleNodeCollapse"
:default-expanded-keys="defaultExpandedKeys"
:expand-on-click-node="true"
:expand-on-click-node="false"
>
<template #default="{ data }">
<span class="custom-tree-node">
<el-dropdown size="mini" trigger="contextmenu">
<span class="el-dropdown-link">
<span style="font-size: 13px" v-if="data.type === enums.ResourceTypeEnum.MENU.value">
<span style="color: #3c8dbc"></span>
{{ data.name }}
<span style="color: #3c8dbc"></span>
<el-tag v-if="data.children !== null" size="mini">{{ data.children.length }}</el-tag>
<el-tag v-if="data.children !== null" size="small">{{ data.children.length }}</el-tag>
</span>
<span style="font-size: 13px" v-if="data.type === enums.ResourceTypeEnum.PERMISSION.value">
<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 #dropdown>
<el-dropdown-menu>
<el-dropdown-item>
<el-link @click.prevent="info(data)" icon="el-icon-view" type="info" :underline="false">查看</el-link>
</el-dropdown-item>
<el-dropdown-item>
<el-link @click.prevent="info(data)" style="margin-left: 25px" icon="view" type="info" :underline="false" />
<el-link
v-auth="'resource:update'"
@click.prevent="editResource(data)"
class="ml5"
type="primary"
icon="el-icon-edit"
icon="edit"
:underline="false"
>
修改
</el-link>
</el-dropdown-item>
<el-dropdown-item>
/>
<el-link
v-auth="'resource:add'"
@click.prevent="addResource(data)"
v-if="data.type === enums.ResourceTypeEnum.MENU.value"
icon="el-icon-circle-plus-outline"
icon="circle-plus"
:underline="false"
type="success"
>
新增
</el-link></el-dropdown-item
>
<el-dropdown-item>
class="ml5"
/>
<el-link
v-auth="'resource:changeStatus'"
@click.prevent="changeStatus(data, -1)"
v-if="data.status === 1 && data.type === enums.ResourceTypeEnum.PERMISSION.value"
icon="el-icon-circle-close"
icon="circle-close"
:underline="false"
type="warning"
>
禁用
</el-link>
</el-dropdown-item>
<el-dropdown-item>
class="ml5"
/>
<el-link
v-auth="'resource:changeStatus'"
@click.prevent="changeStatus(data, 1)"
v-if="data.status === -1 && data.type === enums.ResourceTypeEnum.PERMISSION.value"
type="success"
icon="el-icon-circle-check"
icon="circle-check"
:underline="false"
plain
>
启用
</el-link>
</el-dropdown-item>
<el-dropdown-item>
class="ml5"
/>
<el-link
v-auth="'resource:del'"
v-if="data.children == null && data.name !== '首页'"
@click.prevent="deleteMenu(data)"
type="danger"
icon="el-icon-remove-outline"
icon="delete"
:underline="false"
plain
>
删除
</el-link>
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
class="ml5"
/>
</span>
</template>
</el-tree>
@@ -161,6 +142,7 @@ import { ElMessage, ElMessageBox } from 'element-plus';
import ResourceEdit from './ResourceEdit.vue';
import enums from '../enums';
import { resourceApi } from '../api';
import SvgIcon from '@/components/svgIcon/index.vue';
export default defineComponent({
name: 'ResourceList',

View File

@@ -19,8 +19,8 @@
</el-tree>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="btnOk" size="small"> </el-button>
<el-button @click="cancel" size="small"> </el-button>
<el-button type="primary" @click="btnOk"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</template>
</el-dialog>

View File

@@ -1,12 +1,12 @@
<template>
<div class="role-dialog">
<el-dialog :title="title" v-model="visible" :show-close="false" :before-close="cancel" width="500px">
<el-form :model="form" size="small" label-width="90px">
<el-form :model="form" label-width="90px">
<el-form-item label="角色名称:" required>
<el-input v-model="form.name" auto-complete="off"></el-input>
</el-form-item>
<el-form-item label="角色code:" required>
<el-input :disabled="form.id" v-model="form.code" placeholder="COMMON开头则为所有账号共有角色" auto-complete="off"></el-input>
<el-input :disabled="form.id != null" v-model="form.code" placeholder="COMMON开头则为所有账号共有角色" auto-complete="off"></el-input>
</el-form-item>
<el-form-item label="角色描述:">
<el-input v-model="form.remark" type="textarea" :rows="3" placeholder="请输入角色描述"></el-input>
@@ -14,8 +14,8 @@
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" :loading="btnLoading" @click="btnOk" size="small"> </el-button>
<el-button @click="cancel()" size="small"> </el-button>
<el-button type="primary" :loading="btnLoading" @click="btnOk"> </el-button>
<el-button @click="cancel()"> </el-button>
</div>
</template>
</el-dialog>

View File

@@ -1,34 +1,12 @@
<template>
<div class="role-list">
<el-card>
<el-button v-auth="'role:add'" type="primary" icon="el-icon-plus" size="mini" @click="editRole(false)">添加</el-button>
<el-button
v-auth="'role:update'"
:disabled="chooseId == null"
@click="editRole(chooseData)"
type="primary"
icon="el-icon-edit"
size="mini"
>编辑</el-button
>
<el-button
v-auth="'role:saveResources'"
:disabled="chooseId == null"
@click="editResource(chooseData)"
type="success"
icon="el-icon-setting"
size="mini"
<el-button v-auth="'role:add'" type="primary" icon="plus" @click="editRole(false)">添加</el-button>
<el-button v-auth="'role:update'" :disabled="chooseId == null" @click="editRole(chooseData)" type="primary" icon="edit">编辑</el-button>
<el-button v-auth="'role:saveResources'" :disabled="chooseId == null" @click="editResource(chooseData)" type="success" icon="setting"
>分配菜单&权限</el-button
>
<el-button
v-auth="'role:del'"
:disabled="chooseId == null"
@click="deleteRole(chooseData)"
type="danger"
icon="el-icon-delete"
size="mini"
>删除</el-button
>
<el-button v-auth="'role:del'" :disabled="chooseId == null" @click="deleteRole(chooseData)" type="danger" icon="delete">删除</el-button>
<div style="float: right">
<el-input
@@ -40,7 +18,7 @@
@clear="search"
clearable
></el-input>
<el-button @click="search" type="success" icon="el-icon-search" size="small"></el-button>
<el-button @click="search" type="success" icon="search" size="small"></el-button>
</div>
<el-table :data="roles" @current-change="choose" ref="table" style="width: 100%">
<el-table-column label="选择" width="50px">

View File

@@ -38,12 +38,36 @@ const viteConfig: UserConfig = {
outDir: 'dist',
minify: 'esbuild',
sourcemap: false,
chunkSizeWarningLimit: 1500,
rollupOptions: {
output: {
entryFileNames: `assets/[name].${new Date().getTime()}.js`,
chunkFileNames: `assets/[name].${new Date().getTime()}.js`,
assetFileNames: `assets/[name].${new Date().getTime()}.[ext]`,
},
},
},
define: {
__VUE_I18N_LEGACY_API__: JSON.stringify(false),
__VUE_I18N_FULL_INSTALL__: JSON.stringify(false),
__INTLIFY_PROD_DEVTOOLS__: JSON.stringify(false),
},
css: {
postcss: {
plugins: [
{
postcssPlugin: 'internal:charset-removal',
AtRule: {
charset: (atRule) => {
if (atRule.name === 'charset') {
atRule.remove();
}
}
}
}
]
}
},
};
export default viteConfig;

View File

@@ -117,16 +117,20 @@ func (d *Db) ExecSqlFile(rc *ctx.ReqCtx) {
dbId := GetDbId(g)
go func() {
db := d.DbApp.GetDbInstance(dbId)
dbEntity := d.DbApp.GetById(dbId)
dbInfo := fmt.Sprintf("于%s的%s环境", dbEntity.Name, dbEntity.Env)
defer func() {
if err := recover(); err != nil {
switch t := err.(type) {
case *biz.BizError:
d.MsgApp.CreateAndSend(rc.LoginAccount, ws.ErrMsg("sql脚本执行失败", fmt.Sprintf("[%s]执行失败: [%s]", filename, t.Error())))
d.MsgApp.CreateAndSend(rc.LoginAccount, ws.ErrMsg("sql脚本执行失败", fmt.Sprintf("[%s]%s执行失败: [%s]", filename, dbInfo, t.Error())))
}
}
}()
db := d.DbApp.GetDbInstance(dbId)
for _, sql := range sqls {
sql = strings.Trim(sql, " ")
if sql == "" || sql == "\n" {
@@ -134,11 +138,11 @@ func (d *Db) ExecSqlFile(rc *ctx.ReqCtx) {
}
_, err := db.Exec(sql)
if err != nil {
d.MsgApp.CreateAndSend(rc.LoginAccount, ws.ErrMsg("sql脚本执行失败", fmt.Sprintf("[%s]执行失败: [%s]", filename, err.Error())))
d.MsgApp.CreateAndSend(rc.LoginAccount, ws.ErrMsg("sql脚本执行失败", fmt.Sprintf("[%s]%s执行失败: [%s]", filename, dbInfo, err.Error())))
return
}
}
d.MsgApp.CreateAndSend(rc.LoginAccount, ws.SuccessMsg("sql脚本执行成功", fmt.Sprintf("[%s]执行完成", filename)))
d.MsgApp.CreateAndSend(rc.LoginAccount, ws.SuccessMsg("sql脚本执行成功", fmt.Sprintf("[%s]%s执行完成", filename, dbInfo)))
}()
}

View File

@@ -11,8 +11,22 @@ type Redis struct {
EnvId uint64 `binding:"required" json:"envId"`
}
type KeyValue struct {
type KeyInfo struct {
Key string `binding:"required" json:"key"`
Value interface{} `binding:"required" json:"value"`
Timed uint64
Timed int64
}
type StringValue struct {
KeyInfo
Value interface{} `binding:"required" json:"value"`
}
type HashValue struct {
KeyInfo
Value []map[string]interface{} `binding:"required" json:"value"`
}
type SetValue struct {
KeyInfo
Value []interface{} `binding:"required" json:"value"`
}

View File

@@ -109,7 +109,7 @@ func (r *Redis) Scan(rc *ctx.ReqCtx) {
for i, k := range keys {
ttlType := strings.Split(keyInfoSplit[i], ",")
ttl, _ := strconv.Atoi(ttlType[0])
ki := &vo.KeyInfo{Key: k, Type: ttlType[1], Ttl: uint64(ttl)}
ki := &vo.KeyInfo{Key: k, Type: ttlType[1], Ttl: int64(ttl)}
kis = append(kis, ki)
}
@@ -149,16 +149,9 @@ func (r *Redis) GetHashValue(rc *ctx.ReqCtx) {
rc.ResData = res
}
func (r *Redis) GetSetValue(rc *ctx.ReqCtx) {
ri, key := r.checkKey(rc)
res, err := ri.Cli.SMembers(key).Result()
biz.ErrIsNilAppendErr(err, "获取set值失败: %s")
rc.ResData = res
}
func (r *Redis) SetStringValue(rc *ctx.ReqCtx) {
g := rc.GinCtx
keyValue := new(form.KeyValue)
keyValue := new(form.StringValue)
ginx.BindJsonAndValid(g, keyValue)
ri := r.RedisApp.GetRedisInstance(uint64(ginx.PathParamInt(g, "id")))
@@ -166,3 +159,44 @@ func (r *Redis) SetStringValue(rc *ctx.ReqCtx) {
biz.ErrIsNilAppendErr(err, "保存字符串值失败: %s")
rc.ResData = str
}
func (r *Redis) SetHashValue(rc *ctx.ReqCtx) {
g := rc.GinCtx
hashValue := new(form.HashValue)
ginx.BindJsonAndValid(g, hashValue)
ri := r.RedisApp.GetRedisInstance(uint64(ginx.PathParamInt(g, "id")))
key := hashValue.Key
// 简单处理->先删除,后新增
ri.Cli.Del(key)
for _, v := range hashValue.Value {
res := ri.Cli.HSet(key, v["key"].(string), v["value"])
biz.ErrIsNilAppendErr(res.Err(), "保存hash值失败")
}
if hashValue.Timed != -1 {
ri.Cli.Expire(key, time.Second*time.Duration(hashValue.Timed))
}
}
func (r *Redis) GetSetValue(rc *ctx.ReqCtx) {
ri, key := r.checkKey(rc)
res, err := ri.Cli.SMembers(key).Result()
biz.ErrIsNilAppendErr(err, "获取set值失败: %s")
rc.ResData = res
}
func (r *Redis) SetSetValue(rc *ctx.ReqCtx) {
g := rc.GinCtx
keyvalue := new(form.SetValue)
ginx.BindJsonAndValid(g, keyvalue)
ri := r.RedisApp.GetRedisInstance(uint64(ginx.PathParamInt(g, "id")))
key := keyvalue.Key
// 简单处理->先删除,后新增
ri.Cli.Del(key)
ri.Cli.SAdd(key, keyvalue.Value...)
if keyvalue.Timed != -1 {
ri.Cli.Expire(key, time.Second*time.Duration(keyvalue.Timed))
}
}

View File

@@ -24,6 +24,6 @@ type Keys struct {
type KeyInfo struct {
Key string `json:"key"`
Ttl uint64 `json:"ttl"`
Ttl int64 `json:"ttl"`
Type string `json:"type"`
}

View File

@@ -44,7 +44,7 @@ func InitDbRouter(router *gin.RouterGroup) {
})
db.GET(":dbId/t-create-ddl", func(c *gin.Context) {
ctx.NewReqCtxWithGin(c).WithNeedToken(false).Handle(d.GetCreateTableDdl)
ctx.NewReqCtxWithGin(c).Handle(d.GetCreateTableDdl)
})
// db.GET(":dbId/exec-sql", controllers.SelectData)

View File

@@ -61,14 +61,19 @@ func InitRedisRouter(router *gin.RouterGroup) {
ctx.NewReqCtxWithGin(c).Handle(rs.GetHashValue)
})
// 设置hash类型值
redis.POST(":id/hash-value", func(c *gin.Context) {
ctx.NewReqCtxWithGin(c).Handle(rs.SetHashValue)
})
// 获取set类型值
redis.GET(":id/set-value", func(c *gin.Context) {
ctx.NewReqCtxWithGin(c).Handle(rs.GetSetValue)
})
// 设置hash类型值
redis.POST(":id/hash-value", func(c *gin.Context) {
ctx.NewReqCtxWithGin(c).Handle(rs.SetStringValue)
// 设置set类型值
redis.POST(":id/set-value", func(c *gin.Context) {
ctx.NewReqCtxWithGin(c).Handle(rs.SetSetValue)
})
}
}