浏览代码

角色编辑调整

zhangjie 1 年之前
父节点
当前提交
e783e2e212

+ 6 - 0
src/config/constants.js

@@ -223,3 +223,9 @@ export const FLOW_CHECK_STATUS = {
   UN_APPROVE: '待审核',
   APPROVE: '已审核',
 };
+export const DATA_PRIVILEGE_TYPE = {
+  SELF: '仅本人数据权限',
+  SELF_ORG: '本部门数据权限',
+  SELF_ORG_BELOW: '本部门及下级部门数据权限',
+  ALL: '全部数据权限',
+};

+ 53 - 0
src/style/global.less

@@ -251,6 +251,59 @@ body {
   color: @dark-text-color;
   line-height: 24px;
 }
+
+.table {
+  width: 100%;
+  border-spacing: 0;
+  border-collapse: collapse;
+  text-align: left;
+
+  &.table-white {
+    background-color: #fff;
+  }
+
+  th {
+    padding: 12px;
+    line-height: 1.2;
+    letter-spacing: 1px;
+    color: @light-text-color;
+    border: 1px solid @light-border-color;
+  }
+  td {
+    padding: 14px;
+    line-height: 1.2;
+    color: @dark-text-color;
+    border: 1px solid @light-border-color;
+
+    &.td-link {
+      span {
+        cursor: pointer;
+        &:hover {
+          color: @light-text-color;
+        }
+      }
+    }
+  }
+  .td-th {
+    font-weight: 600;
+    color: @light-text-color;
+  }
+
+  &--border {
+    border: 1px solid @light-border-color;
+    border-radius: 10px;
+    th {
+      background-color: #fcfcfd;
+      border: none;
+      border-bottom: 1px solid @light-border-color;
+    }
+    td {
+      border: none;
+      border-bottom: 1px solid @light-border-color;
+    }
+  }
+}
+
 .box-justify {
   display: flex;
   justify-content: space-between;

+ 1 - 1
src/views/system/config-manage/customer-manage/index.vue

@@ -171,7 +171,7 @@ const params = reactive({
 });
 
 const columns = [
-  { colKey: 'code', title: '客户ID', width: 200 },
+  { colKey: 'id', title: '客户ID', width: 200 },
   { colKey: 'name', title: '客户名称', width: 120 },
   { colKey: 'type', title: '客户类型', cell: 'type', width: 120 },
   { colKey: 'province', title: '省份', width: 100 },

+ 305 - 0
src/views/user/auth-manage/role-manage/PrivilegeSet.vue

@@ -0,0 +1,305 @@
+<template>
+  <div class="privilege-set">
+    <table class="table">
+      <colgroup>
+        <col width="120" />
+        <col width="120" />
+        <col width="140" />
+        <col width="60" />
+        <col width="210" />
+      </colgroup>
+      <tbody>
+        <tr>
+          <th v-for="(item, index) in tableHead" :key="index">{{ item }}</th>
+        </tr>
+        <tr v-for="row in tableData" :key="row.id">
+          <td v-for="(col, cindex) in row.columns" :key="cindex">
+            <div v-if="col && col.type === 'page'">{{ col.name }}</div>
+            <div v-else-if="col && col.type === 'page-checkbox'">
+              <el-checkbox
+                v-model="row.enable"
+                :disabled="row.disabled"
+                @change="(enable) => pageSelectChange(row, enable)"
+              ></el-checkbox>
+            </div>
+            <div
+              v-else-if="
+                row.isPage && col && col.type === 'page-data-permission'
+              "
+            >
+              <el-select
+                v-model="row.dataPermissionType"
+                class="width-200"
+                placeholder="请选择"
+                :disabled="row.disabled"
+              >
+                <el-option
+                  v-for="(val, key) in DATA_PRIVILEGE_TYPE"
+                  :key="key"
+                  :value="key"
+                  :label="val"
+                ></el-option>
+              </el-select>
+            </div>
+            <div v-else-if="col && col.type">
+              <div
+                class="cell-check-list"
+                v-for="item in col.datas"
+                :key="item.field"
+              >
+                <el-checkbox
+                  v-model="item.enable"
+                  :disabled="item.disabled"
+                  @change="(enable) => typeSelectChange(row, enable)"
+                  >{{ item.name }}</el-checkbox
+                >
+              </div>
+            </div>
+            <div v-else></div>
+          </td>
+        </tr>
+      </tbody>
+    </table>
+  </div>
+</template>
+
+<script>
+import { DATA_PRIVILEGE_TYPE } from '../../../constants/enumerate';
+
+export default {
+  name: 'privilege-set',
+  props: {
+    menus: {
+      type: Array,
+      default() {
+        return [];
+      },
+    },
+    showPermission: {
+      type: Boolean,
+      default: true,
+    },
+    disabledPermissionUrls: {
+      type: Array,
+      default() {
+        return ['TaskApplyManage', 'TaskReviewManage'];
+      },
+    },
+  },
+  data() {
+    return {
+      maxDeep: 0,
+      tableData: [],
+      tableHead: [],
+      DATA_PRIVILEGE_TYPE,
+    };
+  },
+  created() {
+    this.initData();
+  },
+  methods: {
+    initData() {
+      this.maxDeep = this.getNavsDeep();
+      this.tableHead = this.buildTableHead();
+      // this.buildTableData();
+    },
+    getNavsDeep() {
+      let maxDeep = 0;
+      const getDeep = (navs, deep) => {
+        ++deep;
+        navs.forEach((nav) => {
+          if (maxDeep < deep) maxDeep = deep;
+
+          if (nav.children && nav.children.length) getDeep(nav.children, deep);
+        });
+      };
+      getDeep(this.menus, maxDeep);
+
+      return maxDeep;
+    },
+    buildTableHead() {
+      let headers = [];
+      let codes = ['一', '二', '三', '四', '五', '六', '七', '八'];
+      for (let index = 0; index < this.maxDeep; index++) {
+        headers.push(`${codes[index]}级页面`);
+      }
+      headers = [...headers, '页面'];
+      if (this.showPermission) headers.push('数据权限');
+      headers = [...headers, '查询条件', '功能按钮', '列表展示', '操作列'];
+
+      return headers;
+    },
+    buildTableData(
+      privilegeIds = [],
+      dataPermissionInfo = [],
+      disabledIds = []
+    ) {
+      let tableData = [];
+      const privColumnCount = this.showPermission ? 6 : 5;
+      let tableColumnCount = this.maxDeep + privColumnCount;
+      const pageSetTypes = ['conditions', 'buttons', 'lists', 'links'];
+
+      let datePermissionMap = {};
+      dataPermissionInfo.forEach((item) => {
+        datePermissionMap[item.privilegeId] = item.dataPermissionType;
+      });
+      const buildData = (navs, deep) => {
+        ++deep;
+        navs.forEach((nav) => {
+          const isDisabledPermissionUrl = this.disabledPermissionUrls.includes(
+            nav.url
+          );
+          let columns = new Array(tableColumnCount);
+          columns[deep - 1] = { type: 'page', name: nav.name };
+          columns[this.maxDeep] = {
+            type: 'page-checkbox',
+          };
+          if (this.showPermission && !isDisabledPermissionUrl) {
+            columns[this.maxDeep + 1] = {
+              type: 'page-data-permission',
+            };
+          }
+
+          const isPage = pageSetTypes.some(
+            (type) => nav[type] && nav[type].length
+          );
+          const offsetPageSetInd = this.showPermission ? 2 : 1;
+          if (isPage) {
+            pageSetTypes.forEach((type, index) => {
+              const datas = !nav[type]
+                ? []
+                : nav[type].map((elem) => {
+                    let data = { ...elem };
+                    data.enable = privilegeIds.includes(elem.id);
+                    data.disabled = disabledIds.includes(elem.id);
+                    return data;
+                  });
+              columns[this.maxDeep + index + offsetPageSetInd] = {
+                type,
+                datas,
+              };
+            });
+          }
+
+          tableData.push({
+            id: nav.id,
+            name: nav.name,
+            url: nav.url,
+            enable: privilegeIds.includes(nav.id),
+            disabled: disabledIds.includes(nav.id),
+            dataPermissionType:
+              isPage && this.showPermission && !isDisabledPermissionUrl
+                ? datePermissionMap[nav.id] || 'SELF'
+                : null,
+            type: nav.type,
+            parentId: nav.parentId,
+            isPage,
+            columns,
+          });
+
+          if (nav.children && nav.children.length)
+            buildData(nav.children, deep);
+        });
+      };
+      buildData(this.menus, 0);
+
+      this.tableData = tableData;
+    },
+    resetdataPermissionType(val) {
+      this.tableData.forEach((item) => {
+        if (
+          item.isPage &&
+          !item.disabled &&
+          this.showPermission &&
+          !this.disabledPermissionUrls.includes(item.url)
+        )
+          item.dataPermissionType = val;
+      });
+    },
+    getSelectedPrivileges() {
+      let privilegeIds = [];
+      let dataPermissionInfo = [];
+      this.tableData
+        .filter((row) => row.enable)
+        .forEach((row) => {
+          privilegeIds.push(row.id);
+          dataPermissionInfo.push({
+            privilegeId: row.id,
+            dataPermissionType: row.dataPermissionType,
+          });
+          row.columns.forEach((column) => {
+            if (!column.datas || !column.datas.length) return;
+
+            column.datas.forEach((item) => {
+              if (item.enable) privilegeIds.push(item.id);
+            });
+          });
+        });
+      return { privilegeIds, dataPermissionInfo };
+    },
+    // set change
+    pageSelectChange(row, enable) {
+      this.changRowColumnEnable(row, enable);
+      this.changeParentNodeSelected(row.parentId, enable);
+      this.changeChildrenNodeSelected(row.id, enable);
+    },
+    typeSelectChange(row, enable) {
+      if (!row.enable && enable) {
+        row.enable = enable;
+        this.changeParentNodeSelected(row.parentId, enable);
+        this.changeChildrenNodeSelected(row.id, enable);
+      }
+    },
+    changRowColumnEnable(row, enable) {
+      if (!row.isPage) return;
+      row.columns.forEach((column) => {
+        if (!column.datas || !column.datas.length) return;
+
+        column.datas.forEach((item) => {
+          item.enable = enable;
+        });
+      });
+    },
+    changeParentNodeSelected(parentId, enable) {
+      if (!parentId) return;
+      let curParentId = parentId;
+      if (enable) {
+        while (curParentId) {
+          let curParentNode = this.tableData.find(
+            (row) => row.id === curParentId
+          );
+          curParentNode.enable = enable;
+          curParentId = curParentNode.parentId;
+          this.changRowColumnEnable(curParentNode, enable);
+        }
+      } else {
+        while (curParentId) {
+          let curParentNode = this.tableData.find(
+            (row) => row.id === curParentId
+          );
+          let childrenHasOneSelected = this.tableData
+            .filter((row) => row.parentId === curParentId)
+            .some((row) => row.enable);
+          curParentNode.enable = childrenHasOneSelected;
+          curParentId = curParentNode.parentId;
+          this.changRowColumnEnable(curParentNode, enable);
+        }
+      }
+    },
+    changeChildrenNodeSelected(id, enable) {
+      if (!id) return;
+      let curIds = [id];
+      while (curIds.length) {
+        const validNodes = this.tableData.filter((row) =>
+          curIds.includes(row.parentId)
+        );
+        validNodes.forEach((row) => {
+          row.enable = enable;
+          this.changRowColumnEnable(row, enable);
+        });
+        curIds = validNodes.map((row) => row.id);
+      }
+    },
+  },
+};
+</script>

+ 56 - 155
src/views/user/auth-manage/role-manage/edit-role-dialog.vue

@@ -14,54 +14,11 @@
       </t-form-item>
 
       <t-form-item label="绑定权限" required-mark>
-        <div>
-          <div class="m-b-10px">
-            <t-button theme="primary" @click="allCheckHandler(true)"
-              >全选</t-button
-            >
-            <t-button
-              theme="primary"
-              variant="outline"
-              @click="allCheckHandler(false)"
-              class="m-l-10px"
-              >全不选</t-button
-            >
-          </div>
-          <t-table
-            row-key="id"
-            :columns="columns"
-            :data="treeFlatArr"
-            bordered
-            v-loading="loading"
-          >
-            <template #page="{ row }">
-              <t-checkbox
-                v-model="row.hasRole"
-                @change="pageRoleChange(row)"
-              ></t-checkbox>
-            </template>
-            <template #conditions="{ row }">
-              <div v-for="item in row.conditions" :key="item.id">
-                <t-checkbox v-model="item.hasRole">{{ item.name }}</t-checkbox>
-              </div>
-            </template>
-            <template #buttons="{ row }">
-              <div v-for="item in row.buttons" :key="item.id">
-                <t-checkbox v-model="item.hasRole">{{ item.name }}</t-checkbox>
-              </div>
-            </template>
-            <template #lists="{ row }">
-              <div v-for="item in row.lists" :key="item.id">
-                <t-checkbox v-model="item.hasRole">{{ item.name }}</t-checkbox>
-              </div>
-            </template>
-            <template #links="{ row }">
-              <div v-for="item in row.links" :key="item.id">
-                <t-checkbox v-model="item.hasRole">{{ item.name }}</t-checkbox>
-              </div>
-            </template>
-          </t-table>
-        </div>
+        <privilege-edit
+          v-if="menus && menus.length"
+          ref="privilegeSetRef"
+          :menus="menus"
+        ></privilege-edit>
       </t-form-item>
     </t-form>
     <template #foot>
@@ -78,9 +35,10 @@
   </my-drawer>
 </template>
 <script setup name="EditRoleDialog">
-import { ref, reactive, watch, computed } from 'vue';
+import { ref, reactive, watch, computed, onMounted, nextTick } from 'vue';
 import { getAllMenuResource, addRole, getRoleDetail } from '@/api/user';
 import { MessagePlugin } from 'tdesign-vue-next';
+import PrivilegeEdit from './privilege-edit.vue';
 
 const props = defineProps({
   visible: Boolean,
@@ -93,8 +51,10 @@ const title = computed(() => {
 });
 
 const formRef = ref(null);
+const privilegeSetRef = ref(null);
 const formData = reactive({
   name: '',
+  privilegeIds: [],
 });
 const curRoleBindIds = ref([]);
 const rules = {
@@ -105,125 +65,66 @@ const rules = {
     },
   ],
 };
-let loading = ref(false);
-let treeFlatArr = ref([]);
+let menus = ref([]);
 
-const allCheckHandler = (bool) => {
-  setAllCheckStatus(treeFlatArr.value, bool);
-};
-const setAllCheckStatus = (data, bool) => {
-  for (let i = 0; i < data.length; i++) {
-    data[i].hasRole = bool;
-    setAllCheckStatus(data[i].children || [], bool);
-    setAllCheckStatus(data[i].conditions || [], bool);
-    setAllCheckStatus(data[i].buttons || [], bool);
-    setAllCheckStatus(data[i].lists || [], bool);
-    setAllCheckStatus(data[i].links || [], bool);
-  }
-};
-const setAllCheckStatusInArr = (arr, bool) => {
-  for (let i = 0; i < arr.length; i++) {
-    arr[i].hasRole = bool;
-  }
-};
-const setPageRangeSubCheckStatus = (row, bool) => {
-  setAllCheckStatusInArr(row.children || [], bool);
-  setAllCheckStatusInArr(row.conditions || [], bool);
-  setAllCheckStatusInArr(row.buttons || [], bool);
-  setAllCheckStatusInArr(row.lists || [], bool);
-  setAllCheckStatusInArr(row.links || [], bool);
-};
-const pageRoleChange = (row) => {
-  console.log('rrr', row);
-  setPageRangeSubCheckStatus(row, row.hasRole);
-};
+onMounted(() => {
+  getMenus();
+});
+
+async function getMenus() {
+  const data = await getAllMenuResource();
+  menus.value = (data || []).map((item) => {
+    item.parentId = null;
+    return item;
+  });
+}
 const getDetail = async () => {
+  let privilegeIds = [],
+    dataPermissionInfo = [],
+    disabledIds = [];
+
   let id = props.curRow?.id;
-  loading.value = true;
   if (id) {
     let roleDetail = await getRoleDetail({ roleId: id });
-    formData.name = roleDetail.name;
-    curRoleBindIds.value = JSON.parse(roleDetail.privilegeIds || '[]').map(
-      (item) => String(item)
+    privilegeIds = JSON.parse(roleDetail.privilegeIds || '[]').map((item) =>
+      String(item)
     );
+    dataPermissionInfo = roleDetail.dataPermissionInfo || [];
+    formData.name = roleDetail.name;
+    formData.privilegeIds = privilegeIds;
   }
-  let treeData = await getAllMenuResource();
-  treeFlatArr.value = treeToArr(treeData || []);
-  loading.value = false;
-};
 
-const columns = [
-  { colKey: 'level1', title: '一级页面' },
-  { colKey: 'level2', title: '二级页面' },
-  { colKey: 'level3', title: '三级页面' },
-  { colKey: 'page', title: '页面', width: 80, align: 'center' },
-  { colKey: 'conditions', title: '查询条件', width: 160 },
-  { colKey: 'buttons', title: '功能按钮', width: 160 },
-  { colKey: 'lists', title: '列表展示', width: 150 },
-  { colKey: 'links', title: '操作列', width: 150 },
-];
-const initCheckBoxValue = (arr) => {
-  return arr.map((item) => {
-    item.hasRole = curRoleBindIds.value.includes(item.id) ? true : false;
-    return item;
+  nextTick(() => {
+    formRef.value.clearValidate();
+    privilegeSetRef.value.buildTableData(
+      privilegeIds,
+      dataPermissionInfo,
+      disabledIds
+    );
   });
 };
-const treeToArr = (tree, arr = [], level = 1) => {
-  for (let i = 0; i < tree.length; i++) {
-    let l = level;
-    arr.push({
-      ...tree[i],
-      level: l,
-      level1: l == 1 ? tree[i].name : '',
-      level2: l == 2 ? tree[i].name : '',
-      level3: l == 3 ? tree[i].name : '',
-      hasRole: curRoleBindIds.value.includes(tree[i].id) ? true : false,
-      conditions: tree[i].conditions
-        ? initCheckBoxValue(tree[i].conditions)
-        : [],
-      buttons: tree[i].buttons ? initCheckBoxValue(tree[i].buttons) : [],
-      links: tree[i].links ? initCheckBoxValue(tree[i].links) : [],
-      lists: tree[i].lists ? initCheckBoxValue(tree[i].lists) : [],
-    });
-    l++;
-    if (tree[i].children && tree[i].children.length) {
-      treeToArr(tree[i].children, arr, l);
-    }
-  }
-  return arr;
-};
-const getHasRoleIds = (data, arr = []) => {
-  for (let i = 0; i < data.length; i++) {
-    if (data[i].hasRole) {
-      arr.push(data[i].id);
-    }
-    getHasRoleIds(data[i].children || [], arr);
-    getHasRoleIds(data[i].conditions || [], arr);
-    getHasRoleIds(data[i].buttons || [], arr);
-    getHasRoleIds(data[i].lists || [], arr);
-    getHasRoleIds(data[i].links || [], arr);
+
+const submitHandler = async () => {
+  const valid = await formRef.value.validate();
+  if (valid !== true) return;
+
+  const { privilegeIds } = privilegeSetRef.value.getSelectedPrivileges();
+  if (!privilegeIds.length) {
+    MessagePlugin.error('请设置功能权限!');
+    return;
   }
-  return Array.from(new Set(arr));
-};
-const addHandler = () => {
-  let checkIds = getHasRoleIds(treeFlatArr.value);
-  // console.log('checkIds', checkIds, checkIds.length);
-  addRole({
+
+  const res = await addRole({
     name: formData.name,
-    privilegeIds: checkIds,
+    privilegeIds,
     id: props.curRow?.id || undefined,
-  }).then(() => {
-    MessagePlugin.success('操作成功');
-    emit('update:visible', false);
-    emit('success');
-  });
-};
-const submitHandler = () => {
-  formRef.value.validate().then(async (result) => {
-    if (result === true) {
-      addHandler();
-    }
-  });
+  }).catch(() => {});
+
+  if (!res) return;
+
+  MessagePlugin.success('操作成功');
+  emit('update:visible', false);
+  emit('success');
 };
 
 watch(

+ 310 - 0
src/views/user/auth-manage/role-manage/privilege-edit.vue

@@ -0,0 +1,310 @@
+<template>
+  <div class="privilege-set">
+    <table class="table">
+      <colgroup>
+        <col width="120" />
+        <col width="120" />
+        <col width="140" />
+        <col width="60" />
+        <col width="210" />
+      </colgroup>
+      <tbody>
+        <tr>
+          <th v-for="(item, index) in tableHead" :key="index">{{ item }}</th>
+        </tr>
+        <tr v-for="row in tableData" :key="row.id">
+          <td v-for="(col, cindex) in row.columns" :key="cindex">
+            <div v-if="col && col.type === 'page'">{{ col.name }}</div>
+            <div v-else-if="col && col.type === 'page-checkbox'">
+              <t-checkbox
+                v-model="row.enable"
+                :disabled="row.disabled"
+                @change="(enable) => pageSelectChange(row, enable)"
+              ></t-checkbox>
+            </div>
+            <div
+              v-else-if="
+                row.isPage && col && col.type === 'page-data-permission'
+              "
+            >
+              <t-select
+                v-model="row.dataPermissionType"
+                class="width-200"
+                placeholder="请选择"
+                :disabled="row.disabled"
+                :options="dictToOptionList(DATA_PRIVILEGE_TYPE)"
+              >
+              </t-select>
+            </div>
+            <div v-else-if="col && col.type">
+              <div
+                class="cell-check-list"
+                v-for="item in col.datas"
+                :key="item.field"
+              >
+                <t-checkbox
+                  v-model="item.enable"
+                  :disabled="item.disabled"
+                  @change="(enable) => typeSelectChange(row, enable)"
+                  >{{ item.name }}</t-checkbox
+                >
+              </div>
+            </div>
+            <div v-else></div>
+          </td>
+        </tr>
+      </tbody>
+    </table>
+  </div>
+</template>
+
+<script setup name="PrivilegeEdit">
+import { onMounted, ref } from 'vue';
+import { DATA_PRIVILEGE_TYPE } from '@/config/constants';
+import { dictToOptionList } from '@/utils/tool';
+
+const props = defineProps({
+  menus: Array,
+  showPermission: {
+    type: Boolean,
+    default: false,
+  },
+  disabledPermissionUrls: {
+    type: Array,
+    default() {
+      return [];
+    },
+  },
+});
+
+const maxDeep = ref(0);
+const tableData = ref([]);
+const tableHead = ref([]);
+
+onMounted(() => {
+  initData();
+});
+
+function initData() {
+  maxDeep.value = getNavsDeep();
+  tableHead.value = buildTableHead();
+}
+
+function getNavsDeep() {
+  let mDeep = 0;
+  const getDeep = (navs, deep) => {
+    ++deep;
+    navs.forEach((nav) => {
+      if (mDeep < deep) mDeep = deep;
+
+      if (nav.children && nav.children.length) getDeep(nav.children, deep);
+    });
+  };
+  getDeep(props.menus, mDeep);
+
+  return mDeep;
+}
+function buildTableHead() {
+  let headers = [];
+  let codes = ['一', '二', '三', '四', '五', '六', '七', '八'];
+  for (let index = 0; index < maxDeep.value; index++) {
+    headers.push(`${codes[index]}级页面`);
+  }
+  headers = [...headers, '页面'];
+  if (props.showPermission) headers.push('数据权限');
+  headers = [...headers, '查询条件', '功能按钮', '列表展示', '操作列'];
+
+  return headers;
+}
+function buildTableData(
+  privilegeIds = [],
+  dataPermissionInfo = [],
+  disabledIds = []
+) {
+  let dataList = [];
+  const privColumnCount = props.showPermission ? 6 : 5;
+  let tableColumnCount = maxDeep.value + privColumnCount;
+  const pageSetTypes = ['conditions', 'buttons', 'lists', 'links'];
+
+  let datePermissionMap = {};
+  dataPermissionInfo.forEach((item) => {
+    datePermissionMap[item.privilegeId] = item.dataPermissionType;
+  });
+  const buildData = (navs, deep) => {
+    ++deep;
+    navs.forEach((nav) => {
+      const isDisabledPermissionUrl = props.disabledPermissionUrls.includes(
+        nav.url
+      );
+      let columns = new Array(tableColumnCount);
+      columns[deep - 1] = { type: 'page', name: nav.name };
+      columns[maxDeep.value] = {
+        type: 'page-checkbox',
+      };
+      if (props.showPermission && !isDisabledPermissionUrl) {
+        columns[maxDeep.value + 1] = {
+          type: 'page-data-permission',
+        };
+      }
+
+      const isPage = pageSetTypes.some((type) => nav[type] && nav[type].length);
+      const offsetPageSetInd = props.showPermission ? 2 : 1;
+      if (isPage) {
+        pageSetTypes.forEach((type, index) => {
+          const datas = !nav[type]
+            ? []
+            : nav[type].map((elem) => {
+                let data = { ...elem };
+                data.enable = privilegeIds.includes(elem.id);
+                data.disabled = disabledIds.includes(elem.id);
+                return data;
+              });
+          columns[maxDeep.value + index + offsetPageSetInd] = {
+            type,
+            datas,
+          };
+        });
+      }
+
+      dataList.push({
+        id: nav.id,
+        name: nav.name,
+        url: nav.url,
+        enable: privilegeIds.includes(nav.id),
+        disabled: disabledIds.includes(nav.id),
+        dataPermissionType:
+          isPage && props.showPermission && !isDisabledPermissionUrl
+            ? datePermissionMap[nav.id] || 'SELF'
+            : null,
+        type: nav.type,
+        parentId: nav.parentId,
+        isPage,
+        columns,
+      });
+
+      if (nav.children && nav.children.length) buildData(nav.children, deep);
+    });
+  };
+  buildData(props.menus, 0);
+
+  tableData.value = dataList;
+}
+function resetdataPermissionType(val) {
+  tableData.value.forEach((item) => {
+    if (
+      item.isPage &&
+      !item.disabled &&
+      props.showPermission &&
+      !this.disabledPermissionUrls.includes(item.url)
+    )
+      item.dataPermissionType = val;
+  });
+}
+function getSelectedPrivileges() {
+  let privilegeIds = [];
+  let dataPermissionInfo = [];
+  tableData.value
+    .filter((row) => row.enable)
+    .forEach((row) => {
+      privilegeIds.push(row.id);
+      dataPermissionInfo.push({
+        privilegeId: row.id,
+        dataPermissionType: row.dataPermissionType,
+      });
+      row.columns.forEach((column) => {
+        if (!column.datas || !column.datas.length) return;
+
+        column.datas.forEach((item) => {
+          if (item.enable) privilegeIds.push(item.id);
+        });
+      });
+    });
+  return { privilegeIds, dataPermissionInfo };
+}
+// set change
+function pageSelectChange(row, enable) {
+  changRowColumnEnable(row, enable);
+  changeParentNodeSelected(row.parentId, enable);
+  changeChildrenNodeSelected(row.id, enable);
+}
+function typeSelectChange(row, enable) {
+  if (!row.enable && enable) {
+    row.enable = enable;
+    changeParentNodeSelected(row.parentId, enable);
+    changeChildrenNodeSelected(row.id, enable);
+  }
+}
+function changRowColumnEnable(row, enable) {
+  if (!row.isPage) return;
+  row.columns.forEach((column) => {
+    if (!column.datas || !column.datas.length) return;
+
+    column.datas.forEach((item) => {
+      item.enable = enable;
+    });
+  });
+}
+function changeParentNodeSelected(parentId, enable) {
+  if (!parentId) return;
+  let curParentId = parentId;
+  if (enable) {
+    while (curParentId) {
+      let curParentNode = tableData.value.find((row) => row.id === curParentId);
+      curParentNode.enable = enable;
+      curParentId = curParentNode.parentId;
+      changRowColumnEnable(curParentNode, enable);
+    }
+  } else {
+    while (curParentId) {
+      let curParentNode = tableData.value.find((row) => row.id === curParentId);
+      let childrenHasOneSelected = tableData.value
+        .filter((row) => row.parentId === curParentId)
+        .some((row) => row.enable);
+      curParentNode.enable = childrenHasOneSelected;
+      curParentId = curParentNode.parentId;
+      changRowColumnEnable(curParentNode, enable);
+    }
+  }
+}
+function changeChildrenNodeSelected(id, enable) {
+  if (!id) return;
+  let curIds = [id];
+  while (curIds.length) {
+    const validNodes = tableData.value.filter((row) =>
+      curIds.includes(row.parentId)
+    );
+    validNodes.forEach((row) => {
+      row.enable = enable;
+      changRowColumnEnable(row, enable);
+    });
+    curIds = validNodes.map((row) => row.id);
+  }
+}
+
+defineExpose({
+  buildTableData,
+  getSelectedPrivileges,
+  resetdataPermissionType,
+});
+</script>
+
+<style lang="less" scoped>
+.privilege-set {
+  overflow: auto;
+  width: 100%;
+  .table {
+    td,
+    th {
+      padding: 8px 10px;
+    }
+
+    th:nth-of-type(4),
+    td:nth-of-type(4) {
+      text-align: center;
+    }
+  }
+  .cell-check-list {
+    text-align: left;
+  }
+}
+</style>