diff --git a/src/components/RightToolbar/index.vue b/src/components/RightToolbar/index.vue index 02a55f78e66d9d88906d6f089349838f9d4f0f9a..899b074ad6b4fdbe3d44096940bbb37b965e27a5 100644 --- a/src/components/RightToolbar/index.vue +++ b/src/components/RightToolbar/index.vue @@ -53,6 +53,7 @@ const style = computed(() => { // 搜索 function toggleSearch() { emits('update:showSearch', !props.showSearch); + nextTick(() => window.dispatchEvent(new Event('resize'))); } // 刷新 diff --git a/src/directive/common/adaptive.ts b/src/directive/common/adaptive.ts new file mode 100644 index 0000000000000000000000000000000000000000..d4472b3d24df99759cd906f18e1f512eaf065ce4 --- /dev/null +++ b/src/directive/common/adaptive.ts @@ -0,0 +1,74 @@ +import type { Directive, DirectiveBinding } from 'vue'; + +// 扩展 HTMLElement 类型 +interface AdaptiveElement extends HTMLElement { + _resizeListener?: () => void; +} + +// 配置接口 +interface AdaptiveOptions { + height?: number; // 距离底部的距离,默认 90 +} + +const DEFAULT_HEIGHT = 105; + +/** + * 自适应高度指令 + * 用法: + *
+ *
+ */ +const vAdaptiveHeight: Directive = { + mounted(el, binding: DirectiveBinding) { + // 获取配置 + const config = binding.value || {}; + const bottomHeight = typeof config.height === 'number' ? config.height : DEFAULT_HEIGHT; + + // 设置高度 + const updateHeight = () => { + const rect = el.getBoundingClientRect(); + const top = rect.top; // 更准确 + const pageHeight = window.innerHeight; + el.style.height = `${pageHeight - top - bottomHeight}px`; + el.style.overflowY = 'auto'; + }; + + // 防抖:避免频繁触发 + let resizeTimer: number; + const onResize = () => { + clearTimeout(resizeTimer); + resizeTimer = window.setTimeout(() => { + requestAnimationFrame(updateHeight); + }, 100); + }; + + // 保存监听器,用于销毁 + el._resizeListener = onResize; + + // 初始设置 + updateHeight(); + + // 监听 resize + window.addEventListener('resize', onResize); + }, + + // 组件更新时重新计算(比如父组件 re-render) + updated(el, binding: DirectiveBinding) { + const config = binding.value || {}; + const bottomHeight = typeof config.height === 'number' ? config.height : DEFAULT_HEIGHT; + + const rect = el.getBoundingClientRect(); + const top = rect.top; + const pageHeight = window.innerHeight; + el.style.height = `${pageHeight - top - bottomHeight}px`; + }, + + unmounted(el) { + if (el._resizeListener) { + window.removeEventListener('resize', el._resizeListener); + delete el._resizeListener; + } + } +}; + +export default vAdaptiveHeight; diff --git a/src/directive/index.ts b/src/directive/index.ts index ef25ee897f6bec346588fae6324e41a4ba2ffed8..8d660c9983c20e3b6225fff5c0024d0bb439982b 100644 --- a/src/directive/index.ts +++ b/src/directive/index.ts @@ -1,9 +1,11 @@ import copyText from './common/copyText'; +import adaptive from './common/adaptive'; import { hasPermi, hasRoles } from './permission'; import { App } from 'vue'; export default (app: App) => { app.directive('copyText', copyText); + app.directive('adaptive', adaptive); app.directive('hasPermi', hasPermi); app.directive('hasRoles', hasRoles); }; diff --git a/src/views/system/dept/index.vue b/src/views/system/dept/index.vue index 56f4b1766714c67d9c16e29be550452bd7bbda05..28a0a5c5b1a059e9d242986ad9a803e9baaaf716 100644 --- a/src/views/system/dept/index.vue +++ b/src/views/system/dept/index.vue @@ -38,6 +38,7 @@ 新增 - 级联删除 + 级联删除 - + @@ -615,9 +616,7 @@ const handleUpdate = async (row?: UserForm) => { dialog.title = '修改用户'; Object.assign(form.value, data.user); postOptions.value = data.posts; - roleOptions.value = Array.from( - new Map([...data.roles, ...data.user.roles].map(role => [role.roleId, role])).values() - ); + roleOptions.value = Array.from(new Map([...data.roles, ...data.user.roles].map((role) => [role.roleId, role])).values()); form.value.postIds = data.postIds; form.value.roleIds = data.roleIds; form.value.password = '';