Browse Source

update 调整代码格式

疯狂的狮子Li 1 năm trước cách đây
mục cha
commit
97187b246b

+ 14 - 14
src/components/Hamburger/index.vue

@@ -1,17 +1,3 @@
-<script setup lang="ts">
-defineProps({
-  isActive: {
-    type: Boolean,
-    default: false
-  }
-})
-
-const emit = defineEmits(['toggleClick'])
-const toggleClick = () => {
-  emit('toggleClick');
-}
-</script>
-
 <template>
   <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">
@@ -22,6 +8,20 @@ const toggleClick = () => {
   </div>
 </template>
 
+<script setup lang="ts">
+defineProps({
+    isActive: {
+        type: Boolean,
+        default: false
+    }
+})
+
+const emit = defineEmits(['toggleClick'])
+const toggleClick = () => {
+    emit('toggleClick');
+}
+</script>
+
 <style scoped>
 .hamburger {
   display: inline-block;

+ 94 - 94
src/components/HeaderSearch/index.vue

@@ -1,3 +1,22 @@
+<template>
+  <div :class="{ 'show': show }" class="header-search">
+    <svg-icon class-name="search-icon" icon-class="search" @click.stop="click" />
+    <el-select
+      ref="headerSearchSelectRef"
+      v-model="search"
+      :remote-method="querySearch"
+      filterable
+      default-first-option
+      remote
+      placeholder="Search"
+      class="header-search-select"
+      @change="change"
+    >
+      <el-option v-for="option in options" :key="option.item.path" :value="option.item" :label="option.item.title.join(' > ')" />
+    </el-select>
+  </div>
+</template>
+
 <script setup lang="ts">
 import Fuse from 'fuse.js'
 import { getNormalPath } from '@/utils/ruoyi'
@@ -6,8 +25,8 @@ import usePermissionStore from '@/store/modules/permission'
 import { RouteOption } from 'vue-router'
 
 type Router = Array<{
-  path: string;
-  title: string[];
+    path: string;
+    title: string[];
 }>
 
 const search = ref('');
@@ -20,126 +39,107 @@ const router = useRouter();
 const routes = computed(() => usePermissionStore().routes);
 
 const click = () => {
-  show.value = !show.value
-  if (show.value) {
-    headerSearchSelectRef.value && headerSearchSelectRef.value.focus()
-  }
+    show.value = !show.value
+    if (show.value) {
+        headerSearchSelectRef.value && headerSearchSelectRef.value.focus()
+    }
 };
 const close = () => {
-  headerSearchSelectRef.value && headerSearchSelectRef.value.blur()
-  options.value = []
-  show.value = false
+    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 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
-    }]
-  })
+    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);
+    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];
+                }
+            }
         }
-      }
-      // recursive child routes
-      if (r.children) {
-        const tempRoutes = generateRoutes(r.children, data.path, data.title);
-        if (tempRoutes.length >= 1) {
-          res = [...res, ...tempRoutes];
-        }
-      }
-    }
-  })
-  return res;
+    })
+    return res;
 }
 const querySearch = (query: string) => {
-  if (query !== '') {
-    options.value = fuse.value.search(query)
-  } else {
-    options.value = []
-  }
+    if (query !== '') {
+        options.value = fuse.value.search(query)
+    } else {
+        options.value = []
+    }
 }
 
 onMounted(() => {
-  searchPool.value = generateRoutes(routes.value);
+    searchPool.value = generateRoutes(routes.value);
 })
 
 watchEffect(() => {
-  searchPool.value = generateRoutes(routes.value)
+    searchPool.value = generateRoutes(routes.value)
 })
 
 watch(show, (value) => {
-  if (value) {
-    document.body.addEventListener('click', close)
-  } else {
-    document.body.removeEventListener('click', close)
-  }
+    if (value) {
+        document.body.addEventListener('click', close)
+    } else {
+        document.body.removeEventListener('click', close)
+    }
 })
 
 watch(searchPool, (list) => {
-  initFuse(list)
+    initFuse(list)
 })
 </script>
 
-<template>
-  <div :class="{ 'show': show }" class="header-search">
-    <svg-icon class-name="search-icon" icon-class="search" @click.stop="click" />
-    <el-select
-      ref="headerSearchSelectRef"
-      v-model="search"
-      :remote-method="querySearch"
-      filterable
-      default-first-option
-      remote
-      placeholder="Search"
-      class="header-search-select"
-      @change="change"
-    >
-      <el-option v-for="option in options" :key="option.item.path" :value="option.item" :label="option.item.title.join(' > ')" />
-    </el-select>
-  </div>
-</template>
-
 <style lang="scss" scoped>
 .header-search {
   font-size: 0 !important;

+ 45 - 45
src/components/IconSelect/index.vue

@@ -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>
   <div class="relative" :style="{ width: width }">
     <el-input v-model="modelValue" readonly @click="visible = !visible" placeholder="点击选择图标">
@@ -74,6 +29,51 @@ const selectedIcon = (iconName: string) => {
   </div>
 </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">
 .el-divider--horizontal {
   margin: 10px auto !important;

+ 38 - 38
src/components/ImagePreview/index.vue

@@ -1,58 +1,58 @@
+<template>
+  <el-image :src="`${realSrc}`" fit="cover" :style="`width:${realWidth};height:${realHeight};`" :preview-src-list="realSrcList" preview-teleported>
+    <template #error>
+      <div class="image-slot">
+        <el-icon><picture-filled /></el-icon>
+      </div>
+    </template>
+  </el-image>
+</template>
+
 <script setup lang="ts">
 const props = defineProps({
-  src: {
-    type: String,
-    default: ""
-  },
-  width: {
-    type: [Number, String],
-    default: ""
-  },
-  height: {
-    type: [Number, String],
-    default: ""
-  }
+    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;
+    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;
+    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`
+    typeof props.width == "string" ? props.width : `${props.width}px`
 );
 
 const realHeight = computed(() =>
-  typeof props.height == "string" ? props.height : `${props.height}px`
+    typeof props.height == "string" ? props.height : `${props.height}px`
 );
 </script>
 
-<template>
-  <el-image :src="`${realSrc}`" fit="cover" :style="`width:${realWidth};height:${realHeight};`" :preview-src-list="realSrcList" preview-teleported>
-    <template #error>
-      <div class="image-slot">
-        <el-icon><picture-filled /></el-icon>
-      </div>
-    </template>
-  </el-image>
-</template>
-
 <style lang="scss" scoped>
 .el-image {
   border-radius: 5px;

+ 17 - 17
src/components/SizeSelect/index.vue

@@ -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>
   <div>
     <el-dropdown trigger="click" @command="handleSetSize">
@@ -32,6 +15,23 @@ const handleSetSize = (size: string) => {
   </div>
 </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>
 .size-icon--style {
   font-size: 18px;

+ 22 - 22
src/components/SvgIcon/index.vue

@@ -1,33 +1,33 @@
+<template>
+  <svg :class="svgClass" aria-hidden="true">
+    <use :xlink:href="iconName" :fill="color" />
+  </svg>
+</template>
+
 <script setup lang="ts">
 const props = defineProps({
-  iconClass: {
-    type: String,
-    required: true
-  },
-  className: {
-    type: String,
-    default: ''
-  },
-  color: {
-    type: String,
-    default: ''
-  },
+    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'
+    if (props.className) {
+        return `svg-icon ${props.className}`
+    }
+    return 'svg-icon'
 })
 </script>
 
-<template>
-  <svg :class="svgClass" aria-hidden="true">
-    <use :xlink:href="iconName" :fill="color" />
-  </svg>
-</template>
-
 <style scope lang="scss">
 .sub-el-icon,
 .nav-icon {

+ 17 - 17
src/components/TopNav/index.vue

@@ -1,21 +1,21 @@
 <template>
-    <el-menu :default-active="activeMenu" mode="horizontal" @select="handleSelect" :ellipsis="false">
-        <template v-for="(item, index) in topMenus">
-            <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
-            >
-        </template>
-
-        <!-- 顶部菜单超出数量折叠 -->
-        <el-sub-menu :style="{'--theme': theme}" index="more" v-if="topMenus.length > visibleNumber">
-            <template #title>更多菜单</template>
-            <template v-for="(item, index) in topMenus">
-                <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
-                >
-            </template>
-        </el-sub-menu>
-    </el-menu>
+  <el-menu :default-active="activeMenu" mode="horizontal" @select="handleSelect" :ellipsis="false">
+    <template v-for="(item, index) in topMenus">
+      <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
+      >
+    </template>
+
+    <!-- 顶部菜单超出数量折叠 -->
+    <el-sub-menu :style="{'--theme': theme}" index="more" v-if="topMenus.length > visibleNumber">
+      <template #title>更多菜单</template>
+      <template v-for="(item, index) in topMenus">
+        <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
+        >
+      </template>
+    </el-sub-menu>
+  </el-menu>
 </template>
 
 <script setup lang="ts">

+ 58 - 58
src/components/TreeSelect/index.vue

@@ -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">
 import { ElTreeSelect } from 'element-plus'
 
 const props = defineProps({
   /* 配置项 */
   objMap: {
-    type: Object,
-    default: () => {
-      return {
-        value: 'id', // ID字段名
-        label: 'label', // 显示名称
-        children: 'children' // 子级字段名
-      }
+  type: Object,
+  default: () => {
+    return {
+    value: 'id', // ID字段名
+    label: 'label', // 显示名称
+    children: 'children' // 子级字段名
     }
+  }
   },
   /* 自动收起 */
   accordion: {
-    type: Boolean,
-    default: () => {
-      return false
-    }
+  type: Boolean,
+  default: () => {
+    return false
+  }
   },
   /**当前双向数据绑定的值 */
   value: {
-    type: [String, Number],
-    default: ''
+  type: [String, Number],
+  default: ''
   },
   /**当前的数据 */
   options: {
-    type: Array,
-    default: () => []
+  type: Array,
+  default: () => []
   },
   /**输入框内部的文字 */
   placeholder: {
-    type: String,
-    default: ''
+  type: String,
+  default: ''
   }
 })
 
@@ -45,7 +75,7 @@ const emit = defineEmits(['update:value']);
 const valueId = computed({
   get: () => props.value,
   set: (val) => {
-    emit('update:value', val)
+  emit('update:value', val)
   }
 });
 const valueTitle = ref('');
@@ -53,17 +83,17 @@ const defaultExpandedKey = ref<any[]>([]);
 
 function initHandle() {
   nextTick(() => {
-    const selectedValue = valueId.value;
-    if(selectedValue !== null && typeof (selectedValue) !== 'undefined') {
-      const node = selectTree.value.getNode(selectedValue)
-      if (node) {
-        valueTitle.value = node.data[props.objMap.label]
-        selectTree.value.setCurrentKey(selectedValue) // 设置默认选中
-        defaultExpandedKey.value = [selectedValue] // 设置默认展开
-      }
-    } else {
-      clearHandle()
+  const selectedValue = valueId.value;
+  if(selectedValue !== null && typeof (selectedValue) !== 'undefined') {
+    const node = selectTree.value.getNode(selectedValue)
+    if (node) {
+    valueTitle.value = node.data[props.objMap.label]
+    selectTree.value.setCurrentKey(selectedValue) // 设置默认选中
+    defaultExpandedKey.value = [selectedValue] // 设置默认展开
     }
+  } else {
+    clearHandle()
+  }
   })
 }
 function handleNodeClick(node: any) {
@@ -126,33 +156,3 @@ ul li .el-tree .el-tree-node__content {
   color: $--color-primary;
 }
 </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>

+ 6 - 6
src/components/iFrame/index.vue

@@ -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">
 const props = defineProps({
   src: {
@@ -19,9 +25,3 @@ onMounted(() => {
   };
 })
 </script>
-
-<template>
-  <div v-loading="loading" :style="'height:' + height">
-    <iframe :src="url" frameborder="no" style="width: 100%; height: 100%" scrolling="auto" />
-  </div>
-</template>

+ 8 - 8
src/layout/components/IframeToggle/index.vue

@@ -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>
   <transition-group name="fade-transform" mode="out-in">
     <inner-link
@@ -17,3 +9,11 @@ const tagsViewStore = useTagsViewStore()
     ></inner-link>
   </transition-group>
 </template>
+
+<script setup lang="ts">
+import InnerLink from "../InnerLink/index.vue";
+import useTagsViewStore from '@/store/modules/tagsView';
+
+const route = useRoute();
+const tagsViewStore = useTagsViewStore()
+</script>

+ 102 - 102
src/layout/components/Settings/index.vue

@@ -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>
   <el-drawer v-model="showSettings" :withHeader="false" direction="rtl" size="300px" close-on-click-modal>
     <div class="setting-drawer-title">
@@ -183,6 +81,108 @@ defineExpose({
   </el-drawer>
 </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>
 .setting-drawer-title {
   margin-bottom: 12px;

+ 23 - 23
src/layout/components/Sidebar/Link.vue

@@ -1,40 +1,40 @@
+<template>
+  <component :is="type" v-bind="linkProps()">
+    <slot />
+  </component>
+</template>
+
 <script setup lang="ts">
 import { isExternal } from '@/utils/validate'
 
 const props = defineProps({
-  to: {
-    type: [String, Object],
-    required: true
-  }
+    to: {
+        type: [String, Object],
+        required: true
+    }
 })
 
 const isExt = computed(() => {
-  return isExternal(props.to as string)
+    return isExternal(props.to as string)
 })
 
 const type = computed(() => {
-  if (isExt.value) {
-    return 'a'
-  }
-  return 'router-link'
+    if (isExt.value) {
+        return 'a'
+    }
+    return 'router-link'
 })
 
 function linkProps() {
-  if (isExt.value) {
+    if (isExt.value) {
+        return {
+            href: props.to,
+            target: '_blank',
+            rel: 'noopener'
+        }
+    }
     return {
-      href: props.to,
-      target: '_blank',
-      rel: 'noopener'
+        to: props.to
     }
-  }
-  return {
-    to: props.to
-  }
 }
 </script>
-
-<template>
-  <component :is="type" v-bind="linkProps()">
-    <slot />
-  </component>
-</template>

+ 19 - 19
src/layout/components/Sidebar/Logo.vue

@@ -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>
   <div
     class="sidebar-logo-container"
@@ -40,6 +21,25 @@ const sideTheme = computed(() => settingsStore.sideTheme);
   </div>
 </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>
 .sidebarLogoFade-enter-active {
   transition: opacity 1.5s;

+ 28 - 28
src/layout/components/Sidebar/index.vue

@@ -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">
 import Logo from './Logo.vue'
 import SidebarItem from './SidebarItem.vue'
@@ -20,36 +42,14 @@ const theme = computed(() => settingsStore.theme);
 const isCollapse = computed(() => !appStore.sidebar.opened);
 
 const activeMenu = computed(() => {
-  const { meta, path } = route;
-  // if set path, the sidebar will highlight the path you set
-  if (meta.activeMenu) {
-    return meta.activeMenu;
-  }
-  return path;
+    const { meta, path } = route;
+    // if set path, the sidebar will highlight the path you set
+    if (meta.activeMenu) {
+        return meta.activeMenu;
+    }
+    return path;
 })
 
 const bgColor = computed(() => sideTheme.value === 'theme-dark' ? variables.menuBackground : variables.menuLightBackground);
 const textColor = computed(() => sideTheme.value === 'theme-dark' ? variables.menuColor : variables.menuLightColor);
 </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>

+ 50 - 50
src/layout/components/TagsView/ScrollPane.vue

@@ -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">
 import useTagsViewStore from '@/store/modules/tagsView'
 import { ElScrollbar } from 'element-plus';
@@ -8,84 +14,78 @@ const scrollContainerRef = ref(ElScrollbar)
 const scrollWrapper = computed(() => scrollContainerRef.value.$refs.wrapRef);
 
 onMounted(() => {
-  scrollWrapper.value.addEventListener('scroll', emitScroll, true)
+    scrollWrapper.value.addEventListener('scroll', emitScroll, true)
 })
 onBeforeUnmount(() => {
-  scrollWrapper.value.removeEventListener('scroll', emitScroll)
+    scrollWrapper.value.removeEventListener('scroll', emitScroll)
 })
 
 const handleScroll = (e: WheelEvent) => {
-  const eventDelta = (e as any).wheelDelta || -e.deltaY * 40
-  const $scrollWrapper = scrollWrapper.value;
-  $scrollWrapper.scrollLeft = $scrollWrapper.scrollLeft + eventDelta / 4
+    const eventDelta = (e as any).wheelDelta || -e.deltaY * 40
+    const $scrollWrapper = scrollWrapper.value;
+    $scrollWrapper.scrollLeft = $scrollWrapper.scrollLeft + eventDelta / 4
 }
 const emits = defineEmits(['scroll'])
 const emitScroll = () => {
-  emits('scroll')
+    emits('scroll')
 }
 
 const tagsViewStore = useTagsViewStore()
 const visitedViews = computed(() => tagsViewStore.visitedViews);
 
 const moveToTarget = (currentTag: TagView) => {
-  const $container = scrollContainerRef.value.$el
-  const $containerWidth = $container.offsetWidth
-  const $scrollWrapper = scrollWrapper.value;
+    const $container = scrollContainerRef.value.$el
+    const $containerWidth = $container.offsetWidth
+    const $scrollWrapper = scrollWrapper.value;
 
-  let firstTag = null
-  let lastTag = null
+    let firstTag = null
+    let lastTag = null
 
-  // find first tag and last tag
-  if (visitedViews.value.length > 0) {
-    firstTag = visitedViews.value[0]
-    lastTag = visitedViews.value[visitedViews.value.length - 1]
-  }
+    // find first tag and last tag
+    if (visitedViews.value.length > 0) {
+        firstTag = visitedViews.value[0]
+        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
+    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];
+        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
-    const afterNextTagOffsetLeft = nextTag.offsetLeft + nextTag.offsetWidth + tagAndTagSpacing.value
+        // 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
+        // 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({
-  moveToTarget,
+    moveToTarget,
 })
 </script>
 
-<template>
-  <el-scrollbar ref="scrollContainerRef" :vertical="false" class="scroll-container" @wheel.prevent="handleScroll">
-    <slot />
-  </el-scrollbar>
-</template>
-
 <style lang="scss" scoped>
 .scroll-container {
   white-space: nowrap;

+ 33 - 33
src/layout/index.vue

@@ -1,3 +1,18 @@
+<template>
+  <div :class="classObj" class="app-wrapper" :style="{ '--current-color': theme }">
+    <div v-if="device === 'mobile' && sidebar.opened" class="drawer-bg" @click="handleClickOutside" />
+    <side-bar v-if="!sidebar.hide" class="sidebar-container" />
+    <div :class="{ hasTagsView: needTagsView, sidebarHide: sidebar.hide }" class="main-container">
+      <div :class="{ 'fixed-header': fixedHeader }">
+        <navbar ref="navbarRef" @setLayout="setLayout" />
+        <tags-view v-if="needTagsView" />
+      </div>
+      <app-main />
+      <settings ref="settingRef" />
+    </div>
+  </div>
+</template>
+
 <script setup lang="ts">
 import SideBar from './components/Sidebar/index.vue'
 import { AppMain, Navbar, Settings, TagsView } from './components'
@@ -12,60 +27,45 @@ 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'
+    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')
-  }
+    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();
-  })
+    nextTick(() => {
+        navbarRef.value.initTenantList();
+    })
 })
 
 const handleClickOutside = () => {
-  useAppStore().closeSideBar({ withoutAnimation: false })
+    useAppStore().closeSideBar({ withoutAnimation: false })
 }
 
 const setLayout = () => {
-  settingRef.value.openSetting();
+    settingRef.value.openSetting();
 }
 </script>
 
-<template>
-  <div :class="classObj" class="app-wrapper" :style="{ '--current-color': theme }">
-    <div v-if="device === 'mobile' && sidebar.opened" class="drawer-bg" @click="handleClickOutside" />
-    <side-bar v-if="!sidebar.hide" class="sidebar-container" />
-    <div :class="{ hasTagsView: needTagsView, sidebarHide: sidebar.hide }" class="main-container">
-      <div :class="{ 'fixed-header': fixedHeader }">
-        <navbar ref="navbarRef" @setLayout="setLayout" />
-        <tags-view v-if="needTagsView" />
-      </div>
-      <app-main />
-      <settings ref="settingRef" />
-    </div>
-  </div>
-</template>
-
 <style lang="scss" scoped>
   @import "@/assets/styles/mixin.scss";
   @import "@/assets/styles/variables.module.scss";

+ 65 - 64
src/views/monitor/cache/index.vue

@@ -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>
   <div class="p-2">
     <el-row>
@@ -186,3 +122,68 @@ onMounted(() => {
     </el-row>
   </div>
 </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>

+ 140 - 140
src/views/system/config/index.vue

@@ -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>
   <div class="p-2">
     <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
@@ -259,3 +119,143 @@ onMounted(() => {
     </el-dialog>
   </div>
 </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>

+ 28 - 28
src/views/system/user/profile/index.vue

@@ -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>
   <div class="p-2">
     <el-row :gutter="20">
@@ -89,3 +61,31 @@ onMounted(() => {
     </el-row>
   </div>
 </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>

+ 36 - 36
src/views/system/user/profile/resetPwd.vue

@@ -1,3 +1,21 @@
+<template>
+  <el-form ref="pwdRef" :model="user" :rules="rules" label-width="80px">
+    <el-form-item label="旧密码" prop="oldPassword">
+      <el-input v-model="user.oldPassword" placeholder="请输入旧密码" type="password" show-password />
+    </el-form-item>
+    <el-form-item label="新密码" prop="newPassword">
+      <el-input v-model="user.newPassword" placeholder="请输入新密码" type="password" show-password />
+    </el-form-item>
+    <el-form-item label="确认密码" prop="confirmPassword">
+      <el-input v-model="user.confirmPassword" placeholder="请确认新密码" type="password" show-password />
+    </el-form-item>
+    <el-form-item>
+      <el-button type="primary" @click="submit">保存</el-button>
+      <el-button type="danger" @click="close">关闭</el-button>
+    </el-form-item>
+  </el-form>
+</template>
+
 <script setup lang="ts">
 import { updateUserPwd } from '@/api/system/user';
 import { ComponentInternalInstance } from 'vue';
@@ -10,53 +28,35 @@ const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 const pwdRef = ref(ElForm);
 
 const user = ref<ResetPwdForm>({
-  oldPassword: '',
-  newPassword: '',
-  confirmPassword: ''
+    oldPassword: '',
+    newPassword: '',
+    confirmPassword: ''
 });
 
 const equalToPassword = (rule: any, value: string, callback: any) => {
-  if (user.value.newPassword !== value) {
-    callback(new Error("两次输入的密码不一致"));
-  } else {
-    callback();
-  }
+    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" }]
+    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("修改成功");
-    }
-  });
+    pwdRef.value.validate(async (valid: boolean) => {
+        if (valid) {
+            await updateUserPwd(user.value.oldPassword, user.value.newPassword)
+            proxy?.$modal.msgSuccess("修改成功");
+        }
+    });
 };
 /** 关闭按钮 */
 const close = () => {
-  proxy?.$tab.closePage();
+    proxy?.$tab.closePage();
 };
 </script>
-
-<template>
-  <el-form ref="pwdRef" :model="user" :rules="rules" label-width="80px">
-    <el-form-item label="旧密码" prop="oldPassword">
-      <el-input v-model="user.oldPassword" placeholder="请输入旧密码" type="password" show-password />
-    </el-form-item>
-    <el-form-item label="新密码" prop="newPassword">
-      <el-input v-model="user.newPassword" placeholder="请输入新密码" type="password" show-password />
-    </el-form-item>
-    <el-form-item label="确认密码" prop="confirmPassword">
-      <el-input v-model="user.confirmPassword" placeholder="请确认新密码" type="password" show-password />
-    </el-form-item>
-    <el-form-item>
-      <el-button type="primary" @click="submit">保存</el-button>
-      <el-button type="danger" @click="close">关闭</el-button>
-    </el-form-item>
-  </el-form>
-</template>

+ 101 - 101
src/views/system/user/profile/userAvatar.vue

@@ -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>
   <div class="user-info-head" @click="editCropper()">
     <img :src="options.img as string" title="点击上传头像" class="img-circle img-lg" />
@@ -154,6 +53,107 @@ const closeDialog = () => {
   </div>
 </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>
 .user-info-head {
   position: relative;

+ 37 - 37
src/views/system/user/profile/userInfo.vue

@@ -1,3 +1,27 @@
+<template>
+  <el-form ref="userRef" :model="userForm" :rules="rules" label-width="80px">
+    <el-form-item label="用户昵称" prop="nickName">
+      <el-input v-model="userForm.nickName" maxlength="30" />
+    </el-form-item>
+    <el-form-item label="手机号码" prop="phonenumber">
+      <el-input v-model="userForm.phonenumber" maxlength="11" />
+    </el-form-item>
+    <el-form-item label="邮箱" prop="email">
+      <el-input v-model="userForm.email" maxlength="50" />
+    </el-form-item>
+    <el-form-item label="性别">
+      <el-radio-group v-model="userForm.sex">
+        <el-radio label="0">男</el-radio>
+        <el-radio label="1">女</el-radio>
+      </el-radio-group>
+    </el-form-item>
+    <el-form-item>
+      <el-button type="primary" @click="submit">保存</el-button>
+      <el-button type="danger" @click="close">关闭</el-button>
+    </el-form-item>
+  </el-form>
+</template>
+
 <script setup lang="ts">
 import { updateUserProfile } from "@/api/system/user";
 import { FormRules } from "element-plus";
@@ -6,9 +30,9 @@ import { PropType } from "vue";
 import { ElForm } from "element-plus";
 
 const props = defineProps({
-  user: {
-    type: Object as PropType<any>,
-  }
+    user: {
+        type: Object as PropType<any>,
+    }
 });
 const userForm = computed(() => props.user);
 
@@ -17,47 +41,23 @@ 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" }],
+    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("修改成功");
-    }
-  });
+    userRef.value.validate(async (valid: boolean) => {
+        if (valid) {
+            await updateUserProfile(props.user)
+            proxy?.$modal.msgSuccess("修改成功");
+        }
+    });
 };
 /** 关闭按钮 */
 const close = () => {
-  proxy?.$tab.closePage();
+    proxy?.$tab.closePage();
 };
 </script>
-
-<template>
-  <el-form ref="userRef" :model="userForm" :rules="rules" label-width="80px">
-    <el-form-item label="用户昵称" prop="nickName">
-      <el-input v-model="userForm.nickName" maxlength="30" />
-    </el-form-item>
-    <el-form-item label="手机号码" prop="phonenumber">
-      <el-input v-model="userForm.phonenumber" maxlength="11" />
-    </el-form-item>
-    <el-form-item label="邮箱" prop="email">
-      <el-input v-model="userForm.email" maxlength="50" />
-    </el-form-item>
-    <el-form-item label="性别">
-      <el-radio-group v-model="userForm.sex">
-        <el-radio label="0">男</el-radio>
-        <el-radio label="1">女</el-radio>
-      </el-radio-group>
-    </el-form-item>
-    <el-form-item>
-      <el-button type="primary" @click="submit">保存</el-button>
-      <el-button type="danger" @click="close">关闭</el-button>
-    </el-form-item>
-  </el-form>
-</template>

+ 23 - 23
src/views/tool/gen/basicInfoForm.vue

@@ -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>
   <el-form ref="basicInfoForm" :model="infoForm" :rules="rules" label-width="150px">
     <el-row>
@@ -52,3 +29,26 @@ const rules = ref({
     </el-row>
   </el-form>
 </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>

+ 73 - 73
src/views/tool/gen/genInfoForm.vue

@@ -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>
   <el-form ref="genInfoForm" :model="infoForm" :rules="rules" label-width="150px">
     <el-row>
@@ -287,3 +214,76 @@ onMounted(() => {
     </template>
   </el-form>
 </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>