index.vue 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. <template>
  2. <div class="main-box">
  3. <TreeFilter title="部门列表" :is-all="false" :data="treeFilterData" :default-value="initParam.deptId" @change="changeTreeFilter" />
  4. <div class="table-box">
  5. <ProTable
  6. ref="proTable"
  7. row-key="userId"
  8. :indent="20"
  9. :columns="columns"
  10. :request-api="listUserApi"
  11. :request-auto="false"
  12. :init-param="initParam"
  13. :search-col="{ xs: 1, sm: 1, md: 2, lg: 3, xl: 3 }"
  14. >
  15. <!-- 表格 header 按钮 -->
  16. <template #tableHeader="scope">
  17. <el-button type="primary" v-auth="['system:user:add']" :icon="CirclePlus" @click="openDialog(1, '用户新增')"> 新增 </el-button>
  18. <el-button type="primary" v-auth="['system:user:import']" :icon="Upload" plain @click="batchAdd">导入</el-button>
  19. <el-button type="primary" v-auth="['system:user:export']" :icon="Download" plain @click="downloadFile">导出</el-button>
  20. <el-button
  21. type="danger"
  22. v-auth="['system:user:remove']"
  23. :icon="Delete"
  24. plain
  25. :disabled="!scope.isSelected"
  26. @click="batchDelete(scope.selectedListIds)"
  27. >
  28. 批量删除
  29. </el-button>
  30. </template>
  31. <!-- 表格操作 -->
  32. <template #operation="scope">
  33. <el-button type="primary" link v-if="scope.row.userId !== 1" :icon="View" @click="openDialog(3, '用户查看', scope.row)">查看</el-button>
  34. <el-button type="primary" link v-if="scope.row.userId !== 1" :icon="EditPen" @click="openDialog(2, '用户编辑', scope.row)">编辑</el-button>
  35. <el-button type="primary" link v-if="scope.row.userId !== 1" :icon="Delete" @click="deleteAccount(scope.row)">删除</el-button>
  36. </template>
  37. </ProTable>
  38. <FormDialog ref="formDialogRef" />
  39. <ImportExcel ref="dialogRef" />
  40. </div>
  41. </div>
  42. </template>
  43. <script setup lang="tsx" name="UserManage">
  44. import { onMounted, reactive, ref } from 'vue'
  45. import { User } from '@/api/interface'
  46. import { useDownload } from '@/hooks/useDownload'
  47. import { useHandleData } from '@/hooks/useHandleData'
  48. import { ElMessageBox } from 'element-plus'
  49. import ProTable from '@/components/ProTable/index.vue'
  50. import TreeFilter from '@/components/TreeFilter/index.vue'
  51. import ImportExcel from '@/components/ImportExcel/index.vue'
  52. import FormDialog from '@/components/DialogOld/form.vue'
  53. import { CirclePlus, Download, Upload, View, Delete, EditPen } from '@element-plus/icons-vue'
  54. import { ColumnProps, ProTableInstance } from '@/components/ProTable/interface'
  55. import {
  56. listUserApi,
  57. delUserApi,
  58. addUserApi,
  59. updateUserApi,
  60. changeUserStatus,
  61. importTemplateApi,
  62. importDataApi,
  63. exportApi,
  64. getUserApi,
  65. deptTreeSelectApi
  66. } from '@/api/modules/system/user'
  67. import { getDictsApi } from '@/api/modules/system/dictData'
  68. onMounted(() => {
  69. getTreeFilter()
  70. })
  71. // ProTable 实例
  72. const proTable = ref<ProTableInstance>()
  73. // 如果表格需要初始化请求参数,直接定义传给 ProTable(之后每次请求都会自动带上该参数,此参数更改之后也会一直带上,改变此参数会自动刷新表格数据)
  74. const initParam = reactive({ deptId: '' })
  75. // 获取 treeFilter 数据
  76. // 当 proTable 的 requestAuto 属性为 false,不会自动请求表格数据,等待 treeFilter 数据回来之后,更改 initParam.departmentId 的值,才会触发请求 proTable 数据
  77. const treeFilterData = ref<any>([])
  78. const getTreeFilter = async () => {
  79. const { data } = await deptTreeSelectApi()
  80. treeFilterData.value = data
  81. initParam.deptId = treeFilterData.value[0].id
  82. }
  83. // 树形筛选切换
  84. const changeTreeFilter = (val: string) => {
  85. // ElMessage.success('请注意查看请求参数变化 🤔')
  86. proTable.value!.pageable.pageNum = 1
  87. initParam.deptId = val
  88. }
  89. // 切换用户状态
  90. const changeStatus = async (row: User.ResUserList) => {
  91. await useHandleData(changeUserStatus, { userId: row.userId, status: row.status == '1' ? 0 : 1 }, `切换【${row.userName}】用户状态`)
  92. proTable.value?.getTableList()
  93. }
  94. // 删除用户信息
  95. const deleteAccount = async (params: User.ResUserList) => {
  96. await useHandleData(delUserApi, params.userId, `删除【${params.userName}】用户`)
  97. proTable.value?.getTableList()
  98. }
  99. // 批量删除用户信息
  100. const batchDelete = async (ids: string[]) => {
  101. await useHandleData(delUserApi, ids, '删除所选用户信息')
  102. proTable.value?.clearSelection()
  103. proTable.value?.getTableList()
  104. }
  105. // 导出用户列表
  106. const downloadFile = async () => {
  107. ElMessageBox.confirm('确认导出用户数据?', '温馨提示', { type: 'warning' }).then(() =>
  108. useDownload(exportApi, '用户列表', proTable.value?.searchParam)
  109. )
  110. }
  111. // 批量添加用户
  112. const dialogRef = ref<InstanceType<typeof ImportExcel> | null>(null)
  113. const batchAdd = () => {
  114. const params = {
  115. title: '用户',
  116. tempApi: importTemplateApi,
  117. importApi: importDataApi,
  118. getTableList: proTable.value?.getTableList
  119. }
  120. dialogRef.value?.acceptParams(params)
  121. }
  122. const formDialogRef = ref<InstanceType<typeof FormDialog> | null>(null)
  123. const postOptions = ref<any[]>([])
  124. const roleOptions = ref<any[]>([])
  125. // 打开弹框的功能
  126. const openDialog = async (type: number, title: string, row?: any) => {
  127. let res = await getUserApi(row?.userId || null)
  128. postOptions.value = res.data.posts
  129. roleOptions.value = res.data.roles
  130. // 表单项配置
  131. const fieldList: Form.FieldItem[] = [
  132. {
  133. label: '用户昵称',
  134. placeholder: '请输入用户昵称',
  135. span: 12,
  136. field: 'nickName',
  137. rules: [{ required: true, message: '用户昵称不能为空' }]
  138. },
  139. {
  140. label: '归属部门',
  141. span: 12,
  142. field: 'deptId',
  143. placeholder: '请选择归属部门',
  144. enum: () => deptTreeSelectApi(),
  145. type: 'select-tree',
  146. options: {
  147. valueKey: 'id',
  148. labelKey: 'label',
  149. children: 'children'
  150. }
  151. },
  152. {
  153. label: '手机号码',
  154. placeholder: '请输入手机号码',
  155. span: 12,
  156. field: 'phonenumber',
  157. rules: [{ pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/, message: '请输入正确的手机号码', trigger: 'blur' }]
  158. },
  159. {
  160. label: '邮箱',
  161. placeholder: '请输入邮箱',
  162. span: 12,
  163. field: 'email',
  164. rules: [{ type: 'email', message: '请输入正确的邮箱地址', trigger: ['blur', 'change'] }]
  165. },
  166. {
  167. label: '性别',
  168. span: 12,
  169. field: 'sex',
  170. enum: () => getDictsApi('sys_user_gender'),
  171. type: 'select',
  172. options: {
  173. labelKey: 'dictLabel',
  174. valueKey: 'dictValue'
  175. }
  176. },
  177. {
  178. label: '状态',
  179. span: 12,
  180. field: 'status',
  181. type: 'radio',
  182. enum: () => getDictsApi('sys_normal_disable'),
  183. options: {
  184. labelKey: 'dictLabel',
  185. valueKey: 'dictValue'
  186. }
  187. },
  188. {
  189. label: '岗位',
  190. span: 12,
  191. field: 'postIds',
  192. enum: postOptions.value,
  193. type: 'select',
  194. options: {
  195. valueKey: 'postId',
  196. labelKey: 'postName',
  197. multiple: true
  198. }
  199. },
  200. {
  201. label: '角色',
  202. span: 12,
  203. field: 'roleIds',
  204. enum: roleOptions.value,
  205. type: 'select',
  206. options: {
  207. valueKey: 'roleId',
  208. labelKey: 'roleName',
  209. multiple: true
  210. }
  211. },
  212. {
  213. label: '备注',
  214. placeholder: '请输入内容',
  215. field: 'remark',
  216. type: 'textarea'
  217. }
  218. ]
  219. if (type == 1) {
  220. fieldList.splice(
  221. 4,
  222. 0,
  223. {
  224. label: '用户名称',
  225. placeholder: '请输入用户名称',
  226. field: 'userName',
  227. span: 12,
  228. rules: [
  229. { required: true, message: '用户名称不能为空' },
  230. { min: 2, max: 20, message: '用户名称长度必须介于 2 和 20 之间', trigger: 'blur' }
  231. ]
  232. },
  233. {
  234. label: '用户密码',
  235. placeholder: '请输入密码',
  236. field: 'password',
  237. type: 'password',
  238. showPassword: true,
  239. span: 12,
  240. rules: [
  241. { required: true, message: '密码不能为空' },
  242. { min: 5, max: 20, message: '用户密码长度必须介于 5 和 20 之间', trigger: 'blur' }
  243. ]
  244. }
  245. )
  246. }
  247. if (row?.userId) {
  248. res.data.user.postIds = res.data.postIds
  249. res.data.user.roleIds = res.data.roleIds
  250. }
  251. const params = {
  252. title,
  253. width: 680,
  254. isEdit: type !== 3,
  255. fieldList: fieldList,
  256. model: type == 1 ? {} : res.data.user,
  257. api: type == 1 ? addUserApi : updateUserApi,
  258. getTableList: proTable.value?.getTableList
  259. }
  260. formDialogRef.value?.openDialog(params)
  261. }
  262. // 表格配置项
  263. const columns = reactive<ColumnProps<User.ResUserList>[]>([
  264. { type: 'selection', fixed: 'left', width: 70 },
  265. { prop: 'userId', label: '用户编号' },
  266. { prop: 'userName', label: '用户名称', search: { el: 'input' }, width: 120 },
  267. { prop: 'nickName', label: '用户昵称', search: { el: 'input' }, width: 120 },
  268. { prop: 'dept.deptName', label: '部门', width: 120 },
  269. { prop: 'phonenumber', label: '手机号码', width: 120 },
  270. {
  271. prop: 'status',
  272. label: '用户状态',
  273. width: 120,
  274. enum: () => getDictsApi('sys_normal_disable'),
  275. search: { el: 'tree-select' },
  276. fieldNames: { label: 'dictLabel', value: 'dictValue' },
  277. render: scope => {
  278. return (
  279. <el-switch
  280. model-value={scope.row.status}
  281. active-text={scope.row.status === '1' ? '禁用' : '启用'}
  282. active-value={'0'}
  283. inactive-value={'1'}
  284. onClick={() => changeStatus(scope.row)}
  285. />
  286. )
  287. }
  288. },
  289. {
  290. prop: 'sex',
  291. label: '性别',
  292. width: 120,
  293. enum: () => getDictsApi('sys_user_gender'),
  294. fieldNames: {
  295. label: 'dictLabel',
  296. value: 'dictValue'
  297. }
  298. },
  299. { prop: 'createTime', label: '创建时间', width: 180 },
  300. { prop: 'operation', label: '操作', width: 230, fixed: 'right' }
  301. ])
  302. </script>