mirror of
https://gitee.com/dromara/mayfly-go
synced 2025-11-04 00:10:25 +08:00
feat: 1.前端组件升级 2.redis数据操作支持string,hash,set的新增修改
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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%",
|
||||
|
||||
@@ -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('未获取到值,请刷新重试');
|
||||
|
||||
@@ -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),
|
||||
};
|
||||
},
|
||||
|
||||
24
mayfly_go_web/src/components/svgIcon/index.vue
Normal file
24
mayfly_go_web/src/components/svgIcon/index.vue
Normal 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>
|
||||
@@ -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);
|
||||
|
||||
@@ -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: '',
|
||||
},
|
||||
},
|
||||
|
||||
@@ -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;
|
||||
|
||||
15
mayfly_go_web/src/views/gateway/api.ts
Normal file
15
mayfly_go_web/src/views/gateway/api.ts
Normal 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'),
|
||||
}
|
||||
192
mayfly_go_web/src/views/gateway/service/ApiEdit.vue
Normal file
192
mayfly_go_web/src/views/gateway/service/ApiEdit.vue
Normal 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>
|
||||
239
mayfly_go_web/src/views/gateway/service/ApiList.vue
Normal file
239
mayfly_go_web/src/views/gateway/service/ApiList.vue
Normal 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>
|
||||
223
mayfly_go_web/src/views/gateway/service/ServiceList.vue
Normal file
223
mayfly_go_web/src/views/gateway/service/ServiceList.vue
Normal 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>
|
||||
@@ -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 {
|
||||
|
||||
@@ -33,7 +33,7 @@ export default {
|
||||
watch(
|
||||
() => route.path,
|
||||
() => {
|
||||
proxy.$refs.layoutDefaultsScrollbarRef.wrap.scrollTop = 0;
|
||||
proxy.$refs.layoutDefaultsScrollbarRef.wrap$.scrollTop = 0;
|
||||
}
|
||||
);
|
||||
return {
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
// 当前滚动条偏移宽度
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
271
mayfly_go_web/src/views/ops/redis/DataEdit.vue
Normal file
271
mayfly_go_web/src/views/ops/redis/DataEdit.vue
Normal 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>
|
||||
@@ -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,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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'),
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)))
|
||||
}()
|
||||
}
|
||||
|
||||
|
||||
@@ -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"`
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"`
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user