update 调整代码格式
This commit is contained in:
parent
a7a31b011a
commit
97187b246b
@ -1,17 +1,3 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
defineProps({
|
|
||||||
isActive: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const emit = defineEmits(['toggleClick'])
|
|
||||||
const toggleClick = () => {
|
|
||||||
emit('toggleClick');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div style="padding: 0 15px;" @click="toggleClick">
|
<div style="padding: 0 15px;" @click="toggleClick">
|
||||||
<svg :class="{'is-active':isActive}" class="hamburger" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="64" height="64">
|
<svg :class="{'is-active':isActive}" class="hamburger" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="64" height="64">
|
||||||
@ -22,6 +8,20 @@ const toggleClick = () => {
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
defineProps({
|
||||||
|
isActive: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits(['toggleClick'])
|
||||||
|
const toggleClick = () => {
|
||||||
|
emit('toggleClick');
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.hamburger {
|
.hamburger {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
@ -1,126 +1,3 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import Fuse from 'fuse.js'
|
|
||||||
import { getNormalPath } from '@/utils/ruoyi'
|
|
||||||
import { isHttp } from '@/utils/validate'
|
|
||||||
import usePermissionStore from '@/store/modules/permission'
|
|
||||||
import { RouteOption } from 'vue-router'
|
|
||||||
|
|
||||||
type Router = Array<{
|
|
||||||
path: string;
|
|
||||||
title: string[];
|
|
||||||
}>
|
|
||||||
|
|
||||||
const search = ref('');
|
|
||||||
const options = ref<any>([]);
|
|
||||||
const searchPool = ref<Router>([]);
|
|
||||||
const show = ref(false);
|
|
||||||
const fuse = ref();
|
|
||||||
const headerSearchSelectRef = ref(ElSelect);
|
|
||||||
const router = useRouter();
|
|
||||||
const routes = computed(() => usePermissionStore().routes);
|
|
||||||
|
|
||||||
const click = () => {
|
|
||||||
show.value = !show.value
|
|
||||||
if (show.value) {
|
|
||||||
headerSearchSelectRef.value && headerSearchSelectRef.value.focus()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const close = () => {
|
|
||||||
headerSearchSelectRef.value && headerSearchSelectRef.value.blur()
|
|
||||||
options.value = []
|
|
||||||
show.value = false
|
|
||||||
}
|
|
||||||
const change = (val: any) => {
|
|
||||||
const path = val.path;
|
|
||||||
if (isHttp(path)) {
|
|
||||||
// http(s):// 路径新窗口打开
|
|
||||||
const pindex = path.indexOf("http");
|
|
||||||
window.open(path.substr(pindex, path.length), "_blank");
|
|
||||||
} else {
|
|
||||||
router.push(path)
|
|
||||||
}
|
|
||||||
search.value = ''
|
|
||||||
options.value = []
|
|
||||||
nextTick(() => {
|
|
||||||
show.value = false
|
|
||||||
})
|
|
||||||
}
|
|
||||||
const initFuse = (list: Router) => {
|
|
||||||
fuse.value = new Fuse(list, {
|
|
||||||
shouldSort: true,
|
|
||||||
threshold: 0.4,
|
|
||||||
location: 0,
|
|
||||||
distance: 100,
|
|
||||||
minMatchCharLength: 1,
|
|
||||||
keys: [{
|
|
||||||
name: 'title',
|
|
||||||
weight: 0.7
|
|
||||||
}, {
|
|
||||||
name: 'path',
|
|
||||||
weight: 0.3
|
|
||||||
}]
|
|
||||||
})
|
|
||||||
}
|
|
||||||
// Filter out the routes that can be displayed in the sidebar
|
|
||||||
// And generate the internationalized title
|
|
||||||
const generateRoutes = (routes: RouteOption[], basePath = '', prefixTitle: string[] = []) => {
|
|
||||||
let res: Router = []
|
|
||||||
routes.forEach(r => {
|
|
||||||
// skip hidden router
|
|
||||||
if (!r.hidden) {
|
|
||||||
const p = r.path.length > 0 && r.path[0] === '/' ? r.path : '/' + r.path;
|
|
||||||
const data = {
|
|
||||||
path: !isHttp(r.path) ? getNormalPath(basePath + p) : r.path,
|
|
||||||
title: [...prefixTitle]
|
|
||||||
}
|
|
||||||
if (r.meta && r.meta.title) {
|
|
||||||
data.title = [...data.title, r.meta.title];
|
|
||||||
if (r.redirect !== 'noRedirect') {
|
|
||||||
// only push the routes with title
|
|
||||||
// special case: need to exclude parent router without redirect
|
|
||||||
res.push(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// recursive child routes
|
|
||||||
if (r.children) {
|
|
||||||
const tempRoutes = generateRoutes(r.children, data.path, data.title);
|
|
||||||
if (tempRoutes.length >= 1) {
|
|
||||||
res = [...res, ...tempRoutes];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
const querySearch = (query: string) => {
|
|
||||||
if (query !== '') {
|
|
||||||
options.value = fuse.value.search(query)
|
|
||||||
} else {
|
|
||||||
options.value = []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
searchPool.value = generateRoutes(routes.value);
|
|
||||||
})
|
|
||||||
|
|
||||||
watchEffect(() => {
|
|
||||||
searchPool.value = generateRoutes(routes.value)
|
|
||||||
})
|
|
||||||
|
|
||||||
watch(show, (value) => {
|
|
||||||
if (value) {
|
|
||||||
document.body.addEventListener('click', close)
|
|
||||||
} else {
|
|
||||||
document.body.removeEventListener('click', close)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
watch(searchPool, (list) => {
|
|
||||||
initFuse(list)
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div :class="{ 'show': show }" class="header-search">
|
<div :class="{ 'show': show }" class="header-search">
|
||||||
<svg-icon class-name="search-icon" icon-class="search" @click.stop="click" />
|
<svg-icon class-name="search-icon" icon-class="search" @click.stop="click" />
|
||||||
@ -140,6 +17,129 @@ watch(searchPool, (list) => {
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import Fuse from 'fuse.js'
|
||||||
|
import { getNormalPath } from '@/utils/ruoyi'
|
||||||
|
import { isHttp } from '@/utils/validate'
|
||||||
|
import usePermissionStore from '@/store/modules/permission'
|
||||||
|
import { RouteOption } from 'vue-router'
|
||||||
|
|
||||||
|
type Router = Array<{
|
||||||
|
path: string;
|
||||||
|
title: string[];
|
||||||
|
}>
|
||||||
|
|
||||||
|
const search = ref('');
|
||||||
|
const options = ref<any>([]);
|
||||||
|
const searchPool = ref<Router>([]);
|
||||||
|
const show = ref(false);
|
||||||
|
const fuse = ref();
|
||||||
|
const headerSearchSelectRef = ref(ElSelect);
|
||||||
|
const router = useRouter();
|
||||||
|
const routes = computed(() => usePermissionStore().routes);
|
||||||
|
|
||||||
|
const click = () => {
|
||||||
|
show.value = !show.value
|
||||||
|
if (show.value) {
|
||||||
|
headerSearchSelectRef.value && headerSearchSelectRef.value.focus()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const close = () => {
|
||||||
|
headerSearchSelectRef.value && headerSearchSelectRef.value.blur()
|
||||||
|
options.value = []
|
||||||
|
show.value = false
|
||||||
|
}
|
||||||
|
const change = (val: any) => {
|
||||||
|
const path = val.path;
|
||||||
|
if (isHttp(path)) {
|
||||||
|
// http(s):// 路径新窗口打开
|
||||||
|
const pindex = path.indexOf("http");
|
||||||
|
window.open(path.substr(pindex, path.length), "_blank");
|
||||||
|
} else {
|
||||||
|
router.push(path)
|
||||||
|
}
|
||||||
|
search.value = ''
|
||||||
|
options.value = []
|
||||||
|
nextTick(() => {
|
||||||
|
show.value = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const initFuse = (list: Router) => {
|
||||||
|
fuse.value = new Fuse(list, {
|
||||||
|
shouldSort: true,
|
||||||
|
threshold: 0.4,
|
||||||
|
location: 0,
|
||||||
|
distance: 100,
|
||||||
|
minMatchCharLength: 1,
|
||||||
|
keys: [{
|
||||||
|
name: 'title',
|
||||||
|
weight: 0.7
|
||||||
|
}, {
|
||||||
|
name: 'path',
|
||||||
|
weight: 0.3
|
||||||
|
}]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// Filter out the routes that can be displayed in the sidebar
|
||||||
|
// And generate the internationalized title
|
||||||
|
const generateRoutes = (routes: RouteOption[], basePath = '', prefixTitle: string[] = []) => {
|
||||||
|
let res: Router = []
|
||||||
|
routes.forEach(r => {
|
||||||
|
// skip hidden router
|
||||||
|
if (!r.hidden) {
|
||||||
|
const p = r.path.length > 0 && r.path[0] === '/' ? r.path : '/' + r.path;
|
||||||
|
const data = {
|
||||||
|
path: !isHttp(r.path) ? getNormalPath(basePath + p) : r.path,
|
||||||
|
title: [...prefixTitle]
|
||||||
|
}
|
||||||
|
if (r.meta && r.meta.title) {
|
||||||
|
data.title = [...data.title, r.meta.title];
|
||||||
|
if (r.redirect !== 'noRedirect') {
|
||||||
|
// only push the routes with title
|
||||||
|
// special case: need to exclude parent router without redirect
|
||||||
|
res.push(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// recursive child routes
|
||||||
|
if (r.children) {
|
||||||
|
const tempRoutes = generateRoutes(r.children, data.path, data.title);
|
||||||
|
if (tempRoutes.length >= 1) {
|
||||||
|
res = [...res, ...tempRoutes];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
const querySearch = (query: string) => {
|
||||||
|
if (query !== '') {
|
||||||
|
options.value = fuse.value.search(query)
|
||||||
|
} else {
|
||||||
|
options.value = []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
searchPool.value = generateRoutes(routes.value);
|
||||||
|
})
|
||||||
|
|
||||||
|
watchEffect(() => {
|
||||||
|
searchPool.value = generateRoutes(routes.value)
|
||||||
|
})
|
||||||
|
|
||||||
|
watch(show, (value) => {
|
||||||
|
if (value) {
|
||||||
|
document.body.addEventListener('click', close)
|
||||||
|
} else {
|
||||||
|
document.body.removeEventListener('click', close)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
watch(searchPool, (list) => {
|
||||||
|
initFuse(list)
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.header-search {
|
.header-search {
|
||||||
font-size: 0 !important;
|
font-size: 0 !important;
|
||||||
|
@ -1,48 +1,3 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import icons from '@/components/IconSelect/requireIcons';
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
modelValue: {
|
|
||||||
type: String,
|
|
||||||
require: true
|
|
||||||
},
|
|
||||||
width: {
|
|
||||||
type: String,
|
|
||||||
require: false,
|
|
||||||
default: '400px'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const emit = defineEmits(['update:modelValue']);
|
|
||||||
const visible = ref(false);
|
|
||||||
const { modelValue, width } = toRefs(props);
|
|
||||||
const iconNames = ref<string[]>(icons);
|
|
||||||
|
|
||||||
const filterValue = ref('');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 筛选图标
|
|
||||||
*/
|
|
||||||
const filterIcons = () => {
|
|
||||||
if (filterValue.value) {
|
|
||||||
iconNames.value = icons.filter(iconName =>
|
|
||||||
iconName.includes(filterValue.value)
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
iconNames.value = icons;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 选择图标
|
|
||||||
* @param iconName 选择的图标名称
|
|
||||||
*/
|
|
||||||
const selectedIcon = (iconName: string) => {
|
|
||||||
emit('update:modelValue', iconName);
|
|
||||||
visible.value = false;
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="relative" :style="{ width: width }">
|
<div class="relative" :style="{ width: width }">
|
||||||
<el-input v-model="modelValue" readonly @click="visible = !visible" placeholder="点击选择图标">
|
<el-input v-model="modelValue" readonly @click="visible = !visible" placeholder="点击选择图标">
|
||||||
@ -74,6 +29,51 @@ const selectedIcon = (iconName: string) => {
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import icons from '@/components/IconSelect/requireIcons';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
modelValue: {
|
||||||
|
type: String,
|
||||||
|
require: true
|
||||||
|
},
|
||||||
|
width: {
|
||||||
|
type: String,
|
||||||
|
require: false,
|
||||||
|
default: '400px'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits(['update:modelValue']);
|
||||||
|
const visible = ref(false);
|
||||||
|
const { modelValue, width } = toRefs(props);
|
||||||
|
const iconNames = ref<string[]>(icons);
|
||||||
|
|
||||||
|
const filterValue = ref('');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 筛选图标
|
||||||
|
*/
|
||||||
|
const filterIcons = () => {
|
||||||
|
if (filterValue.value) {
|
||||||
|
iconNames.value = icons.filter(iconName =>
|
||||||
|
iconName.includes(filterValue.value)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
iconNames.value = icons;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 选择图标
|
||||||
|
* @param iconName 选择的图标名称
|
||||||
|
*/
|
||||||
|
const selectedIcon = (iconName: string) => {
|
||||||
|
emit('update:modelValue', iconName);
|
||||||
|
visible.value = false;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.el-divider--horizontal {
|
.el-divider--horizontal {
|
||||||
margin: 10px auto !important;
|
margin: 10px auto !important;
|
||||||
|
@ -1,48 +1,3 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
const props = defineProps({
|
|
||||||
src: {
|
|
||||||
type: String,
|
|
||||||
default: ""
|
|
||||||
},
|
|
||||||
width: {
|
|
||||||
type: [Number, String],
|
|
||||||
default: ""
|
|
||||||
},
|
|
||||||
height: {
|
|
||||||
type: [Number, String],
|
|
||||||
default: ""
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const realSrc = computed(() => {
|
|
||||||
if (!props.src) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let real_src = props.src.split(",")[0];
|
|
||||||
return real_src;
|
|
||||||
});
|
|
||||||
|
|
||||||
const realSrcList = computed(() => {
|
|
||||||
if (!props.src) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let real_src_list = props.src.split(",");
|
|
||||||
let srcList:string[] = [];
|
|
||||||
real_src_list.forEach(item => {
|
|
||||||
return srcList.push(item);
|
|
||||||
});
|
|
||||||
return srcList;
|
|
||||||
});
|
|
||||||
|
|
||||||
const realWidth = computed(() =>
|
|
||||||
typeof props.width == "string" ? props.width : `${props.width}px`
|
|
||||||
);
|
|
||||||
|
|
||||||
const realHeight = computed(() =>
|
|
||||||
typeof props.height == "string" ? props.height : `${props.height}px`
|
|
||||||
);
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<el-image :src="`${realSrc}`" fit="cover" :style="`width:${realWidth};height:${realHeight};`" :preview-src-list="realSrcList" preview-teleported>
|
<el-image :src="`${realSrc}`" fit="cover" :style="`width:${realWidth};height:${realHeight};`" :preview-src-list="realSrcList" preview-teleported>
|
||||||
<template #error>
|
<template #error>
|
||||||
@ -53,6 +8,51 @@ const realHeight = computed(() =>
|
|||||||
</el-image>
|
</el-image>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
const props = defineProps({
|
||||||
|
src: {
|
||||||
|
type: String,
|
||||||
|
default: ""
|
||||||
|
},
|
||||||
|
width: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: ""
|
||||||
|
},
|
||||||
|
height: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: ""
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const realSrc = computed(() => {
|
||||||
|
if (!props.src) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let real_src = props.src.split(",")[0];
|
||||||
|
return real_src;
|
||||||
|
});
|
||||||
|
|
||||||
|
const realSrcList = computed(() => {
|
||||||
|
if (!props.src) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let real_src_list = props.src.split(",");
|
||||||
|
let srcList:string[] = [];
|
||||||
|
real_src_list.forEach(item => {
|
||||||
|
return srcList.push(item);
|
||||||
|
});
|
||||||
|
return srcList;
|
||||||
|
});
|
||||||
|
|
||||||
|
const realWidth = computed(() =>
|
||||||
|
typeof props.width == "string" ? props.width : `${props.width}px`
|
||||||
|
);
|
||||||
|
|
||||||
|
const realHeight = computed(() =>
|
||||||
|
typeof props.height == "string" ? props.height : `${props.height}px`
|
||||||
|
);
|
||||||
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.el-image {
|
.el-image {
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
|
@ -1,20 +1,3 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import useAppStore from "@/store/modules/app";
|
|
||||||
|
|
||||||
const appStore = useAppStore();
|
|
||||||
const size = computed(() => appStore.size);
|
|
||||||
|
|
||||||
const sizeOptions = ref([
|
|
||||||
{ label: "较大", value: "large" },
|
|
||||||
{ label: "默认", value: "default" },
|
|
||||||
{ label: "稍小", value: "small" },
|
|
||||||
]);
|
|
||||||
|
|
||||||
const handleSetSize = (size: string) => {
|
|
||||||
appStore.setSize(size);
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<el-dropdown trigger="click" @command="handleSetSize">
|
<el-dropdown trigger="click" @command="handleSetSize">
|
||||||
@ -32,6 +15,23 @@ const handleSetSize = (size: string) => {
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import useAppStore from "@/store/modules/app";
|
||||||
|
|
||||||
|
const appStore = useAppStore();
|
||||||
|
const size = computed(() => appStore.size);
|
||||||
|
|
||||||
|
const sizeOptions = ref([
|
||||||
|
{ label: "较大", value: "large" },
|
||||||
|
{ label: "默认", value: "default" },
|
||||||
|
{ label: "稍小", value: "small" },
|
||||||
|
]);
|
||||||
|
|
||||||
|
const handleSetSize = (size: string) => {
|
||||||
|
appStore.setSize(size);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.size-icon--style {
|
.size-icon--style {
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
|
@ -1,33 +1,33 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
const props = defineProps({
|
|
||||||
iconClass: {
|
|
||||||
type: String,
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
className: {
|
|
||||||
type: String,
|
|
||||||
default: ''
|
|
||||||
},
|
|
||||||
color: {
|
|
||||||
type: String,
|
|
||||||
default: ''
|
|
||||||
},
|
|
||||||
})
|
|
||||||
const iconName = computed(() => `#icon-${props.iconClass}`);
|
|
||||||
const svgClass = computed(() => {
|
|
||||||
if (props.className) {
|
|
||||||
return `svg-icon ${props.className}`
|
|
||||||
}
|
|
||||||
return 'svg-icon'
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<svg :class="svgClass" aria-hidden="true">
|
<svg :class="svgClass" aria-hidden="true">
|
||||||
<use :xlink:href="iconName" :fill="color" />
|
<use :xlink:href="iconName" :fill="color" />
|
||||||
</svg>
|
</svg>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
const props = defineProps({
|
||||||
|
iconClass: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
className: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
color: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
})
|
||||||
|
const iconName = computed(() => `#icon-${props.iconClass}`);
|
||||||
|
const svgClass = computed(() => {
|
||||||
|
if (props.className) {
|
||||||
|
return `svg-icon ${props.className}`
|
||||||
|
}
|
||||||
|
return 'svg-icon'
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
<style scope lang="scss">
|
<style scope lang="scss">
|
||||||
.sub-el-icon,
|
.sub-el-icon,
|
||||||
.nav-icon {
|
.nav-icon {
|
||||||
|
@ -1,21 +1,21 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-menu :default-active="activeMenu" mode="horizontal" @select="handleSelect" :ellipsis="false">
|
<el-menu :default-active="activeMenu" mode="horizontal" @select="handleSelect" :ellipsis="false">
|
||||||
<template v-for="(item, index) in topMenus">
|
<template v-for="(item, index) in topMenus">
|
||||||
<el-menu-item :style="{'--theme': theme}" :index="item.path" :key="index" v-if="index < visibleNumber"
|
<el-menu-item :style="{'--theme': theme}" :index="item.path" :key="index" v-if="index < visibleNumber"
|
||||||
><svg-icon :icon-class="item.meta ? item.meta.icon : '' " /> {{ item.meta?.title }}</el-menu-item
|
><svg-icon :icon-class="item.meta ? item.meta.icon : '' " /> {{ item.meta?.title }}</el-menu-item
|
||||||
>
|
>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- 顶部菜单超出数量折叠 -->
|
<!-- 顶部菜单超出数量折叠 -->
|
||||||
<el-sub-menu :style="{'--theme': theme}" index="more" v-if="topMenus.length > visibleNumber">
|
<el-sub-menu :style="{'--theme': theme}" index="more" v-if="topMenus.length > visibleNumber">
|
||||||
<template #title>更多菜单</template>
|
<template #title>更多菜单</template>
|
||||||
<template v-for="(item, index) in topMenus">
|
<template v-for="(item, index) in topMenus">
|
||||||
<el-menu-item :index="item.path" :key="index" v-if="index >= visibleNumber"
|
<el-menu-item :index="item.path" :key="index" v-if="index >= visibleNumber"
|
||||||
><svg-icon :icon-class="item.meta ? item.meta.icon : '' " /> {{ item.meta?.title }}</el-menu-item
|
><svg-icon :icon-class="item.meta ? item.meta.icon : '' " /> {{ item.meta?.title }}</el-menu-item
|
||||||
>
|
>
|
||||||
</template>
|
</template>
|
||||||
</el-sub-menu>
|
</el-sub-menu>
|
||||||
</el-menu>
|
</el-menu>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
@ -1,39 +1,69 @@
|
|||||||
|
<template>
|
||||||
|
<div class="el-tree-select">
|
||||||
|
<el-select
|
||||||
|
style="width: 100%"
|
||||||
|
v-model="valueId"
|
||||||
|
ref="treeSelect"
|
||||||
|
:filterable="true"
|
||||||
|
:clearable="true"
|
||||||
|
@clear="clearHandle"
|
||||||
|
:filter-method="selectFilterData"
|
||||||
|
:placeholder="placeholder"
|
||||||
|
>
|
||||||
|
<el-option :value="valueId" :label="valueTitle">
|
||||||
|
<el-tree
|
||||||
|
id="tree-option"
|
||||||
|
ref="selectTree"
|
||||||
|
:accordion="accordion"
|
||||||
|
:data="options"
|
||||||
|
:props="objMap"
|
||||||
|
:node-key="objMap.value"
|
||||||
|
:expand-on-click-node="false"
|
||||||
|
:default-expanded-keys="defaultExpandedKey"
|
||||||
|
:filter-node-method="filterNode"
|
||||||
|
@node-click="handleNodeClick"
|
||||||
|
></el-tree>
|
||||||
|
</el-option>
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ElTreeSelect } from 'element-plus'
|
import { ElTreeSelect } from 'element-plus'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
/* 配置项 */
|
/* 配置项 */
|
||||||
objMap: {
|
objMap: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: () => {
|
default: () => {
|
||||||
return {
|
return {
|
||||||
value: 'id', // ID字段名
|
value: 'id', // ID字段名
|
||||||
label: 'label', // 显示名称
|
label: 'label', // 显示名称
|
||||||
children: 'children' // 子级字段名
|
children: 'children' // 子级字段名
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
/* 自动收起 */
|
/* 自动收起 */
|
||||||
accordion: {
|
accordion: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: () => {
|
default: () => {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
/**当前双向数据绑定的值 */
|
/**当前双向数据绑定的值 */
|
||||||
value: {
|
value: {
|
||||||
type: [String, Number],
|
type: [String, Number],
|
||||||
default: ''
|
default: ''
|
||||||
},
|
},
|
||||||
/**当前的数据 */
|
/**当前的数据 */
|
||||||
options: {
|
options: {
|
||||||
type: Array,
|
type: Array,
|
||||||
default: () => []
|
default: () => []
|
||||||
},
|
},
|
||||||
/**输入框内部的文字 */
|
/**输入框内部的文字 */
|
||||||
placeholder: {
|
placeholder: {
|
||||||
type: String,
|
type: String,
|
||||||
default: ''
|
default: ''
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -45,7 +75,7 @@ const emit = defineEmits(['update:value']);
|
|||||||
const valueId = computed({
|
const valueId = computed({
|
||||||
get: () => props.value,
|
get: () => props.value,
|
||||||
set: (val) => {
|
set: (val) => {
|
||||||
emit('update:value', val)
|
emit('update:value', val)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const valueTitle = ref('');
|
const valueTitle = ref('');
|
||||||
@ -53,17 +83,17 @@ const defaultExpandedKey = ref<any[]>([]);
|
|||||||
|
|
||||||
function initHandle() {
|
function initHandle() {
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
const selectedValue = valueId.value;
|
const selectedValue = valueId.value;
|
||||||
if(selectedValue !== null && typeof (selectedValue) !== 'undefined') {
|
if(selectedValue !== null && typeof (selectedValue) !== 'undefined') {
|
||||||
const node = selectTree.value.getNode(selectedValue)
|
const node = selectTree.value.getNode(selectedValue)
|
||||||
if (node) {
|
if (node) {
|
||||||
valueTitle.value = node.data[props.objMap.label]
|
valueTitle.value = node.data[props.objMap.label]
|
||||||
selectTree.value.setCurrentKey(selectedValue) // 设置默认选中
|
selectTree.value.setCurrentKey(selectedValue) // 设置默认选中
|
||||||
defaultExpandedKey.value = [selectedValue] // 设置默认展开
|
defaultExpandedKey.value = [selectedValue] // 设置默认展开
|
||||||
}
|
|
||||||
} else {
|
|
||||||
clearHandle()
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
clearHandle()
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
function handleNodeClick(node: any) {
|
function handleNodeClick(node: any) {
|
||||||
@ -126,33 +156,3 @@ ul li .el-tree .el-tree-node__content {
|
|||||||
color: $--color-primary;
|
color: $--color-primary;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<template>
|
|
||||||
<div class="el-tree-select">
|
|
||||||
<el-select
|
|
||||||
style="width: 100%"
|
|
||||||
v-model="valueId"
|
|
||||||
ref="treeSelect"
|
|
||||||
:filterable="true"
|
|
||||||
:clearable="true"
|
|
||||||
@clear="clearHandle"
|
|
||||||
:filter-method="selectFilterData"
|
|
||||||
:placeholder="placeholder"
|
|
||||||
>
|
|
||||||
<el-option :value="valueId" :label="valueTitle">
|
|
||||||
<el-tree
|
|
||||||
id="tree-option"
|
|
||||||
ref="selectTree"
|
|
||||||
:accordion="accordion"
|
|
||||||
:data="options"
|
|
||||||
:props="objMap"
|
|
||||||
:node-key="objMap.value"
|
|
||||||
:expand-on-click-node="false"
|
|
||||||
:default-expanded-keys="defaultExpandedKey"
|
|
||||||
:filter-node-method="filterNode"
|
|
||||||
@node-click="handleNodeClick"
|
|
||||||
></el-tree>
|
|
||||||
</el-option>
|
|
||||||
</el-select>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
@ -1,3 +1,9 @@
|
|||||||
|
<template>
|
||||||
|
<div v-loading="loading" :style="'height:' + height">
|
||||||
|
<iframe :src="url" frameborder="no" style="width: 100%; height: 100%" scrolling="auto" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
src: {
|
src: {
|
||||||
@ -19,9 +25,3 @@ onMounted(() => {
|
|||||||
};
|
};
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
|
||||||
<div v-loading="loading" :style="'height:' + height">
|
|
||||||
<iframe :src="url" frameborder="no" style="width: 100%; height: 100%" scrolling="auto" />
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
@ -1,11 +1,3 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import InnerLink from "../InnerLink/index.vue";
|
|
||||||
import useTagsViewStore from '@/store/modules/tagsView';
|
|
||||||
|
|
||||||
const route = useRoute();
|
|
||||||
const tagsViewStore = useTagsViewStore()
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<transition-group name="fade-transform" mode="out-in">
|
<transition-group name="fade-transform" mode="out-in">
|
||||||
<inner-link
|
<inner-link
|
||||||
@ -17,3 +9,11 @@ const tagsViewStore = useTagsViewStore()
|
|||||||
></inner-link>
|
></inner-link>
|
||||||
</transition-group>
|
</transition-group>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import InnerLink from "../InnerLink/index.vue";
|
||||||
|
import useTagsViewStore from '@/store/modules/tagsView';
|
||||||
|
|
||||||
|
const route = useRoute();
|
||||||
|
const tagsViewStore = useTagsViewStore()
|
||||||
|
</script>
|
@ -1,105 +1,3 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import { useDynamicTitle } from '@/utils/dynamicTitle'
|
|
||||||
import useAppStore from '@/store/modules/app'
|
|
||||||
import useSettingsStore from '@/store/modules/settings'
|
|
||||||
import usePermissionStore from '@/store/modules/permission'
|
|
||||||
import { handleThemeStyle } from '@/utils/theme'
|
|
||||||
import { ComponentInternalInstance } from "vue";
|
|
||||||
import { SettingTypeEnum } from "@/enums/SettingTypeEnum";
|
|
||||||
|
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
|
||||||
const appStore = useAppStore()
|
|
||||||
const settingsStore = useSettingsStore()
|
|
||||||
const permissionStore = usePermissionStore()
|
|
||||||
|
|
||||||
|
|
||||||
const showSettings = ref(false);
|
|
||||||
const theme = ref(settingsStore.theme);
|
|
||||||
const sideTheme = ref(settingsStore.sideTheme);
|
|
||||||
const storeSettings = computed(() => settingsStore);
|
|
||||||
const predefineColors = ref(["#409EFF", "#ff4500", "#ff8c00", "#ffd700", "#90ee90", "#00ced1", "#1e90ff", "#c71585"]);
|
|
||||||
|
|
||||||
/** 是否需要topnav */
|
|
||||||
const topNav = computed({
|
|
||||||
get: () => storeSettings.value.topNav,
|
|
||||||
set: (val) => {
|
|
||||||
settingsStore.changeSetting({ key: SettingTypeEnum.TOP_NAV, value: val })
|
|
||||||
if (!val) {
|
|
||||||
appStore.toggleSideBarHide(false);
|
|
||||||
permissionStore.setSidebarRouters(permissionStore.defaultRoutes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
/** 是否需要tagview */
|
|
||||||
const tagsView = computed({
|
|
||||||
get: () => storeSettings.value.tagsView,
|
|
||||||
set: (val) => {
|
|
||||||
settingsStore.changeSetting({ key: SettingTypeEnum.TAGS_VIEW, value: val })
|
|
||||||
}
|
|
||||||
})
|
|
||||||
/**是否需要固定头部 */
|
|
||||||
const fixedHeader = computed({
|
|
||||||
get: () => storeSettings.value.fixedHeader,
|
|
||||||
set: (val) => {
|
|
||||||
settingsStore.changeSetting({ key: SettingTypeEnum.FIXED_HEADER, value: val })
|
|
||||||
}
|
|
||||||
})
|
|
||||||
/**是否需要侧边栏的logo */
|
|
||||||
const sidebarLogo = computed({
|
|
||||||
get: () => storeSettings.value.sidebarLogo,
|
|
||||||
set: (val) => {
|
|
||||||
settingsStore.changeSetting({ key: SettingTypeEnum.SIDEBAR_LOGO, value: val })
|
|
||||||
}
|
|
||||||
})
|
|
||||||
/**是否需要侧边栏的动态网页的title */
|
|
||||||
const dynamicTitle = computed({
|
|
||||||
get: () => storeSettings.value.dynamicTitle,
|
|
||||||
set: (val) => {
|
|
||||||
settingsStore.changeSetting({ key: SettingTypeEnum.DYNAMIC_TITLE, value: val })
|
|
||||||
// 动态设置网页标题
|
|
||||||
useDynamicTitle()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const themeChange = (val: string | null) => {
|
|
||||||
settingsStore.changeSetting({ key: SettingTypeEnum.THEME, value: val })
|
|
||||||
theme.value = val;
|
|
||||||
if (val) {
|
|
||||||
handleThemeStyle(val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const handleTheme = (val: string) => {
|
|
||||||
settingsStore.changeSetting({ key: SettingTypeEnum.SIDE_THEME, value: val })
|
|
||||||
sideTheme.value = val;
|
|
||||||
}
|
|
||||||
const saveSetting = () => {
|
|
||||||
proxy?.$modal.loading("正在保存到本地,请稍候...");
|
|
||||||
let layoutSetting = {
|
|
||||||
"topNav": storeSettings.value.topNav,
|
|
||||||
"tagsView": storeSettings.value.tagsView,
|
|
||||||
"fixedHeader": storeSettings.value.fixedHeader,
|
|
||||||
"sidebarLogo": storeSettings.value.sidebarLogo,
|
|
||||||
"dynamicTitle": storeSettings.value.dynamicTitle,
|
|
||||||
"sideTheme": storeSettings.value.sideTheme,
|
|
||||||
"theme": storeSettings.value.theme
|
|
||||||
};
|
|
||||||
localStorage.setItem("layout-setting", JSON.stringify(layoutSetting));
|
|
||||||
setTimeout(() => {proxy?.$modal.closeLoading()}, 1000)
|
|
||||||
}
|
|
||||||
const resetSetting = () => {
|
|
||||||
proxy?.$modal.loading("正在清除设置缓存并刷新,请稍候...");
|
|
||||||
localStorage.removeItem("layout-setting")
|
|
||||||
setTimeout("window.location.reload()", 1000)
|
|
||||||
}
|
|
||||||
const openSetting = () => {
|
|
||||||
showSettings.value = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
defineExpose({
|
|
||||||
openSetting,
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<el-drawer v-model="showSettings" :withHeader="false" direction="rtl" size="300px" close-on-click-modal>
|
<el-drawer v-model="showSettings" :withHeader="false" direction="rtl" size="300px" close-on-click-modal>
|
||||||
<div class="setting-drawer-title">
|
<div class="setting-drawer-title">
|
||||||
@ -183,6 +81,108 @@ defineExpose({
|
|||||||
</el-drawer>
|
</el-drawer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useDynamicTitle } from '@/utils/dynamicTitle'
|
||||||
|
import useAppStore from '@/store/modules/app'
|
||||||
|
import useSettingsStore from '@/store/modules/settings'
|
||||||
|
import usePermissionStore from '@/store/modules/permission'
|
||||||
|
import { handleThemeStyle } from '@/utils/theme'
|
||||||
|
import { ComponentInternalInstance } from "vue";
|
||||||
|
import { SettingTypeEnum } from "@/enums/SettingTypeEnum";
|
||||||
|
|
||||||
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
|
const appStore = useAppStore()
|
||||||
|
const settingsStore = useSettingsStore()
|
||||||
|
const permissionStore = usePermissionStore()
|
||||||
|
|
||||||
|
|
||||||
|
const showSettings = ref(false);
|
||||||
|
const theme = ref(settingsStore.theme);
|
||||||
|
const sideTheme = ref(settingsStore.sideTheme);
|
||||||
|
const storeSettings = computed(() => settingsStore);
|
||||||
|
const predefineColors = ref(["#409EFF", "#ff4500", "#ff8c00", "#ffd700", "#90ee90", "#00ced1", "#1e90ff", "#c71585"]);
|
||||||
|
|
||||||
|
/** 是否需要topnav */
|
||||||
|
const topNav = computed({
|
||||||
|
get: () => storeSettings.value.topNav,
|
||||||
|
set: (val) => {
|
||||||
|
settingsStore.changeSetting({ key: SettingTypeEnum.TOP_NAV, value: val })
|
||||||
|
if (!val) {
|
||||||
|
appStore.toggleSideBarHide(false);
|
||||||
|
permissionStore.setSidebarRouters(permissionStore.defaultRoutes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
/** 是否需要tagview */
|
||||||
|
const tagsView = computed({
|
||||||
|
get: () => storeSettings.value.tagsView,
|
||||||
|
set: (val) => {
|
||||||
|
settingsStore.changeSetting({ key: SettingTypeEnum.TAGS_VIEW, value: val })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
/**是否需要固定头部 */
|
||||||
|
const fixedHeader = computed({
|
||||||
|
get: () => storeSettings.value.fixedHeader,
|
||||||
|
set: (val) => {
|
||||||
|
settingsStore.changeSetting({ key: SettingTypeEnum.FIXED_HEADER, value: val })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
/**是否需要侧边栏的logo */
|
||||||
|
const sidebarLogo = computed({
|
||||||
|
get: () => storeSettings.value.sidebarLogo,
|
||||||
|
set: (val) => {
|
||||||
|
settingsStore.changeSetting({ key: SettingTypeEnum.SIDEBAR_LOGO, value: val })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
/**是否需要侧边栏的动态网页的title */
|
||||||
|
const dynamicTitle = computed({
|
||||||
|
get: () => storeSettings.value.dynamicTitle,
|
||||||
|
set: (val) => {
|
||||||
|
settingsStore.changeSetting({ key: SettingTypeEnum.DYNAMIC_TITLE, value: val })
|
||||||
|
// 动态设置网页标题
|
||||||
|
useDynamicTitle()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const themeChange = (val: string | null) => {
|
||||||
|
settingsStore.changeSetting({ key: SettingTypeEnum.THEME, value: val })
|
||||||
|
theme.value = val;
|
||||||
|
if (val) {
|
||||||
|
handleThemeStyle(val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const handleTheme = (val: string) => {
|
||||||
|
settingsStore.changeSetting({ key: SettingTypeEnum.SIDE_THEME, value: val })
|
||||||
|
sideTheme.value = val;
|
||||||
|
}
|
||||||
|
const saveSetting = () => {
|
||||||
|
proxy?.$modal.loading("正在保存到本地,请稍候...");
|
||||||
|
let layoutSetting = {
|
||||||
|
"topNav": storeSettings.value.topNav,
|
||||||
|
"tagsView": storeSettings.value.tagsView,
|
||||||
|
"fixedHeader": storeSettings.value.fixedHeader,
|
||||||
|
"sidebarLogo": storeSettings.value.sidebarLogo,
|
||||||
|
"dynamicTitle": storeSettings.value.dynamicTitle,
|
||||||
|
"sideTheme": storeSettings.value.sideTheme,
|
||||||
|
"theme": storeSettings.value.theme
|
||||||
|
};
|
||||||
|
localStorage.setItem("layout-setting", JSON.stringify(layoutSetting));
|
||||||
|
setTimeout(() => {proxy?.$modal.closeLoading()}, 1000)
|
||||||
|
}
|
||||||
|
const resetSetting = () => {
|
||||||
|
proxy?.$modal.loading("正在清除设置缓存并刷新,请稍候...");
|
||||||
|
localStorage.removeItem("layout-setting")
|
||||||
|
setTimeout("window.location.reload()", 1000)
|
||||||
|
}
|
||||||
|
const openSetting = () => {
|
||||||
|
showSettings.value = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
openSetting,
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.setting-drawer-title {
|
.setting-drawer-title {
|
||||||
margin-bottom: 12px;
|
margin-bottom: 12px;
|
||||||
|
@ -1,40 +1,40 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import { isExternal } from '@/utils/validate'
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
to: {
|
|
||||||
type: [String, Object],
|
|
||||||
required: true
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const isExt = computed(() => {
|
|
||||||
return isExternal(props.to as string)
|
|
||||||
})
|
|
||||||
|
|
||||||
const type = computed(() => {
|
|
||||||
if (isExt.value) {
|
|
||||||
return 'a'
|
|
||||||
}
|
|
||||||
return 'router-link'
|
|
||||||
})
|
|
||||||
|
|
||||||
function linkProps() {
|
|
||||||
if (isExt.value) {
|
|
||||||
return {
|
|
||||||
href: props.to,
|
|
||||||
target: '_blank',
|
|
||||||
rel: 'noopener'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
to: props.to
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<component :is="type" v-bind="linkProps()">
|
<component :is="type" v-bind="linkProps()">
|
||||||
<slot />
|
<slot />
|
||||||
</component>
|
</component>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { isExternal } from '@/utils/validate'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
to: {
|
||||||
|
type: [String, Object],
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const isExt = computed(() => {
|
||||||
|
return isExternal(props.to as string)
|
||||||
|
})
|
||||||
|
|
||||||
|
const type = computed(() => {
|
||||||
|
if (isExt.value) {
|
||||||
|
return 'a'
|
||||||
|
}
|
||||||
|
return 'router-link'
|
||||||
|
})
|
||||||
|
|
||||||
|
function linkProps() {
|
||||||
|
if (isExt.value) {
|
||||||
|
return {
|
||||||
|
href: props.to,
|
||||||
|
target: '_blank',
|
||||||
|
rel: 'noopener'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
to: props.to
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
@ -1,22 +1,3 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import variables from '@/assets/styles/variables.module.scss'
|
|
||||||
import logo from '@/assets/logo/logo.png'
|
|
||||||
import useSettingsStore from '@/store/modules/settings'
|
|
||||||
import { ComponentInternalInstance } from "vue";
|
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
|
||||||
|
|
||||||
defineProps({
|
|
||||||
collapse: {
|
|
||||||
type: Boolean,
|
|
||||||
required: true
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const title = ref('RuoYi-Vue-Plus');
|
|
||||||
const settingsStore = useSettingsStore();
|
|
||||||
const sideTheme = computed(() => settingsStore.sideTheme);
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
class="sidebar-logo-container"
|
class="sidebar-logo-container"
|
||||||
@ -40,6 +21,25 @@ const sideTheme = computed(() => settingsStore.sideTheme);
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import variables from '@/assets/styles/variables.module.scss'
|
||||||
|
import logo from '@/assets/logo/logo.png'
|
||||||
|
import useSettingsStore from '@/store/modules/settings'
|
||||||
|
import { ComponentInternalInstance } from "vue";
|
||||||
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
|
|
||||||
|
defineProps({
|
||||||
|
collapse: {
|
||||||
|
type: Boolean,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const title = ref('RuoYi-Vue-Plus');
|
||||||
|
const settingsStore = useSettingsStore();
|
||||||
|
const sideTheme = computed(() => settingsStore.sideTheme);
|
||||||
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.sidebarLogoFade-enter-active {
|
.sidebarLogoFade-enter-active {
|
||||||
transition: opacity 1.5s;
|
transition: opacity 1.5s;
|
||||||
|
@ -1,3 +1,25 @@
|
|||||||
|
<template>
|
||||||
|
<div :class="{ 'has-logo': showLogo }" :style="{ backgroundColor: bgColor }">
|
||||||
|
<logo v-if="showLogo" :collapse="isCollapse" />
|
||||||
|
<el-scrollbar :class="sideTheme" wrap-class="scrollbar-wrapper">
|
||||||
|
<transition :enter-active-class="proxy?.animate.menuSearchAnimate.enter" mode="out-in">
|
||||||
|
<el-menu
|
||||||
|
:default-active="activeMenu as string"
|
||||||
|
:collapse="isCollapse"
|
||||||
|
:background-color="bgColor"
|
||||||
|
:text-color="textColor"
|
||||||
|
:unique-opened="true"
|
||||||
|
:active-text-color="theme"
|
||||||
|
:collapse-transition="false"
|
||||||
|
mode="vertical"
|
||||||
|
>
|
||||||
|
<sidebar-item v-for="(route, index) in sidebarRouters" :key="route.path + index" :item="route" :base-path="route.path" />
|
||||||
|
</el-menu>
|
||||||
|
</transition>
|
||||||
|
</el-scrollbar>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import Logo from './Logo.vue'
|
import Logo from './Logo.vue'
|
||||||
import SidebarItem from './SidebarItem.vue'
|
import SidebarItem from './SidebarItem.vue'
|
||||||
@ -20,36 +42,14 @@ const theme = computed(() => settingsStore.theme);
|
|||||||
const isCollapse = computed(() => !appStore.sidebar.opened);
|
const isCollapse = computed(() => !appStore.sidebar.opened);
|
||||||
|
|
||||||
const activeMenu = computed(() => {
|
const activeMenu = computed(() => {
|
||||||
const { meta, path } = route;
|
const { meta, path } = route;
|
||||||
// if set path, the sidebar will highlight the path you set
|
// if set path, the sidebar will highlight the path you set
|
||||||
if (meta.activeMenu) {
|
if (meta.activeMenu) {
|
||||||
return meta.activeMenu;
|
return meta.activeMenu;
|
||||||
}
|
}
|
||||||
return path;
|
return path;
|
||||||
})
|
})
|
||||||
|
|
||||||
const bgColor = computed(() => sideTheme.value === 'theme-dark' ? variables.menuBackground : variables.menuLightBackground);
|
const bgColor = computed(() => sideTheme.value === 'theme-dark' ? variables.menuBackground : variables.menuLightBackground);
|
||||||
const textColor = computed(() => sideTheme.value === 'theme-dark' ? variables.menuColor : variables.menuLightColor);
|
const textColor = computed(() => sideTheme.value === 'theme-dark' ? variables.menuColor : variables.menuLightColor);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
|
||||||
<div :class="{ 'has-logo': showLogo }" :style="{ backgroundColor: bgColor }">
|
|
||||||
<logo v-if="showLogo" :collapse="isCollapse" />
|
|
||||||
<el-scrollbar :class="sideTheme" wrap-class="scrollbar-wrapper">
|
|
||||||
<transition :enter-active-class="proxy?.animate.menuSearchAnimate.enter" mode="out-in">
|
|
||||||
<el-menu
|
|
||||||
:default-active="activeMenu as string"
|
|
||||||
:collapse="isCollapse"
|
|
||||||
:background-color="bgColor"
|
|
||||||
:text-color="textColor"
|
|
||||||
:unique-opened="true"
|
|
||||||
:active-text-color="theme"
|
|
||||||
:collapse-transition="false"
|
|
||||||
mode="vertical"
|
|
||||||
>
|
|
||||||
<sidebar-item v-for="(route, index) in sidebarRouters" :key="route.path + index" :item="route" :base-path="route.path" />
|
|
||||||
</el-menu>
|
|
||||||
</transition>
|
|
||||||
</el-scrollbar>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
@ -1,3 +1,9 @@
|
|||||||
|
<template>
|
||||||
|
<el-scrollbar ref="scrollContainerRef" :vertical="false" class="scroll-container" @wheel.prevent="handleScroll">
|
||||||
|
<slot />
|
||||||
|
</el-scrollbar>
|
||||||
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import useTagsViewStore from '@/store/modules/tagsView'
|
import useTagsViewStore from '@/store/modules/tagsView'
|
||||||
import { ElScrollbar } from 'element-plus';
|
import { ElScrollbar } from 'element-plus';
|
||||||
@ -8,84 +14,78 @@ const scrollContainerRef = ref(ElScrollbar)
|
|||||||
const scrollWrapper = computed(() => scrollContainerRef.value.$refs.wrapRef);
|
const scrollWrapper = computed(() => scrollContainerRef.value.$refs.wrapRef);
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
scrollWrapper.value.addEventListener('scroll', emitScroll, true)
|
scrollWrapper.value.addEventListener('scroll', emitScroll, true)
|
||||||
})
|
})
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
scrollWrapper.value.removeEventListener('scroll', emitScroll)
|
scrollWrapper.value.removeEventListener('scroll', emitScroll)
|
||||||
})
|
})
|
||||||
|
|
||||||
const handleScroll = (e: WheelEvent) => {
|
const handleScroll = (e: WheelEvent) => {
|
||||||
const eventDelta = (e as any).wheelDelta || -e.deltaY * 40
|
const eventDelta = (e as any).wheelDelta || -e.deltaY * 40
|
||||||
const $scrollWrapper = scrollWrapper.value;
|
const $scrollWrapper = scrollWrapper.value;
|
||||||
$scrollWrapper.scrollLeft = $scrollWrapper.scrollLeft + eventDelta / 4
|
$scrollWrapper.scrollLeft = $scrollWrapper.scrollLeft + eventDelta / 4
|
||||||
}
|
}
|
||||||
const emits = defineEmits(['scroll'])
|
const emits = defineEmits(['scroll'])
|
||||||
const emitScroll = () => {
|
const emitScroll = () => {
|
||||||
emits('scroll')
|
emits('scroll')
|
||||||
}
|
}
|
||||||
|
|
||||||
const tagsViewStore = useTagsViewStore()
|
const tagsViewStore = useTagsViewStore()
|
||||||
const visitedViews = computed(() => tagsViewStore.visitedViews);
|
const visitedViews = computed(() => tagsViewStore.visitedViews);
|
||||||
|
|
||||||
const moveToTarget = (currentTag: TagView) => {
|
const moveToTarget = (currentTag: TagView) => {
|
||||||
const $container = scrollContainerRef.value.$el
|
const $container = scrollContainerRef.value.$el
|
||||||
const $containerWidth = $container.offsetWidth
|
const $containerWidth = $container.offsetWidth
|
||||||
const $scrollWrapper = scrollWrapper.value;
|
const $scrollWrapper = scrollWrapper.value;
|
||||||
|
|
||||||
let firstTag = null
|
let firstTag = null
|
||||||
let lastTag = null
|
let lastTag = null
|
||||||
|
|
||||||
// find first tag and last tag
|
// find first tag and last tag
|
||||||
if (visitedViews.value.length > 0) {
|
if (visitedViews.value.length > 0) {
|
||||||
firstTag = visitedViews.value[0]
|
firstTag = visitedViews.value[0]
|
||||||
lastTag = visitedViews.value[visitedViews.value.length - 1]
|
lastTag = visitedViews.value[visitedViews.value.length - 1]
|
||||||
}
|
|
||||||
|
|
||||||
if (firstTag === currentTag) {
|
|
||||||
$scrollWrapper.scrollLeft = 0
|
|
||||||
} else if (lastTag === currentTag) {
|
|
||||||
$scrollWrapper.scrollLeft = $scrollWrapper.scrollWidth - $containerWidth
|
|
||||||
} else {
|
|
||||||
const tagListDom: any = document.getElementsByClassName('tags-view-item');
|
|
||||||
const currentIndex = visitedViews.value.findIndex(item => item === currentTag)
|
|
||||||
let prevTag = null
|
|
||||||
let nextTag = null
|
|
||||||
|
|
||||||
for (const k in tagListDom) {
|
|
||||||
if (k !== 'length' && Object.hasOwnProperty.call(tagListDom, k)) {
|
|
||||||
if (tagListDom[k].dataset.path === visitedViews.value[currentIndex - 1].path) {
|
|
||||||
prevTag = tagListDom[k];
|
|
||||||
}
|
|
||||||
if (tagListDom[k].dataset.path === visitedViews.value[currentIndex + 1].path) {
|
|
||||||
nextTag = tagListDom[k];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// the tag's offsetLeft after of nextTag
|
if (firstTag === currentTag) {
|
||||||
const afterNextTagOffsetLeft = nextTag.offsetLeft + nextTag.offsetWidth + tagAndTagSpacing.value
|
$scrollWrapper.scrollLeft = 0
|
||||||
|
} else if (lastTag === currentTag) {
|
||||||
|
$scrollWrapper.scrollLeft = $scrollWrapper.scrollWidth - $containerWidth
|
||||||
|
} else {
|
||||||
|
const tagListDom: any = document.getElementsByClassName('tags-view-item');
|
||||||
|
const currentIndex = visitedViews.value.findIndex(item => item === currentTag)
|
||||||
|
let prevTag = null
|
||||||
|
let nextTag = null
|
||||||
|
|
||||||
// the tag's offsetLeft before of prevTag
|
for (const k in tagListDom) {
|
||||||
const beforePrevTagOffsetLeft = prevTag.offsetLeft - tagAndTagSpacing.value
|
if (k !== 'length' && Object.hasOwnProperty.call(tagListDom, k)) {
|
||||||
if (afterNextTagOffsetLeft > $scrollWrapper.scrollLeft + $containerWidth) {
|
if (tagListDom[k].dataset.path === visitedViews.value[currentIndex - 1].path) {
|
||||||
$scrollWrapper.scrollLeft = afterNextTagOffsetLeft - $containerWidth
|
prevTag = tagListDom[k];
|
||||||
} else if (beforePrevTagOffsetLeft < $scrollWrapper.scrollLeft) {
|
}
|
||||||
$scrollWrapper.scrollLeft = beforePrevTagOffsetLeft
|
if (tagListDom[k].dataset.path === visitedViews.value[currentIndex + 1].path) {
|
||||||
|
nextTag = tagListDom[k];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// the tag's offsetLeft after of nextTag
|
||||||
|
const afterNextTagOffsetLeft = nextTag.offsetLeft + nextTag.offsetWidth + tagAndTagSpacing.value
|
||||||
|
|
||||||
|
// the tag's offsetLeft before of prevTag
|
||||||
|
const beforePrevTagOffsetLeft = prevTag.offsetLeft - tagAndTagSpacing.value
|
||||||
|
if (afterNextTagOffsetLeft > $scrollWrapper.scrollLeft + $containerWidth) {
|
||||||
|
$scrollWrapper.scrollLeft = afterNextTagOffsetLeft - $containerWidth
|
||||||
|
} else if (beforePrevTagOffsetLeft < $scrollWrapper.scrollLeft) {
|
||||||
|
$scrollWrapper.scrollLeft = beforePrevTagOffsetLeft
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
moveToTarget,
|
moveToTarget,
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
|
||||||
<el-scrollbar ref="scrollContainerRef" :vertical="false" class="scroll-container" @wheel.prevent="handleScroll">
|
|
||||||
<slot />
|
|
||||||
</el-scrollbar>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.scroll-container {
|
.scroll-container {
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
@ -1,56 +1,3 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import SideBar from './components/Sidebar/index.vue'
|
|
||||||
import { AppMain, Navbar, Settings, TagsView } from './components'
|
|
||||||
import useAppStore from '@/store/modules/app'
|
|
||||||
import useSettingsStore from '@/store/modules/settings'
|
|
||||||
|
|
||||||
const settingsStore = useSettingsStore()
|
|
||||||
const theme = computed(() => settingsStore.theme);
|
|
||||||
const sidebar = computed(() => useAppStore().sidebar);
|
|
||||||
const device = computed(() => useAppStore().device);
|
|
||||||
const needTagsView = computed(() => settingsStore.tagsView);
|
|
||||||
const fixedHeader = computed(() => settingsStore.fixedHeader);
|
|
||||||
|
|
||||||
const classObj = computed(() => ({
|
|
||||||
hideSidebar: !sidebar.value.opened,
|
|
||||||
openSidebar: sidebar.value.opened,
|
|
||||||
withoutAnimation: sidebar.value.withoutAnimation,
|
|
||||||
mobile: device.value === 'mobile'
|
|
||||||
}))
|
|
||||||
|
|
||||||
const { width } = useWindowSize();
|
|
||||||
const WIDTH = 992; // refer to Bootstrap's responsive design
|
|
||||||
|
|
||||||
watchEffect(() => {
|
|
||||||
if (device.value === 'mobile' && sidebar.value.opened) {
|
|
||||||
useAppStore().closeSideBar({ withoutAnimation: false })
|
|
||||||
}
|
|
||||||
if (width.value - 1 < WIDTH) {
|
|
||||||
useAppStore().toggleDevice('mobile')
|
|
||||||
useAppStore().closeSideBar({ withoutAnimation: true })
|
|
||||||
} else {
|
|
||||||
useAppStore().toggleDevice('desktop')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const navbarRef = ref(Navbar);
|
|
||||||
const settingRef = ref(Settings);
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
nextTick(() => {
|
|
||||||
navbarRef.value.initTenantList();
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
const handleClickOutside = () => {
|
|
||||||
useAppStore().closeSideBar({ withoutAnimation: false })
|
|
||||||
}
|
|
||||||
|
|
||||||
const setLayout = () => {
|
|
||||||
settingRef.value.openSetting();
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div :class="classObj" class="app-wrapper" :style="{ '--current-color': theme }">
|
<div :class="classObj" class="app-wrapper" :style="{ '--current-color': theme }">
|
||||||
<div v-if="device === 'mobile' && sidebar.opened" class="drawer-bg" @click="handleClickOutside" />
|
<div v-if="device === 'mobile' && sidebar.opened" class="drawer-bg" @click="handleClickOutside" />
|
||||||
@ -66,6 +13,59 @@ const setLayout = () => {
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import SideBar from './components/Sidebar/index.vue'
|
||||||
|
import { AppMain, Navbar, Settings, TagsView } from './components'
|
||||||
|
import useAppStore from '@/store/modules/app'
|
||||||
|
import useSettingsStore from '@/store/modules/settings'
|
||||||
|
|
||||||
|
const settingsStore = useSettingsStore()
|
||||||
|
const theme = computed(() => settingsStore.theme);
|
||||||
|
const sidebar = computed(() => useAppStore().sidebar);
|
||||||
|
const device = computed(() => useAppStore().device);
|
||||||
|
const needTagsView = computed(() => settingsStore.tagsView);
|
||||||
|
const fixedHeader = computed(() => settingsStore.fixedHeader);
|
||||||
|
|
||||||
|
const classObj = computed(() => ({
|
||||||
|
hideSidebar: !sidebar.value.opened,
|
||||||
|
openSidebar: sidebar.value.opened,
|
||||||
|
withoutAnimation: sidebar.value.withoutAnimation,
|
||||||
|
mobile: device.value === 'mobile'
|
||||||
|
}))
|
||||||
|
|
||||||
|
const { width } = useWindowSize();
|
||||||
|
const WIDTH = 992; // refer to Bootstrap's responsive design
|
||||||
|
|
||||||
|
watchEffect(() => {
|
||||||
|
if (device.value === 'mobile' && sidebar.value.opened) {
|
||||||
|
useAppStore().closeSideBar({ withoutAnimation: false })
|
||||||
|
}
|
||||||
|
if (width.value - 1 < WIDTH) {
|
||||||
|
useAppStore().toggleDevice('mobile')
|
||||||
|
useAppStore().closeSideBar({ withoutAnimation: true })
|
||||||
|
} else {
|
||||||
|
useAppStore().toggleDevice('desktop')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const navbarRef = ref(Navbar);
|
||||||
|
const settingRef = ref(Settings);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
nextTick(() => {
|
||||||
|
navbarRef.value.initTenantList();
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
const handleClickOutside = () => {
|
||||||
|
useAppStore().closeSideBar({ withoutAnimation: false })
|
||||||
|
}
|
||||||
|
|
||||||
|
const setLayout = () => {
|
||||||
|
settingRef.value.openSetting();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@import "@/assets/styles/mixin.scss";
|
@import "@/assets/styles/mixin.scss";
|
||||||
@import "@/assets/styles/variables.module.scss";
|
@import "@/assets/styles/variables.module.scss";
|
||||||
|
129
src/views/monitor/cache/index.vue
vendored
129
src/views/monitor/cache/index.vue
vendored
@ -1,67 +1,3 @@
|
|||||||
<script setup name="Cache" lang="ts">
|
|
||||||
import { getCache } from '@/api/monitor/cache';
|
|
||||||
import * as echarts from 'echarts';
|
|
||||||
import { ComponentInternalInstance } from "vue";
|
|
||||||
|
|
||||||
const cache = ref<any>({});
|
|
||||||
const commandstats = ref();
|
|
||||||
const usedmemory = ref();
|
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
|
||||||
|
|
||||||
const getList = async () => {
|
|
||||||
proxy?.$modal.loading("正在加载缓存监控数据,请稍候!");
|
|
||||||
const res = await getCache();
|
|
||||||
proxy?.$modal.closeLoading();
|
|
||||||
cache.value = res.data;
|
|
||||||
const commandstatsIntance = echarts.init(commandstats.value, "macarons");
|
|
||||||
commandstatsIntance.setOption({
|
|
||||||
tooltip: {
|
|
||||||
trigger: "item",
|
|
||||||
formatter: "{a} <br/>{b} : {c} ({d}%)"
|
|
||||||
},
|
|
||||||
series: [
|
|
||||||
{
|
|
||||||
name: "命令",
|
|
||||||
type: "pie",
|
|
||||||
roseType: "radius",
|
|
||||||
radius: [15, 95],
|
|
||||||
center: ["50%", "38%"],
|
|
||||||
data: res.data.commandStats,
|
|
||||||
animationEasing: "cubicInOut",
|
|
||||||
animationDuration: 1000
|
|
||||||
}
|
|
||||||
]
|
|
||||||
});
|
|
||||||
|
|
||||||
const usedmemoryInstance = echarts.init(usedmemory.value, "macarons");
|
|
||||||
usedmemoryInstance.setOption({
|
|
||||||
tooltip: {
|
|
||||||
formatter: "{b} <br/>{a} : " + cache.value.info.used_memory_human
|
|
||||||
},
|
|
||||||
series: [
|
|
||||||
{
|
|
||||||
name: "峰值",
|
|
||||||
type: "gauge",
|
|
||||||
min: 0,
|
|
||||||
max: 1000,
|
|
||||||
detail: {
|
|
||||||
formatter: cache.value.info.used_memory_human
|
|
||||||
},
|
|
||||||
data: [
|
|
||||||
{
|
|
||||||
value: parseFloat(cache.value.info.used_memory_human),
|
|
||||||
name: "内存消耗"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
getList();
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
<template>
|
<template>
|
||||||
<div class="p-2">
|
<div class="p-2">
|
||||||
<el-row>
|
<el-row>
|
||||||
@ -186,3 +122,68 @@ onMounted(() => {
|
|||||||
</el-row>
|
</el-row>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<script setup name="Cache" lang="ts">
|
||||||
|
import { getCache } from '@/api/monitor/cache';
|
||||||
|
import * as echarts from 'echarts';
|
||||||
|
import { ComponentInternalInstance } from "vue";
|
||||||
|
|
||||||
|
const cache = ref<any>({});
|
||||||
|
const commandstats = ref();
|
||||||
|
const usedmemory = ref();
|
||||||
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
|
|
||||||
|
const getList = async () => {
|
||||||
|
proxy?.$modal.loading("正在加载缓存监控数据,请稍候!");
|
||||||
|
const res = await getCache();
|
||||||
|
proxy?.$modal.closeLoading();
|
||||||
|
cache.value = res.data;
|
||||||
|
const commandstatsIntance = echarts.init(commandstats.value, "macarons");
|
||||||
|
commandstatsIntance.setOption({
|
||||||
|
tooltip: {
|
||||||
|
trigger: "item",
|
||||||
|
formatter: "{a} <br/>{b} : {c} ({d}%)"
|
||||||
|
},
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: "命令",
|
||||||
|
type: "pie",
|
||||||
|
roseType: "radius",
|
||||||
|
radius: [15, 95],
|
||||||
|
center: ["50%", "38%"],
|
||||||
|
data: res.data.commandStats,
|
||||||
|
animationEasing: "cubicInOut",
|
||||||
|
animationDuration: 1000
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
const usedmemoryInstance = echarts.init(usedmemory.value, "macarons");
|
||||||
|
usedmemoryInstance.setOption({
|
||||||
|
tooltip: {
|
||||||
|
formatter: "{b} <br/>{a} : " + cache.value.info.used_memory_human
|
||||||
|
},
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: "峰值",
|
||||||
|
type: "gauge",
|
||||||
|
min: 0,
|
||||||
|
max: 1000,
|
||||||
|
detail: {
|
||||||
|
formatter: cache.value.info.used_memory_human
|
||||||
|
},
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
value: parseFloat(cache.value.info.used_memory_human),
|
||||||
|
name: "内存消耗"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getList();
|
||||||
|
})
|
||||||
|
</script>
|
@ -1,143 +1,3 @@
|
|||||||
<script setup name="Config" lang="ts">
|
|
||||||
import { listConfig, getConfig, delConfig, addConfig, updateConfig, refreshCache } from "@/api/system/config";
|
|
||||||
import { ConfigForm, ConfigQuery, ConfigVO } from "@/api/system/config/types";
|
|
||||||
import { ComponentInternalInstance } from "vue";
|
|
||||||
import { DateModelType } from 'element-plus';
|
|
||||||
|
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
|
||||||
const { sys_yes_no } = toRefs<any>(proxy?.useDict("sys_yes_no"));
|
|
||||||
|
|
||||||
const configList = ref<ConfigVO[]>([]);
|
|
||||||
const loading = ref(true);
|
|
||||||
const showSearch = ref(true);
|
|
||||||
const ids = ref<Array<number | string>>([]);
|
|
||||||
const single = ref(true);
|
|
||||||
const multiple = ref(true);
|
|
||||||
const total = ref(0);
|
|
||||||
const dateRange = ref<[DateModelType, DateModelType]>(['', '']);
|
|
||||||
|
|
||||||
const queryFormRef = ref(ElForm);
|
|
||||||
const configFormRef = ref(ElForm);
|
|
||||||
const dialog = reactive<DialogOption>({
|
|
||||||
visible: false,
|
|
||||||
title: ''
|
|
||||||
});
|
|
||||||
const initFormData: ConfigForm = {
|
|
||||||
configId: undefined,
|
|
||||||
configName: '',
|
|
||||||
configKey: '',
|
|
||||||
configValue: '',
|
|
||||||
configType: "Y",
|
|
||||||
remark: ''
|
|
||||||
}
|
|
||||||
const data = reactive<PageData<ConfigForm, ConfigQuery>>({
|
|
||||||
form: {...initFormData},
|
|
||||||
queryParams: {
|
|
||||||
pageNum: 1,
|
|
||||||
pageSize: 10,
|
|
||||||
configName: '',
|
|
||||||
configKey: '',
|
|
||||||
configType: '',
|
|
||||||
},
|
|
||||||
rules: {
|
|
||||||
configName: [{ required: true, message: "参数名称不能为空", trigger: "blur" }],
|
|
||||||
configKey: [{ required: true, message: "参数键名不能为空", trigger: "blur" }],
|
|
||||||
configValue: [{ required: true, message: "参数键值不能为空", trigger: "blur" }]
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const { queryParams, form, rules } = toRefs(data);
|
|
||||||
|
|
||||||
/** 查询参数列表 */
|
|
||||||
const getList = async () => {
|
|
||||||
loading.value = true;
|
|
||||||
const res = await listConfig(proxy?.addDateRange(queryParams.value, dateRange.value));
|
|
||||||
configList.value = res.rows;
|
|
||||||
total.value = res.total;
|
|
||||||
loading.value = false;
|
|
||||||
}
|
|
||||||
/** 取消按钮 */
|
|
||||||
const cancel = () => {
|
|
||||||
reset();
|
|
||||||
dialog.visible = false;
|
|
||||||
}
|
|
||||||
/** 表单重置 */
|
|
||||||
const reset = () => {
|
|
||||||
form.value = {...initFormData};
|
|
||||||
configFormRef.value.resetFields();
|
|
||||||
}
|
|
||||||
/** 搜索按钮操作 */
|
|
||||||
const handleQuery = () => {
|
|
||||||
queryParams.value.pageNum = 1;
|
|
||||||
getList();
|
|
||||||
}
|
|
||||||
/** 重置按钮操作 */
|
|
||||||
const resetQuery = () => {
|
|
||||||
dateRange.value = ['', ''];
|
|
||||||
queryFormRef.value.resetFields();
|
|
||||||
handleQuery();
|
|
||||||
}
|
|
||||||
/** 多选框选中数据 */
|
|
||||||
const handleSelectionChange = (selection: ConfigVO[]) => {
|
|
||||||
ids.value = selection.map(item => item.configId);
|
|
||||||
single.value = selection.length != 1;
|
|
||||||
multiple.value = !selection.length;
|
|
||||||
}
|
|
||||||
/** 新增按钮操作 */
|
|
||||||
const handleAdd = () => {
|
|
||||||
dialog.visible = true;
|
|
||||||
dialog.title = "添加参数";
|
|
||||||
nextTick(() => {
|
|
||||||
reset();
|
|
||||||
})
|
|
||||||
}
|
|
||||||
/** 修改按钮操作 */
|
|
||||||
const handleUpdate = (row?: ConfigVO) => {
|
|
||||||
dialog.visible = true;
|
|
||||||
dialog.title = "修改参数";
|
|
||||||
const configId = row?.configId || ids.value[0];
|
|
||||||
nextTick(async () => {
|
|
||||||
reset();
|
|
||||||
const res = await getConfig(configId);
|
|
||||||
form.value = res.data;
|
|
||||||
})
|
|
||||||
}
|
|
||||||
/** 提交按钮 */
|
|
||||||
const submitForm = () => {
|
|
||||||
configFormRef.value.validate(async (valid: boolean) => {
|
|
||||||
if (valid) {
|
|
||||||
form.value.configId ? await updateConfig(form.value) : await addConfig(form.value);
|
|
||||||
proxy?.$modal.msgSuccess("操作成功");
|
|
||||||
dialog.visible = false;
|
|
||||||
getList();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
/** 删除按钮操作 */
|
|
||||||
const handleDelete = async (row?: ConfigVO) => {
|
|
||||||
const configIds = row?.configId || ids.value;
|
|
||||||
await proxy?.$modal.confirm('是否确认删除参数编号为"' + configIds + '"的数据项?');
|
|
||||||
await delConfig(configIds);
|
|
||||||
getList();
|
|
||||||
proxy?.$modal.msgSuccess("删除成功");
|
|
||||||
}
|
|
||||||
/** 导出按钮操作 */
|
|
||||||
const handleExport = () => {
|
|
||||||
proxy?.download("system/config/export", {
|
|
||||||
...queryParams.value
|
|
||||||
}, `config_${new Date().getTime()}.xlsx`);
|
|
||||||
}
|
|
||||||
/** 刷新缓存按钮操作 */
|
|
||||||
const handleRefreshCache = async () => {
|
|
||||||
await refreshCache();
|
|
||||||
proxy?.$modal.msgSuccess("刷新缓存成功");
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
getList();
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="p-2">
|
<div class="p-2">
|
||||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||||
@ -259,3 +119,143 @@ onMounted(() => {
|
|||||||
</el-dialog>
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<script setup name="Config" lang="ts">
|
||||||
|
import { listConfig, getConfig, delConfig, addConfig, updateConfig, refreshCache } from "@/api/system/config";
|
||||||
|
import { ConfigForm, ConfigQuery, ConfigVO } from "@/api/system/config/types";
|
||||||
|
import { ComponentInternalInstance } from "vue";
|
||||||
|
import { DateModelType } from 'element-plus';
|
||||||
|
|
||||||
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
|
const { sys_yes_no } = toRefs<any>(proxy?.useDict("sys_yes_no"));
|
||||||
|
|
||||||
|
const configList = ref<ConfigVO[]>([]);
|
||||||
|
const loading = ref(true);
|
||||||
|
const showSearch = ref(true);
|
||||||
|
const ids = ref<Array<number | string>>([]);
|
||||||
|
const single = ref(true);
|
||||||
|
const multiple = ref(true);
|
||||||
|
const total = ref(0);
|
||||||
|
const dateRange = ref<[DateModelType, DateModelType]>(['', '']);
|
||||||
|
|
||||||
|
const queryFormRef = ref(ElForm);
|
||||||
|
const configFormRef = ref(ElForm);
|
||||||
|
const dialog = reactive<DialogOption>({
|
||||||
|
visible: false,
|
||||||
|
title: ''
|
||||||
|
});
|
||||||
|
const initFormData: ConfigForm = {
|
||||||
|
configId: undefined,
|
||||||
|
configName: '',
|
||||||
|
configKey: '',
|
||||||
|
configValue: '',
|
||||||
|
configType: "Y",
|
||||||
|
remark: ''
|
||||||
|
}
|
||||||
|
const data = reactive<PageData<ConfigForm, ConfigQuery>>({
|
||||||
|
form: {...initFormData},
|
||||||
|
queryParams: {
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
configName: '',
|
||||||
|
configKey: '',
|
||||||
|
configType: '',
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
configName: [{ required: true, message: "参数名称不能为空", trigger: "blur" }],
|
||||||
|
configKey: [{ required: true, message: "参数键名不能为空", trigger: "blur" }],
|
||||||
|
configValue: [{ required: true, message: "参数键值不能为空", trigger: "blur" }]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const { queryParams, form, rules } = toRefs(data);
|
||||||
|
|
||||||
|
/** 查询参数列表 */
|
||||||
|
const getList = async () => {
|
||||||
|
loading.value = true;
|
||||||
|
const res = await listConfig(proxy?.addDateRange(queryParams.value, dateRange.value));
|
||||||
|
configList.value = res.rows;
|
||||||
|
total.value = res.total;
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
/** 取消按钮 */
|
||||||
|
const cancel = () => {
|
||||||
|
reset();
|
||||||
|
dialog.visible = false;
|
||||||
|
}
|
||||||
|
/** 表单重置 */
|
||||||
|
const reset = () => {
|
||||||
|
form.value = {...initFormData};
|
||||||
|
configFormRef.value.resetFields();
|
||||||
|
}
|
||||||
|
/** 搜索按钮操作 */
|
||||||
|
const handleQuery = () => {
|
||||||
|
queryParams.value.pageNum = 1;
|
||||||
|
getList();
|
||||||
|
}
|
||||||
|
/** 重置按钮操作 */
|
||||||
|
const resetQuery = () => {
|
||||||
|
dateRange.value = ['', ''];
|
||||||
|
queryFormRef.value.resetFields();
|
||||||
|
handleQuery();
|
||||||
|
}
|
||||||
|
/** 多选框选中数据 */
|
||||||
|
const handleSelectionChange = (selection: ConfigVO[]) => {
|
||||||
|
ids.value = selection.map(item => item.configId);
|
||||||
|
single.value = selection.length != 1;
|
||||||
|
multiple.value = !selection.length;
|
||||||
|
}
|
||||||
|
/** 新增按钮操作 */
|
||||||
|
const handleAdd = () => {
|
||||||
|
dialog.visible = true;
|
||||||
|
dialog.title = "添加参数";
|
||||||
|
nextTick(() => {
|
||||||
|
reset();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/** 修改按钮操作 */
|
||||||
|
const handleUpdate = (row?: ConfigVO) => {
|
||||||
|
dialog.visible = true;
|
||||||
|
dialog.title = "修改参数";
|
||||||
|
const configId = row?.configId || ids.value[0];
|
||||||
|
nextTick(async () => {
|
||||||
|
reset();
|
||||||
|
const res = await getConfig(configId);
|
||||||
|
form.value = res.data;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/** 提交按钮 */
|
||||||
|
const submitForm = () => {
|
||||||
|
configFormRef.value.validate(async (valid: boolean) => {
|
||||||
|
if (valid) {
|
||||||
|
form.value.configId ? await updateConfig(form.value) : await addConfig(form.value);
|
||||||
|
proxy?.$modal.msgSuccess("操作成功");
|
||||||
|
dialog.visible = false;
|
||||||
|
getList();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/** 删除按钮操作 */
|
||||||
|
const handleDelete = async (row?: ConfigVO) => {
|
||||||
|
const configIds = row?.configId || ids.value;
|
||||||
|
await proxy?.$modal.confirm('是否确认删除参数编号为"' + configIds + '"的数据项?');
|
||||||
|
await delConfig(configIds);
|
||||||
|
getList();
|
||||||
|
proxy?.$modal.msgSuccess("删除成功");
|
||||||
|
}
|
||||||
|
/** 导出按钮操作 */
|
||||||
|
const handleExport = () => {
|
||||||
|
proxy?.download("system/config/export", {
|
||||||
|
...queryParams.value
|
||||||
|
}, `config_${new Date().getTime()}.xlsx`);
|
||||||
|
}
|
||||||
|
/** 刷新缓存按钮操作 */
|
||||||
|
const handleRefreshCache = async () => {
|
||||||
|
await refreshCache();
|
||||||
|
proxy?.$modal.msgSuccess("刷新缓存成功");
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getList();
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
@ -1,31 +1,3 @@
|
|||||||
<script setup name="Profile" lang="ts">
|
|
||||||
import userAvatar from "./userAvatar.vue";
|
|
||||||
import userInfo from "./userInfo.vue";
|
|
||||||
import resetPwd from "./resetPwd.vue";
|
|
||||||
import { getUserProfile } from "@/api/system/user";
|
|
||||||
|
|
||||||
const activeTab = ref("userinfo");
|
|
||||||
const state = ref<{ user: any; roleGroup: string; postGroup: string}>({
|
|
||||||
user: {},
|
|
||||||
roleGroup: '',
|
|
||||||
postGroup: ''
|
|
||||||
});
|
|
||||||
|
|
||||||
const userForm = ref({});
|
|
||||||
|
|
||||||
const getUser = async () => {
|
|
||||||
const res = await getUserProfile();
|
|
||||||
state.value.user = res.data.user;
|
|
||||||
userForm.value = { ...res.data.user }
|
|
||||||
state.value.roleGroup = res.data.roleGroup;
|
|
||||||
state.value.postGroup = res.data.postGroup;
|
|
||||||
};
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
getUser();
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="p-2">
|
<div class="p-2">
|
||||||
<el-row :gutter="20">
|
<el-row :gutter="20">
|
||||||
@ -89,3 +61,31 @@ onMounted(() => {
|
|||||||
</el-row>
|
</el-row>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<script setup name="Profile" lang="ts">
|
||||||
|
import userAvatar from "./userAvatar.vue";
|
||||||
|
import userInfo from "./userInfo.vue";
|
||||||
|
import resetPwd from "./resetPwd.vue";
|
||||||
|
import { getUserProfile } from "@/api/system/user";
|
||||||
|
|
||||||
|
const activeTab = ref("userinfo");
|
||||||
|
const state = ref<{ user: any; roleGroup: string; postGroup: string}>({
|
||||||
|
user: {},
|
||||||
|
roleGroup: '',
|
||||||
|
postGroup: ''
|
||||||
|
});
|
||||||
|
|
||||||
|
const userForm = ref({});
|
||||||
|
|
||||||
|
const getUser = async () => {
|
||||||
|
const res = await getUserProfile();
|
||||||
|
state.value.user = res.data.user;
|
||||||
|
userForm.value = { ...res.data.user }
|
||||||
|
state.value.roleGroup = res.data.roleGroup;
|
||||||
|
state.value.postGroup = res.data.postGroup;
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getUser();
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
@ -1,48 +1,3 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import { updateUserPwd } from '@/api/system/user';
|
|
||||||
import { ComponentInternalInstance } from 'vue';
|
|
||||||
import { ResetPwdForm } from '@/api/system/user/types'
|
|
||||||
import { ElForm } from 'element-plus';
|
|
||||||
|
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
|
||||||
|
|
||||||
|
|
||||||
const pwdRef = ref(ElForm);
|
|
||||||
|
|
||||||
const user = ref<ResetPwdForm>({
|
|
||||||
oldPassword: '',
|
|
||||||
newPassword: '',
|
|
||||||
confirmPassword: ''
|
|
||||||
});
|
|
||||||
|
|
||||||
const equalToPassword = (rule: any, value: string, callback: any) => {
|
|
||||||
if (user.value.newPassword !== value) {
|
|
||||||
callback(new Error("两次输入的密码不一致"));
|
|
||||||
} else {
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const rules = ref({
|
|
||||||
oldPassword: [{ required: true, message: "旧密码不能为空", trigger: "blur" }],
|
|
||||||
newPassword: [{ required: true, message: "新密码不能为空", trigger: "blur" }, { min: 6, max: 20, message: "长度在 6 到 20 个字符", trigger: "blur" }],
|
|
||||||
confirmPassword: [{ required: true, message: "确认密码不能为空", trigger: "blur" }, { required: true, validator: equalToPassword, trigger: "blur" }]
|
|
||||||
});
|
|
||||||
|
|
||||||
/** 提交按钮 */
|
|
||||||
const submit = () => {
|
|
||||||
pwdRef.value.validate(async (valid: boolean) => {
|
|
||||||
if (valid) {
|
|
||||||
await updateUserPwd(user.value.oldPassword, user.value.newPassword)
|
|
||||||
proxy?.$modal.msgSuccess("修改成功");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
/** 关闭按钮 */
|
|
||||||
const close = () => {
|
|
||||||
proxy?.$tab.closePage();
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<el-form ref="pwdRef" :model="user" :rules="rules" label-width="80px">
|
<el-form ref="pwdRef" :model="user" :rules="rules" label-width="80px">
|
||||||
<el-form-item label="旧密码" prop="oldPassword">
|
<el-form-item label="旧密码" prop="oldPassword">
|
||||||
@ -60,3 +15,48 @@ const close = () => {
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { updateUserPwd } from '@/api/system/user';
|
||||||
|
import { ComponentInternalInstance } from 'vue';
|
||||||
|
import { ResetPwdForm } from '@/api/system/user/types'
|
||||||
|
import { ElForm } from 'element-plus';
|
||||||
|
|
||||||
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
|
|
||||||
|
|
||||||
|
const pwdRef = ref(ElForm);
|
||||||
|
|
||||||
|
const user = ref<ResetPwdForm>({
|
||||||
|
oldPassword: '',
|
||||||
|
newPassword: '',
|
||||||
|
confirmPassword: ''
|
||||||
|
});
|
||||||
|
|
||||||
|
const equalToPassword = (rule: any, value: string, callback: any) => {
|
||||||
|
if (user.value.newPassword !== value) {
|
||||||
|
callback(new Error("两次输入的密码不一致"));
|
||||||
|
} else {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const rules = ref({
|
||||||
|
oldPassword: [{ required: true, message: "旧密码不能为空", trigger: "blur" }],
|
||||||
|
newPassword: [{ required: true, message: "新密码不能为空", trigger: "blur" }, { min: 6, max: 20, message: "长度在 6 到 20 个字符", trigger: "blur" }],
|
||||||
|
confirmPassword: [{ required: true, message: "确认密码不能为空", trigger: "blur" }, { required: true, validator: equalToPassword, trigger: "blur" }]
|
||||||
|
});
|
||||||
|
|
||||||
|
/** 提交按钮 */
|
||||||
|
const submit = () => {
|
||||||
|
pwdRef.value.validate(async (valid: boolean) => {
|
||||||
|
if (valid) {
|
||||||
|
await updateUserPwd(user.value.oldPassword, user.value.newPassword)
|
||||||
|
proxy?.$modal.msgSuccess("修改成功");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
/** 关闭按钮 */
|
||||||
|
const close = () => {
|
||||||
|
proxy?.$tab.closePage();
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
@ -1,104 +1,3 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import "vue-cropper/dist/index.css";
|
|
||||||
import { VueCropper } from "vue-cropper";
|
|
||||||
import { uploadAvatar } from "@/api/system/user";
|
|
||||||
import useUserStore from "@/store/modules/user";
|
|
||||||
import { ComponentInternalInstance } from "vue";
|
|
||||||
|
|
||||||
interface Options {
|
|
||||||
img: string | ArrayBuffer | null // 裁剪图片的地址
|
|
||||||
autoCrop: boolean // 是否默认生成截图框
|
|
||||||
autoCropWidth: number // 默认生成截图框宽度
|
|
||||||
autoCropHeight: number // 默认生成截图框高度
|
|
||||||
fixedBox: boolean // 固定截图框大小 不允许改变
|
|
||||||
fileName: string
|
|
||||||
previews: any // 预览数据
|
|
||||||
outputType: string
|
|
||||||
visible: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const userStore = useUserStore();
|
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
|
||||||
|
|
||||||
const open = ref(false);
|
|
||||||
const visible = ref(false);
|
|
||||||
const title = ref("修改头像");
|
|
||||||
|
|
||||||
const cropper = ref<any>({});
|
|
||||||
//图片裁剪数据
|
|
||||||
const options = reactive<Options>({
|
|
||||||
img: userStore.avatar,
|
|
||||||
autoCrop: true,
|
|
||||||
autoCropWidth: 200,
|
|
||||||
autoCropHeight: 200,
|
|
||||||
fixedBox: true,
|
|
||||||
outputType: "png",
|
|
||||||
fileName: '',
|
|
||||||
previews: {},
|
|
||||||
visible: false
|
|
||||||
});
|
|
||||||
|
|
||||||
/** 编辑头像 */
|
|
||||||
const editCropper = () => {
|
|
||||||
open.value = true;
|
|
||||||
}
|
|
||||||
/** 打开弹出层结束时的回调 */
|
|
||||||
const modalOpened = () => {
|
|
||||||
visible.value = true;
|
|
||||||
}
|
|
||||||
/** 覆盖默认上传行为 */
|
|
||||||
const requestUpload = (): any => {}
|
|
||||||
/** 向左旋转 */
|
|
||||||
const rotateLeft = () => {
|
|
||||||
cropper.value.rotateLeft();
|
|
||||||
}
|
|
||||||
/** 向右旋转 */
|
|
||||||
const rotateRight = () => {
|
|
||||||
cropper.value.rotateRight();
|
|
||||||
}
|
|
||||||
/** 图片缩放 */
|
|
||||||
const changeScale = (num: number) => {
|
|
||||||
num = num || 1;
|
|
||||||
cropper.value.changeScale(num);
|
|
||||||
}
|
|
||||||
/** 上传预处理 */
|
|
||||||
const beforeUpload = (file: any) => {
|
|
||||||
if (file.type.indexOf("image/") == -1) {
|
|
||||||
proxy?.$modal.msgError("文件格式错误,请上传图片类型,如:JPG,PNG后缀的文件。");
|
|
||||||
} else {
|
|
||||||
const reader = new FileReader();
|
|
||||||
reader.readAsDataURL(file);
|
|
||||||
reader.onload = () => {
|
|
||||||
options.img = reader.result;
|
|
||||||
options.fileName = file.name;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/** 上传图片 */
|
|
||||||
const uploadImg = async () => {
|
|
||||||
cropper.value.getCropBlob(async (data: any) => {
|
|
||||||
let formData = new FormData();
|
|
||||||
formData.append("avatarfile", data, options.fileName);
|
|
||||||
const res = await uploadAvatar(formData);
|
|
||||||
open.value = false;
|
|
||||||
options.img = res.data.imgUrl;
|
|
||||||
userStore.avatar = options.img as string;
|
|
||||||
proxy?.$modal.msgSuccess("修改成功");
|
|
||||||
visible.value = false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
/** 实时预览 */
|
|
||||||
const realTime = (data: any) => {
|
|
||||||
options.previews = data;
|
|
||||||
}
|
|
||||||
/** 关闭窗口 */
|
|
||||||
const closeDialog = () => {
|
|
||||||
options.img = userStore.avatar;
|
|
||||||
options.visible = false;
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="user-info-head" @click="editCropper()">
|
<div class="user-info-head" @click="editCropper()">
|
||||||
<img :src="options.img as string" title="点击上传头像" class="img-circle img-lg" />
|
<img :src="options.img as string" title="点击上传头像" class="img-circle img-lg" />
|
||||||
@ -154,6 +53,107 @@ const closeDialog = () => {
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import "vue-cropper/dist/index.css";
|
||||||
|
import { VueCropper } from "vue-cropper";
|
||||||
|
import { uploadAvatar } from "@/api/system/user";
|
||||||
|
import useUserStore from "@/store/modules/user";
|
||||||
|
import { ComponentInternalInstance } from "vue";
|
||||||
|
|
||||||
|
interface Options {
|
||||||
|
img: string | ArrayBuffer | null // 裁剪图片的地址
|
||||||
|
autoCrop: boolean // 是否默认生成截图框
|
||||||
|
autoCropWidth: number // 默认生成截图框宽度
|
||||||
|
autoCropHeight: number // 默认生成截图框高度
|
||||||
|
fixedBox: boolean // 固定截图框大小 不允许改变
|
||||||
|
fileName: string
|
||||||
|
previews: any // 预览数据
|
||||||
|
outputType: string
|
||||||
|
visible: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const userStore = useUserStore();
|
||||||
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
|
|
||||||
|
const open = ref(false);
|
||||||
|
const visible = ref(false);
|
||||||
|
const title = ref("修改头像");
|
||||||
|
|
||||||
|
const cropper = ref<any>({});
|
||||||
|
//图片裁剪数据
|
||||||
|
const options = reactive<Options>({
|
||||||
|
img: userStore.avatar,
|
||||||
|
autoCrop: true,
|
||||||
|
autoCropWidth: 200,
|
||||||
|
autoCropHeight: 200,
|
||||||
|
fixedBox: true,
|
||||||
|
outputType: "png",
|
||||||
|
fileName: '',
|
||||||
|
previews: {},
|
||||||
|
visible: false
|
||||||
|
});
|
||||||
|
|
||||||
|
/** 编辑头像 */
|
||||||
|
const editCropper = () => {
|
||||||
|
open.value = true;
|
||||||
|
}
|
||||||
|
/** 打开弹出层结束时的回调 */
|
||||||
|
const modalOpened = () => {
|
||||||
|
visible.value = true;
|
||||||
|
}
|
||||||
|
/** 覆盖默认上传行为 */
|
||||||
|
const requestUpload = (): any => {}
|
||||||
|
/** 向左旋转 */
|
||||||
|
const rotateLeft = () => {
|
||||||
|
cropper.value.rotateLeft();
|
||||||
|
}
|
||||||
|
/** 向右旋转 */
|
||||||
|
const rotateRight = () => {
|
||||||
|
cropper.value.rotateRight();
|
||||||
|
}
|
||||||
|
/** 图片缩放 */
|
||||||
|
const changeScale = (num: number) => {
|
||||||
|
num = num || 1;
|
||||||
|
cropper.value.changeScale(num);
|
||||||
|
}
|
||||||
|
/** 上传预处理 */
|
||||||
|
const beforeUpload = (file: any) => {
|
||||||
|
if (file.type.indexOf("image/") == -1) {
|
||||||
|
proxy?.$modal.msgError("文件格式错误,请上传图片类型,如:JPG,PNG后缀的文件。");
|
||||||
|
} else {
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.readAsDataURL(file);
|
||||||
|
reader.onload = () => {
|
||||||
|
options.img = reader.result;
|
||||||
|
options.fileName = file.name;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/** 上传图片 */
|
||||||
|
const uploadImg = async () => {
|
||||||
|
cropper.value.getCropBlob(async (data: any) => {
|
||||||
|
let formData = new FormData();
|
||||||
|
formData.append("avatarfile", data, options.fileName);
|
||||||
|
const res = await uploadAvatar(formData);
|
||||||
|
open.value = false;
|
||||||
|
options.img = res.data.imgUrl;
|
||||||
|
userStore.avatar = options.img as string;
|
||||||
|
proxy?.$modal.msgSuccess("修改成功");
|
||||||
|
visible.value = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/** 实时预览 */
|
||||||
|
const realTime = (data: any) => {
|
||||||
|
options.previews = data;
|
||||||
|
}
|
||||||
|
/** 关闭窗口 */
|
||||||
|
const closeDialog = () => {
|
||||||
|
options.img = userStore.avatar;
|
||||||
|
options.visible = false;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.user-info-head {
|
.user-info-head {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
@ -1,43 +1,3 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import { updateUserProfile } from "@/api/system/user";
|
|
||||||
import { FormRules } from "element-plus";
|
|
||||||
import { ComponentInternalInstance } from "vue";
|
|
||||||
import { PropType } from "vue";
|
|
||||||
import { ElForm } from "element-plus";
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
user: {
|
|
||||||
type: Object as PropType<any>,
|
|
||||||
}
|
|
||||||
});
|
|
||||||
const userForm = computed(() => props.user);
|
|
||||||
|
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
|
||||||
|
|
||||||
const userRef = ref(ElForm);
|
|
||||||
|
|
||||||
const rules = ref<FormRules>({
|
|
||||||
nickName: [{ required: true, message: "用户昵称不能为空", trigger: "blur" }],
|
|
||||||
email: [{ required: true, message: "邮箱地址不能为空", trigger: "blur" }, { type: "email", message: "请输入正确的邮箱地址", trigger: ["blur", "change"] }],
|
|
||||||
phonenumber: [{ required: true, message: "手机号码不能为空", trigger: "blur" }, { pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/, message: "请输入正确的手机号码", trigger: "blur" }],
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
/** 提交按钮 */
|
|
||||||
const submit = () => {
|
|
||||||
userRef.value.validate(async (valid: boolean) => {
|
|
||||||
if (valid) {
|
|
||||||
await updateUserProfile(props.user)
|
|
||||||
proxy?.$modal.msgSuccess("修改成功");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
/** 关闭按钮 */
|
|
||||||
const close = () => {
|
|
||||||
proxy?.$tab.closePage();
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<el-form ref="userRef" :model="userForm" :rules="rules" label-width="80px">
|
<el-form ref="userRef" :model="userForm" :rules="rules" label-width="80px">
|
||||||
<el-form-item label="用户昵称" prop="nickName">
|
<el-form-item label="用户昵称" prop="nickName">
|
||||||
@ -61,3 +21,43 @@ const close = () => {
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { updateUserProfile } from "@/api/system/user";
|
||||||
|
import { FormRules } from "element-plus";
|
||||||
|
import { ComponentInternalInstance } from "vue";
|
||||||
|
import { PropType } from "vue";
|
||||||
|
import { ElForm } from "element-plus";
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
user: {
|
||||||
|
type: Object as PropType<any>,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const userForm = computed(() => props.user);
|
||||||
|
|
||||||
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
|
|
||||||
|
const userRef = ref(ElForm);
|
||||||
|
|
||||||
|
const rules = ref<FormRules>({
|
||||||
|
nickName: [{ required: true, message: "用户昵称不能为空", trigger: "blur" }],
|
||||||
|
email: [{ required: true, message: "邮箱地址不能为空", trigger: "blur" }, { type: "email", message: "请输入正确的邮箱地址", trigger: ["blur", "change"] }],
|
||||||
|
phonenumber: [{ required: true, message: "手机号码不能为空", trigger: "blur" }, { pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/, message: "请输入正确的手机号码", trigger: "blur" }],
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/** 提交按钮 */
|
||||||
|
const submit = () => {
|
||||||
|
userRef.value.validate(async (valid: boolean) => {
|
||||||
|
if (valid) {
|
||||||
|
await updateUserProfile(props.user)
|
||||||
|
proxy?.$modal.msgSuccess("修改成功");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
/** 关闭按钮 */
|
||||||
|
const close = () => {
|
||||||
|
proxy?.$tab.closePage();
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
@ -1,26 +1,3 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import { PropType } from 'vue';
|
|
||||||
|
|
||||||
const prop = defineProps({
|
|
||||||
info: {
|
|
||||||
type: Object as PropType<any>,
|
|
||||||
default: () => {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const infoForm = computed(() => prop.info)
|
|
||||||
|
|
||||||
// 表单校验
|
|
||||||
const rules = ref({
|
|
||||||
tableName: [{ required: true, message: "请输入表名称", trigger: "blur" }],
|
|
||||||
tableComment: [{ required: true, message: "请输入表描述", trigger: "blur" }],
|
|
||||||
className: [{ required: true, message: "请输入实体类名称", trigger: "blur" }],
|
|
||||||
functionAuthor: [{ required: true, message: "请输入作者", trigger: "blur" }]
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<el-form ref="basicInfoForm" :model="infoForm" :rules="rules" label-width="150px">
|
<el-form ref="basicInfoForm" :model="infoForm" :rules="rules" label-width="150px">
|
||||||
<el-row>
|
<el-row>
|
||||||
@ -52,3 +29,26 @@ const rules = ref({
|
|||||||
</el-row>
|
</el-row>
|
||||||
</el-form>
|
</el-form>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { PropType } from 'vue';
|
||||||
|
|
||||||
|
const prop = defineProps({
|
||||||
|
info: {
|
||||||
|
type: Object as PropType<any>,
|
||||||
|
default: () => {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const infoForm = computed(() => prop.info)
|
||||||
|
|
||||||
|
// 表单校验
|
||||||
|
const rules = ref({
|
||||||
|
tableName: [{ required: true, message: "请输入表名称", trigger: "blur" }],
|
||||||
|
tableComment: [{ required: true, message: "请输入表描述", trigger: "blur" }],
|
||||||
|
className: [{ required: true, message: "请输入实体类名称", trigger: "blur" }],
|
||||||
|
functionAuthor: [{ required: true, message: "请输入作者", trigger: "blur" }]
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
@ -1,76 +1,3 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import { listMenu } from '@/api/system/menu';
|
|
||||||
import { ComponentInternalInstance, PropType } from 'vue';
|
|
||||||
|
|
||||||
interface MenuOptionsType {
|
|
||||||
menuId: number;
|
|
||||||
menuName: string;
|
|
||||||
children: MenuOptionsType[] | undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
const subColumns = ref<any>([]);
|
|
||||||
const menuOptions = ref<Array<MenuOptionsType>>([]);
|
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
info: {
|
|
||||||
type: Object as PropType<any>,
|
|
||||||
default: null
|
|
||||||
},
|
|
||||||
tables: {
|
|
||||||
type: Array as PropType<any[]>,
|
|
||||||
default: null
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const infoForm = computed(() => props.info);
|
|
||||||
|
|
||||||
const table = computed(() => props.tables);
|
|
||||||
|
|
||||||
// 表单校验
|
|
||||||
const rules = ref({
|
|
||||||
tplCategory: [{ required: true, message: "请选择生成模板", trigger: "blur" }],
|
|
||||||
packageName: [{ required: true, message: "请输入生成包路径", trigger: "blur" }],
|
|
||||||
moduleName: [{ required: true, message: "请输入生成模块名", trigger: "blur" }],
|
|
||||||
businessName: [{ required: true, message: "请输入生成业务名", trigger: "blur" }],
|
|
||||||
functionName: [{ required: true, message: "请输入生成功能名", trigger: "blur" }]
|
|
||||||
});
|
|
||||||
const subSelectChange = () => {
|
|
||||||
infoForm.value.subTableFkName = "";
|
|
||||||
}
|
|
||||||
const tplSelectChange = (value: string) => {
|
|
||||||
if (value !== "sub") {
|
|
||||||
infoForm.value.subTableName = "";
|
|
||||||
infoForm.value.subTableFkName = "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const setSubTableColumns = (value: string) => {
|
|
||||||
table.value.forEach(item => {
|
|
||||||
const name = item.tableName;
|
|
||||||
if (value === name) {
|
|
||||||
subColumns.value = item.columns;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
/** 查询菜单下拉树结构 */
|
|
||||||
const getMenuTreeselect = async () => {
|
|
||||||
const res = await listMenu();
|
|
||||||
const data = proxy?.handleTree<MenuOptionsType>(res.data, "menuId");
|
|
||||||
if (data) {
|
|
||||||
menuOptions.value = data
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
watch(() => props.info.subTableName, val => {
|
|
||||||
setSubTableColumns(val);
|
|
||||||
});
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
getMenuTreeselect();
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<el-form ref="genInfoForm" :model="infoForm" :rules="rules" label-width="150px">
|
<el-form ref="genInfoForm" :model="infoForm" :rules="rules" label-width="150px">
|
||||||
<el-row>
|
<el-row>
|
||||||
@ -287,3 +214,76 @@ onMounted(() => {
|
|||||||
</template>
|
</template>
|
||||||
</el-form>
|
</el-form>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { listMenu } from '@/api/system/menu';
|
||||||
|
import { ComponentInternalInstance, PropType } from 'vue';
|
||||||
|
|
||||||
|
interface MenuOptionsType {
|
||||||
|
menuId: number;
|
||||||
|
menuName: string;
|
||||||
|
children: MenuOptionsType[] | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const subColumns = ref<any>([]);
|
||||||
|
const menuOptions = ref<Array<MenuOptionsType>>([]);
|
||||||
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
info: {
|
||||||
|
type: Object as PropType<any>,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
tables: {
|
||||||
|
type: Array as PropType<any[]>,
|
||||||
|
default: null
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const infoForm = computed(() => props.info);
|
||||||
|
|
||||||
|
const table = computed(() => props.tables);
|
||||||
|
|
||||||
|
// 表单校验
|
||||||
|
const rules = ref({
|
||||||
|
tplCategory: [{ required: true, message: "请选择生成模板", trigger: "blur" }],
|
||||||
|
packageName: [{ required: true, message: "请输入生成包路径", trigger: "blur" }],
|
||||||
|
moduleName: [{ required: true, message: "请输入生成模块名", trigger: "blur" }],
|
||||||
|
businessName: [{ required: true, message: "请输入生成业务名", trigger: "blur" }],
|
||||||
|
functionName: [{ required: true, message: "请输入生成功能名", trigger: "blur" }]
|
||||||
|
});
|
||||||
|
const subSelectChange = () => {
|
||||||
|
infoForm.value.subTableFkName = "";
|
||||||
|
}
|
||||||
|
const tplSelectChange = (value: string) => {
|
||||||
|
if (value !== "sub") {
|
||||||
|
infoForm.value.subTableName = "";
|
||||||
|
infoForm.value.subTableFkName = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const setSubTableColumns = (value: string) => {
|
||||||
|
table.value.forEach(item => {
|
||||||
|
const name = item.tableName;
|
||||||
|
if (value === name) {
|
||||||
|
subColumns.value = item.columns;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/** 查询菜单下拉树结构 */
|
||||||
|
const getMenuTreeselect = async () => {
|
||||||
|
const res = await listMenu();
|
||||||
|
const data = proxy?.handleTree<MenuOptionsType>(res.data, "menuId");
|
||||||
|
if (data) {
|
||||||
|
menuOptions.value = data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(() => props.info.subTableName, val => {
|
||||||
|
setSubTableColumns(val);
|
||||||
|
});
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getMenuTreeselect();
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user