Browse Source

feat:优化 dept、menu 支持选择“当前层级”

YunaiV 4 months ago
parent
commit
f82b1aa47c

+ 32 - 11
src/pages-system/dept/form/components/dept-picker.vue

@@ -4,6 +4,8 @@
     :label="label"
     label-width="180rpx"
     :columns="deptColumns"
+    value-key="id"
+    label-key="name"
     :column-change="handleColumnChange"
     :display-format="displayFormat"
     @confirm="handleConfirm"
@@ -64,17 +66,25 @@ function initFirstColumn() {
   if (props.showRoot) {
     deptColumns.value = [
       [
-        { label: '顶级部门', value: 0 },
-        ...topDepts.map(item => ({ value: item.id, label: item.name })),
+        { id: 0, name: '顶级部门' },
+        ...topDepts,
       ],
     ]
   } else {
-    deptColumns.value = [
-      topDepts.map(item => ({ value: item.id, label: item.name })),
-    ]
+    deptColumns.value = [topDepts]
   }
 }
 
+/** 构建带"选择当前"选项的子列表 */
+function buildChildrenWithCurrent(parentId: number) {
+  const children = deptList.value.filter(item => item.parentId === parentId)
+  // 添加"选择当前"选项,使用父节点 ID 的负数作为标识
+  return [
+    { id: -parentId, name: '✓ 选择当前' },
+    ...children,
+  ]
+}
+
 /** 加载部门列表 */
 async function loadDeptList() {
   deptList.value = await getSimpleDeptList()
@@ -122,7 +132,7 @@ function buildColumnsForPath(path: number[]) {
     const parentId = path[i]
     const children = deptList.value.filter(item => item.parentId === parentId)
     if (children.length > 0) {
-      columns.push(children.map(item => ({ value: item.id, label: item.name })))
+      columns.push(children)
     }
   }
   deptColumns.value = columns
@@ -130,13 +140,14 @@ function buildColumnsForPath(path: number[]) {
 
 /** 列变化 */
 function handleColumnChange({ selectedItem, resolve, finish }: any) {
-  if (selectedItem.value === 0) {
+  // 选择顶级部门或"选择当前",结束
+  if (selectedItem.id === 0 || selectedItem.id < 0) {
     finish()
     return
   }
-  const children = deptList.value.filter(item => item.parentId === selectedItem.value)
+  const children = deptList.value.filter(item => item.parentId === selectedItem.id)
   if (children.length > 0) {
-    resolve(children.map(item => ({ value: item.id, label: item.name })))
+    resolve(buildChildrenWithCurrent(selectedItem.id))
   } else {
     finish()
   }
@@ -144,13 +155,23 @@ function handleColumnChange({ selectedItem, resolve, finish }: any) {
 
 /** 格式化显示 */
 function displayFormat(selectedItems: any[]) {
-  return selectedItems.map(item => item.label).join('/')
+  // 过滤掉"选择当前"选项
+  return selectedItems
+    .filter(item => item.id >= 0)
+    .map(item => item.name)
+    .join('/')
 }
 
 /** 确认选择 */
 function handleConfirm({ value }: { value: number[] }) {
   if (value && value.length > 0) {
-    emit('update:modelValue', value[value.length - 1])
+    const lastValue = value[value.length - 1]
+    // 如果选择的是"选择当前"(负数 ID),取其绝对值作为实际选中的部门 ID
+    if (lastValue < 0) {
+      emit('update:modelValue', Math.abs(lastValue))
+    } else {
+      emit('update:modelValue', lastValue)
+    }
   } else {
     // 如果允许 root,默认顶级 0;否则 undefined
     emit('update:modelValue', props.showRoot ? 0 : undefined)

+ 31 - 9
src/pages-system/menu/form/components/menu-picker.vue

@@ -4,6 +4,8 @@
     label="上级菜单"
     label-width="180rpx"
     :columns="menuColumns"
+    value-key="id"
+    label-key="name"
     :column-change="handleColumnChange"
     :display-format="displayFormat"
     @confirm="handleConfirm"
@@ -50,8 +52,8 @@ async function loadMenuList() {
   // 构建第一列数据(主类目 + 顶级菜单)
   const topMenus = menuList.value.filter(item => item.parentId === 0)
   menuColumns.value = [[
-    { value: 0, label: '主类目' },
-    ...topMenus.map(item => ({ value: item.id, label: item.name })),
+    { id: 0, name: '主类目' },
+    ...topMenus,
   ]]
   // 如果有初始值,回显
   if (props.modelValue !== undefined && props.modelValue !== 0) {
@@ -101,22 +103,32 @@ function buildColumnsForPath(path: number[]) {
     }
     const children = menuList.value.filter(item => item.parentId === parentId)
     if (children.length > 0) {
-      columns.push(children.map(item => ({ value: item.id, label: item.name })))
+      columns.push(children)
     }
   }
   menuColumns.value = columns
 }
 
+/** 构建带"选择当前"选项的子列表 */
+function buildChildrenWithCurrent(parentId: number) {
+  const children = menuList.value.filter(item => item.parentId === parentId)
+  // 添加"选择当前"选项,使用父节点 ID 的负数作为标识
+  return [
+    { id: -parentId, name: '✓ 选择当前' },
+    ...children,
+  ]
+}
+
 /** 列变化 */
 function handleColumnChange({ selectedItem, resolve, finish }: any) {
-  if (selectedItem.value === 0) {
-    // 选择主类目,结束
+  // 选择主类目或"选择当前",结束
+  if (selectedItem.id === 0 || selectedItem.id < 0) {
     finish()
     return
   }
-  const children = menuList.value.filter(item => item.parentId === selectedItem.value)
+  const children = menuList.value.filter(item => item.parentId === selectedItem.id)
   if (children.length > 0) {
-    resolve(children.map(item => ({ value: item.id, label: item.name })))
+    resolve(buildChildrenWithCurrent(selectedItem.id))
   } else {
     finish()
   }
@@ -124,13 +136,23 @@ function handleColumnChange({ selectedItem, resolve, finish }: any) {
 
 /** 格式化显示 */
 function displayFormat(selectedItems: any[]) {
-  return selectedItems.map(item => item.label).join(' / ')
+  // 过滤掉"选择当前"选项
+  return selectedItems
+    .filter(item => item.id >= 0)
+    .map(item => item.name)
+    .join(' / ')
 }
 
 /** 确认选择 */
 function handleConfirm({ value }: { value: number[] }) {
   if (value && value.length > 0) {
-    emit('update:modelValue', value[value.length - 1])
+    const lastValue = value[value.length - 1]
+    // 如果选择的是"选择当前"(负数 ID),取其绝对值作为实际选中的菜单 ID
+    if (lastValue < 0) {
+      emit('update:modelValue', Math.abs(lastValue))
+    } else {
+      emit('update:modelValue', lastValue)
+    }
   } else {
     emit('update:modelValue', 0)
   }

+ 4 - 10
src/pages-system/post/form/components/post-picker.vue

@@ -3,7 +3,9 @@
     v-model="selectedIds"
     label="岗位"
     label-width="180rpx"
-    :columns="columns"
+    :columns="postList"
+    value-key="id"
+    label-key="name"
     type="checkbox"
     filterable
     @confirm="handleConfirm"
@@ -12,7 +14,7 @@
 
 <script lang="ts" setup>
 import type { Post } from '@/api/system/post'
-import { computed, onMounted, ref, watch } from 'vue'
+import { onMounted, ref, watch } from 'vue'
 import { getSimplePostList } from '@/api/system/post'
 
 const props = defineProps<{
@@ -26,14 +28,6 @@ const emit = defineEmits<{
 const postList = ref<Post[]>([])
 const selectedIds = ref<number[]>([])
 
-/** 构建 columns 数据 */
-const columns = computed(() => {
-  return postList.value.map(item => ({
-    label: item.name,
-    value: item.id,
-  }))
-})
-
 watch(
   () => props.modelValue,
   (val) => {