优化问题
第一个问题,本小节的提示语优化,老师是放在事件执行函数里面,手动自行提示的,但是在 vben 框架中,作者有在 api中封装提示语的方式,这样直接调用应该更 ok 的
相关截图:
第二个问题,再前面章节中,老师对禁用菜单进行了处理,禁用当前菜单时,需要判断其下面有没有二级、三级菜单处于启用状态,如果有,需要先将所有二三级菜单禁用,然后才能禁用自身,但是单独去依次判断二三级菜单是否会过于臃肿,而且并未判断更深层级的菜单,比如四五级菜单等,换成递归是否会更好
第三个问题,禁用菜单进行了处理,启用菜单按理来说也是需要的,启用当前菜单,需要判断父级菜单是否被启用,不然直接启用当前菜单,会造成错误的
以下是针对上述问题进行的优化,请老师看看有没什么问题
第一个问题
第二、三个问题
相关代码:
<template>
<BasicDrawer v-bind="$attrs" @register="registerDrawer" showFooter :title="getTitle" width="50%" @ok="handleSubmit">
<BasicForm @register="registerForm" />
</BasicDrawer>
</template>
<script lang="ts" setup>
import { ref, computed, unref } from 'vue';
import { BasicForm, useForm } from '@/components/Form';
import { formSchema } from './menu.data';
import { BasicDrawer, useDrawerInner } from '@/components/Drawer';
import { getMenuList } from '@/api/demo/system';
import { createMenu, updateMenu } from '@/api/sys/menu';
import { useMessage } from '@/hooks/web/useMessage';
defineOptions({ name: 'MenuDrawer' });
const { createMessage } = useMessage();
const emit = defineEmits(['success', 'register']);
const isUpdate = ref(true);
const activeMenu = ref<any>({});
const menulist = ref<any>([]);
const [registerForm, { resetFields, setFieldsValue, updateSchema, validate }] = useForm({
labelWidth: 100,
schemas: formSchema,
showActionButtonGroup: false,
baseColProps: { lg: 12, md: 24 },
});
const [registerDrawer, { setDrawerProps, closeDrawer }] = useDrawerInner(async (data) => {
resetFields();
setDrawerProps({ confirmLoading: false });
isUpdate.value = !!data?.isUpdate;
if (unref(isUpdate)) {
activeMenu.value = data.record;
data.record.active = + data.record.active;
setFieldsValue({
...data.record,
});
}
const treeData = await getMenuList();
menulist.value = treeData;
updateSchema({
field: 'pid',
componentProps: { treeData },
});
});
const getTitle = computed(() => (!unref(isUpdate) ? '新增菜单' : '编辑菜单'));
function checkDisableRoute(menu: Recordable<any>): boolean {
// 过滤其所有的子菜单
const children = menulist.value.filter((item: Recordable<any>) => item.pid === menu.id);
let allDisabled = true;
// 通过递归的方式,检查是否有二级、三级、...菜单
for (let i = 0; i < children.length; i++) {
const itIsDisabled = checkDisableRoute(children[i]);
if (!itIsDisabled) {
allDisabled = false; // 只要有一个子菜单不可禁用,就将 allDisabled 置为 false
}
}
// 如果当前菜单禁用且其所有子菜单也都禁用,则返回 true,否则返回 false
if (menu.active === 0 && allDisabled) {
return true;
}
return false;
}
function checkEnableRoute(menu: Recordable<any>): boolean {
// 如果当前菜单没有父菜单,则直接返回当前菜单的启用状态
if (menu.pid === 0) {
return true;
}
// 查找当前菜单的父菜单
const parentMenu = menulist.value.find((item: Recordable<any>) => item.id === menu.pid);
// 如果找不到父菜单,返回 true
if (!parentMenu) {
return true;
}
// 递归检查父菜单是否启用,直到没有父菜单或找到未启用的父菜单为止
return parentMenu.active == 1 && checkEnableRoute(parentMenu);
}
async function handleSubmit() {
try {
const values = await validate();
setDrawerProps({ confirmLoading: true });
// TODO custom api
if (unref(isUpdate)) {
values.id = activeMenu.value.id;
const itIsDisabled = checkDisableRoute(values);
const itIsEnabled = checkEnableRoute(values);
if (!itIsDisabled && values.active === 0) {
throw new Error('存在未禁用的子菜单,请先禁用所有子菜单后再禁用主菜单.');
}
if (!itIsEnabled && values.active === 1) {
throw new Error('存在未启用的主菜单,请先启用所有主菜单后再启用子菜单.');
}
await updateMenu(values);
} else {
await createMenu(values);
}
closeDrawer();
emit('success');
} catch (error) {
createMessage.error(error.message);
}finally {
setDrawerProps({ confirmLoading: false });
}
}
</script>23
收起
正在回答
2回答
同学你好,按照开发逻辑来说:
1、如API上有提供,那么首先考虑使用API提供的。
2、关于菜单这一块,需要使用到递归的思想, 要不然后面追加时会出现再次调整代码给工作带来更多的工作量这样是不优的。
3、思路是没什么问题的。
总结,在正式开发中多想几部是一个程序员对业务逻辑的理解与经验,以上提到的点都很不错。
祝学习愉快!
相似问题
登录后可查看更多问答,登录/注册
恭喜解决一个难题,获得1积分~
来为老师/同学的回答评分吧
0 星