index.vue 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. <script setup lang="ts">
  2. import { useI18n } from '@/hooks/web/useI18n'
  3. import { ElInput, ElCard, ElTree, ElTreeSelect } from 'element-plus'
  4. import { handleTree } from '@/utils/tree'
  5. import { onMounted, ref, unref, watch } from 'vue'
  6. import * as DeptApi from '@/api/system/dept'
  7. import { Form, FormExpose } from '@/components/Form'
  8. import { modelSchema } from './dept.data'
  9. import { DeptVO } from '@/api/system/dept/types'
  10. import { useMessage } from '@/hooks/web/useMessage'
  11. const message = useMessage()
  12. interface Tree {
  13. id: number
  14. name: string
  15. children?: Tree[]
  16. }
  17. const defaultProps = {
  18. children: 'children',
  19. label: 'name',
  20. value: 'id'
  21. }
  22. const { t } = useI18n() // 国际化
  23. const loading = ref(false) // 遮罩层
  24. const dialogVisible = ref(false) // 是否显示弹出层
  25. const showForm = ref(false) // 显示form表单
  26. const formTitle = ref('部门信息') // 显示form标题
  27. const deptParentId = ref(0) // 上级ID
  28. // 创建form表单
  29. const formRef = ref<FormExpose>()
  30. // ========== 创建部门树结构 ==========
  31. const filterText = ref('')
  32. const deptOptions = ref() // 树形结构
  33. const treeRef = ref<InstanceType<typeof ElTree>>()
  34. const getTree = async () => {
  35. const res = await DeptApi.getDeptPageApi(null)
  36. deptOptions.value = handleTree(res)
  37. }
  38. const filterNode = (value: string, data: Tree) => {
  39. if (!value) return true
  40. return data.name.includes(value)
  41. }
  42. watch(filterText, (val) => {
  43. treeRef.value!.filter(val)
  44. })
  45. // 新增
  46. const handleAdd = (data: { id: number }) => {
  47. // 重置表单
  48. deptParentId.value = data.id
  49. formTitle.value = '新增部门'
  50. unref(formRef)?.getElFormRef()?.resetFields()
  51. showForm.value = true
  52. }
  53. // 编辑
  54. const handleUpdate = async (data: { id: number }) => {
  55. showForm.value = true
  56. const res = await DeptApi.getDeptApi(data.id)
  57. formTitle.value = '修改- ' + res?.name
  58. deptParentId.value = res.parentId
  59. unref(formRef)?.setValues(res)
  60. }
  61. // 删除
  62. const handleDelete = async (data: { id: number }) => {
  63. message
  64. .confirm(t('common.delDataMessage'), t('common.confirmTitle'))
  65. .then(async () => {
  66. await DeptApi.deleteDeptApi(data.id)
  67. message.success(t('common.delSuccess'))
  68. })
  69. .catch(() => {})
  70. await getTree()
  71. }
  72. // 提交按钮
  73. const submitForm = async () => {
  74. loading.value = true
  75. // 提交请求
  76. try {
  77. const data = unref(formRef)?.formModel as DeptVO
  78. data.parentId = deptParentId.value
  79. // TODO: 表单提交待完善
  80. if (formTitle.value.startsWith('新增')) {
  81. await DeptApi.createDeptApi(data)
  82. } else if (formTitle.value.startsWith('修改')) {
  83. await DeptApi.updateDeptApi(data)
  84. }
  85. // 操作成功,重新加载列表
  86. dialogVisible.value = false
  87. } finally {
  88. loading.value = false
  89. }
  90. }
  91. onMounted(async () => {
  92. await getTree()
  93. })
  94. </script>
  95. <template>
  96. <div class="flex">
  97. <el-card class="w-1/3 dept" :gutter="12" shadow="always">
  98. <template #header>
  99. <div class="card-header">
  100. <span>部门列表</span>
  101. <el-button type="primary" v-hasPermi="['system:dept:create']" @click="handleAdd">
  102. 新增根节点
  103. </el-button>
  104. </div>
  105. </template>
  106. <div class="custom-tree-container">
  107. <!-- <p>部门列表</p> -->
  108. <!-- 操作工具栏 -->
  109. <el-input v-model="filterText" placeholder="搜索部门" />
  110. <el-tree
  111. ref="treeRef"
  112. node-key="id"
  113. :data="deptOptions"
  114. :props="defaultProps"
  115. :highlight-current="true"
  116. default-expand-all
  117. :filter-node-method="filterNode"
  118. :expand-on-click-node="false"
  119. >
  120. <template #default="{ node, data }">
  121. <span class="custom-tree-node">
  122. <span>{{ node.label }}</span>
  123. <span>
  124. <el-button link v-hasPermi="['system:dept:create']" @click="handleAdd(data)">
  125. <Icon icon="ep:plus" class="mr-1px" />
  126. </el-button>
  127. <el-button link v-hasPermi="['system:dept:update']" @click="handleUpdate(data)">
  128. <Icon icon="ep:edit" class="mr-1px" />
  129. </el-button>
  130. <el-button link v-hasPermi="['system:dept:delete']" @click="handleDelete(data)">
  131. <Icon icon="ep:delete" class="mr-1px" />
  132. </el-button>
  133. </span>
  134. </span>
  135. </template>
  136. </el-tree>
  137. </div>
  138. </el-card>
  139. <el-card class="w-2/3 dept" style="margin-left: 10px" :gutter="12" shadow="hover">
  140. <template #header>
  141. <div class="card-header">
  142. <span>{{ formTitle }}</span>
  143. </div>
  144. </template>
  145. <div v-if="!showForm">
  146. <span><p>请从左侧选择部门</p></span>
  147. </div>
  148. <div v-if="showForm">
  149. <!-- 操作工具栏 -->
  150. <Form :schema="modelSchema" ref="formRef">
  151. <template #parentId>
  152. <el-tree-select
  153. node-key="id"
  154. v-model="deptParentId"
  155. :props="defaultProps"
  156. :data="deptOptions"
  157. check-strictly
  158. />
  159. </template>
  160. </Form>
  161. <!-- 操作按钮 -->
  162. <el-button
  163. type="primary"
  164. v-hasPermi="['system:dept:update']"
  165. :loading="loading"
  166. @click="submitForm"
  167. >
  168. {{ t('action.save') }}
  169. </el-button>
  170. <el-button type="danger" @click="showForm = false">取消</el-button>
  171. </div>
  172. </el-card>
  173. </div>
  174. </template>
  175. <style scoped>
  176. .dept {
  177. height: 600px;
  178. max-height: 1800px;
  179. }
  180. .card-header {
  181. display: flex;
  182. justify-content: space-between;
  183. align-items: center;
  184. }
  185. .custom-tree-node {
  186. flex: 1;
  187. display: flex;
  188. align-items: center;
  189. justify-content: space-between;
  190. font-size: 14px;
  191. padding-right: 8px;
  192. }
  193. </style>