Browse Source

细节调整,打包配置文件

zouzs 1 week ago
parent
commit
2aff45c6ea

+ 13 - 0
docker-app-compose.yml

@@ -0,0 +1,13 @@
+version: '3'
+services:
+  auth_perm_system_front:                      # 指定服务的名称
+    image: "auth_perm_system_front:${biz_tag_name}"                         # 镜像名 .注意:${app_tag_name} 变量名不能带'-'符号,第一个'-'后会认为是默认值,而非变量名的一部分。
+    environment:                        # 环境变量
+      - VIRTUAL_HOST=test.nacos.jiebide.xin          # nginx-proxy 所用域名
+    networks:                           # 网络 (用于容器间通信)
+      - nginx-proxy
+
+networks:                               # 定义网络
+  nginx-proxy:
+    external:
+      name: nginx-proxy

+ 13 - 0
src/api/user.ts

@@ -86,3 +86,16 @@ export const refreshTokenApi = (data?: object) => {
     data
   });
 };
+
+/**
+ * 获取用户信息
+ */
+export const getUserInfo = (data?: object) => {
+  return http.request<BasicResponseModel>(
+    "get",
+    baseUrlApi("system/user/getInfo"),
+    {
+      data
+    }
+  );
+};

+ 1 - 1
src/api/utils.ts

@@ -1,4 +1,4 @@
 export const baseUrlApi = (url: string) =>
   process.env.NODE_ENV === "development"
     ? `/api/${url}`
-    : `http://127.0.0.1:3000/${url}`;
+    : `http://192.168.1.168:20000/${url}`;

+ 19 - 3
src/store/modules/user.ts

@@ -12,10 +12,17 @@ import {
   type RefreshTokenResult,
   getLogin,
   refreshTokenApi,
-  verifySmsLogin
+  verifySmsLogin,
+  getUserInfo
 } from "@/api/user";
 import { useMultiTagsStoreHook } from "./multiTags";
-import { type DataInfo, setToken, removeToken, userKey } from "@/utils/auth";
+import {
+  type DataInfo,
+  setToken,
+  removeToken,
+  userKey,
+  setUserInfo
+} from "@/utils/auth";
 
 export const useUserStore = defineStore("pure-user", {
   state: (): userType => ({
@@ -70,7 +77,16 @@ export const useUserStore = defineStore("pure-user", {
         const loginfn = submitType === 1 ? getLogin : verifySmsLogin;
         loginfn(data)
           .then(res => {
-            if (res?.code === 200) setToken(res.data);
+            console.log(321321, res);
+            if (res?.code === 200) {
+              setToken(res.data);
+              getUserInfo().then(response => {
+                if (response?.code === 200) {
+                  console.log(response);
+                  setUserInfo(response);
+                }
+              });
+            }
             resolve(res);
           })
           .catch(error => {

+ 15 - 7
src/utils/auth.ts

@@ -32,6 +32,12 @@ export interface DataInfo<T> {
   userModule: string;
   _businessDockingId: number;
 
+  user: {
+    avatar: string;
+    username: string;
+    nickname: string;
+  };
+
   access_token: string;
   expires_in: number;
 }
@@ -84,7 +90,9 @@ export function setToken(data: DataInfo<number>) {
         }
       : {}
   );
+}
 
+export function setUserInfo(data: DataInfo<number>) {
   function setUserKey({ avatar, username, nickname, roles, permissions }) {
     useUserStoreHook().SET_AVATAR(avatar);
     useUserStoreHook().SET_USERNAME(username);
@@ -93,7 +101,6 @@ export function setToken(data: DataInfo<number>) {
     useUserStoreHook().SET_PERMS(permissions);
     storageLocal().setItem(userKey, {
       // refreshToken,
-      expires,
       avatar,
       username,
       nickname,
@@ -102,14 +109,15 @@ export function setToken(data: DataInfo<number>) {
     });
   }
 
-  if (data.username && data.roles) {
-    const { username, roles } = data;
+  if (data.permissions && data.roles) {
+    const { permissions, roles } = data;
+    const user = data.user;
     setUserKey({
-      avatar: data?.avatar ?? "",
-      username,
-      nickname: data?.nickname ?? "",
+      avatar: user?.avatar ?? "",
+      username: user?.username ?? "",
+      nickname: user?.nickname ?? "",
       roles,
-      permissions: data?.permissions ?? []
+      permissions
     });
   } else {
     const avatar =

+ 2 - 1
src/views/login/index.vue

@@ -57,7 +57,8 @@ const ruleForm = reactive({
   username: "admin",
   password: "admin123",
   code: "",
-  uuid: ""
+  uuid: "",
+  agree: false
 });
 
 const smsRuleForm = reactive({

+ 62 - 33
src/views/system/role/components/deptTree.vue

@@ -1,5 +1,5 @@
 <script setup lang="ts">
-import { onMounted, ref, watch, nextTick } from "vue";
+import { onMounted, ref, watch, nextTick, computed } from "vue";
 import { getSystemRoleDeptTree } from "@/api/system/role";
 import { type CheckboxValueType } from "element-plus";
 
@@ -16,16 +16,13 @@ const getDeptList = async () => {
   deptList.value = res.depts;
 };
 
-const model = defineModel();
+const model = defineModel<number[]>();
 
 watch(
   model,
   (value: number[]) => {
     nextTick(() => {
       setCheckedKeys(value, true);
-      const allKeys = getAllKeys(deptList.value);
-      menuNodeAll.value = value.length === allKeys.length;
-      isIndeterminate.value = value.length > 0 && value.length < allKeys.length;
     });
   },
   { immediate: true, deep: true }
@@ -34,9 +31,7 @@ watch(
 const menuRef = ref(null);
 
 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 < deptList.value.length; i++) {
@@ -44,38 +39,75 @@ const handleCheckedTreeExpand = (value: CheckboxValueType) => {
   }
 };
 
-const handleCheckedTreeNodeAll = (value: CheckboxValueType) => {
-  menuRef.value.setCheckedNodes(value ? deptList.value : []);
-  isIndeterminate.value = false;
-  const allKeys = getAllKeys(deptList.value);
-  model.value = value ? allKeys : [];
-  console.log(model.value);
-  console.log(menuNodeAll.value);
+// 只返回所有叶子节点 id
+const getLeafKeys = (data: any[]) => {
+  const keys: number[] = [];
+  data.forEach(node => {
+    if (node.children && node.children.length) {
+      keys.push(...getLeafKeys(node.children));
+    } else {
+      keys.push(node.id);
+    }
+  });
+  return keys;
 };
 
-const handleTreeCheck = (_: any, checkedState: any) => {
-  const allKeys = getAllKeys(deptList.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);
+// 叶子节点总集合(随菜单树变化动态计算)
+const allLeafKeys = computed(() => getLeafKeys(deptList.value));
+
+// 全选状态:由 model 与叶子总集合计算;设置时驱动 model 更新
+const allSelected = computed({
+  get() {
+    const leafKeys = allLeafKeys.value;
+    if (!leafKeys.length) return false;
+    // model 中的所有 key 都在叶子集合,并且数量一致视为全选
+    return (
+      model.value.length === leafKeys.length &&
+      model.value.every(k => leafKeys.includes(k))
+    );
+  },
+  set(checked: boolean) {
+    model.value = checked ? [...allLeafKeys.value] : [];
+  }
+});
+
+// 半选状态:仅基于数量计算
+const indeterminate = computed(() => {
+  const total = allLeafKeys.value.length;
+  const count = model.value.length;
+  return count > 0 && count < total;
+});
+
+// 通过 watch(model) 来同步 UI 勾选状态,因此这里不再需要手动方法
+
+const handleTreeCheck = (_: any, _checkedState: any) => {
+  const leafKeys = menuRef.value?.getCheckedKeys(true) ?? [];
+  model.value = leafKeys;
+  emit("update:modelValue", leafKeys);
 };
 
 // 递归获取所有节点key
-const getAllKeys = (data: any) => {
-  return data.reduce((keys: any, node: any) => {
-    keys.push(node.id);
-    if (node.children && menuCheckStrictly) {
-      keys.push(...getAllKeys(node.children));
-    }
-    return keys;
-  }, []);
+const getAllKeys = () => {
+  // 目前被选中的菜单节点
+  let checkedKeys = menuRef.value.getCheckedKeys();
+  // 半选中的菜单节点
+  let halfCheckedKeys = menuRef.value.getHalfCheckedKeys();
+  checkedKeys.unshift.apply(checkedKeys, halfCheckedKeys);
+  return checkedKeys;
 };
 
 const setCheckedKeys = (keys: number[], leafOnly: boolean) => {
   return menuRef.value.setCheckedKeys(keys, leafOnly);
 };
+
+// 级联开关变化时,重新应用当前 model 的叶子集合到树上
+watch(menuCheckStrictly, () => {
+  nextTick(() => setCheckedKeys(model.value, true));
+});
+
+defineExpose({
+  getAllKeys
+});
 </script>
 
 <template>
@@ -89,10 +121,7 @@ const setCheckedKeys = (keys: number[], leafOnly: boolean) => {
         </el-checkbox>
       </el-col>
       <el-col :span="4">
-        <el-checkbox
-          v-model="menuNodeAll"
-          :indeterminate="isIndeterminate"
-          @change="handleCheckedTreeNodeAll($event)"
+        <el-checkbox v-model="allSelected" :indeterminate="indeterminate"
           >全选/全不选
         </el-checkbox>
       </el-col>

+ 11 - 2
src/views/system/role/components/menuTree.vue

@@ -87,8 +87,13 @@ const handleTreeCheck = (_: any, _checkedState: any) => {
 };
 
 // 递归获取所有节点key
-const getAllKeys = (data: any) => {
-  return getLeafKeys(data);
+const getAllKeys = () => {
+  // 目前被选中的菜单节点
+  let checkedKeys = menuRef.value.getCheckedKeys();
+  // 半选中的菜单节点
+  let halfCheckedKeys = menuRef.value.getHalfCheckedKeys();
+  checkedKeys.unshift.apply(checkedKeys, halfCheckedKeys);
+  return checkedKeys;
 };
 
 const setCheckedKeys = (keys: number[], leafOnly: boolean) => {
@@ -99,6 +104,10 @@ const setCheckedKeys = (keys: number[], leafOnly: boolean) => {
 watch(menuCheckStrictly, () => {
   nextTick(() => setCheckedKeys(model.value, true));
 });
+
+defineExpose({
+  getAllKeys
+});
 </script>
 
 <template>

+ 32 - 8
src/views/system/role/index.vue

@@ -20,7 +20,11 @@
     >
       <template #table-title>
         <el-row class="button-row">
-          <el-button size="default" type="success" @click="handleCreate"
+          <el-button
+            v-perms="'system:role:add'"
+            size="default"
+            type="success"
+            @click="handleCreate"
             >新增
           </el-button>
         </el-row>
@@ -72,7 +76,16 @@
 </template>
 
 <script lang="ts" setup>
-import { computed, nextTick, onMounted, reactive, ref, toRefs } from "vue";
+import {
+  computed,
+  nextTick,
+  onMounted,
+  reactive,
+  ref,
+  resolveDirective,
+  toRefs,
+  useTemplateRef
+} from "vue";
 import type { FormRules } from "element-plus";
 import { ElMessage, ElMessageBox } from "element-plus";
 import {
@@ -110,7 +123,8 @@ onMounted(async () => {
   await getDeptList();
 });
 
-const menuRef = ref(null);
+const menuRef = useTemplateRef("menuRef");
+const deptRef = useTemplateRef("deptRef");
 
 interface TableRow {
   id: number;
@@ -144,6 +158,8 @@ const handleBeforeSearch = (values: any) => {
     Reflect.set(params, "params", {});
     Reflect.set(params.params, "beginTime", values.daterange[0]);
     Reflect.set(params.params, "endTime", values.daterange[1]);
+  } else {
+    Reflect.deleteProperty(params, "params");
   }
   return params;
 };
@@ -513,9 +529,11 @@ const handleOpen = () => {
 const handleSubmit = async (values: FieldValues) => {
   console.log(values, "Submit");
   confirmLoading.value = true;
+  console.log(menuRef.value.getAllKeys());
+  let params = form.value;
+  params.menuIds = menuRef.value.getAllKeys();
   if (state.isCreate) {
     try {
-      let params = form.value;
       // params.isMenuCheckStrictly = "0";
       let res = await addSystemRole(params);
       if (res.code === 200) {
@@ -532,7 +550,6 @@ const handleSubmit = async (values: FieldValues) => {
   } else {
     // 编辑
     try {
-      let params = form.value;
       // params.isMenuCheckStrictly = "0";
       let res = await updateSystemRole(params);
       if (res.code === 200) {
@@ -553,6 +570,7 @@ const handlePermissionSubmit = async (values: FieldValues) => {
   confirmLoading.value = true;
   try {
     let params = form.value;
+    params.menuIds = deptRef.value.getAllKeys();
     let res = await putSystemRoleDataScope(params);
     if (res.code === 200) {
       ElMessage.success("修改成功");
@@ -580,6 +598,9 @@ const handleClose = () => {
   console.log(dialogForm.value.formInstance);
 };
 
+// 权限
+const perms = resolveDirective("perms");
+
 buttons.value = [
   {
     // 修改
@@ -587,20 +608,23 @@ buttons.value = [
     code: "edit",
     // props v0.1.16 版本新增函数类型
     props: { type: "primary" },
-    show: (row: any) => row.roleKey !== "admin"
+    show: (row: any) => row.roleKey !== "admin",
+    directives: [[perms, "system:role:edit"]]
   },
   {
     // 删除
     text: "删除",
     code: "delete",
     props: { type: "danger" },
-    show: (row: any) => row.roleKey !== "admin"
+    show: (row: any) => row.roleKey !== "admin",
+    directives: [[perms, "system:role:remove"]]
   },
   {
     text: "数据权限",
     code: "dataPermission",
     props: { type: "primary" },
-    show: (row: any) => row.roleKey !== "admin"
+    show: (row: any) => row.roleKey !== "admin",
+    directives: [[perms, "system:role:dataPermission"]]
   }
 ];
 

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

@@ -17,7 +17,12 @@
     >
       <template #table-title>
         <el-row class="button-row">
-          <el-button size="default" type="success" @click="handleCreate">
+          <el-button
+            v-perms="'system:user:add'"
+            size="default"
+            type="success"
+            @click="handleCreate"
+          >
             新增
           </el-button>
         </el-row>
@@ -44,7 +49,15 @@
 </template>
 
 <script lang="ts" setup>
-import { computed, onMounted, reactive, ref, toRefs, type Ref } from "vue";
+import {
+  computed,
+  onMounted,
+  reactive,
+  ref,
+  toRefs,
+  type Ref,
+  resolveDirective
+} from "vue";
 import type { FormRules } from "element-plus";
 import { ElMessage } from "element-plus";
 import {
@@ -372,12 +385,14 @@ const handleClose = () => {
   console.log(dialogForm.value.formInstance);
 };
 
+// 权限
+const perms = resolveDirective("perms");
+
 buttons.value = [
   {
     // 修改
     text: "修改",
     code: "edit",
-    // props v0.1.16 版本新增函数类型
     props: {
       type: "primary"
     },
@@ -388,13 +403,16 @@ buttons.value = [
         state.isCreate = false;
         state.dialogVisible = true;
       });
-    }
+    },
+    directives: [
+      // 相当于 v-perms="'system:user:edit'"
+      [perms, "system:user:edit"]
+    ]
   },
   {
     // 删除
     text: "删除",
     code: "delete",
-    // props v0.1.16 版本新增计算属性支持
     props: computed(() => ({ type: "danger" })),
     confirm: {
       options: {
@@ -414,7 +432,11 @@ buttons.value = [
       } catch (e) {
         ElMessage.error("删除失败");
       }
-    }
+    },
+    directives: [
+      // 相当于 v-perms="'system:user:remove'"
+      [perms, "system:user:remove"]
+    ]
   }
 ];