Просмотр исходного кода

✨ feat(日报): 填报,重新封装组织树组件

Zimo 6 дней назад
Родитель
Сommit
47409eab01

+ 117 - 0
src/components/DeptTreeSelect/index.vue

@@ -0,0 +1,117 @@
+<script lang="ts" setup>
+import { defaultProps, handleTree } from '@/utils/tree'
+import { ElTree } from 'element-plus'
+import * as DeptApi from '@/api/system/dept'
+import { Search } from '@element-plus/icons-vue'
+
+const props = defineProps({
+  deptId: {
+    type: Number,
+    default: 157
+  },
+  modelValue: {
+    type: Number,
+    default: undefined
+  }
+})
+
+const emits = defineEmits(['update:modelValue', 'node-click'])
+
+const deptName = ref('')
+
+const deptList = ref<Tree[]>([])
+
+const treeRef = ref<InstanceType<typeof ElTree>>()
+
+const expandedKeys = ref<number[]>([])
+
+const loadTree = async () => {
+  try {
+    const res = await DeptApi.specifiedSimpleDepts(props.deptId)
+    deptList.value = handleTree(res)
+
+    // 加载完成后,如果有选中值,尝试高亮并展开
+    nextTick(() => {
+      if (props.modelValue && treeRef.value) {
+        treeRef.value.setCurrentKey(props.modelValue)
+        expandedKeys.value = [props.modelValue] // 默认展开选中的节点
+      } else if (deptList.value.length > 0) {
+        // 默认展开第一级
+        expandedKeys.value = deptList.value.map((item) => item.id)
+      }
+    })
+  } catch (error) {
+    console.error('加载部门树失败:', error)
+  }
+}
+
+const handleNodeClick = (data: Tree) => {
+  // 1. 更新 v-model
+  emits('update:modelValue', data.id)
+  // 2. 抛出点击事件供父组件其他用途
+  emits('node-click', data)
+}
+
+/** 筛选节点逻辑 */
+const filterNode = (value: string, data: Tree) => {
+  if (!value) return true
+  return data.name.includes(value)
+}
+
+/** 监听输入框进行过滤 */
+watch(deptName, (val) => {
+  treeRef.value?.filter(val)
+})
+
+watch(
+  () => props.deptId,
+  (newVal, oldVal) => {
+    if (newVal !== oldVal) {
+      loadTree()
+    }
+  }
+)
+
+watch(
+  () => props.modelValue,
+  (newVal) => {
+    if (newVal && treeRef.value) {
+      // 设置高亮
+      treeRef.value.setCurrentKey(newVal)
+      // 自动展开该节点 (将新ID加入展开数组)
+      if (!expandedKeys.value.includes(newVal)) {
+        expandedKeys.value.push(newVal)
+      }
+    }
+  }
+)
+
+/** 初始化 */
+onMounted(() => {
+  loadTree()
+})
+</script>
+
+<template>
+  <h1 class="text-lg font-medium">部门</h1>
+  <el-input
+    v-model="deptName"
+    size="default"
+    placeholder="请输入部门名称"
+    clearable
+    :prefix-icon="Search"
+  />
+  <el-scrollbar max-height="700px">
+    <el-tree
+      ref="treeRef"
+      :data="deptList"
+      :props="defaultProps"
+      :expand-on-click-node="false"
+      :filter-node-method="filterNode"
+      node-key="id"
+      highlight-current
+      :default-expanded-keys="expandedKeys"
+      @node-click="handleNodeClick"
+    />
+  </el-scrollbar>
+</template>

+ 1 - 1
src/layout/components/AppView.vue

@@ -38,7 +38,7 @@ provide('reload', reload)
     :class="[
       'p-[var(--app-content-padding)] w-full bg-[var(--app-content-bg-color)] dark:bg-[var(--el-bg-color)]',
       {
-        '!min-h-[calc(100vh-var(--top-tool-height)-var(--tags-view-height)-var(--app-footer-height))] pb-0':
+        'h-[calc(100vh-var(--top-tool-height)-var(--tags-view-height)-var(--app-footer-height))] !min-h-[calc(100vh-var(--top-tool-height)-var(--tags-view-height)-var(--app-footer-height))] pb-0':
           footer
       }
     ]"

+ 13 - 0
src/views/pms/iotrhdailyreport/fill.vue

@@ -0,0 +1,13 @@
+<script lang="ts" setup>
+const deptId = 157
+
+const modelValue = ref()
+</script>
+
+<template>
+  <div class="grid grid-cols-[15%_1fr] gap-4 h-full">
+    <div class="flex flex-col p-4 gap-2 bg-white dark:bg-[#1d1e1f] shadow rounded-lg h-full">
+      <DeptTreeSelect :deptId="deptId" v-model="modelValue" />
+    </div>
+  </div>
+</template>