Browse Source

样式调整,代码格式化

zouzs 4 tuần trước cách đây
mục cha
commit
1613127bf7

+ 1 - 1
src/api/routes.ts

@@ -1,5 +1,5 @@
 import { http } from "@/utils/http";
-import {baseUrlApi} from "./utils";
+import { baseUrlApi } from "./utils";
 
 type Result = {
   success: boolean;

+ 44 - 23
src/api/system/menu.ts

@@ -1,47 +1,68 @@
-import {http} from "@/utils/http";
-import {baseUrlApi} from "../utils";
+import { http } from "@/utils/http";
+import { baseUrlApi } from "../utils";
 
 export interface BasicResponseModel<T = any> {
-    code: number;
-    msg: string;
-    data: T;
+  code: number;
+  msg: string;
+  data: T;
 }
 
 export const getSystemMenuList = (query?: object) => {
-    return http.request<BasicResponseModel>("get", baseUrlApi("system/menu/list"), {params: query});
+  return http.request<BasicResponseModel>(
+    "get",
+    baseUrlApi("system/menu/list"),
+    { params: query }
+  );
 };
 
 export const getSystemMenuDetailById = (id: number) => {
-    return http.request<BasicResponseModel>("get", baseUrlApi(`system/menu/${id}`));
+  return http.request<BasicResponseModel>(
+    "get",
+    baseUrlApi(`system/menu/${id}`)
+  );
 };
 
 export const addMenu = (data?: object) => {
-    return http.post<BasicResponseModel, any>(baseUrlApi(`system/menu`), {data});
+  return http.post<BasicResponseModel, any>(baseUrlApi(`system/menu`), {
+    data
+  });
 };
 
 export const updateMenu = (data?: object) => {
-    return http.put<BasicResponseModel, any>(baseUrlApi(`system/menu`), {data});
-}
+  return http.put<BasicResponseModel, any>(baseUrlApi(`system/menu`), { data });
+};
 
 export const deleteMenu = (id: number) => {
-    return http.request<BasicResponseModel>("delete", baseUrlApi(`system/menu/${id}`));
-}
+  return http.request<BasicResponseModel>(
+    "delete",
+    baseUrlApi(`system/menu/${id}`)
+  );
+};
 
 export const getSystemList = () => {
-    return http.request<BasicResponseModel>("get", baseUrlApi(`system/businessSystem/list`));
-}
+  return http.request<BasicResponseModel>(
+    "get",
+    baseUrlApi(`system/businessSystem/list`)
+  );
+};
 
 export interface DeptTreeModel<T = any> {
-    code: number;
-    msg: string;
-    depts: T,
-    checkedKeys: number[]
+  code: number;
+  msg: string;
+  depts: T;
+  checkedKeys: number[];
 }
 
 export const getMenuListTree = () => {
-    return http.request<BasicResponseModel>("get", baseUrlApi(`system/menu/treeselect`));
-}
+  return http.request<BasicResponseModel>(
+    "get",
+    baseUrlApi(`system/menu/treeselect`)
+  );
+};
 
-export const getMenuListTreeSelect = (id?: number) => {
-    return http.request<DeptTreeModel>("get", baseUrlApi(`system/menu/roleMenuTreeselect/${id}`));
-}
+export const getMenuListTreeSelect = (id?: string) => {
+  return http.request<DeptTreeModel>(
+    "get",
+    baseUrlApi(`system/menu/roleMenuTreeselect/${id}`)
+  );
+};

+ 58 - 30
src/api/system/role.ts

@@ -1,55 +1,83 @@
-import {http} from "@/utils/http";
-import {baseUrlApi} from "../utils";
+import { http } from "@/utils/http";
+import { baseUrlApi } from "../utils";
 
 export interface BasicResponseModel<T = any> {
-    code: number;
-    msg: string;
-    data: T;
+  code: number;
+  msg: string;
+  data: T;
 }
 
 export interface BasicPageResponseModel<T = any> {
-    code: number;
-    msg: string;
-    rows: T;
-    total: number;
+  code: number;
+  msg: string;
+  rows: T;
+  total: number;
 }
 
 export interface DeptTreeModel<T = any> {
-    code: number;
-    msg: string;
-    depts: T,
-    checkedKeys: number[]
+  code: number;
+  msg: string;
+  depts: T;
+  checkedKeys: number[];
 }
 
 export const getSystemRoleList = (query?: object) => {
-    return http.request<BasicPageResponseModel>("post", baseUrlApi("system/role/list"), {params: query});
+  return http.request<BasicPageResponseModel>(
+    "post",
+    baseUrlApi("system/role/list"),
+    { params: query }
+  );
 };
 
 export const changeRoleStatus = (roleId: number, status: string) => {
-    const data = {
-        roleId,
-        status
-    };
-    return http.request<BasicResponseModel>("put", baseUrlApi("system/role/changeStatus"), {data});
-}
+  const data = {
+    roleId,
+    status
+  };
+  return http.request<BasicResponseModel>(
+    "put",
+    baseUrlApi("system/role/changeStatus"),
+    { data }
+  );
+};
 
 export const getSystemRoleDeptTree = (id?: string) => {
-    return http.request<DeptTreeModel>("get", baseUrlApi(`system/role/deptTree/${id}`));
-}
+  return http.request<DeptTreeModel>(
+    "get",
+    baseUrlApi(`system/role/deptTree/${id}`)
+  );
+};
 
 export const addSystemRole = (data: object) => {
-    return http.request<BasicResponseModel>("post", baseUrlApi("system/role"), {data});
-}
+  return http.request<BasicResponseModel>("post", baseUrlApi("system/role"), {
+    data
+  });
+};
 
 export const updateSystemRole = (data: object) => {
-    return http.request<BasicResponseModel>("put", baseUrlApi("system/role"), {data});
-}
+  return http.request<BasicResponseModel>("put", baseUrlApi("system/role"), {
+    data
+  });
+};
 
 export const deleteSystemRole = (id: string) => {
-    return http.request<BasicResponseModel>("delete", baseUrlApi(`system/role/${id}`));
-}
+  return http.request<BasicResponseModel>(
+    "delete",
+    baseUrlApi(`system/role/${id}`)
+  );
+};
 
 export const getSystemRoleById = (id?: string) => {
-    return http.request<BasicResponseModel>("get", baseUrlApi(`system/role/${id}`));
-}
+  return http.request<BasicResponseModel>(
+    "get",
+    baseUrlApi(`system/role/${id}`)
+  );
+};
 
+export const putSystemRoleDataScope = (data: object) => {
+  return http.request<BasicResponseModel>(
+    "put",
+    baseUrlApi("system/role/dataScope"),
+    { data }
+  );
+};

+ 6 - 6
src/api/upload.ts

@@ -1,12 +1,12 @@
-import {http} from "@/utils/http";
-import {baseUrlApi} from "@/api/utils";
+import { http } from "@/utils/http";
+import { baseUrlApi } from "@/api/utils";
 
 type Result = {
-    msg: boolean;
-    data: any;
-    code: number;
+  msg: boolean;
+  data: any;
+  code: number;
 };
 
 export const getAliossToken = () => {
-    return http.request<Result>("post", baseUrlApi("/alioss/token"));
+  return http.request<Result>("post", baseUrlApi("/alioss/token"));
 };

+ 49 - 55
src/api/user.ts

@@ -1,94 +1,88 @@
-import {http} from "@/utils/http";
-import {baseUrlApi} from "./utils";
+import { http } from "@/utils/http";
+import { baseUrlApi } from "./utils";
 
 export interface BasicResponseModel<T = any> {
-    code: number;
-    msg: string;
-    data: T;
+  code: number;
+  msg: string;
+  data: T;
 }
 
 export type RefreshTokenResult = {
-    success: boolean;
-    data: {
-        /** `token` */
-        accessToken: string;
-        /** 用于调用刷新`accessToken`的接口时所需的`token` */
-        refreshToken: string;
-        /** `accessToken`的过期时间(格式'xxxx/xx/xx xx:xx:xx') */
-        expires: Date;
-    };
+  success: boolean;
+  data: {
+    /** `token` */
+    accessToken: string;
+    /** 用于调用刷新`accessToken`的接口时所需的`token` */
+    refreshToken: string;
+    /** `accessToken`的过期时间(格式'xxxx/xx/xx xx:xx:xx') */
+    expires: Date;
+  };
 };
 
 export type LoginNameResult = {
-    code: number;
-    msg: string;
-    data: boolean;
+  code: number;
+  msg: string;
+  data: boolean;
 };
 
 /** 登录姓名验证 */
 export const checkLoginNameApi = (data?: string) => {
-    return http.request<LoginNameResult>(
-        "post",
-        baseUrlApi(`adm/account/checkLoginName/${data}`)
-    );
+  return http.request<LoginNameResult>(
+    "post",
+    baseUrlApi(`adm/account/checkLoginName/${data}`)
+  );
 };
 
 export type VerificationCodeResult = {
-    code: number;
-    msg: string;
-    captchaEnabled: boolean;
-    uuid: string;
-    img: string;
+  code: number;
+  msg: string;
+  captchaEnabled: boolean;
+  uuid: string;
+  img: string;
 };
 
 /** 获取验证码 */
 export const getVerificationCode = (data?: object) => {
-    return http.request<VerificationCodeResult>(
-        "get",
-        baseUrlApi("code"),
-        {data}
-    );
+  return http.request<VerificationCodeResult>("get", baseUrlApi("code"), {
+    data
+  });
 };
 
 /** 获取短信验证码 */
 export const getVerifySmsApi = (data?: object) => {
-    return http.request<BasicResponseModel>(
-        "post",
-        baseUrlApi("adm/account/sendVerifySms"),
-        {data}
-    );
+  return http.request<BasicResponseModel>(
+    "post",
+    baseUrlApi("adm/account/sendVerifySms"),
+    { data }
+  );
 };
 
 export type UserResult = {
-    code: number;
-    msg: string;
-    data: {
-        access_token: string,
-        expires_in: number
-    };
+  code: number;
+  msg: string;
+  data: {
+    access_token: string;
+    expires_in: number;
+  };
 };
 
 /** 登录 */
 export const getLogin = (data?: object) => {
-    return http.request<UserResult>(
-        "post",
-        baseUrlApi("auth/login"),
-        {data}
-    );
+  return http.request<UserResult>("post", baseUrlApi("auth/login"), { data });
 };
 
 /** 登录 */
 export const verifySmsLogin = (data?: object) => {
-    return http.request<UserResult>(
-        "post",
-        baseUrlApi("adm/account/verifySmsLogin"),
-        {data}
-    );
+  return http.request<UserResult>(
+    "post",
+    baseUrlApi("adm/account/verifySmsLogin"),
+    { data }
+  );
 };
 
 /** 刷新`token` */
 export const refreshTokenApi = (data?: object) => {
-    return http.request<RefreshTokenResult>("post", baseUrlApi("refresh-token"), {
-        data
-    });
+  return http.request<RefreshTokenResult>("post", baseUrlApi("refresh-token"), {
+    data
+  });
 };

+ 158 - 160
src/views/login/index.vue

@@ -1,21 +1,21 @@
 <script setup lang="ts">
 // @ts-check
 import Motion from "./utils/motion";
-import {useRoute, useRouter} from "vue-router";
-import {message} from "@/utils/message";
-import {loginRules, smsRules} from "./utils/rule";
-import {onMounted, reactive, ref, toRaw} from "vue";
-import {debounce} from "@pureadmin/utils";
-import {useNav} from "@/layout/hooks/useNav";
-import {useEventListener} from "@vueuse/core";
-import type {FormInstance} from "element-plus";
-import {ElMessage} from "element-plus";
-import {useLayout} from "@/layout/hooks/useLayout";
-import {useUserStoreHook} from "@/store/modules/user";
-import {addPathMatch, getTopMenu, initRouter} from "@/router/utils";
-import {avatar, bg, illustration} from "./utils/static";
-import {useRenderIcon} from "@/components/ReIcon/src/hooks";
-import {useDataThemeChange} from "@/layout/hooks/useDataThemeChange";
+import { useRoute, useRouter } from "vue-router";
+import { message } from "@/utils/message";
+import { loginRules, smsRules } from "./utils/rule";
+import { onMounted, reactive, ref, toRaw } from "vue";
+import { debounce } from "@pureadmin/utils";
+import { useNav } from "@/layout/hooks/useNav";
+import { useEventListener } from "@vueuse/core";
+import type { FormInstance } from "element-plus";
+import { ElMessage } from "element-plus";
+import { useLayout } from "@/layout/hooks/useLayout";
+import { useUserStoreHook } from "@/store/modules/user";
+import { addPathMatch, getTopMenu, initRouter } from "@/router/utils";
+import { avatar, bg, illustration } from "./utils/static";
+import { useRenderIcon } from "@/components/ReIcon/src/hooks";
+import { useDataThemeChange } from "@/layout/hooks/useDataThemeChange";
 
 import dayIcon from "@/assets/svg/day.svg?component";
 import darkIcon from "@/assets/svg/dark.svg?component";
@@ -23,11 +23,11 @@ import Lock from "~icons/ri/lock-fill";
 import User from "~icons/ri/user-3-fill";
 import MaterialSymbolsLightDomainVerificationRounded from "~icons/material-symbols-light/domain-verification-rounded";
 import EpIphone from "~icons/ep/iphone";
-import {getVerificationCode, getVerifySmsApi} from "@/api/user";
-import {usePermissionStoreHook} from "@/store/modules/permission";
-import {AesEncode} from "@/utils/crypto";
-import {md5} from "js-md5";
-import {rule} from "postcss";
+import { getVerificationCode, getVerifySmsApi } from "@/api/user";
+import { usePermissionStoreHook } from "@/store/modules/permission";
+import { AesEncode } from "@/utils/crypto";
+import { md5 } from "js-md5";
+import { rule } from "postcss";
 
 defineOptions({
   name: "Login"
@@ -46,18 +46,18 @@ const sendInterval = ref();
 const countdown = ref<number>(60);
 const imgSrc = ref<string>(null);
 
-const {initStorage} = useLayout();
+const { initStorage } = useLayout();
 initStorage();
 
-const {dataTheme, overallStyle, dataThemeChange} = useDataThemeChange();
+const { dataTheme, overallStyle, dataThemeChange } = useDataThemeChange();
 dataThemeChange(overallStyle.value);
-const {title} = useNav();
+const { title } = useNav();
 
 const ruleForm = reactive({
   username: "admin",
   password: "admin123",
   code: "",
-  uuid: "",
+  uuid: ""
 });
 
 const smsRuleForm = reactive({
@@ -87,28 +87,26 @@ const getVerifySmsCode = () => {
     username: ruleForm.username,
     password: ruleForm.password
   })
-      .then(() => {
-        sendInterval.value = setInterval(function () {
-          if (countdown.value === 0) {
-            clearInterval(sendInterval.value);
-            sendVerifySmsCodeText.value = "点击发送验证码";
-            canSendSecond.value = true;
-            countdown.value = 60;
-            sendInterval.value = null;
-          } else {
-            countdown.value = countdown.value - 1;
-            sendVerifySmsCodeText.value = `${countdown.value}秒后重试`;
-          }
-        }, 1000);
-      })
-      .catch(() => {
-        canSendSecond.value = true;
-      });
+    .then(() => {
+      sendInterval.value = setInterval(function () {
+        if (countdown.value === 0) {
+          clearInterval(sendInterval.value);
+          sendVerifySmsCodeText.value = "点击发送验证码";
+          canSendSecond.value = true;
+          countdown.value = 60;
+          sendInterval.value = null;
+        } else {
+          countdown.value = countdown.value - 1;
+          sendVerifySmsCodeText.value = `${countdown.value}秒后重试`;
+        }
+      }, 1000);
+    })
+    .catch(() => {
+      canSendSecond.value = true;
+    });
 };
 
-const onLogin = async (
-    formEl: FormInstance | undefined,
-) => {
+const onLogin = async (formEl: FormInstance | undefined) => {
   if (!formEl) return;
   const submitType = showVerifySms.value ? 2 : 1;
   // 1普通登录 2短信登录
@@ -120,13 +118,13 @@ const onLogin = async (
         ...ruleForm
       };
       useUserStoreHook()
-          .loginByUsername(params, submitType)
-          .then(res => {
-            console.log(res);
-            let {code, msg} = res;
-            if (code === 200 || code === 3) {
-              // 存储输入信息
-              /*const { storageExpires } = commonSetting;
+        .loginByUsername(params, submitType)
+        .then(res => {
+          console.log(res);
+          let { code, msg } = res;
+          if (code === 200 || code === 3) {
+            // 存储输入信息
+            /*const { storageExpires } = commonSetting;
               if (formData.agree) {
                 storage.setCookie(
                   "loginRemember",
@@ -150,77 +148,77 @@ const onLogin = async (
                   storageExpires * 24 * 60 * 60
                 );
               }*/
-              message("登录成功,即将进入系统", {
-                type: "success",
-                duration: 1000,
-                onClose() {
-                  if (code === 3) {
-                    ElMessage.warning(
-                        "为了保障您的账号信息安全,请修改登录密码,需包含8位数字、字母、特殊字符"
-                    );
-                    // 去修改密码页
-                    router.replace("/system/pwd_reset");
-                  } else {
-                    const toPath = decodeURIComponent(
-                        (route.query?.redirect || "/") as string
-                    );
-                    console.log(route.name);
-                    if (route.name === "Login") {
-                      initRouter().then(() => {
-                        router.push(getTopMenu(true).path);
-                      });
-                      // 全部采取静态路由模式
-                      /*usePermissionStoreHook().handleWholeMenus([]);
+            message("登录成功,即将进入系统", {
+              type: "success",
+              duration: 1000,
+              onClose() {
+                if (code === 3) {
+                  ElMessage.warning(
+                    "为了保障您的账号信息安全,请修改登录密码,需包含8位数字、字母、特殊字符"
+                  );
+                  // 去修改密码页
+                  router.replace("/system/pwd_reset");
+                } else {
+                  const toPath = decodeURIComponent(
+                    (route.query?.redirect || "/") as string
+                  );
+                  console.log(route.name);
+                  if (route.name === "Login") {
+                    initRouter().then(() => {
+                      router.push(getTopMenu(true).path);
+                    });
+                    // 全部采取静态路由模式
+                    /*usePermissionStoreHook().handleWholeMenus([]);
                       addPathMatch();
                       router.push(getTopMenu(true).path);*/
-                    } else router.replace(toPath);
-                  }
+                  } else router.replace(toPath);
                 }
-              });
-              return;
-            }
-
-            if (submitType === 1) {
-              // 普通登录
-              if (
-                  msg === "短信锁已过期" ||
-                  msg === "不是常用IP登录" ||
-                  msg === "上次登录时间超过7天" ||
-                  msg === "错误次数超过3次"
-              ) {
-                showVerifySms.value = true;
-                canSendSecond.value = true;
-              } else {
-                ElMessage.warning(msg);
-                getVerifyCode();
               }
+            });
+            return;
+          }
+
+          if (submitType === 1) {
+            // 普通登录
+            if (
+              msg === "短信锁已过期" ||
+              msg === "不是常用IP登录" ||
+              msg === "上次登录时间超过7天" ||
+              msg === "错误次数超过3次"
+            ) {
+              showVerifySms.value = true;
+              canSendSecond.value = true;
             } else {
-              // sms登录
               ElMessage.warning(msg);
               getVerifyCode();
-              showVerifySms.value = false;
             }
-          })
-          .catch((e) => {
-            ElMessage.error('登录失败');
+          } else {
+            // sms登录
+            ElMessage.warning(msg);
             getVerifyCode();
-          })
-          .finally(() => (loading.value = false));
+            showVerifySms.value = false;
+          }
+        })
+        .catch(e => {
+          ElMessage.error("登录失败");
+          getVerifyCode();
+        })
+        .finally(() => (loading.value = false));
     }
   });
 };
 
 const immediateDebounce: any = debounce(
-    formRef => onLogin(formRef),
-    1000,
-    true
+  formRef => onLogin(formRef),
+  1000,
+  true
 );
 
-useEventListener(document, "keydown", ({code}) => {
+useEventListener(document, "keydown", ({ code }) => {
   if (
-      ["Enter", "NumpadEnter"].includes(code) &&
-      !disabled.value &&
-      !loading.value
+    ["Enter", "NumpadEnter"].includes(code) &&
+    !disabled.value &&
+    !loading.value
   )
     immediateDebounce(ruleFormRef.value);
 });
@@ -232,42 +230,42 @@ onMounted(() => {
 
 <template>
   <div class="select-none">
-    <img :src="bg" class="wave"/>
+    <img :src="bg" class="wave" />
     <div class="flex-c absolute right-5 top-3">
       <!-- 主题 -->
       <el-switch
-          v-model="dataTheme"
-          inline-prompt
-          :active-icon="dayIcon"
-          :inactive-icon="darkIcon"
-          @change="dataThemeChange"
+        v-model="dataTheme"
+        inline-prompt
+        :active-icon="dayIcon"
+        :inactive-icon="darkIcon"
+        @change="dataThemeChange"
       />
     </div>
     <div class="login-container">
       <div class="img">
-        <component :is="toRaw(illustration)"/>
+        <component :is="toRaw(illustration)" />
       </div>
       <div class="login-box">
         <div class="login-form">
-          <avatar class="avatar"/>
+          <avatar class="avatar" />
           <Motion>
             <h2 class="outline-hidden">{{ title }}</h2>
           </Motion>
 
           <el-form
-              v-show="!showVerifySms"
-              ref="ruleFormRef"
-              :model="ruleForm"
-              :rules="loginRules"
-              size="large"
+            v-show="!showVerifySms"
+            ref="ruleFormRef"
+            :model="ruleForm"
+            :rules="loginRules"
+            size="large"
           >
             <Motion :delay="100">
               <el-form-item prop="username">
                 <el-input
-                    v-model="ruleForm.username"
-                    clearable
-                    placeholder="账号"
-                    :prefix-icon="useRenderIcon(User)"
+                  v-model="ruleForm.username"
+                  clearable
+                  placeholder="账号"
+                  :prefix-icon="useRenderIcon(User)"
                 />
               </el-form-item>
             </Motion>
@@ -275,11 +273,11 @@ onMounted(() => {
             <Motion :delay="150">
               <el-form-item prop="password">
                 <el-input
-                    v-model="ruleForm.password"
-                    clearable
-                    show-password
-                    placeholder="密码"
-                    :prefix-icon="useRenderIcon(Lock)"
+                  v-model="ruleForm.password"
+                  clearable
+                  show-password
+                  placeholder="密码"
+                  :prefix-icon="useRenderIcon(Lock)"
                 />
               </el-form-item>
             </Motion>
@@ -289,9 +287,9 @@ onMounted(() => {
                 <el-row class="w-full">
                   <el-col :span="17">
                     <el-input
-                        v-model="ruleForm.code"
-                        clearable
-                        :prefix-icon="
+                      v-model="ruleForm.code"
+                      clearable
+                      :prefix-icon="
                         useRenderIcon(
                           MaterialSymbolsLightDomainVerificationRounded
                         )
@@ -300,15 +298,15 @@ onMounted(() => {
                   </el-col>
                   <el-col :span="6" :offset="1">
                     <div
-                        v-optimize="{
+                      v-optimize="{
                         event: 'click',
                         fn: getVerifyCode,
                         immediate: true,
                         timeout: 1000
                       }"
-                        class="verify-code"
+                      class="verify-code"
                     >
-                      <img class="w-full! h-full!" :src="imgSrc" alt="">
+                      <img class="w-full! h-full!" :src="imgSrc" alt="" />
                     </div>
                   </el-col>
                 </el-row>
@@ -325,12 +323,12 @@ onMounted(() => {
 
             <Motion :delay="300">
               <el-button
-                  class="w-full"
-                  size="default"
-                  type="primary"
-                  :loading="loading"
-                  :disabled="disabled"
-                  @click="onLogin(ruleFormRef)"
+                class="w-full"
+                size="default"
+                type="primary"
+                :loading="loading"
+                :disabled="disabled"
+                @click="onLogin(ruleFormRef)"
               >
                 登录
               </el-button>
@@ -339,36 +337,36 @@ onMounted(() => {
 
           <!-- 短信验证码表单 -->
           <el-form
-              v-show="showVerifySms"
-              ref="smsFormRef"
-              :model="smsRuleForm"
-              :rules="smsRules"
-              size="large"
-              @submit.prevent
+            v-show="showVerifySms"
+            ref="smsFormRef"
+            :model="smsRuleForm"
+            :rules="smsRules"
+            size="large"
+            @submit.prevent
           >
             <Motion :delay="100">
               <el-form-item prop="username">
                 <el-row class="w-full">
                   <el-col :span="15">
                     <el-input
-                        v-model="smsRuleForm.verifySmsCode"
-                        clearable
-                        placeholder="请输入验证码"
-                        :prefix-icon="useRenderIcon(EpIphone)"
+                      v-model="smsRuleForm.verifySmsCode"
+                      clearable
+                      placeholder="请输入验证码"
+                      :prefix-icon="useRenderIcon(EpIphone)"
                     />
                   </el-col>
                   <el-col :span="8" :offset="1">
                     <el-button
-                        v-optimize="{
+                      v-optimize="{
                         event: 'click',
                         fn: getVerifySmsCode,
                         immediate: true,
                         timeout: 1000
                       }"
-                        class="w-full"
-                        type="primary"
-                        :disabled="!canSendSecond"
-                    >{{ sendVerifySmsCodeText }}
+                      class="w-full"
+                      type="primary"
+                      :disabled="!canSendSecond"
+                      >{{ sendVerifySmsCodeText }}
                     </el-button>
                   </el-col>
                 </el-row>
@@ -385,12 +383,12 @@ onMounted(() => {
 
             <Motion :delay="200">
               <el-button
-                  class="w-full"
-                  size="default"
-                  type="primary"
-                  :loading="loading"
-                  :disabled="disabled"
-                  @click="onLogin(smsFormRef)"
+                class="w-full"
+                size="default"
+                type="primary"
+                :loading="loading"
+                :disabled="disabled"
+                @click="onLogin(smsFormRef)"
               >
                 登录
               </el-button>

+ 245 - 223
src/views/system/menu/index.vue

@@ -1,46 +1,64 @@
 <template>
   <div>
     <PlusPage
-        ref="plusPageInstance"
-        :columns="tableConfig"
-        :request="getList"
-        :before-search-submit="handleBeforeSearch"
-        :is-card="true"
-        :search="{
-          labelWidth: 100,
-          showNumber: 3
-        }"
-        :table="{
-          actionBar: { buttons, type: 'link', width: 140 },
-          adaptive: { offsetBottom: 50 },
-          treeProps: { children: 'children' },
-          rowKey: 'menuId'
-        }"
-        :pagination="false"
+      ref="plusPageInstance"
+      :columns="tableConfig"
+      :request="getList"
+      :before-search-submit="handleBeforeSearch"
+      :is-card="true"
+      :search="{
+        labelWidth: 100,
+        showNumber: 3
+      }"
+      :table="{
+        actionBar: { buttons, type: 'link', width: 140 },
+        adaptive: { offsetBottom: 50 },
+        treeProps: { children: 'children' },
+        rowKey: 'menuId'
+      }"
+      :pagination="false"
     >
       <template #table-title>
         <el-row class="button-row">
-          <el-button size="default" type="success" @click="handleCreate">新增</el-button>
+          <el-button size="default" type="success" @click="handleCreate"
+            >新增</el-button
+          >
         </el-row>
       </template>
     </PlusPage>
     <!-- 弹窗编辑 -->
     <PlusDialogForm
-        ref="dialogForm"
-        v-model="form"
-        v-model:visible="dialogVisible"
-        @confirm="handleSubmit"
-        @close="handleClose"
-        :form="{ columns, labelPosition: 'right',labelWidth: 100, rules, rowProps: {gutter: 20}, colProps: {span: 12} }"
-        :dialog="{ title: dialogTitle + '菜单', width: 800, confirmLoading }"
+      ref="dialogForm"
+      v-model="form"
+      v-model:visible="dialogVisible"
+      :form="{
+        columns,
+        labelPosition: 'right',
+        labelWidth: 100,
+        rules,
+        rowProps: { gutter: 20 },
+        colProps: { span: 12 }
+      }"
+      :dialog="{ title: dialogTitle + '菜单', width: 800, confirmLoading }"
+      @confirm="handleSubmit"
+      @close="handleClose"
     />
   </div>
 </template>
 
 <script lang="ts" setup>
-import {computed, defineOptions, h, nextTick, onMounted, reactive, ref, toRefs} from "vue";
-import type {FormRules} from 'element-plus'
-import {ElMessage} from "element-plus";
+import {
+  computed,
+  defineOptions,
+  h,
+  nextTick,
+  onMounted,
+  reactive,
+  ref,
+  toRefs
+} from "vue";
+import type { FormRules } from "element-plus";
+import { ElMessage } from "element-plus";
 import {
   type FieldValues,
   type PlusColumn,
@@ -49,7 +67,7 @@ import {
   PlusPageInstance,
   useTable
 } from "plus-pro-components";
-import {cloneDeep} from "lodash-es";
+import { cloneDeep } from "lodash-es";
 import {
   addMenu,
   deleteMenu,
@@ -72,13 +90,12 @@ interface TableRow {
 }
 
 onMounted(async () => {
-  await getSystem()
-})
-
+  await getSystem();
+});
 
 // 菜单列表
 const menuList = ref([]);
-const plusPageInstance = ref<PlusPageInstance | null>(null)
+const plusPageInstance = ref<PlusPageInstance | null>(null);
 
 const getList = async (query: Record<string, any>) => {
   let res = await getSystemMenuList(query);
@@ -86,8 +103,8 @@ const getList = async (query: Record<string, any>) => {
   menuList.value = list;
   return {
     data: list,
-    total: list.length,
-  }
+    total: list.length
+  };
 };
 
 const listToTree = (data: object[]) => {
@@ -111,12 +128,12 @@ const listToTree = (data: object[]) => {
     }
   });
   return parentList;
-}
+};
 
 // 重新请求列表接口
 const refresh = () => {
-  plusPageInstance.value?.getList()
-}
+  plusPageInstance.value?.getList();
+};
 
 // 搜索之前函数
 const handleBeforeSearch = (values: any) => {
@@ -124,9 +141,9 @@ const handleBeforeSearch = (values: any) => {
   return cloneDeep(values);
 };
 
-const dialogTitle = computed(() => (state.isCreate ? '新增' : '编辑'))
+const dialogTitle = computed(() => (state.isCreate ? "新增" : "编辑"));
 
-const {buttons} = useTable<TableRow[]>();
+const { buttons } = useTable<TableRow[]>();
 
 const systemList = ref([]);
 
@@ -136,8 +153,8 @@ const getSystem = async () => {
   systemList.value = res.data.map((item: any) => ({
     label: item.sysName,
     value: item.sysCode
-  }))
-}
+  }));
+};
 
 // 表格数据
 const tableConfig: PlusColumn[] = [
@@ -147,7 +164,7 @@ const tableConfig: PlusColumn[] = [
     width: 180,
     tableColumnProps: {
       showOverflowTooltip: true
-    },
+    }
   },
   {
     label: "图标",
@@ -155,13 +172,11 @@ const tableConfig: PlusColumn[] = [
     hideInSearch: true,
     width: 80,
     // 返回一个组件
-    render: (value) =>
-        h('i',
-            {
-              class: `${value} iconfont`,
-              style: {fontSize: '16px'}
-            },
-        )
+    render: value =>
+      h("i", {
+        class: `${value} iconfont`,
+        style: { fontSize: "16px" }
+      })
   },
   {
     label: "排序",
@@ -190,10 +205,10 @@ const tableConfig: PlusColumn[] = [
     valueType: "tag",
     hideInSearch: true,
     fieldProps: value => ({
-      type: value === '0' ? 'primary' : 'danger'
+      type: value === "0" ? "primary" : "danger"
     }),
     fieldSlots: {
-      default: ({value}) => (value === '0' ? '正常' : '停用')
+      default: ({ value }) => (value === "0" ? "正常" : "停用")
     }
   },
   {
@@ -204,20 +219,23 @@ const tableConfig: PlusColumn[] = [
     hideInTable: true,
     fieldProps: {
       clearable: true,
-      placeholder: '请选择系统',
-      style: {width: '100%'}
+      placeholder: "请选择系统",
+      style: { width: "100%" }
     }
   },
   {
     label: "菜单状态",
     prop: "status",
     valueType: "select",
-    options: [{label: '正常', value: '0'}, {label: '停用', value: '1'}],
+    options: [
+      { label: "正常", value: "0" },
+      { label: "停用", value: "1" }
+    ],
     hideInTable: true,
     fieldProps: {
       clearable: true,
-      placeholder: '请选择菜单状态',
-      style: {width: '100%'}
+      placeholder: "请选择菜单状态",
+      style: { width: "100%" }
     }
   },
   {
@@ -241,23 +259,23 @@ interface State {
   selectedIds: number[];
   isCreate: boolean;
   form: {
-    component: string, // 组件路径
-    icon: string, // 菜单图标
-    isCache: string, // 是否缓存 (0缓存 1不缓存)
-    isFrame: string, // 是否外链 (0是 1否)
-    menuName: string,// 菜单名称
-    menuType: string, // 菜单类型(M目录 C菜单 F按钮)
-    orderNum: string,// 显示排序
-    parentId: number,// 上级菜单
-    path: string, // 路由地址
-    perms: string, // 权限标识
-    query: string, // 路由参数
-    routeName: string, // 路由名称
-    status: string, // 菜单状态(0正常 1停用)
-    systemCode: string, // 系统编码
-    url: string, // 网关URL
-    urlmatch: string, // 网关权限
-    visible: string, // 显示状态(0显示 1隐藏)
+    component: string; // 组件路径
+    icon: string; // 菜单图标
+    isCache: string; // 是否缓存 (0缓存 1不缓存)
+    isFrame: string; // 是否外链 (0是 1否)
+    menuName: string; // 菜单名称
+    menuType: string; // 菜单类型(M目录 C菜单 F按钮)
+    orderNum: string; // 显示排序
+    parentId: number; // 上级菜单
+    path: string; // 路由地址
+    perms: string; // 权限标识
+    query: string; // 路由参数
+    routeName: string; // 路由名称
+    status: string; // 菜单状态(0正常 1停用)
+    systemCode: string; // 系统编码
+    url: string; // 网关URL
+    urlmatch: string; // 网关权限
+    visible: string; // 显示状态(0显示 1隐藏)
   };
   rules: FormRules;
 }
@@ -271,301 +289,305 @@ const state = reactive<State>({
   form: {
     component: null, // 组件路径
     icon: null, // 菜单图标
-    isCache: '0', // 是否缓存 (0缓存 1不缓存)
-    isFrame: '1', // 是否外链 (0是 1否)
-    menuName: null,// 菜单名称
-    menuType: 'M', // 菜单类型(M目录 C菜单 F按钮)
-    orderNum: null,// 显示排序
-    parentId: 0,// 上级菜单
+    isCache: "0", // 是否缓存 (0缓存 1不缓存)
+    isFrame: "1", // 是否外链 (0是 1否)
+    menuName: null, // 菜单名称
+    menuType: "M", // 菜单类型(M目录 C菜单 F按钮)
+    orderNum: null, // 显示排序
+    parentId: 0, // 上级菜单
     path: null, // 路由地址
     perms: null, // 权限标识
     query: null, // 路由参数
     routeName: null, // 路由名称
-    status: '0', // 菜单状态(0正常 1停用)
+    status: "0", // 菜单状态(0正常 1停用)
     systemCode: null, // 系统编码
     url: null, // 网关URL
     urlmatch: null, // 网关权限
-    visible: '0', // 显示状态(0显示 1隐藏)
+    visible: "0" // 显示状态(0显示 1隐藏)
   },
   rules: {
-    parentId: [{required: true, message: '请选择上级菜单', trigger: 'blur'}],
-    orderNum: [{required: true, message: '请输入排序', trigger: 'blur'}],
-    menuName: [{required: true, message: '请输入菜单名称', trigger: 'blur'}],
-    path: [{required: true, message: '请输入路由地址', trigger: 'blur'}],
+    parentId: [{ required: true, message: "请选择上级菜单", trigger: "blur" }],
+    orderNum: [{ required: true, message: "请输入排序", trigger: "blur" }],
+    menuName: [{ required: true, message: "请输入菜单名称", trigger: "blur" }],
+    path: [{ required: true, message: "请输入路由地址", trigger: "blur" }]
   }
-})
+});
 
 const columns: PlusColumn[] = [
   {
-    label: '上级菜单',
-    prop: 'parentId',
-    colProps: {span: 24},
-    valueType: 'tree-select',
+    label: "上级菜单",
+    prop: "parentId",
+    colProps: { span: 24 },
+    valueType: "tree-select",
     fieldProps: {
-      placeholder: '请选择上级菜单',
+      placeholder: "请选择上级菜单",
       clearable: true,
       showSearch: true,
       checkStrictly: true,
       defaultExpandAll: false,
-      style: {width: '100%'},
+      style: { width: "100%" },
       data: computed(() => {
-        return [{menuId: 0, menuName: '主类目', children: [...menuList.value]},]
+        return [
+          { menuId: 0, menuName: "主类目", children: [...menuList.value] }
+        ];
       }),
       // el-tree-select 组件属性
       props: {
-        label: 'menuName',
-        value: 'menuId',
-        children: 'children'
+        label: "menuName",
+        value: "menuId",
+        children: "children"
       }
     }
   },
   {
     label: "系统编码",
     prop: "systemCode",
-    valueType: 'input',
-    colProps: {span: 24},
+    valueType: "input",
+    colProps: { span: 24 },
     fieldProps: {
-      placeholder: '请输入系统编码',
+      placeholder: "请输入系统编码",
       clearable: true
     }
   },
   {
     label: "菜单类型",
     prop: "menuType",
-    valueType: 'radio',
-    colProps: {span: 24},
+    valueType: "radio",
+    colProps: { span: 24 },
     fieldProps: {
-      placeholder: '请选择菜单类型',
+      placeholder: "请选择菜单类型",
       clearable: true,
       options: [
-        {label: '目录', value: 'M'},
-        {label: '菜单', value: 'C'},
-        {label: '按钮', value: 'F'}
-      ],
-    },
+        { label: "目录", value: "M" },
+        { label: "菜单", value: "C" },
+        { label: "按钮", value: "F" }
+      ]
+    }
   },
   {
     label: "菜单图标",
     prop: "icon",
-    valueType: 'input',
-    colProps: {span: 12},
+    valueType: "input",
+    colProps: { span: 12 },
     fieldProps: {
-      placeholder: '请输入菜单图标',
-      clearable: true,
+      placeholder: "请输入菜单图标",
+      clearable: true
     },
-    hideInForm: computed(() => form.value.menuType === 'F')
+    hideInForm: computed(() => form.value.menuType === "F")
   },
   {
     label: "显示排序",
     prop: "orderNum",
-    valueType: 'input-number',
-    colProps: {span: 12},
+    valueType: "input-number",
+    colProps: { span: 12 },
     fieldProps: {
-      placeholder: '请输入显示排序',
-      style: {width: '100%'},
+      placeholder: "请输入显示排序",
+      style: { width: "100%" },
       min: 0
     }
   },
   {
     label: "菜单名称",
     prop: "menuName",
-    colProps: {span: 12},
+    colProps: { span: 12 },
     fieldProps: {
-      placeholder: '请输入菜单名称',
+      placeholder: "请输入菜单名称",
       clearable: true
     }
   },
   {
     label: "路由名称",
     prop: "routeName",
-    colProps: {span: 12},
+    colProps: { span: 12 },
     fieldProps: {
-      placeholder: '请输入路由名称',
+      placeholder: "请输入路由名称",
       clearable: true
     },
-    hideInForm: computed(() => form.value.menuType !== 'C')
+    hideInForm: computed(() => form.value.menuType !== "C")
   },
   {
     label: "是否外链",
     prop: "isFrame",
-    valueType: 'radio',
-    colProps: {span: 12},
+    valueType: "radio",
+    colProps: { span: 12 },
     fieldProps: {
       options: [
-        {label: '是', value: '0'},
-        {label: '否', value: '1'}
+        { label: "是", value: "0" },
+        { label: "否", value: "1" }
       ]
     },
-    tooltip: '选择是外链则路由地址需要以`http(s)://`开头',
-    hideInForm: computed(() => form.value.menuType === 'F')
+    tooltip: "选择是外链则路由地址需要以`http(s)://`开头",
+    hideInForm: computed(() => form.value.menuType === "F")
   },
   {
     label: "路由地址",
     prop: "path",
-    colProps: {span: 12},
+    colProps: { span: 12 },
     fieldProps: {
-      placeholder: '请输入路由地址',
+      placeholder: "请输入路由地址",
       clearable: true
     },
-    tooltip: "访问的路由地址,如:`role`,如外网地址需内链访问则以`http(s)://`开头",
-    hideInForm: computed(() => form.value.menuType === 'F')
+    tooltip:
+      "访问的路由地址,如:`role`,如外网地址需内链访问则以`http(s)://`开头",
+    hideInForm: computed(() => form.value.menuType === "F")
   },
   {
     label: "组件路径",
     prop: "component",
-    colProps: {span: 12},
+    colProps: { span: 12 },
     fieldProps: {
-      placeholder: '请输入组件路径',
+      placeholder: "请输入组件路径",
       clearable: true
     },
     tooltip: "访问的组件路径,如:`system/role/index`,默认在`views`目录下",
-    hideInForm: computed(() => form.value.menuType !== 'C')
+    hideInForm: computed(() => form.value.menuType !== "C")
   },
   {
     label: "权限字符",
     prop: "perms",
-    colProps: {span: 12},
+    colProps: { span: 12 },
     fieldProps: {
-      placeholder: '请输入权限标识',
+      placeholder: "请输入权限标识",
       clearable: true
     },
-    tooltip: "控制器中定义的权限字符,如:@PreAuthorize(`@ss.hasPermi('system:role:list')`)",
-    hideInForm: computed(() => form.value.menuType === 'M')
+    tooltip:
+      "控制器中定义的权限字符,如:@PreAuthorize(`@ss.hasPermi('system:role:list')`)",
+    hideInForm: computed(() => form.value.menuType === "M")
   },
   {
     label: "网关URL",
     prop: "url",
-    colProps: {span: 12},
+    colProps: { span: 12 },
     fieldProps: {
-      placeholder: '请输入URL',
+      placeholder: "请输入URL",
       clearable: true
-    },
+    }
   },
   {
     label: "网关权限",
     prop: "urlmatch",
-    colProps: {span: 12},
+    colProps: { span: 12 },
     fieldProps: {
-      placeholder: '请输入网关权限标识',
+      placeholder: "请输入网关权限标识",
       clearable: true
     },
-    tooltip: "控制器中定义的权限字符",
+    tooltip: "控制器中定义的权限字符"
   },
   {
     label: "路由参数",
     prop: "query",
-    colProps: {span: 12},
+    colProps: { span: 12 },
     fieldProps: {
-      placeholder: '请输入路由参数',
+      placeholder: "请输入路由参数",
       clearable: true
     },
-    tooltip: "访问路由的默认传递参数,如:`{\"id\": 1, \"name\": \"ry\"}`",
-    hideInForm: computed(() => form.value.menuType !== 'C')
+    tooltip: '访问路由的默认传递参数,如:`{"id": 1, "name": "ry"}`',
+    hideInForm: computed(() => form.value.menuType !== "C")
   },
   {
     label: "是否缓存",
     prop: "isCache",
-    valueType: 'radio',
-    colProps: {span: 12},
+    valueType: "radio",
+    colProps: { span: 12 },
     fieldProps: {
       options: [
-        {label: '是', value: '0'},
-        {label: '否', value: '1'}
+        { label: "是", value: "0" },
+        { label: "否", value: "1" }
       ]
     },
     tooltip: "选择是则会被`keep-alive`缓存,需要匹配组件的`name`和地址保持一致",
-    hideInForm: computed(() => form.value.menuType !== 'C')
+    hideInForm: computed(() => form.value.menuType !== "C")
   },
   {
     label: "显示状态",
     prop: "visible",
-    valueType: 'radio',
-    colProps: {span: 12},
+    valueType: "radio",
+    colProps: { span: 12 },
     fieldProps: {
       options: [
-        {label: '显示', value: '0'},
-        {label: '隐藏', value: '1'}
+        { label: "显示", value: "0" },
+        { label: "隐藏", value: "1" }
       ]
     },
     tooltip: "选择隐藏则路由将不会出现在侧边栏,但仍然可以访问",
-    hideInForm: computed(() => form.value.menuType === 'F')
+    hideInForm: computed(() => form.value.menuType === "F")
   },
   {
     label: "菜单状态",
     prop: "status",
-    valueType: 'radio',
-    colProps: {span: 12},
+    valueType: "radio",
+    colProps: { span: 12 },
     fieldProps: {
       options: [
-        {label: '正常', value: '0'},
-        {label: '停用', value: '1'}
+        { label: "正常", value: "0" },
+        { label: "停用", value: "1" }
       ]
     },
     tooltip: "选择停用则路由将不会出现在侧边栏,也不能被访问"
-  },
-]
+  }
+];
 
 // 创建
 const handleCreate = (): void => {
   form.value = {
     component: null, // 组件路径
     icon: null, // 菜单图标
-    isCache: '0', // 是否缓存 (0缓存 1不缓存)
-    isFrame: '1', // 是否外链 (0是 1否)
-    menuName: null,// 菜单名称
-    menuType: 'M', // 菜单类型(M目录 C菜单 F按钮)
-    orderNum: null,// 显示排序
-    parentId: 0,// 上级菜单
+    isCache: "0", // 是否缓存 (0缓存 1不缓存)
+    isFrame: "1", // 是否外链 (0是 1否)
+    menuName: null, // 菜单名称
+    menuType: "M", // 菜单类型(M目录 C菜单 F按钮)
+    orderNum: null, // 显示排序
+    parentId: 0, // 上级菜单
     path: null, // 路由地址
     perms: null, // 权限标识
     query: null, // 路由参数
     routeName: null, // 路由名称
-    status: '0', // 菜单状态(0正常 1停用)
+    status: "0", // 菜单状态(0正常 1停用)
     systemCode: null, // 系统编码
     url: null, // 网关URL
     urlmatch: null, // 网关权限
-    visible: '0', // 显示状态(0显示 1隐藏)
-  }
-  state.isCreate = true
-  state.dialogVisible = true
-}
+    visible: "0" // 显示状态(0显示 1隐藏)
+  };
+  state.isCreate = true;
+  state.dialogVisible = true;
+};
 
 const handleSubmit = async (values: FieldValues) => {
-  console.log(values, 'Submit')
-  confirmLoading.value = true
+  console.log(values, "Submit");
+  confirmLoading.value = true;
   if (state.isCreate) {
     try {
-      let params = form.value
-      let res = await addMenu(params)
+      let params = form.value;
+      let res = await addMenu(params);
       if (res.code === 200) {
-        ElMessage.success('新增成功')
-        confirmLoading.value = false
-        dialogVisible.value = false
-        refresh()
+        ElMessage.success("新增成功");
+        confirmLoading.value = false;
+        dialogVisible.value = false;
+        refresh();
       } else {
-        ElMessage.error(res.msg)
+        ElMessage.error(res.msg);
       }
     } finally {
-      confirmLoading.value = false
+      confirmLoading.value = false;
     }
   } else {
     // 编辑
     try {
-      let params = form.value
-      let res = await updateMenu(params)
+      let params = form.value;
+      let res = await updateMenu(params);
       if (res.code === 200) {
-        ElMessage.success('修改成功')
-        confirmLoading.value = false
-        dialogVisible.value = false
-        refresh()
+        ElMessage.success("修改成功");
+        confirmLoading.value = false;
+        dialogVisible.value = false;
+        refresh();
       } else {
-        ElMessage.error(res.msg)
+        ElMessage.error(res.msg);
       }
     } finally {
-      confirmLoading.value = false
+      confirmLoading.value = false;
     }
   }
-}
+};
 
 const handleClose = () => {
   /*// 重置表单
@@ -574,8 +596,8 @@ const handleClose = () => {
       dialogForm.value.formInstance.resetFields()
     }
   })*/
-  console.log(dialogForm.value.formInstance)
-}
+  console.log(dialogForm.value.formInstance);
+};
 
 buttons.value = [
   {
@@ -588,11 +610,11 @@ buttons.value = [
     },
     onClick(params) {
       getSystemMenuDetailById(params.row.menuId).then(res => {
-        form.value = res.data
-        state.isCreate = false
-        state.dialogVisible = true
-      })
-    },
+        form.value = res.data;
+        state.isCreate = false;
+        state.dialogVisible = true;
+      });
+    }
   },
   {
     // 新增
@@ -602,57 +624,57 @@ buttons.value = [
       type: "success"
     },
     onClick(params) {
-      console.log("新增", params)
+      console.log("新增", params);
       form.value = {
         component: null, // 组件路径
         icon: null, // 菜单图标
-        isCache: '0', // 是否缓存 (0缓存 1不缓存)
-        isFrame: '1', // 是否外链 (0是 1否)
-        menuName: null,// 菜单名称
-        menuType: 'M', // 菜单类型(M目录 C菜单 F按钮)
-        orderNum: null,// 显示排序
-        parentId: params.row.menuId,// 上级菜单
+        isCache: "0", // 是否缓存 (0缓存 1不缓存)
+        isFrame: "1", // 是否外链 (0是 1否)
+        menuName: null, // 菜单名称
+        menuType: "M", // 菜单类型(M目录 C菜单 F按钮)
+        orderNum: null, // 显示排序
+        parentId: params.row.menuId, // 上级菜单
         path: null, // 路由地址
         perms: null, // 权限标识
         query: null, // 路由参数
         routeName: null, // 路由名称
-        status: '0', // 菜单状态(0正常 1停用)
+        status: "0", // 菜单状态(0正常 1停用)
         systemCode: null, // 系统编码
         url: null, // 网关URL
         urlmatch: null, // 网关权限
-        visible: '0', // 显示状态(0显示 1隐藏)
-      }
-      state.isCreate = true
-      state.dialogVisible = true
-    },
+        visible: "0" // 显示状态(0显示 1隐藏)
+      };
+      state.isCreate = true;
+      state.dialogVisible = true;
+    }
   },
   {
     // 删除
     text: "删除",
     code: "delete",
     // props v0.1.16 版本新增计算属性支持
-    props: computed(() => ({type: "danger"})),
+    props: computed(() => ({ type: "danger" })),
     confirm: {
       options: {
         draggable: true,
         message: "确定删除此数据吗?"
       }
     },
-    onConfirm: async (params) => {
+    onConfirm: async params => {
       try {
-        let res = await deleteMenu(params.row.menuId)
+        let res = await deleteMenu(params.row.menuId);
         if (res.code === 200) {
-          ElMessage.success('删除成功')
-          refresh()
+          ElMessage.success("删除成功");
+          refresh();
         } else {
-          ElMessage.error(res.msg)
+          ElMessage.error(res.msg);
         }
       } catch (e) {
-        ElMessage.error('删除失败')
+        ElMessage.error("删除失败");
       }
     }
   }
 ];
 
-const {form, confirmLoading, rules, dialogVisible} = toRefs(state)
+const { form, confirmLoading, rules, dialogVisible } = toRefs(state);
 </script>

+ 57 - 43
src/views/system/role/components/menuTree.vue

@@ -1,63 +1,66 @@
 <script setup lang="ts">
-import {onMounted, ref, defineEmits, watch, nextTick} from "vue";
-import {getMenuListTree} from "@/api/system/menu";
-import {type CheckboxValueType} from 'element-plus'
-
+import { onMounted, ref, defineEmits, watch, nextTick } from "vue";
+import { getMenuListTree } from "@/api/system/menu";
+import { type CheckboxValueType } from "element-plus";
 
 onMounted(() => {
   getMenuList();
-  console.log(model.value)
-})
+  console.log(model.value);
+});
 
-const emit = defineEmits(['update:modelValue'])
+const emit = defineEmits(["update:modelValue"]);
 
 const menuList = ref([]);
 const getMenuList = async () => {
   let res = await getMenuListTree();
   menuList.value = res.data;
-}
+};
 
-const model = defineModel()
+const model = defineModel();
 
-watch(model, (value: number[]) => {
-  nextTick(() => {
-    setCheckedKeys(value, true)
-    const allKeys = getAllKeys(menuList.value);
-    menuNodeAll.value = value.length === allKeys.length;
-    isIndeterminate.value = value.length > 0 && value.length < allKeys.length;
-  })
-}, {immediate: true, deep: true})
+watch(
+  model,
+  (value: number[]) => {
+    nextTick(() => {
+      setCheckedKeys(value, true);
+      const allKeys = getAllKeys(menuList.value);
+      menuNodeAll.value = value.length === allKeys.length;
+      isIndeterminate.value = value.length > 0 && value.length < allKeys.length;
+    });
+  },
+  { immediate: true, deep: true }
+);
 
-const menuRef = ref(null)
+const menuRef = ref(null);
 
-const menuCheckStrictly = ref(true)
-const menuNodeAll = ref(false)
-const menuExpand = ref(false)
-const isIndeterminate = ref(false)
+const menuCheckStrictly = ref(true);
+const menuNodeAll = ref(false);
+const menuExpand = ref(false);
+const isIndeterminate = ref(false);
 const handleCheckedTreeExpand = (value: CheckboxValueType) => {
   // 递归展开
   for (let i = 0; i < menuList.value.length; i++) {
     menuRef.value.store.nodesMap[menuList.value[i].id].expanded = value;
   }
-}
+};
 
 const handleCheckedTreeNodeAll = (value: CheckboxValueType) => {
   menuRef.value.setCheckedNodes(value ? menuList.value : []);
   isIndeterminate.value = false;
   const allKeys = getAllKeys(menuList.value);
   model.value = value ? allKeys : [];
-  console.log(model.value)
-  console.log(menuNodeAll.value)
-}
+  console.log(model.value);
+  console.log(menuNodeAll.value);
+};
 
 const handleTreeCheck = (_: any, checkedState: any) => {
   const allKeys = getAllKeys(menuList.value);
   const checkedCount = checkedState.checkedKeys.length;
   menuNodeAll.value = checkedCount === allKeys.length;
   isIndeterminate.value = checkedCount > 0 && checkedCount < allKeys.length;
-  model.value = checkedState.checkedKeys
-  emit("update:modelValue", checkedState.checkedKeys)
-}
+  model.value = checkedState.checkedKeys;
+  emit("update:modelValue", checkedState.checkedKeys);
+};
 
 // 递归获取所有节点key
 const getAllKeys = (data: any) => {
@@ -68,34 +71,45 @@ const getAllKeys = (data: any) => {
     }
     return keys;
   }, []);
-}
+};
 
 const setCheckedKeys = (keys: number[], leafOnly: boolean) => {
-  return menuRef.value.setCheckedKeys(keys, leafOnly)
-}
+  return menuRef.value.setCheckedKeys(keys, leafOnly);
+};
 </script>
 
 <template>
   <div style="width: 100%">
     <el-row type="flex" justify="space-between" align="middle">
       <el-col :span="4">
-        <el-checkbox v-model="menuExpand" @change="handleCheckedTreeExpand($event)">全部展开/折叠
+        <el-checkbox
+          v-model="menuExpand"
+          @change="handleCheckedTreeExpand($event)"
+          >全部展开/折叠
         </el-checkbox>
       </el-col>
       <el-col :span="4">
-        <el-checkbox :indeterminate="isIndeterminate" v-model="menuNodeAll"
-                     @change="handleCheckedTreeNodeAll($event)">全选/全不选
+        <el-checkbox
+          v-model="menuNodeAll"
+          :indeterminate="isIndeterminate"
+          @change="handleCheckedTreeNodeAll($event)"
+          >全选/全不选
         </el-checkbox>
       </el-col>
       <el-col :span="4">
-        <el-checkbox v-model="menuCheckStrictly">级联下级
-        </el-checkbox>
+        <el-checkbox v-model="menuCheckStrictly">级联下级 </el-checkbox>
       </el-col>
     </el-row>
-    <el-tree class="tree-border" :data="menuList" show-checkbox ref="menuRef" node-key="id"
-             empty-text="加载中,请稍后"
-             :check-strictly="!menuCheckStrictly" @check="handleTreeCheck">
-    </el-tree>
+    <el-tree
+      ref="menuRef"
+      class="tree-border"
+      :data="menuList"
+      show-checkbox
+      node-key="id"
+      empty-text="加载中,请稍后"
+      :check-strictly="!menuCheckStrictly"
+      @check="handleTreeCheck"
+    />
   </div>
 </template>
 
@@ -105,7 +119,7 @@ const setCheckedKeys = (keys: number[], leafOnly: boolean) => {
   width: 100%;
   margin-top: 5px;
   border: 1px solid #e5e6e7;
-  background: #FFFFFF none;
+  background: #ffffff none;
   border-radius: 4px;
 }
-</style>
+</style>

+ 324 - 197
src/views/system/role/index.vue

@@ -1,53 +1,84 @@
 <template>
   <div>
     <PlusPage
-        ref="plusPageInstance"
-        :columns="tableConfig"
-        :request="getList"
-        :before-search-submit="handleBeforeSearch"
-        :is-card="true"
-        :search="{
-          labelWidth: 100,
-          showNumber: 3
-        }"
-        :table="{
-          actionBar: { buttons, type: 'link', width: 180, showNumber: 2 },
-          adaptive: { offsetBottom: 50 },
-          onSelectionChange: handleSelect,
-          onFormChange: handleTableChange,
-          onClickAction: handleTableOption,
-        }"
+      ref="plusPageInstance"
+      :columns="tableConfig"
+      :request="getList"
+      :before-search-submit="handleBeforeSearch"
+      :is-card="true"
+      :search="{
+        labelWidth: 100,
+        showNumber: 3
+      }"
+      :table="{
+        actionBar: { buttons, type: 'link', width: 180, showNumber: 2 },
+        adaptive: { offsetBottom: 50 },
+        onSelectionChange: handleSelect,
+        onFormChange: handleTableChange,
+        onClickAction: handleTableOption
+      }"
     >
       <template #table-title>
         <el-row class="button-row">
-          <el-button size="default" type="success" @click="handleCreate">新增</el-button>
+          <el-button size="default" type="success" @click="handleCreate"
+            >新增
+          </el-button>
         </el-row>
       </template>
     </PlusPage>
     <!-- 弹窗编辑 -->
     <PlusDialogForm
-        ref="dialogForm"
-        v-model="form"
-        v-model:visible="dialogVisible"
-        @confirm="handleSubmit"
-        @change="handleFormChange"
-        @submit-error="handleSubmitError"
-        @close="handleClose"
-        @opened="handleOpen"
-        :form="{ columns, labelPosition: 'right',labelWidth: 100, rules, rowProps: {gutter: 20}, colProps: {span: 12} }"
-        :dialog="{ title: dialogTitle + '角色', width: 600, confirmLoading }"
+      ref="dialogForm"
+      v-model="form"
+      v-model:visible="dialogVisible"
+      :form="{
+        columns,
+        labelPosition: 'right',
+        labelWidth: 100,
+        rules,
+        rowProps: { gutter: 20 },
+        colProps: { span: 12 }
+      }"
+      :dialog="{ title: dialogTitle + '角色', width: 600, confirmLoading }"
+      @confirm="handleSubmit"
+      @change="handleFormChange"
+      @submit-error="handleSubmitError"
+      @close="handleClose"
+      @opened="handleOpen"
     >
       <template #plus-field-menuIds>
-        <menu-tree ref="menuRef" v-model="form.menuIds"></menu-tree>
+        <menu-tree ref="menuRef" v-model="form.menuIds" />
       </template>
     </PlusDialogForm>
+
+    <PlusDialogForm
+      v-model="form"
+      v-model:visible="dialogPermissionVisible"
+      :form="{
+        columns: permissionColumns,
+        labelPosition: 'right',
+        labelWidth: 100,
+        rowProps: { gutter: 20 },
+        colProps: { span: 12 }
+      }"
+      :dialog="{ title: '分配数据权限', width: 600, confirmLoading }"
+      @confirm="handlePermissionSubmit"
+    />
   </div>
 </template>
 
 <script lang="ts" setup>
-import {computed, defineOptions, nextTick, onMounted, reactive, ref, toRefs} from "vue";
-import type {FormRules} from 'element-plus'
-import {ElMessage, ElMessageBox} from "element-plus";
+import {
+  computed,
+  defineOptions,
+  nextTick,
+  onMounted,
+  reactive,
+  ref,
+  toRefs
+} from "vue";
+import type { FormRules } from "element-plus";
+import { ElMessage, ElMessageBox } from "element-plus";
 import {
   type FieldValues,
   type PlusColumn,
@@ -57,26 +88,29 @@ import {
   PlusPageInstance,
   useTable
 } from "plus-pro-components";
-import {cloneDeep} from "lodash-es";
+import { cloneDeep } from "lodash-es";
 import {
   addSystemRole,
-  changeRoleStatus, deleteSystemRole,
+  changeRoleStatus,
+  deleteSystemRole,
   getSystemRoleById,
   getSystemRoleDeptTree,
-  getSystemRoleList, updateSystemRole
+  getSystemRoleList,
+  putSystemRoleDataScope,
+  updateSystemRole
 } from "@/api/system/role";
 import MenuTree from "@/views/system/role/components/menuTree.vue";
-import {getMenuListTreeSelect} from "@/api/system/menu";
+import { getMenuListTreeSelect } from "@/api/system/menu";
 
 defineOptions({
   name: "Role"
 });
 
 onMounted(async () => {
-  await getDeptList()
-})
+  await getDeptList();
+});
 
-const menuRef = ref(null)
+const menuRef = ref(null);
 
 interface TableRow {
   id: number;
@@ -88,20 +122,20 @@ interface TableRow {
 
 // 菜单列表
 
-const plusPageInstance = ref<PlusPageInstance | null>(null)
+const plusPageInstance = ref<PlusPageInstance | null>(null);
 
 const getList = async (query: Record<string, any>) => {
   let res = await getSystemRoleList(query);
   return {
     data: res.rows,
     total: res.total
-  }
+  };
 };
 
 // 重新请求列表接口
 const refresh = () => {
-  plusPageInstance.value?.getList()
-}
+  plusPageInstance.value?.getList();
+};
 
 // 搜索之前函数
 const handleBeforeSearch = (values: any) => {
@@ -109,21 +143,19 @@ const handleBeforeSearch = (values: any) => {
   return cloneDeep(values);
 };
 
-const dialogTitle = computed(() => (state.isCreate ? '新增' : '编辑'))
-const {buttons} = useTable<TableRow[]>();
-
-const systemList = ref([]);
+const dialogTitle = computed(() => (state.isCreate ? "新增" : "编辑"));
+const { buttons } = useTable<TableRow[]>();
 
 // 表格数据
 const tableConfig: PlusColumn[] = [
   {
     label: "角色编号",
     prop: "roleId",
-    hideInSearch: true,
+    hideInSearch: true
   },
   {
     label: "角色名称",
-    prop: "roleName",
+    prop: "roleName"
   },
   {
     label: "权限字符",
@@ -132,7 +164,7 @@ const tableConfig: PlusColumn[] = [
   {
     label: "显示顺序",
     prop: "roleSort",
-    hideInSearch: true,
+    hideInSearch: true
   },
   {
     label: "组织ID",
@@ -142,15 +174,15 @@ const tableConfig: PlusColumn[] = [
     fieldProps: {
       checkStrictly: true,
       defaultExpandAll: false,
-      style: {width: '100%'},
+      style: { width: "100%" },
       data: computed(() => {
-        return deptList.value
+        return deptList.value;
       }),
       // el-tree-select 组件属性
       props: {
-        label: 'label',
-        value: 'id',
-        children: 'children'
+        label: "label",
+        value: "id",
+        children: "children"
       }
     }
   },
@@ -160,8 +192,8 @@ const tableConfig: PlusColumn[] = [
     valueType: "select",
     fieldProps: {
       options: [
-        {label: '正常', value: '0'},
-        {label: '停用', value: '1'}
+        { label: "正常", value: "0" },
+        { label: "停用", value: "1" }
       ]
     },
     hideInTable: true
@@ -169,30 +201,30 @@ const tableConfig: PlusColumn[] = [
   {
     label: "状态",
     prop: "status",
-    valueType: 'switch',
+    valueType: "switch",
     hideInSearch: true,
     fieldProps: {
-      placeholder: '角色状态',
+      placeholder: "角色状态",
       activeValue: "0",
-      inactiveValue: "1",
+      inactiveValue: "1"
     },
     editable: true,
-    colProps: {span: 8}
+    colProps: { span: 8 }
   },
   {
     label: "创建时间",
     prop: "createTime",
-    valueType: 'date-picker',
+    valueType: "date-picker",
     fieldProps: {
-      type: 'daterange',
-      startPlaceholder: '开始日期',
-      endPlaceholder: '结束日期',
-      style: {width: '100%'},
+      type: "daterange",
+      startPlaceholder: "开始日期",
+      endPlaceholder: "结束日期",
+      style: { width: "100%" },
       unlinkPanels: true,
-      format: 'YYYY-MM-DD'
+      format: "YYYY-MM-DD"
     },
     hideInTable: true,
-    colProps: {span: 16}
+    colProps: { span: 16 }
   }
 ];
 
@@ -202,30 +234,33 @@ const dialogForm = ref(null);
 
 interface State {
   dialogVisible: boolean;
+  dialogPermissionVisible: boolean;
   confirmLoading: boolean;
   selectedIds: number[];
   isCreate: boolean;
   form: {
-    businessType: string
-    deptId: number
-    menuIds: number[]
-    remark: string
-    roleKey: string
-    roleName: string
-    roleSort: number
-    status: string,
-    isMenuCheckStrictly: string
+    businessType: string;
+    deptId: number;
+    menuIds: number[];
+    remark: string;
+    roleKey: string;
+    roleName: string;
+    roleSort: number;
+    status: string;
+    isMenuCheckStrictly: string;
+    dataScope: string;
   };
   rules: FormRules;
 }
 
 const state = reactive<State>({
   dialogVisible: false,
+  dialogPermissionVisible: false,
   confirmLoading: false,
   selectedIds: [],
   isCreate: false,
   form: {
-    businessType: '',
+    businessType: "",
     deptId: null,
     menuIds: [],
     remark: "",
@@ -233,24 +268,23 @@ const state = reactive<State>({
     roleName: "",
     roleSort: null,
     status: "",
-    isMenuCheckStrictly: '0'
+    isMenuCheckStrictly: "0",
+    dataScope: ""
   },
   rules: {
-    parentId: [{required: true, message: '请选择上级菜单', trigger: 'blur'}],
-    orderNum: [{required: true, message: '请输入排序', trigger: 'blur'}],
-    menuName: [{required: true, message: '请输入菜单名称', trigger: 'blur'}],
-    path: [{required: true, message: '请输入路由地址', trigger: 'blur'}],
+    roleName: [{ required: true, message: "请输入角色名称", trigger: "blur" }],
+    roleSort: [{ required: true, message: "请输入角色排序", trigger: "blur" }]
   }
-})
+});
 
-const deptList = ref([])
+const deptList = ref([]);
 
 const getDeptList = async () => {
-  let res = await getSystemRoleDeptTree('2');
+  let res = await getSystemRoleDeptTree("2");
   if (res.code === 200) {
-    deptList.value = res.depts
+    deptList.value = res.depts;
   }
-}
+};
 
 // 表单字段
 const columns: PlusColumn[] = [
@@ -258,7 +292,7 @@ const columns: PlusColumn[] = [
     label: "角色名称",
     prop: "roleName",
     valueType: "input",
-    colProps: {span: 24},
+    colProps: { span: 24 },
     fieldProps: {
       clearable: true
     }
@@ -267,8 +301,9 @@ const columns: PlusColumn[] = [
     label: "权限字符",
     prop: "roleKey",
     valueType: "input",
-    colProps: {span: 24},
-    tooltip: "控制器中定义的权限字符,如:@PreAuthorize(`@ss.hasRole('admin')`)",
+    colProps: { span: 24 },
+    tooltip:
+      "控制器中定义的权限字符,如:@PreAuthorize(`@ss.hasRole('admin')`)",
     fieldProps: {
       clearable: true
     }
@@ -277,7 +312,7 @@ const columns: PlusColumn[] = [
     label: "业务类型",
     prop: "businessType",
     valueType: "input",
-    colProps: {span: 24},
+    colProps: { span: 24 },
     fieldProps: {
       clearable: true
     }
@@ -286,19 +321,19 @@ const columns: PlusColumn[] = [
     label: "组织ID",
     prop: "deptId",
     valueType: "tree-select",
-    colProps: {span: 24},
+    colProps: { span: 24 },
     fieldProps: {
       checkStrictly: true,
       defaultExpandAll: false,
-      style: {width: '100%'},
+      style: { width: "100%" },
       data: computed(() => {
-        return deptList.value
+        return deptList.value;
       }),
       // el-tree-select 组件属性
       props: {
-        label: 'label',
-        value: 'id',
-        children: 'children'
+        label: "label",
+        value: "id",
+        children: "children"
       }
     }
   },
@@ -306,7 +341,7 @@ const columns: PlusColumn[] = [
     label: "角色顺序",
     prop: "roleSort",
     valueType: "input-number",
-    colProps: {span: 24},
+    colProps: { span: 24 },
     fieldProps: {
       clearable: true,
       min: 0
@@ -316,17 +351,17 @@ const columns: PlusColumn[] = [
     label: "状态",
     prop: "status",
     valueType: "radio",
-    colProps: {span: 24},
+    colProps: { span: 24 },
     fieldProps: {
       clearable: true,
       options: [
         {
-          label: '正常',
-          value: '0'
+          label: "正常",
+          value: "0"
         },
         {
-          label: '停用',
-          value: '1'
+          label: "停用",
+          value: "1"
         }
       ]
     }
@@ -334,131 +369,204 @@ const columns: PlusColumn[] = [
   {
     label: "菜单权限",
     prop: "menuIds",
-    colProps: {span: 24},
-    fieldProps: {
-
-    }
+    colProps: { span: 24 },
+    fieldProps: {}
   },
   {
     label: "备注",
     prop: "remark",
     valueType: "textarea",
-    colProps: {span: 24},
+    colProps: { span: 24 },
     fieldProps: {
       clearable: true,
       minRow: 2
     }
   }
-]
+];
+
+const permissionColumns: PlusColumn[] = [
+  {
+    label: "角色名称",
+    prop: "roleName",
+    colProps: { span: 24 },
+    fieldProps: {
+      disabled: true
+    }
+  },
+  {
+    label: "权限字符",
+    prop: "roleKey",
+    colProps: { span: 24 },
+    fieldProps: {
+      disabled: true
+    }
+  },
+  {
+    label: "权限范围",
+    prop: "dataScope",
+    valueType: "select",
+    colProps: { span: 24 },
+    fieldProps: {
+      options: [
+        {
+          label: "全部数据权限",
+          value: "1"
+        },
+        {
+          label: "自定义数据权限",
+          value: "2"
+        },
+        {
+          label: "本部门数据权限",
+          value: "3"
+        },
+        {
+          label: "本部门及以下数据权限",
+          value: "4"
+        },
+        {
+          label: "仅本人数据权限",
+          value: "5"
+        }
+      ]
+    }
+  },
+  {
+    label: "数据权限",
+    prop: "deptIds",
+    colProps: { span: 24 },
+    hideInForm: computed(() => form.value.dataScope !== "2")
+  }
+];
 
 // 创建
 const handleCreate = (): void => {
   form.value = {
-    businessType: '',
+    businessType: "",
     deptId: null,
     menuIds: [],
     remark: "",
     roleKey: "",
     roleName: "",
     roleSort: null,
-    status: '0',
-    isMenuCheckStrictly: '0'
-  }
-  state.isCreate = true
-  state.dialogVisible = true
-}
+    status: "0",
+    isMenuCheckStrictly: "0",
+    dataScope: null
+  };
+  state.isCreate = true;
+  state.dialogVisible = true;
+};
 
 // 选择
 const handleSelect = (data: any) => {
-  state.selectedIds = [...data].map(item => item.id)
-}
+  state.selectedIds = [...data].map(item => item.id);
+};
 
 const handleFormChange = (values: FieldValues) => {
-  console.log(values)
-}
+  console.log(values);
+};
 
 const handleTableChange = (values: FieldValues) => {
-  console.log(values)
+  console.log(values);
   ElMessageBox.confirm("确定修改此数据吗?", "提示", {
     confirmButtonText: "确定",
     cancelButtonText: "取消",
-    type: "warning",
+    type: "warning"
   })
-      .then(async () => {
-        try {
-          let res = await changeRoleStatus(values.row.roleId, values.row.status)
-          if (res.code === 200) {
-            ElMessage.success('修改成功')
-            refresh()
-          } else {
-            ElMessage.error(res.msg)
-          }
-        } catch (e) {
-          ElMessage.error('修改失败')
+    .then(async () => {
+      try {
+        let res = await changeRoleStatus(values.row.roleId, values.row.status);
+        if (res.code === 200) {
+          ElMessage.success("修改成功");
+          refresh();
+        } else {
+          ElMessage.error(res.msg);
         }
-      })
-      .finally(() => {
-        refresh()
-      });
-}
+      } catch (e) {
+        ElMessage.error("修改失败");
+      }
+    })
+    .finally(() => {
+      refresh();
+    });
+};
 
 const handleOpen = () => {
-  console.log('open')
+  console.log("open");
   if (!state.isCreate) {
-    console.log(menuRef.value)
+    console.log(menuRef.value);
   }
-}
+};
 
 const handleSubmit = async (values: FieldValues) => {
-  console.log(values, 'Submit')
-  confirmLoading.value = true
+  console.log(values, "Submit");
+  confirmLoading.value = true;
   if (state.isCreate) {
     try {
-      let params = form.value
-      params.isMenuCheckStrictly = '0'
-      let res = await addSystemRole(params)
+      let params = form.value;
+      params.isMenuCheckStrictly = "0";
+      let res = await addSystemRole(params);
       if (res.code === 200) {
-        ElMessage.success('新增成功')
-        confirmLoading.value = false
-        dialogVisible.value = false
-        refresh()
+        ElMessage.success("新增成功");
+        confirmLoading.value = false;
+        dialogVisible.value = false;
+        refresh();
       } else {
-        ElMessage.error(res.msg)
+        ElMessage.error(res.msg);
       }
     } finally {
-      confirmLoading.value = false
+      confirmLoading.value = false;
     }
   } else {
     // 编辑
     try {
-      let params = form.value
-      params.isMenuCheckStrictly = '0'
-      let res = await updateSystemRole(params)
+      let params = form.value;
+      params.isMenuCheckStrictly = "0";
+      let res = await updateSystemRole(params);
       if (res.code === 200) {
-        ElMessage.success('修改成功')
-        confirmLoading.value = false
-        dialogVisible.value = false
-        refresh()
+        ElMessage.success("修改成功");
+        confirmLoading.value = false;
+        dialogVisible.value = false;
+        refresh();
       } else {
-        ElMessage.error(res.msg)
+        ElMessage.error(res.msg);
       }
     } finally {
-      confirmLoading.value = false
+      confirmLoading.value = false;
     }
   }
-}
+};
+
+const handlePermissionSubmit = async (values: FieldValues) => {
+  confirmLoading.value = true;
+  try {
+    let params = form.value;
+    let res = await putSystemRoleDataScope(params);
+    if (res.code === 200) {
+      ElMessage.success("修改成功");
+      confirmLoading.value = false;
+      dialogVisible.value = false;
+      refresh();
+    } else {
+      ElMessage.error(res.msg);
+    }
+  } finally {
+    confirmLoading.value = false;
+  }
+};
+
 const handleSubmitError = (err: any) => {
-  console.log(err, 'err')
-}
+  console.log(err, "err");
+};
 const handleClose = () => {
   // 重置表单
   nextTick(() => {
     if (dialogForm.value) {
-      dialogForm.value.formInstance.resetFields()
+      dialogForm.value.formInstance.resetFields();
     }
-  })
-  console.log(dialogForm.value.formInstance)
-}
+  });
+  console.log(dialogForm.value.formInstance);
+};
 
 buttons.value = [
   {
@@ -474,55 +582,74 @@ buttons.value = [
     // 删除
     text: "删除",
     code: "delete",
-    props: {type: "danger"},
+    props: { type: "danger" }
   },
   {
     text: "数据权限",
-    code: "dataPermission",
+    code: "dataPermission"
   },
   {
     text: "分配用户",
-    code: "assignUser",
+    code: "assignUser"
   }
 ];
 
-const handleTableOption = ({row, buttonRow}: ButtonsCallBackParams): void => {
-  console.log(row)
+const handleTableOption = ({ row, buttonRow }: ButtonsCallBackParams): void => {
+  console.log(row);
   switch (buttonRow.code) {
-    case 'edit':
-      handleEdit(row.roleId)
-      break
-    case 'delete':
-      handleDelete(row.roleId)
-      break
+    case "edit":
+      handleEdit(row.roleId);
+      break;
+    case "delete":
+      handleDelete(row.roleId);
+      break;
+    case "dataPermission":
+      handleDataPermission(row.roleId);
+      break;
+    case "assignUser":
+      handleAssignUser(row.roleId);
+      break;
   }
-}
+};
 
 const handleEdit = async (id: string) => {
   let res = await getSystemRoleById(id);
   let res1 = await getMenuListTreeSelect(id);
-  console.log(res, res1)
-  form.value = res.data
-  form.value.menuIds = res1.checkedKeys
-  state.isCreate = false
-  state.dialogVisible = true
-}
+  console.log(res, res1);
+  form.value = res.data;
+  form.value.menuIds = res1.checkedKeys;
+  state.isCreate = false;
+  state.dialogVisible = true;
+};
 
 const handleDelete = (id: string) => {
-  ElMessageBox.confirm('确定删除吗?', '提示', {
-    confirmButtonText: '确定',
-    cancelButtonText: '取消',
-    type: 'warning'
+  ElMessageBox.confirm("确定删除吗?", "提示", {
+    confirmButtonText: "确定",
+    cancelButtonText: "取消",
+    type: "warning"
   }).then(async () => {
-    let res = await deleteSystemRole(id)
+    let res = await deleteSystemRole(id);
     if (res.code === 200) {
-      ElMessage.success(res.msg)
-      refresh()
+      ElMessage.success(res.msg);
+      refresh();
     } else {
-      ElMessage.error(res.msg)
+      ElMessage.error(res.msg);
     }
-  })
-}
+  });
+};
+
+const handleDataPermission = async (id: string) => {
+  console.log(id);
+  let res = await getSystemRoleById(id);
+  form.value = res.data;
+  state.isCreate = false;
+  state.dialogPermissionVisible = true;
+};
+
+const handleAssignUser = (id: string) => {
+  console.log(id);
+};
 
-const {form, confirmLoading, rules, dialogVisible} = toRefs(state)
+const { form, confirmLoading, rules, dialogVisible, dialogPermissionVisible } =
+  toRefs(state);
 </script>