index.vue 6.7 KB

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