index.vue 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  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 } 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 link v-hasPermi="['system:dept:create']" @click="handleAdd(data)">
  135. <Icon icon="ep:plus" class="mr-1px" />
  136. </el-button>
  137. <el-button link v-hasPermi="['system:dept:update']" @click="handleUpdate(data)">
  138. <Icon icon="ep:edit" class="mr-1px" />
  139. </el-button>
  140. <el-button link v-hasPermi="['system:dept:delete']" @click="handleDelete(data)">
  141. <Icon icon="ep:delete" class="mr-1px" />
  142. </el-button>
  143. </span>
  144. </span>
  145. </template>
  146. </el-tree>
  147. </div>
  148. </el-card>
  149. <el-card class="w-2/3 dept" style="margin-left: 10px" :gutter="12" shadow="hover">
  150. <template #header>
  151. <div class="card-header">
  152. <span>{{ formTitle }}</span>
  153. </div>
  154. </template>
  155. <div v-if="!showForm">
  156. <span><p>请从左侧选择部门</p></span>
  157. </div>
  158. <div v-if="showForm">
  159. <!-- 操作工具栏 -->
  160. <Form :schema="modelSchema" ref="formRef">
  161. <template #parentId>
  162. <el-tree-select
  163. node-key="id"
  164. v-model="deptParentId"
  165. :props="defaultProps"
  166. :data="deptOptions"
  167. check-strictly
  168. />
  169. </template>
  170. <template #leaderUserId>
  171. <el-select v-model="leaderUserId">
  172. <el-option
  173. v-for="item in userOption"
  174. :key="parseInt(item.id)"
  175. :label="item.nickname"
  176. :value="parseInt(item.id)"
  177. />
  178. </el-select>
  179. </template>
  180. </Form>
  181. <!-- 操作按钮 -->
  182. <el-button
  183. type="primary"
  184. v-hasPermi="['system:dept:update']"
  185. :loading="loading"
  186. @click="submitForm"
  187. >
  188. {{ t('action.save') }}
  189. </el-button>
  190. <el-button type="danger" @click="showForm = false">取消</el-button>
  191. </div>
  192. </el-card>
  193. </div>
  194. </template>
  195. <style scoped>
  196. .dept {
  197. height: 600px;
  198. max-height: 1800px;
  199. }
  200. .card-header {
  201. display: flex;
  202. justify-content: space-between;
  203. align-items: center;
  204. }
  205. .custom-tree-node {
  206. flex: 1;
  207. display: flex;
  208. align-items: center;
  209. justify-content: space-between;
  210. font-size: 14px;
  211. padding-right: 8px;
  212. }
  213. </style>