Răsfoiți Sursa

优化权限设置,实现角色权限配置的反显

yanglzh 2 ani în urmă
părinte
comite
7cfd5d8f17

+ 7 - 5
.env.development

@@ -1,5 +1,7 @@
-# 本地环境
-# VITE_SERVER_PROTOCOL = 'http:'
-# VITE_SERVER_HOSTNAME = 'sgadserver.wdeveloperw.xyz'
-VITE_SERVER_PROTOCOL = 'https:'
-VITE_SERVER_HOSTNAME = 'zhgy.sagoo.cn'
+VITE_SERVER_PROTOCOL = 'http:'
+VITE_SERVER_HOSTNAME = 'sgadserver.wdeveloperw.xyz'
+VITE_SERVER_URL = ''
+VITE_API_URL = '/api/v1'
+
+# VITE_SERVER_PROTOCOL = 'https:'
+# VITE_SERVER_HOSTNAME = 'zhgy.sagoo.cn'

+ 242 - 213
src/layout/navBars/breadcrumb/user.vue

@@ -1,6 +1,9 @@
 <template>
-	<div class="layout-navbars-breadcrumb-user" :style="{ flex: layoutUserFlexNum }">
-		<!-- <el-dropdown :show-timeout="70" :hide-timeout="50" trigger="click" @command="onComponentSizeChange">
+  <div
+    class="layout-navbars-breadcrumb-user"
+    :style="{ flex: layoutUserFlexNum }"
+  >
+    <!-- <el-dropdown :show-timeout="70" :hide-timeout="50" trigger="click" @command="onComponentSizeChange">
 			<div class="layout-navbars-breadcrumb-user-icon">
 				<i class="iconfont icon-ziti" :title="$t('message.user.title0')"></i>
 			</div>
@@ -12,7 +15,7 @@
 				</el-dropdown-menu>
 			</template>
 		</el-dropdown> -->
-		<!-- <el-dropdown :show-timeout="70" :hide-timeout="50" trigger="click" @command="onLanguageChange">
+    <!-- <el-dropdown :show-timeout="70" :hide-timeout="50" trigger="click" @command="onLanguageChange">
 			<div class="layout-navbars-breadcrumb-user-icon">
 				<i class="iconfont" :class="disabledI18n === 'en' ? 'icon-fuhao-yingwen' : 'icon-fuhao-zhongwen'" :title="$t('message.user.title1')"></i>
 			</div>
@@ -24,51 +27,77 @@
 				</el-dropdown-menu>
 			</template>
 		</el-dropdown> -->
-		<div class="layout-navbars-breadcrumb-user-icon" @click="onSearchClick">
-			<el-icon :title="$t('message.user.title2')">
-				<ele-Search />
-			</el-icon>
-		</div>
-		<div class="layout-navbars-breadcrumb-user-icon" @click="onLayoutSetingClick">
-			<i class="icon-skin iconfont" :title="$t('message.user.title3')"></i>
-		</div>
-		<div class="layout-navbars-breadcrumb-user-icon">
-			<el-popover placement="bottom" trigger="click" :width="300">
-				<template #reference>
-					<el-badge :is-dot="true">
-						<el-icon :title="$t('message.user.title4')">
-							<ele-Bell />
-						</el-icon>
-					</el-badge>
-				</template>
-				<UserNews />
-			</el-popover>
-		</div>
-		<div class="layout-navbars-breadcrumb-user-icon mr10" @click="onScreenfullClick">
-			<i
-				class="iconfont"
-				:title="isScreenfull ? $t('message.user.title6') : $t('message.user.title5')"
-				:class="!isScreenfull ? 'icon-fullscreen' : 'icon-tuichuquanping'"
-			></i>
-		</div>
-		<el-dropdown :show-timeout="70" :hide-timeout="50" @command="onHandleCommandClick">
-			<span class="layout-navbars-breadcrumb-user-link">
-				<img :src="getUserInfos.avatar" class="layout-navbars-breadcrumb-user-link-photo mr5" />
-				{{ getUserInfos.userName === '' ? 'common' : getUserInfos.userName }}
-				<el-icon class="el-icon--right">
-					<ele-ArrowDown />
-				</el-icon>
-			</span>
-			<template #dropdown>
-				<el-dropdown-menu>
-					<el-dropdown-item command="/home">{{ $t('message.user.dropdown1') }}</el-dropdown-item>
-					<el-dropdown-item command="/personal">{{ $t('message.user.dropdown2') }}</el-dropdown-item>
-					<el-dropdown-item divided command="logOut">{{ $t('message.user.dropdown5') }}</el-dropdown-item>
-				</el-dropdown-menu>
-			</template>
-		</el-dropdown>
-		<Search ref="searchRef" />
-	</div>
+    <div
+      class="layout-navbars-breadcrumb-user-icon"
+      @click="onSearchClick"
+    >
+      <el-icon :title="$t('message.user.title2')">
+        <ele-Search />
+      </el-icon>
+    </div>
+    <div
+      class="layout-navbars-breadcrumb-user-icon"
+      @click="onLayoutSetingClick"
+    >
+      <i
+        class="icon-skin iconfont"
+        :title="$t('message.user.title3')"
+      ></i>
+    </div>
+    <div class="layout-navbars-breadcrumb-user-icon">
+      <el-popover
+        placement="bottom"
+        trigger="click"
+        :width="300"
+      >
+        <template #reference>
+          <el-badge :is-dot="true">
+            <el-icon :title="$t('message.user.title4')">
+              <ele-Bell />
+            </el-icon>
+          </el-badge>
+        </template>
+        <UserNews />
+      </el-popover>
+    </div>
+    <div
+      class="layout-navbars-breadcrumb-user-icon mr10"
+      @click="onScreenfullClick"
+    >
+      <i
+        class="iconfont"
+        :title="isScreenfull ? $t('message.user.title6') : $t('message.user.title5')"
+        :class="!isScreenfull ? 'icon-fullscreen' : 'icon-tuichuquanping'"
+      ></i>
+    </div>
+    <el-dropdown
+      :show-timeout="70"
+      :hide-timeout="50"
+      @command="onHandleCommandClick"
+    >
+      <span class="layout-navbars-breadcrumb-user-link">
+        <img
+          :src="getUserInfos.avatar"
+          class="layout-navbars-breadcrumb-user-link-photo mr5"
+        />
+        {{ getUserInfos.userName === '' ? 'common' : getUserInfos.userName }}
+        <el-icon class="el-icon--right">
+          <ele-ArrowDown />
+        </el-icon>
+      </span>
+      <template #dropdown>
+        <el-dropdown-menu>
+          <el-dropdown-item command="/home">{{ $t('message.user.dropdown1') }}</el-dropdown-item>
+          <el-dropdown-item command="/personal">{{ $t('message.user.dropdown2') }}</el-dropdown-item>
+          <el-dropdown-item
+            divided
+            command="logOut"
+          >{{ $t('message.user.dropdown5') }}</el-dropdown-item>
+        </el-dropdown-menu>
+      </template>
+    </el-dropdown>
+    <Search ref="searchRef" />
+  </div>
 </template>
 
 <script lang="ts">
@@ -85,171 +114,171 @@ import UserNews from '/@/layout/navBars/breadcrumb/userNews.vue';
 import Search from '/@/layout/navBars/breadcrumb/search.vue';
 import api from '/@/api/system';
 export default defineComponent({
-	name: 'layoutBreadcrumbUser',
-	components: { UserNews, Search },
-	setup() {
-		const { t } = useI18n();
-		const { proxy } = <any>getCurrentInstance();
-		const router = useRouter();
-		const store = useStore();
-		const searchRef = ref();
-		const state = reactive({
-			isScreenfull: false,
-			disabledI18n: 'zh-cn',
-			disabledSize: 'large',
-		});
-		// 获取用户信息 vuex
-		const getUserInfos = computed(() => {
-			return <any>store.state.userInfos.userInfos;
-		});
-		// 获取布局配置信息
-		const getThemeConfig = computed(() => {
-			return store.state.themeConfig.themeConfig;
-		});
-		// 设置分割样式
-		const layoutUserFlexNum = computed(() => {
-			let num: string | number = '';
-			const { layout, isClassicSplitMenu } = getThemeConfig.value;
-			const layoutArr: string[] = ['defaults', 'columns'];
-			if (layoutArr.includes(layout) || (layout === 'classic' && !isClassicSplitMenu)) num = '1';
-			else num = '';
-			return num;
-		});
-		// 全屏点击时
-		const onScreenfullClick = () => {
-			if (!screenfull.isEnabled) {
-				ElMessage.warning('暂不不支持全屏');
-				return false;
-			}
-			screenfull.toggle();
-			screenfull.on('change', () => {
-				if (screenfull.isFullscreen) state.isScreenfull = true;
-				else state.isScreenfull = false;
-			});
-		};
-		// 布局配置 icon 点击时
-		const onLayoutSetingClick = () => {
-			proxy.mittBus.emit('openSetingsDrawer');
-		};
-		// 下拉菜单点击时
-		const onHandleCommandClick = (path: string) => {
-			if (path === 'logOut') {
-				ElMessageBox({
-					closeOnClickModal: false,
-					closeOnPressEscape: false,
-					title: t('message.user.logOutTitle'),
-					message: t('message.user.logOutMessage'),
-					showCancelButton: true,
-					confirmButtonText: t('message.user.logOutConfirm'),
-					cancelButtonText: t('message.user.logOutCancel'),
-					buttonSize: 'default',
-					beforeClose: (action, instance, done) => {
-						if (action === 'confirm') {
-							instance.confirmButtonLoading = true;
-							instance.confirmButtonText = t('message.user.logOutExit');
-							setTimeout(() => {
-								done();
-								setTimeout(() => {
-									instance.confirmButtonLoading = false;
-								}, 300);
-							}, 700);
-						} else {
-							done();
-						}
-					},
-				})
-					.then(async () => {
-						await api.login.logout();
-						Session.clear(); // 清除缓存/token等
-						await resetRoute(); // 删除/重置路由
-						ElMessage.success(t('message.user.logOutSuccess'));
-						setTimeout(() => {
-							window.location.href = ''; // 去登录页
-						}, 500);
-					})
-					.catch(() => {});
-			} else if (path === 'wareHouse') {
-				window.open('https://sagoo.cn');
-			} else {
-				router.push(path);
-			}
-		};
-		// 菜单搜索点击
-		const onSearchClick = () => {
-			searchRef.value.openSearch();
-		};
-		// 组件大小改变
-		const onComponentSizeChange = (size: string) => {
-			Local.remove('themeConfig');
-			getThemeConfig.value.globalComponentSize = size;
-			Local.set('themeConfig', getThemeConfig.value);
-			initComponentSize();
-			window.location.reload();
-		};
-		// 语言切换
-		const onLanguageChange = (lang: string) => {
-			Local.remove('themeConfig');
-			getThemeConfig.value.globalI18n = lang;
-			Local.set('themeConfig', getThemeConfig.value);
-			proxy.$i18n.locale = lang;
-			initI18n();
-			other.useTitle();
-		};
-		// 设置 element plus 组件的国际化
-		const setI18nConfig = (locale: string) => {
-			proxy.mittBus.emit('getI18nConfig', proxy.$i18n.messages[locale]);
-		};
-		// 初始化言语国际化
-		const initI18n = () => {
-			switch (Local.get('themeConfig').globalI18n) {
-				case 'zh-cn':
-					state.disabledI18n = 'zh-cn';
-					setI18nConfig('zh-cn');
-					break;
-				case 'en':
-					state.disabledI18n = 'en';
-					setI18nConfig('en');
-					break;
-				case 'zh-tw':
-					state.disabledI18n = 'zh-tw';
-					setI18nConfig('zh-tw');
-					break;
-			}
-		};
-		// 初始化全局组件大小
-		const initComponentSize = () => {
-			switch (Local.get('themeConfig').globalComponentSize) {
-				case 'large':
-					state.disabledSize = 'large';
-					break;
-				case 'default':
-					state.disabledSize = 'default';
-					break;
-				case 'small':
-					state.disabledSize = 'small';
-					break;
-			}
-		};
-		// 页面加载时
-		onMounted(() => {
-			if (Local.get('themeConfig')) {
-				initI18n();
-				initComponentSize();
-			}
-		});
-		return {
-			getUserInfos,
-			onLayoutSetingClick,
-			onHandleCommandClick,
-			onScreenfullClick,
-			onSearchClick,
-			onComponentSizeChange,
-			onLanguageChange,
-			searchRef,
-			layoutUserFlexNum,
-			...toRefs(state),
-		};
-	},
+  name: 'layoutBreadcrumbUser',
+  components: { UserNews, Search },
+  setup() {
+    const { t } = useI18n();
+    const { proxy } = <any>getCurrentInstance();
+    const router = useRouter();
+    const store = useStore();
+    const searchRef = ref();
+    const state = reactive({
+      isScreenfull: false,
+      disabledI18n: 'zh-cn',
+      disabledSize: 'large',
+    });
+    // 获取用户信息 vuex
+    const getUserInfos = computed(() => {
+      return <any>store.state.userInfos.userInfos;
+    });
+    // 获取布局配置信息
+    const getThemeConfig = computed(() => {
+      return store.state.themeConfig.themeConfig;
+    });
+    // 设置分割样式
+    const layoutUserFlexNum = computed(() => {
+      let num: string | number = '';
+      const { layout, isClassicSplitMenu } = getThemeConfig.value;
+      const layoutArr: string[] = ['defaults', 'columns'];
+      if (layoutArr.includes(layout) || (layout === 'classic' && !isClassicSplitMenu)) num = '1';
+      else num = '';
+      return num;
+    });
+    // 全屏点击时
+    const onScreenfullClick = () => {
+      if (!screenfull.isEnabled) {
+        ElMessage.warning('暂不不支持全屏');
+        return false;
+      }
+      screenfull.toggle();
+      screenfull.on('change', () => {
+        if (screenfull.isFullscreen) state.isScreenfull = true;
+        else state.isScreenfull = false;
+      });
+    };
+    // 布局配置 icon 点击时
+    const onLayoutSetingClick = () => {
+      proxy.mittBus.emit('openSetingsDrawer');
+    };
+    // 下拉菜单点击时
+    const onHandleCommandClick = (path: string) => {
+      if (path === 'logOut') {
+        ElMessageBox({
+          closeOnClickModal: false,
+          closeOnPressEscape: false,
+          title: t('message.user.logOutTitle'),
+          message: t('message.user.logOutMessage'),
+          showCancelButton: true,
+          confirmButtonText: t('message.user.logOutConfirm'),
+          cancelButtonText: t('message.user.logOutCancel'),
+          buttonSize: 'default',
+          beforeClose: (action, instance, done) => {
+            if (action === 'confirm') {
+              instance.confirmButtonLoading = true;
+              instance.confirmButtonText = t('message.user.logOutExit');
+              setTimeout(() => {
+                done();
+                setTimeout(() => {
+                  instance.confirmButtonLoading = false;
+                }, 300);
+              }, 700);
+            } else {
+              done();
+            }
+          },
+        })
+          .then(async () => {
+            Session.clear(); // 清除缓存/token等
+            await resetRoute(); // 删除/重置路由
+            ElMessage.success(t('message.user.logOutSuccess'));
+            api.login.logout();
+            setTimeout(() => {
+              window.location.href = ''; // 去登录页
+            }, 500);
+          })
+          .catch(() => { });
+      } else if (path === 'wareHouse') {
+        window.open('https://sagoo.cn');
+      } else {
+        router.push(path);
+      }
+    };
+    // 菜单搜索点击
+    const onSearchClick = () => {
+      searchRef.value.openSearch();
+    };
+    // 组件大小改变
+    const onComponentSizeChange = (size: string) => {
+      Local.remove('themeConfig');
+      getThemeConfig.value.globalComponentSize = size;
+      Local.set('themeConfig', getThemeConfig.value);
+      initComponentSize();
+      window.location.reload();
+    };
+    // 语言切换
+    const onLanguageChange = (lang: string) => {
+      Local.remove('themeConfig');
+      getThemeConfig.value.globalI18n = lang;
+      Local.set('themeConfig', getThemeConfig.value);
+      proxy.$i18n.locale = lang;
+      initI18n();
+      other.useTitle();
+    };
+    // 设置 element plus 组件的国际化
+    const setI18nConfig = (locale: string) => {
+      proxy.mittBus.emit('getI18nConfig', proxy.$i18n.messages[locale]);
+    };
+    // 初始化言语国际化
+    const initI18n = () => {
+      switch (Local.get('themeConfig').globalI18n) {
+        case 'zh-cn':
+          state.disabledI18n = 'zh-cn';
+          setI18nConfig('zh-cn');
+          break;
+        case 'en':
+          state.disabledI18n = 'en';
+          setI18nConfig('en');
+          break;
+        case 'zh-tw':
+          state.disabledI18n = 'zh-tw';
+          setI18nConfig('zh-tw');
+          break;
+      }
+    };
+    // 初始化全局组件大小
+    const initComponentSize = () => {
+      switch (Local.get('themeConfig').globalComponentSize) {
+        case 'large':
+          state.disabledSize = 'large';
+          break;
+        case 'default':
+          state.disabledSize = 'default';
+          break;
+        case 'small':
+          state.disabledSize = 'small';
+          break;
+      }
+    };
+    // 页面加载时
+    onMounted(() => {
+      if (Local.get('themeConfig')) {
+        initI18n();
+        initComponentSize();
+      }
+    });
+    return {
+      getUserInfos,
+      onLayoutSetingClick,
+      onHandleCommandClick,
+      onScreenfullClick,
+      onSearchClick,
+      onComponentSizeChange,
+      onLanguageChange,
+      searchRef,
+      layoutUserFlexNum,
+      ...toRefs(state),
+    };
+  },
 });
 </script>
 

+ 183 - 121
src/views/system/manage/role/component/permission.vue

@@ -1,36 +1,70 @@
 <template>
-	<el-dialog :title="title" v-model="isShowDialog" width="1100px">
-		<div class="mb-4 tr">
-			<el-dropdown>
-				<el-button plain class="mr-3">
-					操作<el-icon>
-						<ele-ArrowDown />
-					</el-icon>
-				</el-button>
-				<template #dropdown>
-					<el-dropdown-menu>
-						<el-dropdown-item @click.native="checkAll(true)">全部勾选</el-dropdown-item>
-						<el-dropdown-item @click.native="checkAll(false)">取消全选</el-dropdown-item>
-						<el-dropdown-item @click.native="expand(true)">展开所有</el-dropdown-item>
-						<el-dropdown-item @click.native="expand(false)">折叠所有</el-dropdown-item>
-					</el-dropdown-menu>
-				</template>
-			</el-dropdown>
-			<el-button :disabled="step <= 0" @click="prev">上一步</el-button>
-			<el-button :disabled="step >= 3" @click="next">下一步</el-button>
-			<el-button type="primary" :loading="btnLoading" :disabled="step < 3" @click="submit">确定</el-button>
-			<el-button @click="cancel">取消</el-button>
-		</div>
-		<el-steps :active="step" simple>
-			<el-step name title="菜单权限" />
-			<el-step title="按钮权限" />
-			<el-step title="列表权限" />
-			<el-step title="接口权限" />
-		</el-steps>
-		<div class="scroll-part mt-3">
-			<el-tree ref="treeRef" :data="treeData" show-checkbox default-expand-all node-key="id" highlight-current :props="defaultProps" check-on-click-node :expand-on-click-node="false" />
-		</div>
-	</el-dialog>
+  <el-dialog
+    :title="title"
+    v-model="isShowDialog"
+    width="1100px"
+  >
+    <div class="mb-4 tr">
+      <el-dropdown>
+        <el-button
+          plain
+          class="mr-3"
+        >
+          操作<el-icon>
+            <ele-ArrowDown />
+          </el-icon>
+        </el-button>
+        <template #dropdown>
+          <el-dropdown-menu>
+            <el-dropdown-item @click.native="checkAll(true)">全部勾选</el-dropdown-item>
+            <el-dropdown-item @click.native="checkAll(false)">取消全选</el-dropdown-item>
+            <el-dropdown-item @click.native="expand(true)">展开所有</el-dropdown-item>
+            <el-dropdown-item @click.native="expand(false)">折叠所有</el-dropdown-item>
+          </el-dropdown-menu>
+        </template>
+      </el-dropdown>
+      <el-button
+        :disabled="step <= 0"
+        @click="prev"
+      >上一步</el-button>
+      <el-button
+        :disabled="step >= 3"
+        @click="next"
+      >下一步</el-button>
+      <el-button
+        type="primary"
+        :loading="btnLoading"
+        :disabled="step < 3"
+        @click="submit"
+      >确定</el-button>
+      <el-button @click="cancel">取消</el-button>
+    </div>
+    <el-steps
+      :active="step"
+      simple
+    >
+      <el-step
+        name
+        title="菜单权限"
+      />
+      <el-step title="按钮权限" />
+      <el-step title="列表权限" />
+      <el-step title="接口权限" />
+    </el-steps>
+    <div class="scroll-part mt-3">
+      <el-tree
+        ref="treeRef"
+        :data="treeData"
+        show-checkbox
+        default-expand-all
+        node-key="id"
+        highlight-current
+        :props="defaultProps"
+        check-on-click-node
+        :expand-on-click-node="false"
+      />
+    </div>
+  </el-dialog>
 </template>
 
 <script lang="ts" setup>
@@ -48,129 +82,157 @@ const menuData = ref([]);
 const buttonData = ref([]);
 const listData = ref([]);
 const apiData = ref([]);
-const menuIds = ref([]);
+const menuIds = ref<number[]>([]);
 // 菜单id的半选节点
-const menuIdsHalf = ref([]);
-const buttonIds = ref([]);
-const columnIds = ref([]);
-const apiIds = ref([]);
+const menuIdsHalf = ref<number[]>([]);
+const buttonIds = ref<number[]>([]);
+// 按钮id的半选节点
+const buttonIdsHalf = ref<number[]>([]);
+const columnIds = ref<number[]>([]);
+const apiIds = ref<number[]>([]);
 
 const typeList = ['menu', 'button', 'column', 'api'];
 let idsList = [menuIds, buttonIds, columnIds, apiIds];
 const treeDataList = [menuData, buttonData, listData, apiData];
 const defaultProps = {
-	children: 'children',
-	label: 'title',
+  children: 'children',
+  label: 'title',
+};
+
+// 返回的所有id都是 5_0 7_1 这种形式,_0代表半选 _1代表已选
+const getIds = (idsArr: string[], isHalf = false) => {
+  const ids: number[] = [];
+  const idsHalf: number[] = [];
+  (idsArr || []).forEach(idStr => {
+    const [id, tag] = idStr.split('_');
+    if (tag === '1') {
+      ids.push(Number(id))
+    } else {
+      idsHalf.push(Number(id))
+    }
+  });
+  return isHalf ? idsHalf : ids;
+};
+
+// 设置id 5_0 7_1 这种形式,_0代表半选 _1代表已选
+const setIds = (idsArr: number[], isHalf = false) => {
+  return idsArr.map(id => `${id}_${isHalf ? 0 : 1}`)
 };
 
 const openDialog = async (row: any) => {
-	title.value = '角色权限设置 - ' + row.name;
-	roleId.value = row.id;
-	isShowDialog.value = true;
-	step.value = 0;
-	const ids = await api.role.getRoleIds(row.id);
-	// idsList = ids.menuIds || [];
-	menuIds.value = ids.menuIds || [];
-	buttonIds.value = ids.buttonIds || [];
-	columnIds.value = ids.columnIds || [];
-	apiIds.value = ids.apiIds || [];
-	// 设置选中
-	treeRef.value.setCheckedKeys(ids.menuIds);
-	const res = await api.role.auth.getList(typeList[step.value]);
-	// console.log(res);
-	treeData.value = res;
-	menuData.value = res;
+  title.value = '角色权限设置 - ' + row.name;
+  roleId.value = row.id;
+  isShowDialog.value = true;
+  step.value = 0;
+  const ids = await api.role.getRoleIds(row.id);
+  // idsList = ids.menuIds || [];
+  menuIds.value = getIds(ids.menuIds);
+  buttonIds.value = getIds(ids.buttonIds);
+  columnIds.value = getIds(ids.columnIds);
+  apiIds.value = getIds(ids.apiIds);
+  // 设置选中
+  treeRef.value.setCheckedKeys(menuIds.value);
+  const res = await api.role.auth.getList(typeList[step.value]);
+  // console.log(res);
+  treeData.value = res;
+  menuData.value = res;
 };
+
 const cancel = () => {
-	isShowDialog.value = false;
+  isShowDialog.value = false;
 };
 
 const expand = (expand: boolean) => {
-	const nodes = treeRef.value.store.nodesMap;
-	for (let i in nodes) {
-		nodes[i].expanded = expand;
-	}
+  const nodes = treeRef.value.store.nodesMap;
+  for (let i in nodes) {
+    nodes[i].expanded = expand;
+  }
 };
 
 const prev = async () => {
-	stepChange()
-	const prevStep = step.value - 1;
-	// 获取选中id
-	treeData.value = treeDataList[prevStep].value;
-	treeRef.value.setCheckedKeys(idsList[prevStep].value);
-	step.value = prevStep;
+  stepChange()
+  const prevStep = step.value - 1;
+  // 获取选中id
+  treeData.value = treeDataList[prevStep].value;
+  treeRef.value.setCheckedKeys(idsList[prevStep].value);
+  step.value = prevStep;
 };
 
 const next = async () => {
-	stepChange()
-	const nextStep = step.value + 1;
-	const treeDataRes = await api.role.auth.getList(typeList[nextStep], menuIds.value.concat(menuIdsHalf.value));
-	// 最外层是菜单,如果菜单下没有按钮,列表或者接口,就不显示这个菜单
-	// 菜单id和其他id可能会重复,所以最外层的菜单id变一下,避免重复
-	const treeDateFilter = (treeDataRes || []).filter((item: any) => {
-		if (item.children?.length) {
-			item.id += '_numu'
-			return true
-		}
-		return false
-	});
-	treeData.value = treeDateFilter;
-	treeDataList[nextStep].value = treeDateFilter;
-	treeRef.value.setCheckedKeys(idsList[nextStep].value);
-	step.value = nextStep;
+  stepChange()
+  const nextStep = step.value + 1;
+  const treeDataRes = await api.role.auth.getList(typeList[nextStep], menuIds.value.concat(menuIdsHalf.value));
+  // 最外层是菜单,如果菜单下没有按钮,列表或者接口,就不显示这个菜单
+  // 菜单id和其他id可能会重复,所以最外层的菜单id变一下,避免重复
+  const treeDateFilter = (treeDataRes || []).filter((item: any) => {
+    if (item.children?.length) {
+      item.id += '_memu'
+      return true
+    }
+    return false
+  });
+  treeData.value = treeDateFilter;
+  treeDataList[nextStep].value = treeDateFilter;
+  treeRef.value.setCheckedKeys(idsList[nextStep].value);
+  step.value = nextStep;
 };
 
 // 切换时候赋值
 const stepChange = () => {
-	if (step.value === 0) {
-		// 包含被选中节点和半选中节点
-		idsList[step.value].value = treeRef.value.getCheckedKeys(false);
-		menuIdsHalf.value = treeRef.value.getHalfCheckedKeys()
-	} else {
-		// 只返回叶子节点
-		idsList[step.value].value = treeRef.value.getCheckedKeys(true);
-	}
+  if (step.value === 0) {
+    // 包含被选中节点和半选中节点
+    idsList[step.value].value = treeRef.value.getCheckedKeys(false);
+    menuIdsHalf.value = treeRef.value.getHalfCheckedKeys()
+  } else if (step.value === 1) {
+    // 包含被选中节点和半选中节点
+    idsList[step.value].value = treeRef.value.getCheckedKeys(false).filter((id: any) => typeof id === 'number')
+    // 按钮的半选节点过滤菜单id, 菜单id是字符串类型。 id_menu 这种形式,把这种过滤掉
+    buttonIdsHalf.value = treeRef.value.getHalfCheckedKeys().filter((id: any) => typeof id === 'number')
+  } else {
+    // 只返回叶子节点
+    idsList[step.value].value = treeRef.value.getCheckedKeys(true);
+  }
 };
 
 // 全选取消全选
 const checkAll = (all: boolean) => {
-	if (!all) {
-		treeRef.value.setCheckedKeys([]);
-	} else {
-		const ids = deepTree(treeDataList[step.value].value, []);
-		treeRef.value.setCheckedKeys(ids);
-	}
+  if (!all) {
+    treeRef.value.setCheckedKeys([]);
+  } else {
+    const ids = deepTree(treeDataList[step.value].value, []);
+    treeRef.value.setCheckedKeys(ids);
+  }
 };
 
 const submit = async () => {
-	stepChange()
-	const data = {
-		menuIds: menuIds.value.concat(menuIdsHalf.value),
-		buttonIds: buttonIds.value,
-		columnIds: columnIds.value,
-		apiIds: apiIds.value,
-		roleId: roleId.value,
-	};
-	// console.log(data);
-
-	btnLoading.value = true;
-	api.role.auth
-		.set(data)
-		.then(() => {
-			ElMessage.success('权限设置成功');
-		})
-		.finally(() => {
-			btnLoading.value = false;
-			isShowDialog.value = false;
-		});
+  stepChange()
+  //  5_0 7_1 这种形式,_0代表半选 _1代表已选
+  const data = {
+    menuIds: setIds(menuIds.value).concat(setIds(menuIdsHalf.value, true)),
+    buttonIds: setIds(buttonIds.value).concat(setIds(buttonIdsHalf.value, true)),
+    columnIds: setIds(columnIds.value),
+    apiIds: setIds(apiIds.value),
+    roleId: roleId.value,
+  };
+
+  btnLoading.value = true;
+  api.role.auth
+    .set(data)
+    .then(() => {
+      ElMessage.success('权限设置成功');
+    })
+    .finally(() => {
+      btnLoading.value = false;
+      isShowDialog.value = false;
+    });
 };
 
 function deepTree(tree: any[], arr: number[]) {
-	for (let item of tree) {
-		arr.push(item.id);
-		if (item.children?.length) deepTree(item.children, arr);
-	}
-	return arr;
+  for (let item of tree) {
+    arr.push(item.id);
+    if (item.children?.length) deepTree(item.children, arr);
+  }
+  return arr;
 }
 
 // openDialog({ name: '超级管理员', id: 3 });