Quellcode durchsuchen

菜单优化,第三级默认展开

zhangchong vor 2 Jahren
Ursprung
Commit
cfa8b5712b

+ 12 - 2
src/layout/navMenu/vertical.vue

@@ -1,6 +1,13 @@
 <template>
-	<el-menu router :default-active="state.defaultActive" background-color="transparent" :collapse="state.isCollapse"
-		:unique-opened="getThemeConfig.isUniqueOpened" :collapse-transition="false">
+	<el-menu
+		router
+		:default-active="state.defaultActive"
+		background-color="transparent"
+		:collapse="state.isCollapse"
+		:unique-opened="getThemeConfig.isUniqueOpened"
+		:collapse-transition="false"
+		:default-openeds="state.defaultOpeneds"
+	>
 		<template v-for="val in menuLists">
 			<el-sub-menu :index="val.path" v-if="val.children && val.children.length > 0" :key="val.path">
 				<template #title>
@@ -49,7 +56,10 @@ const state = reactive({
 	// 修复:https://gitee.com/lyt-top/vue-next-admin/issues/I3YX6G
 	defaultActive: route.meta.isDynamic ? route.meta.isDynamicPath : route.path,
 	isCollapse: false,
+	defaultOpeneds: <any>[],
 });
+const path = route.path.split('/');
+state.defaultOpeneds = ['/' + path[1]]; //默认展开父级
 // 获取父级菜单数据
 const menuLists = computed(() => {
 	return <any>props.menuList;

+ 4 - 6
src/views/business/order/accept/repeatOrderDetail.vue

@@ -25,13 +25,12 @@
 								<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="6" v-if="state.ruleForm.fromPhone">
 									<el-form-item label="来电号码">
 										{{ state.ruleForm.fromPhone }}
-										<el-popover :width="480" trigger="hover">
+										<!-- <el-popover :width="480" trigger="hover">
 											<template #reference>
 												<el-button link type="primary" class="ml5" title="播放录音"><SvgIcon name="ele-Headset" size="16px" /></el-button>
 											</template>
-											<!-- 音频播放器 -->
-											<!-- <AudioPlayer ref="AudioPlayerRef" :url="state.ruleForm.url" /> -->
-										</el-popover>
+											<AudioPlayer ref="AudioPlayerRef" :url="state.ruleForm.url" />
+										</el-popover> -->
 									</el-form-item>
 								</el-col>
 								<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="6">
@@ -270,7 +269,7 @@ import { upNumber } from '/@/utils/tools';
 
 // 引入组件
 const ExpandForm = defineAsyncComponent(() => import('/@/views/business/order/components/Expand.vue'));
-const AudioPlayer = defineAsyncComponent(() => import('/@/components/AudioPlayer/index.vue'));
+// const AudioPlayer = defineAsyncComponent(() => import('/@/components/AudioPlayer/index.vue'));
 
 // 定义变量内容
 const state = reactive<any>({
@@ -309,7 +308,6 @@ const state = reactive<any>({
 });
 const ruleFormRef = ref();
 const ExpandFormRef = ref();
-const AudioPlayerRef = ref();
 const route = useRoute();
 const router = useRouter();
 // 查看详情

+ 4 - 6
src/views/business/order/components/orderDetail.vue

@@ -25,13 +25,12 @@
 								<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="6" v-if="state.ruleForm.fromPhone">
 									<el-form-item label="来电号码">
 										{{ state.ruleForm.fromPhone }}
-										<el-popover :width="480" trigger="hover">
+										<!-- <el-popover :width="480" trigger="hover">
 											<template #reference>
 												<el-button link type="primary" class="ml5" title="播放录音"><SvgIcon name="ele-Headset" size="16px" /></el-button>
 											</template>
-											<!-- 音频播放器 -->
-											<!-- <AudioPlayer ref="AudioPlayerRef" :url="state.ruleForm.url" /> -->
-										</el-popover>
+											<AudioPlayer ref="AudioPlayerRef" :url="state.ruleForm.url" />
+										</el-popover> -->
 									</el-form-item>
 								</el-col>
 								<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="6">
@@ -297,7 +296,7 @@ const ExpandForm = defineAsyncComponent(() => import('/@/views/business/order/co
 const CrculationRecord = defineAsyncComponent(() => import('/@/views/business/order/components/CrculationRecord.vue'));
 const Process = defineAsyncComponent(() => import('/@/views/business/order/components/Process.vue'));
 const Supply = defineAsyncComponent(() => import('/@/views/business/order/components/Supply.vue'));
-const AudioPlayer = defineAsyncComponent(() => import('/@/components/AudioPlayer/index.vue'));
+// const AudioPlayer = defineAsyncComponent(() => import('/@/components/AudioPlayer/index.vue'));
 
 // 定义子组件向父组件传值/事件
 const emit = defineEmits(['updateList', 'handle']);
@@ -341,7 +340,6 @@ const processRef = ref();
 const ExpandFormRef = ref();
 const CrculationRecordRef = ref();
 const SupplyRef = ref();
-const AudioPlayerRef = ref();
 const router = useRouter();
 // 打开弹窗
 const openDialog = (val: any) => {

+ 230 - 201
src/views/changePwd/component/changePwd.vue

@@ -1,46 +1,76 @@
 <template>
-  <el-form class="login-content-form" ref="changePwdRef" :model="state.ruleForm" :rules="rules" label-position="top" label-width="100px">
-    <p class="currentAccount login-animation4">账号 <span>{{ userName }}</span></p>
-    <el-form-item prop="currentPassword" label="旧密码" class="login-animation2">
-      <el-input class="inputDeep" clearable type="password" show-password placeholder="请输旧就密码"
-        v-model="state.ruleForm.currentPassword" autocomplete="off">
-        <template #prefix>
-          <el-icon class="el-input__icon">
-            <ele-Unlock />
-          </el-icon>
-        </template>
-      </el-input>
-    </el-form-item>
-    <el-form-item class="login-animation2" prop="newPassword" label="新密码">
-      <el-input class="inputDeep" clearable type="password" show-password placeholder="请输入新密码"
-        v-model="state.ruleForm.newPassword" autocomplete="off">
-        <template #prefix>
-          <el-icon class="el-input__icon">
-            <ele-Unlock />
-          </el-icon>
-        </template>
-      </el-input>
-      <div class="intensity login-animation4">
-        <span class="psdText">密码强度:{{ modes === 1 ? '弱' : modes === 2 ? '中' : modes === 3 ? '强' : '' }}</span>
-        <span class="line ruo" :class="modes === 1 ? 'low' : ''"></span>
-        <span class="line zhong" :class="modes === 2 ? 'middle' : ''"></span>
-        <span class="line qiang" :class="modes === 3 ? 'high' : ''"></span>
-      </div>
-    </el-form-item>
-    <el-form-item prop="confirmPassword" label="确认密码" class="login-animation2">
-      <el-input class="inputDeep" clearable type="password" show-password placeholder="请再次输入密码"
-        v-model="state.ruleForm.confirmPassword" autocomplete="off">
-        <template #prefix>
-          <el-icon class="el-input__icon">
-            <ele-Unlock />
-          </el-icon>
-        </template>
-      </el-input>
-    </el-form-item>
-    <el-button type="primary" class="login-content-submit login-animation4" round @click="onChangeConfirm(changePwdRef)"
-      v-waves="'light'" :loading="state.loading">确认修改</el-button>
-    <div class="font12 mt10 login-animation4 login-msg">提示:密码不得少于8位数,且必须包含数字、字母大小写和特殊字符</div>
-  </el-form>
+	<el-form class="login-content-form" ref="changePwdRef" :model="state.ruleForm" :rules="rules" label-position="top" label-width="100px">
+		<p class="currentAccount login-animation4">
+			账号 <span>{{ userName }}</span>
+		</p>
+		<el-form-item prop="currentPassword" label="旧密码" class="login-animation2">
+			<el-input
+				class="inputDeep"
+				clearable
+				type="password"
+				show-password
+				placeholder="请输旧就密码"
+				v-model="state.ruleForm.currentPassword"
+				autocomplete="off"
+			>
+				<template #prefix>
+					<el-icon class="el-input__icon">
+						<ele-Unlock />
+					</el-icon>
+				</template>
+			</el-input>
+		</el-form-item>
+		<el-form-item class="login-animation2" prop="newPassword" label="新密码">
+			<el-input
+				class="inputDeep"
+				clearable
+				type="password"
+				show-password
+				placeholder="请输入新密码"
+				v-model="state.ruleForm.newPassword"
+				autocomplete="off"
+			>
+				<template #prefix>
+					<el-icon class="el-input__icon">
+						<ele-Unlock />
+					</el-icon>
+				</template>
+			</el-input>
+			<div class="intensity login-animation4">
+				<span class="psdText">密码强度:{{ modes === 1 ? '弱' : modes === 2 ? '中' : modes === 3 ? '强' : '' }}</span>
+				<span class="line ruo" :class="modes === 1 ? 'low' : ''"></span>
+				<span class="line zhong" :class="modes === 2 ? 'middle' : ''"></span>
+				<span class="line qiang" :class="modes === 3 ? 'high' : ''"></span>
+			</div>
+		</el-form-item>
+		<el-form-item prop="confirmPassword" label="确认密码" class="login-animation2">
+			<el-input
+				class="inputDeep"
+				clearable
+				type="password"
+				show-password
+				placeholder="请再次输入密码"
+				v-model="state.ruleForm.confirmPassword"
+				autocomplete="off"
+			>
+				<template #prefix>
+					<el-icon class="el-input__icon">
+						<ele-Unlock />
+					</el-icon>
+				</template>
+			</el-input>
+		</el-form-item>
+		<el-button
+			type="primary"
+			class="login-content-submit login-animation4"
+			round
+			@click="onChangeConfirm(changePwdRef)"
+			v-waves="'light'"
+			:loading="state.loading"
+			>确认修改</el-button
+		>
+		<div class="font12 mt10 login-animation4 login-msg">提示:密码不得少于8位数,且必须包含数字、字母大小写和特殊字符</div>
+	</el-form>
 </template>
 
 <script setup lang="ts" name="changePwdComponent">
@@ -54,202 +84,201 @@ import { storeToRefs } from 'pinia';
 import { useUserInfo } from '/@/stores/userInfo';
 // 修改密码参数类型
 interface ChangePwdState {
-  currentPassword:string;
-  newPassword: string;
-  confirmPassword: string;
+	currentPassword: string;
+	newPassword: string;
+	confirmPassword: string;
 }
 // 定义变量
 const router = useRouter();
 const state = reactive({
-  ruleForm: <ChangePwdState>{
-    currentPassword:'',
-    newPassword: '',
-    confirmPassword: ''
-  },
-  loading: false
+	ruleForm: <ChangePwdState>{
+		currentPassword: '',
+		newPassword: '',
+		confirmPassword: '',
+	},
+	loading: false,
 });
-const changePwdRef = ref<FormInstance>()
+const changePwdRef = ref<FormInstance>();
 const storesUserInfo = useUserInfo();
 const { userInfos } = storeToRefs(storesUserInfo);
 const userName = computed(() => {
-  return userInfos.value.name;
-})
+	return userInfos.value.name;
+});
 // 确认修改
 const onChangeConfirm = async (formEl: FormInstance | undefined) => {
-  if (!formEl) return;
-  await formEl.validate((valid, fields) => {
-    if (valid) {
-      state.loading = true;
-      changePwd(state.ruleForm).then(async () => {//
-        // 清楚缓存
-        Session.clear()
-        router.push('/')
-        ElNotification({
-          title: '成功',
-          type: 'success',
-          message: '密码修改成功,请重新登录',
-        })
-
-      }).catch(() => {
-        state.loading = false;
-      })
-    } else {
-      console.log('error submit!', fields)
-    }
-  })
+	if (!formEl) return;
+	await formEl.validate((valid) => {
+		if (valid) {
+			state.loading = true;
+			changePwd(state.ruleForm)
+				.then(async () => {
+					//
+					// 清楚缓存
+					Session.clear();
+					router.push('/');
+					ElNotification({
+						title: '成功',
+						type: 'success',
+						message: '密码修改成功,请重新登录',
+					});
+				})
+				.catch(() => {
+					state.loading = false;
+				});
+		}
+	});
 };
 //  检查密码强度
 let modes = ref<number>(0);
 const checkPassword = (rule: any, value: string, callback: any) => {
-  if (!value) {
-    modes.value = 0;
-    return callback('新密码不能为空')
-  }
-  if (value.length < 8) {
-    modes.value = 0;
-    return callback('新密码不少于8位')
-  }
-  /*
+	if (!value) {
+		modes.value = 0;
+		return callback('新密码不能为空');
+	}
+	if (value.length < 8) {
+		modes.value = 0;
+		return callback('新密码不少于8位');
+	}
+	/*
     最短8位, {6,}
     可以包含小写大母 [a-z] 和大写字母 [A-Z]
     可以包含数字 [0-9]
     可以包含下划线 [ _ ] 和减号 [ - ]
   */
-  if (/^[\w_-]{6,}$/.test(state.ruleForm.newPassword)) {
-    modes.value = 1;
-  }
-  /*
+	if (/^[\w_-]{6,}$/.test(state.ruleForm.newPassword)) {
+		modes.value = 1;
+	}
+	/*
     最短8位, {8,}
     必须包含1个数字
     必须包含1个小写字母
     必须包含1个大写字母
     必须包含1个特殊字符
   */
-  if (/^\S*(?=\S{8,})(?=\S*\d)(?=\S*[A-Z])(?=\S*[a-z])(?=\S*[!@#$%^&*.?])\S*$/.test(state.ruleForm.newPassword)) modes.value = 2; //中等
-  /*
+	if (/^\S*(?=\S{8,})(?=\S*\d)(?=\S*[A-Z])(?=\S*[a-z])(?=\S*[!@#$%^&*.?])\S*$/.test(state.ruleForm.newPassword)) modes.value = 2; //中等
+	/*
     最短8位, {8,}
     必须包含1个数字
     必须包含1个小写字母
     必须包含1个大写字母
     必须包含2个特殊字符
   */
-  if (/^\S*(?=\S{8,})(?=\S*\d)(?=\S*[A-Z])(?=\S*[a-z])(?=\S*[!@#$%^&*.?]{2,})\S*$/.test(state.ruleForm.newPassword)) modes.value = 3; //强密码
-  if (modes.value == 0 || modes.value == 1) {
-    return callback('提示:密码不得少于8位数,且必须包含字母大小写和特殊字符') //弱密码
-  }
-  return callback()
-}
+	if (/^\S*(?=\S{8,})(?=\S*\d)(?=\S*[A-Z])(?=\S*[a-z])(?=\S*[!@#$%^&*.?]{2,})\S*$/.test(state.ruleForm.newPassword)) modes.value = 3; //强密码
+	if (modes.value == 0 || modes.value == 1) {
+		return callback('提示:密码不得少于8位数,且必须包含字母大小写和特殊字符'); //弱密码
+	}
+	return callback();
+};
 // 检查输入密码是否一致
 const checkConfirmPassword = (rule: any, value: any, callback: any) => {
-  if (!value) {
-    return callback('请再次输入密码')
-  }
-  if (value != state.ruleForm.newPassword) {
-    return callback('两次密码输入不一致,请重新输入')
-  }
-  return callback()
-}
+	if (!value) {
+		return callback('请再次输入密码');
+	}
+	if (value != state.ruleForm.newPassword) {
+		return callback('两次密码输入不一致,请重新输入');
+	}
+	return callback();
+};
 const rules = reactive({
-  currentPassword: [{ required: true, message:"请输入旧密码", trigger: ['change', 'blur'] }],
-  newPassword: [{ required: true, validator: checkPassword, trigger: ['change', 'blur'] }],
-  confirmPassword: [{ required: true, validator: checkConfirmPassword, trigger: 'blur' }]
-})
-
+	currentPassword: [{ required: true, message: '请输入旧密码', trigger: ['change', 'blur'] }],
+	newPassword: [{ required: true, validator: checkPassword, trigger: ['change', 'blur'] }],
+	confirmPassword: [{ required: true, validator: checkConfirmPassword, trigger: 'blur' }],
+});
 </script>
 
 <style scoped lang="scss">
 .login-content-form {
-  .currentAccount {
-    margin: 40px 0 10px 0;
-    font-size: var(--el-form-label-font-size);
-    color: var(--el-text-color-regular);
-
-    span {
-      padding-left: 20px;
-    }
-  }
-
-  margin-top: 20px;
-
-  @for $i from 1 through 4 {
-    .login-animation#{$i} {
-      opacity: 0;
-      animation-name: error-num;
-      animation-duration: 0.5s;
-      animation-fill-mode: forwards;
-      animation-delay: calc($i/10) + s;
-    }
-  }
-
-  .login-content-password {
-    display: inline-block;
-    width: 20px;
-    cursor: pointer;
-
-    &:hover {
-      color: #909399;
-    }
-  }
-
-  .login-content-code {
-    width: 100%;
-    padding: 0;
-    font-weight: bold;
-    letter-spacing: 5px;
-  }
-
-  .login-content-submit {
-    width: 100%;
-    font-weight: 300;
-    background: linear-gradient(-90deg, #3C7EE0 0%, #3C50E0 100%);
-    border: none;
-    border-radius: 8px;
-    height: 40px;
-    margin-top: 20px;
-  }
-
-  .login-msg {
-    color: var(--el-text-color-placeholder);
-  }
-
-  .intensity {
-    .psdText {
-      font-size: 14px;
-      margin-right: 10px;
-      color: #5a5a5a;
-    }
-
-    .line {
-      display: inline-block;
-      width: 48px;
-      height: 10px;
-      background: #d8d8d8;
-      margin-right: 2px;
-
-      &.ruo {
-        border-radius: 6px 0 0 6px;
-      }
-
-      &.low {
-        background: #BFCDFF;
-      }
-
-      &.middle {
-        background: #93A6FA;
-      }
-
-      &.high {
-        background: #3C50E0;
-      }
-
-      &.qiang {
-        border-radius: 0 6px 6px 0;
-      }
-    }
-
-    .level {
-      margin: 0 16px 0 8px;
-    }
-  }
+	.currentAccount {
+		margin: 40px 0 10px 0;
+		font-size: var(--el-form-label-font-size);
+		color: var(--el-text-color-regular);
+
+		span {
+			padding-left: 20px;
+		}
+	}
+
+	margin-top: 20px;
+
+	@for $i from 1 through 4 {
+		.login-animation#{$i} {
+			opacity: 0;
+			animation-name: error-num;
+			animation-duration: 0.5s;
+			animation-fill-mode: forwards;
+			animation-delay: calc($i/10) + s;
+		}
+	}
+
+	.login-content-password {
+		display: inline-block;
+		width: 20px;
+		cursor: pointer;
+
+		&:hover {
+			color: #909399;
+		}
+	}
+
+	.login-content-code {
+		width: 100%;
+		padding: 0;
+		font-weight: bold;
+		letter-spacing: 5px;
+	}
+
+	.login-content-submit {
+		width: 100%;
+		font-weight: 300;
+		background: linear-gradient(-90deg, #3c7ee0 0%, #3c50e0 100%);
+		border: none;
+		border-radius: 8px;
+		height: 40px;
+		margin-top: 20px;
+	}
+
+	.login-msg {
+		color: var(--el-text-color-placeholder);
+	}
+
+	.intensity {
+		.psdText {
+			font-size: 14px;
+			margin-right: 10px;
+			color: #5a5a5a;
+		}
+
+		.line {
+			display: inline-block;
+			width: 48px;
+			height: 10px;
+			background: #d8d8d8;
+			margin-right: 2px;
+
+			&.ruo {
+				border-radius: 6px 0 0 6px;
+			}
+
+			&.low {
+				background: #bfcdff;
+			}
+
+			&.middle {
+				background: #93a6fa;
+			}
+
+			&.high {
+				background: #3c50e0;
+			}
+
+			&.qiang {
+				border-radius: 0 6px 6px 0;
+			}
+		}
+
+		.level {
+			margin: 0 16px 0 8px;
+		}
+	}
 }
 </style>

+ 1 - 0
src/views/changePwd/index.vue

@@ -32,6 +32,7 @@ const { themeConfig } = storeToRefs(storesThemeConfig);
 const router = useRouter();
 const backToLogin = () => {
   Session.clear();
+  Local.clear();
   router.push('/')
 }
 // 页面加载时

+ 11 - 23
src/views/knowledge/knowledge/index.vue

@@ -7,25 +7,13 @@
 					<div class="h100 pr10">
 						<el-tabs v-model="state.activeName" stretch>
 							<el-tab-pane label="部门" name="0">
-								<el-input v-model="filterOrg" placeholder="请输入部门名称" class="input-with-select mt10 mb10" clearable>
-									<template #append>
-										<el-button type="primary" class="btn" :loading="state.loading" @click="getList">搜索</el-button>
-									</template>
-								</el-input>
+								<el-input v-model="filterOrg" placeholder="请输入部门名称" class="input-with-select mt10 mb10" clearable> </el-input>
 							</el-tab-pane>
 							<el-tab-pane label="类型" name="1">
-								<el-input v-model="filterType" placeholder="请输入类型名称" class="input-with-select mt10 mb10" clearable>
-									<template #append>
-										<el-button type="primary" class="btn" :loading="state.loading" @click="getList">搜索</el-button>
-									</template>
-								</el-input>
+								<el-input v-model="filterType" placeholder="请输入类型名称" class="input-with-select mt10 mb10" clearable> </el-input>
 							</el-tab-pane>
 							<el-tab-pane label="热点" name="2">
-								<el-input v-model="filterHot" placeholder="请输入热点名称" class="input-with-select mt10 mb10" clearable>
-									<template #append>
-										<el-button type="primary" class="btn" :loading="state.loading" @click="getList">搜索</el-button>
-									</template>
-								</el-input>
+								<el-input v-model="filterHot" placeholder="请输入热点名称" class="input-with-select mt10 mb10" clearable> </el-input>
 							</el-tab-pane>
 						</el-tabs>
 						<div v-show="state.activeName === '0'" style="height: calc(100% - 100px);'">
@@ -405,7 +393,7 @@ const handleQuery = throttle(() => {
 const getOrgListApi = async () => {
 	state.loading = true;
 	try {
-		const res: any = await Promise.all([getOrgList(), treelist({IsEnable:1})]);
+		const res: any = await Promise.all([getOrgList(), treelist({ IsEnable: 1 })]);
 		state.orgData = res[0].result ?? [];
 		state.knowledgeOptions = res[1].result ?? [];
 		state.loading = false;
@@ -490,12 +478,12 @@ const onEdit = (row: any) => {
 // 预览
 const onPreview = (row: any) => {
 	router.push({
-		name:'knowledgePreview',
-		params:{
-			id:row.id,
-			tagsViewName:'知识预览'
-		}
-	})
+		name: 'knowledgePreview',
+		params: {
+			id: row.id,
+			tagsViewName: '知识预览',
+		},
+	});
 };
 // 查看审核记录
 const onRecord = (row: any) => {
@@ -503,7 +491,7 @@ const onRecord = (row: any) => {
 };
 // 发起更新
 const onRenew = (row: any) => {
-	updateKnowledge.value.openDialog(row,state.orgData,state.knowledgeOptions);
+	updateKnowledge.value.openDialog(row, state.orgData, state.knowledgeOptions);
 };
 // 申请流程成功
 const onSubmitProcess = () => {

+ 235 - 123
src/views/system/roles/component/permission.vue

@@ -1,31 +1,25 @@
 <template>
 	<div class="system-edit-role-container">
-		<el-dialog title="配置权限" v-model="state.isShowDialog" draggable>
+		<el-dialog title="权限配置" v-model="state.isShowDialog" draggable @opened="opened">
 			<div class="custom-tree-node-container">
-				<el-table :data="state.menuTableData" style="width: 100%; margin-bottom: 20px" row-key="id" border
-					default-expand-all>
-					<el-table-column width="180">
-						<template #header>
-							<el-checkbox v-model="checkAllMenu" :indeterminate="isIndeterminateMenu"
-								@change="handleCheckAllChangeMenu">菜单</el-checkbox>
-						</template>
+				<el-table :data="state.menuTableData" stripe row-key="permissionCode" border :expand-row-keys="state.expandRowKeys">
+					<el-table-column width="180" label="菜单">
 						<template #default="scope">
-							<el-checkbox-group v-model="state.systemMenuArr" @change="handleCheckedMenuChange">
-								<el-checkbox :label="scope.row.permissionCode">{{ scope.row.pageName }}</el-checkbox>
-							</el-checkbox-group>
+							<el-checkbox
+								v-if="scope.row.children"
+								:indeterminate="scope.row.indeterminate"
+								v-model="scope.row.checked"
+								@change="changeRowSelect(scope.row)"
+								>{{ scope.row.pageName }}</el-checkbox
+							>
+							<el-checkbox v-else v-model="scope.row.checked" @change="changeRowSelect(scope.row)">{{ scope.row.pageName }}</el-checkbox>
 						</template>
 					</el-table-column>
-					<el-table-column prop="children">
-						<template #header>
-							<el-checkbox v-model="checkAllBtn" :indeterminate="isIndeterminateBtn"
-								@change="handleCheckAllChangeBtn">按钮</el-checkbox>
-						</template>
+					<el-table-column prop="children" label="按钮">
 						<template #default="scope">
 							<el-checkbox-group v-model="state.systemButtonArr" @change="handleCheckedBtnChange">
-								<el-checkbox v-for="(item) in scope.row.buttonArr" :key="item.id"
-									:label="item.permissionCode"><span v-if="showSetting">{{ item.permissionCode }}-{{
-											item.btnName
-									}}</span>
+								<el-checkbox v-for="item in scope.row.buttonArr" :key="item.id" :label="item.permissionCode"
+									><span v-if="showSetting">{{ item.permissionCode }}-{{ item.btnName }}</span>
 									<span v-else>{{ item.btnName }}</span>
 								</el-checkbox>
 							</el-checkbox-group>
@@ -35,6 +29,7 @@
 			</div>
 			<template #footer>
 				<span class="dialog-footer">
+					<el-button class="default-button"><el-checkbox v-model="state.checkedAll" @change="changeAllSelect">全选</el-checkbox></el-button>
 					<el-button @click="onCancel" class="default-button">取 消</el-button>
 					<el-button type="primary" @click="onSubmit">确 定</el-button>
 				</span>
@@ -44,12 +39,12 @@
 </template>
 
 <script setup lang="ts" name="systemEditRole">
-import { reactive, onMounted, ref, computed } from 'vue';
+import { reactive, onMounted, computed } from 'vue';
 import { ElMessage } from 'element-plus';
 import { storeToRefs } from 'pinia';
 import { useUserInfo } from '/@/stores/userInfo';
-import { getMenuList } from "/@/api/system/menu";
-import { getRolePower, setRolePower } from "/@/api/system/roles"
+import { getMenuList } from '/@/api/system/menu';
+import { getRolePower, setRolePower } from '/@/api/system/roles';
 
 // 定义子组件向父组件传值/事件
 const emit = defineEmits(['updateList']);
@@ -61,13 +56,9 @@ const state = reactive<any>({
 	systemMenuArr: <any>[],
 	systemButtonArr: <any>[],
 	currentRow: {},
-	allMenuArr: <any>[],
-	allButtonArr: <any>[],
+	checkedAll: false,
+	expandRowKeys:[]
 });
-const checkAllMenu = ref(false)
-const checkAllBtn = ref(false)
-const isIndeterminateMenu = ref(false)
-const isIndeterminateBtn = ref(false);
 const storesUserInfo = useUserInfo();
 const { userInfos } = storeToRefs(storesUserInfo);
 // 打开弹窗
@@ -75,37 +66,51 @@ const openDialog = (row: any) => {
 	state.currentRow = row;
 	state.systemMenuArr = <any>[];
 	state.systemButtonArr = <any>[];
+	const loop = (data: any) => {
+		data.forEach((item: any) => {
+			item.checked = false;
+			if (item.children && item.children.length) {
+				loop(item.children);
+			}
+		});
+	};
+	loop(state.menuTableData);
 	if (userInfos.value.authBtnList.includes('100205')) {
 		getRolePower({ roleid: row.id }).then((res: any) => {
 			state.systemMenuArr = res.result?.systemMenuArr ?? [];
 			state.systemButtonArr = res.result?.systemButtonArr ?? [];
-			// 设置全选状态
-			if (state.allButtonArr.length === state.systemButtonArr.length) {
-				checkAllBtn.value = true;
-				isIndeterminateBtn.value = false;
-			} else if (state.systemButtonArr.length !== 0) {
-				checkAllBtn.value = false;
-				isIndeterminateBtn.value = true;
-			} else {
-				checkAllBtn.value = false;
-				isIndeterminateBtn.value = false;
-			}
-			if (state.allMenuArr.length === state.systemMenuArr.length) {
-				checkAllMenu.value = true;
-				isIndeterminateMenu.value = false;
-			} else if (state.systemMenuArr.length !== 0) {
-				checkAllMenu.value = false;
-				isIndeterminateMenu.value = true;
-			} else {
-				checkAllMenu.value = false;
-				isIndeterminateMenu.value = false;
-			}
+			const loop = (data: any) => {
+				data.forEach((item: any) => {
+					for (let i of state.systemMenuArr) {
+						if (item.permissionCode === i) {
+							item.checked = true;
+							if (item.children && item.children.length) {
+								loop(item.children);
+							}
+						}
+					}
+				});
+			};
+			loop(state.menuTableData);
+			state.expandRowKeys = state.systemMenuArr;
 			state.isShowDialog = true;
 		});
 	} else {
 		ElMessage.warning('您没有获取角色权限的权限');
 	}
 };
+// 检查是否全选
+const opened = () => {
+	const loopMenu = (data: any) => {
+		return data.every((item: any) => {
+			if (item.children && item.children.length) {
+				loopMenu(item.children);
+			}
+			return item.checked;
+		});
+	};
+	state.checkedAll = loopMenu(state.menuTableData);
+};
 // 关闭弹窗
 const closeDialog = () => {
 	state.isShowDialog = false;
@@ -114,93 +119,200 @@ const closeDialog = () => {
 const onCancel = () => {
 	closeDialog();
 };
-// 保存
-const onSubmit = () => {
-	let req = {
-		roleId: state.currentRow.id,
-		roleCode: state.currentRow.name,
-		systemMenuArr: state.systemMenuArr,
-		systemButtonArr: state.systemButtonArr
-	}
-	setRolePower(req).then(() => {
-		ElMessage({
-			message: '操作成功',
-			type: 'success',
-		})
-		closeDialog();
-		emit("updateList")
-	}).catch(() => { // 新增失败
-		closeDialog();
-	})
-};
 // 获取所有菜单
 const getMenuListApi = () => {
 	getMenuList().then((res: any) => {
 		state.menuTableData = res?.result ?? [];
-		state.allMenuArr = getAllMenuCode(state.menuTableData);
-		state.allButtonArr = getAllButtonCode(state.menuTableData);
-	})
-}
-// 获取所有的菜单code集合
-const getAllMenuCode = (arr: any[]) => {
-	const newArr = <any>[];
-	arr.forEach(v => {
-		newArr.push(v.permissionCode);
-		if (v.children?.length) {
-			newArr.push(...getAllMenuCode(v.children));
-		}
 	});
-	return newArr;
-}
-// 获取所有按钮的code集合
-let newArr1 = <any>[];
-const getAllButtonCode = (arr: any) => {
-	if (!arr.length) return;
+};
+// 开发环境不显示设置
+const showSetting = computed(() => {
+	return import.meta.env.VITE_MODE_NAME === 'development';
+});
 
-	// 定义一个帮助函数,用于处理每一项数据
-	const processItem = (item: any) => {
-		for (let i of item.buttonArr) {
-			newArr1.push(i.permissionCode)
-		}
-		if (item.children?.length) {
-			getAllButtonCode(item.children)
+// 选择表格(全选)
+const changeAllSelect = (val: any) => {
+	const loop = (data: any) => {
+		data.forEach((item: any) => {
+			item.checked = val;
+			if ('indeterminate' in item) {
+				item.indeterminate = false;
+			}
+			if (item.buttonArr && item.buttonArr.length) {
+				item.buttonArr.forEach((item: any) => {
+					if (val) {
+						state.systemButtonArr.push(item.permissionCode);
+					} else {
+						for (let i in state.systemButtonArr) {
+							if (state.systemButtonArr[i] === item.permissionCode) {
+								state.systemButtonArr.splice(i, 1);
+							}
+						}
+					}
+				});
+			}
+			state.systemButtonArr = Array.from(new Set(state.systemButtonArr));
+			if (item.children && item.children.length) {
+				loop(item.children);
+			}
+		});
+	};
+	loop(state.menuTableData);
+};
+const find = (v: any, list: any[]) => {
+	let data;
+	(list || []).map((i) => {
+		if (i.id === v) {
+			data = i;
+		} else {
+			const child = find(v, i.children);
+			if (child) {
+				data = child;
+			}
 		}
+	});
+	return data;
+};
+// 选择表格(表格行选择)
+const changeRowSelect = (val: any) => {
+	const loopBtn = (data: any, checked = val.checked) => {
+		data.forEach((item: any) => {
+			if (checked) {
+				state.systemButtonArr.push(item.permissionCode);
+			} else {
+				for (let i in state.systemButtonArr) {
+					if (state.systemButtonArr[i] === item.permissionCode) {
+						state.systemButtonArr.splice(i, 1);
+					}
+				}
+			}
+			if (item.buttonArr && item.buttonArr.length) {
+				loopBtn(item.buttonArr);
+			}
+		});
+	};
+	const loop = (data: any) => {
+		data.forEach((item: any) => {
+			item.checked = val.checked;
+			if (item.children && item.children.length) {
+				loop(item.children);
+			}
+			if (item.buttonArr && item.buttonArr.length) {
+				loopBtn(item.buttonArr);
+			}
+		});
+	};
+	state.systemButtonArr = Array.from(new Set(state.systemButtonArr));
+	if (val.buttonArr && val.buttonArr.length) {
+		loopBtn(val.buttonArr);
 	}
+	if (val.children && val.children.length) {
+		loop(val.children);
+		if ('indeterminate' in val) {
+			val.indeterminate = false;
+		}
+	} else {
+		let checkedLeg = 0;
+		const loop = (data: any) => {
+			data.forEach((item: any) => {
+				if (item.id === val.parentId) {
+					// 获取当前父级下子级选中条数
+					const leg = item.children.length;
+					checkedLeg = item.children.filter((ss: any) => ss.checked).length;
+					// 根据条数改变父级的indeterminate和checked
+					if (checkedLeg === 0) {
+						item.indeterminate = false;
+						item.checked = false;
+					} else if (checkedLeg < leg) {
+						item.indeterminate = true;
+						item.checked = false;
+					} else if (checkedLeg === leg) {
+						item.indeterminate = false;
+						item.checked = true;
+					}
 
-	arr.forEach(processItem);
-	return newArr1;
-}
-// 全选菜单
-const handleCheckAllChangeMenu = (val: boolean) => {
-	state.systemMenuArr = val ? state.allMenuArr : []
-	isIndeterminateMenu.value = false
-}
-const handleCheckedMenuChange = (value: string[]) => {
-	const checkedCount = value.length;
-	checkAllMenu.value = checkedCount === state.allMenuArr.length
-	isIndeterminateMenu.value = checkedCount > 0 && checkedCount < state.allMenuArr.length;
-}
-// 全选按钮
-const handleCheckAllChangeBtn = (val: boolean) => {
-	state.systemButtonArr = val ? state.allButtonArr : []
-	isIndeterminateBtn.value = false
-}
+					const currentI: any = find(item.parentId, state.menuTableData);
+					if (currentI) {
+						let checkedLeg1 = 0;
+						const leg1 = currentI.children.length;
+						checkedLeg1 = item.children.filter((ss: any) => ss.checked).length;
+						// 根据条数改变父级的indeterminate和checked
+						if (checkedLeg1 === 0) {
+							currentI.indeterminate = false;
+						} else if (checkedLeg < leg1) {
+							currentI.indeterminate = true;
+						} else if (checkedLeg === leg1) {
+							currentI.indeterminate = false;
+						}
+					}
+					return;
+				}
+				if (item.children && item.children.length) {
+					loop(item.children);
+				}
+			});
+		};
+		loop(state.menuTableData);
+	}
+	// 判断是否全部选择了,改变全选框的样式
+	let flag = true;
+	state.menuTableData.some((item: any) => {
+		if (!item.checked) {
+			flag = false;
+			return;
+		}
+	});
+	state.checkedAll = flag;
+};
+// 选择按钮
 const handleCheckedBtnChange = (value: string[]) => {
-	const checkedCount = value.length;
-	checkAllBtn.value = checkedCount === state.allButtonArr.length;
-	isIndeterminateBtn.value = checkedCount > 0 && checkedCount < state.allButtonArr.length;
-}
-// 开发环境不显示设置
-const showSetting = computed(() => {
-	return import.meta.env.VITE_MODE_NAME === 'development'
-})
+	state.systemButtonArr = value;
+};
+// 点击提交选中的表格
+const handleSelectTable = () => {
+	let selectedCodes = <any>[];
+	const loop = (data: any) => {
+		data.forEach((item: any) => {
+			if (item.checked || item.indeterminate) {
+				selectedCodes.push(item.permissionCode);
+				if (item.children) {
+					loop(item.children);
+				}
+			}
+		});
+	};
+	loop(state.menuTableData);
+	return selectedCodes;
+};
+// 保存
+const onSubmit = () => {
+	let req = {
+		roleId: state.currentRow.id,
+		roleCode: state.currentRow.name,
+		systemMenuArr: handleSelectTable(),
+		systemButtonArr: state.systemButtonArr,
+	};
+	setRolePower(req)
+		.then(() => {
+			ElMessage({
+				message: '操作成功',
+				type: 'success',
+			});
+			closeDialog();
+			emit('updateList');
+		})
+		.catch(() => {
+			// 新增失败
+			closeDialog();
+		});
+};
 onMounted(() => {
-	getMenuListApi()
-})
+	getMenuListApi();
+});
 // 暴露变量
 defineExpose({
 	openDialog,
-	closeDialog
+	closeDialog,
 });
 </script>
 

+ 5 - 5
src/views/system/roles/component/userList.vue

@@ -1,13 +1,13 @@
 <template>
     <div class="system-add-blackList-container">
-        <el-dialog v-model="state.isShowDialog" draggable :title="'(' + state.currentRow.displayName + ')' + '用户列表'">
+        <el-dialog v-model="state.isShowDialog" draggable :title="'用户列表'+'(' + state.currentRow.displayName + ')'">
             <!-- 表格 -->
             <el-table :data="state.tableData">
-                <el-table-column type="index" width="60" label="序号" />
-                <el-table-column prop="name" label="姓名" show-overflow-tooltip width="120"></el-table-column>
-                <el-table-column prop="userName" label="账号" show-overflow-tooltip width="120"></el-table-column>
+                <el-table-column type="index" width="60" label="序号" fixed="left"/>
+                <el-table-column prop="name" label="姓名" show-overflow-tooltip width="200" fixed="left"></el-table-column>
+                <el-table-column prop="userName" label="账号" show-overflow-tooltip width="200"></el-table-column>
                 <el-table-column prop="orgName" label="所属部门" show-overflow-tooltip width="190"></el-table-column>
-                <el-table-column prop="roles" label="角色" show-overflow-tooltip width="300"></el-table-column>
+                <el-table-column prop="roles" label="角色" show-overflow-tooltip width="100"></el-table-column>
                 <el-table-column prop="phoneNo" label="电话号码" show-overflow-tooltip width="130"></el-table-column>
                 <el-table-column prop="staffNo" label="工号" show-overflow-tooltip width="80"></el-table-column>
                 <el-table-column prop="genderText" label="性别" show-overflow-tooltip width="80"></el-table-column>

+ 12 - 12
src/views/system/roles/index.vue

@@ -14,7 +14,7 @@
 					</el-form-item>
 					<el-form-item>
 						<el-button type="primary" @click="handleQuery" :loading="loading" v-waves> <SvgIcon name="ele-Search" class="mr5" />查询 </el-button>
-						<el-button @click="resetQuery(ruleFormRef)" v-waves class="default-button"> <SvgIcon name="ele-Refresh" class="mr5" />重置 </el-button>
+						<el-button @click="resetQuery(ruleFormRef)" class="default-button"> <SvgIcon name="ele-Refresh" class="mr5" />重置 </el-button>
 					</el-form-item>
 				</el-form>
 			</transition>
@@ -50,7 +50,7 @@
 						<el-button text type="info" @click="onDataAuth(scope.row)" v-auth="'100204'" title="数据权限">
 							<SvgIcon name="ele-MessageBox" size="var(--hotline-table-icon-font-size)" />
 						</el-button>
-						<el-button text type="danger" @click="onRowDel(scope.row)" v-auth="'100202'" title="删除">
+						<el-button text type="danger" @click="onRowDel(scope.row)" v-if="scope.row.state === '正常'" v-auth="'100202'" title="删除">
 							<SvgIcon name="ele-Delete" size="var(--hotline-table-icon-font-size)" />
 						</el-button>
 					</template>
@@ -142,13 +142,13 @@ const router = useRouter();
 const handleQuery = throttle(() => {
 	data.queryParams.PageIndex = 1;
 	getList();
-}, 1000);
+}, 300);
 /** 重置按钮操作 */
 const resetQuery = throttle((formEl: FormInstance | undefined) => {
 	if (!formEl) return;
 	formEl.resetFields();
 	handleQuery();
-}, 1000);
+}, 300);
 /** 获取角色列表 */
 const getList = () => {
 	state.loading = true;
@@ -181,14 +181,14 @@ const showUserList = (row: Object) => {
 // 打开数据权限
 const onDataAuth = (row: any) => {
 	router.push({
-		path:'/system/roles/dataAuth',
-		query:{
-			id:row.id,
-			code:row.name,
-			tagsViewName:'数据权限 '+row.displayName
-		}
-	})
-}
+		path: '/system/roles/dataAuth',
+		query: {
+			id: row.id,
+			code: row.name,
+			tagsViewName: '数据权限 ' + row.displayName,
+		},
+	});
+};
 // 表格多选
 const handleSelectionChange = (val: any) => {
 	state.multipleSelection = val;

+ 43 - 29
src/views/system/user/index.vue

@@ -4,26 +4,30 @@
 			<el-row :gutter="20" class="h100">
 				<!-- 左侧组织树 -->
 				<el-col :xs="6" :sm="6" :md="4" :lg="4" :xl="4" class="orgTree">
-					<el-scrollbar height="100%" class="pr10">
-						<template v-if="state.orgData.length">
-							<el-tree
-								:data="state.orgData"
-								highlight-current
-								:expand-on-click-node="false"
-								default-expand-all
-								:props="{ children: 'children', label: 'orgName' }"
-								@node-click="handleNodeClick"
-								ref="treRef"
-								v-loading="state.loading"
-								node-key="id"
-								style="min-width: 100%; display: inline-block"
-							>
-							</el-tree>
-						</template>
-						<template v-else>
-							<Empty description="暂无组织数据" />
-						</template>
-					</el-scrollbar>
+					<div class="h100 pr10">
+						<el-input v-model="filterOrg" placeholder="请输入部门名称" class="input-with-select mt10 mb10" clearable> </el-input>
+						<el-scrollbar style="height: calc(100% - 40px);'">
+							<template v-if="state.orgData.length">
+								<el-tree
+									:data="state.orgData"
+									highlight-current
+									:expand-on-click-node="false"
+									default-expand-all
+									:props="{ children: 'children', label: 'orgName' }"
+									@node-click="handleNodeClick"
+									ref="treRef"
+									v-loading="state.loading"
+									node-key="id"
+									style="min-width: 100%; display: inline-block"
+									:filter-node-method="filterNodeOrg"
+								>
+								</el-tree>
+							</template>
+							<template v-else>
+								<Empty description="暂无组织数据" />
+							</template>
+						</el-scrollbar>
+					</div>
 				</el-col>
 				<!-- 右侧表格 -->
 				<el-col :xs="18" :sm="18" :md="20" :lg="20" :xl="20" class="rightContent">
@@ -37,10 +41,10 @@
 									<el-select-v2 v-model="state.queryParams.Role" filterable :options="state.options" placeholder="请选择角色" clearable />
 								</el-form-item>
 								<el-form-item>
-									<el-button type="primary" @click="handleQuery" :loading="state.tableLoading" v-waves>
+									<el-button type="primary" @click="handleQuery" :loading="state.tableLoading">
 										<SvgIcon name="ele-Search" class="mr5" />查询
 									</el-button>
-									<el-button @click="resetQuery(ruleFormRef)" v-waves class="default-button">
+									<el-button @click="resetQuery(ruleFormRef)" class="default-button">
 										<SvgIcon name="ele-Refresh" class="mr5" />重置
 									</el-button>
 								</el-form-item>
@@ -48,8 +52,8 @@
 							<div class="flex-center-between mb20">
 								<p class="table-title"></p>
 								<div>
-									<el-button type="primary" @click="onOpenAddUser" v-waves v-auth="'100102'"> <SvgIcon name="ele-Plus" class="mr5" />新增 </el-button>
-									<el-button type="primary" v-waves @click="onImportTable" :disabled="!state.multipleSelection.length">
+									<el-button type="primary" @click="onOpenAddUser" v-auth="'100102'"> <SvgIcon name="ele-Plus" class="mr5" />新增 </el-button>
+									<el-button type="primary" @click="onImportTable" :disabled="!state.multipleSelection.length">
 										<SvgIcon name="iconfont icon-daochu" class="mr5" />导出
 									</el-button>
 								</div>
@@ -58,7 +62,7 @@
 							<el-table :data="state.tableData" v-loading="state.tableLoading" row-key="id" @selection-change="handleSelectionChange">
 								<el-table-column type="selection" width="55" :reserve-selection="true" />
 								<el-table-column type="index" width="60" label="序号" />
-								<el-table-column prop="name" label="名" show-overflow-tooltip width="120"></el-table-column>
+								<el-table-column prop="name" label="用户名" show-overflow-tooltip width="120"></el-table-column>
 								<el-table-column prop="userName" label="账号" show-overflow-tooltip width="120"></el-table-column>
 								<el-table-column prop="orgName" label="所属部门" show-overflow-tooltip width="190"></el-table-column>
 								<el-table-column prop="roles" label="角色" show-overflow-tooltip width="300"></el-table-column>
@@ -111,7 +115,7 @@
 </template>
 
 <script lang="ts" setup name="systemUser">
-import { defineAsyncComponent, ref, reactive, onMounted } from 'vue';
+import { defineAsyncComponent, ref, reactive, onMounted, watch } from 'vue';
 import { ElMessageBox, ElMessage } from 'element-plus';
 import type { FormInstance } from 'element-plus';
 import table2excel from 'js-table2excel';
@@ -157,7 +161,7 @@ const state = reactive<QueryState>({
 	tableData: [],
 	total: 0,
 	loading: false,
-	tableLoading:false,
+	tableLoading: false,
 	multipleSelection: [],
 	orgData: [],
 	options: [],
@@ -166,8 +170,18 @@ const ruleFormRef = ref<FormInstance>(); //表单ref
 const addUserRef = ref(); //新增用户
 const editUserRef = ref(); //修改用户信息
 const setRoleRef = ref(); //设置角色
-const treRef = ref();
 const rightScrollRef = ref();
+
+const filterOrg = ref('');
+const treRef = ref();
+watch(filterOrg, (val) => {
+	treRef.value!.filter(val);
+});
+// 搜索部门名称
+const filterNodeOrg = (value: string, data: any) => {
+	if (!value) return true;
+	return data.orgName.includes(value);
+};
 /** 搜索按钮操作 节流操作 */
 const handleQuery = throttle(() => {
 	state.queryParams.PageIndex = 1;
@@ -233,7 +247,7 @@ const resetQuery = throttle((formEl: FormInstance | undefined) => {
 	state.queryParams.OrgCode = '';
 	treRef.value?.setCurrentKey(null);
 	handleQuery();
-}, 1000);
+}, 300);
 // 打开修改用户弹窗
 const onOpenEditUser = (row: any) => {
 	editUserRef.value.openDialog(row);