index.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464
  1. <script lang="ts" setup>
  2. import { ElMessage, ElMessageBox } from 'element-plus'
  3. import type Node from 'element-plus/es/components/tree/src/model/node'
  4. import Group from './components/Group.vue'
  5. import User from './components/User.vue'
  6. import { deleteGroupById, getGroupByList } from '@/api/system/groupApi'
  7. import { deleteUserById, getUserByPage, resetPassword, updateUserStatus } from '@/api/system/userApi'
  8. import { packageTreeData } from '@/utils/tool'
  9. import useUserStore from '@/store/modules/user'
  10. const userStore = useUserStore()
  11. const { pagination, getParams, onSizeChange, onCurrentChange } = usePagination()
  12. const userData = userStore.getUserData()
  13. interface TreeNode {
  14. label: string
  15. groupId: number
  16. children?: TreeNode[]
  17. }
  18. const state = reactive({
  19. loading: false,
  20. curGroupId: 0,
  21. groups: [] as TreeNode[],
  22. userList: [],
  23. search: {
  24. keywords: '',
  25. },
  26. })
  27. const groupTreeRef = ref()
  28. // 查询帐号列表
  29. const getUserData = async () => {
  30. const params = getParams()
  31. const curGroupId = state.curGroupId
  32. if (curGroupId > 0) {
  33. params.groupId = curGroupId
  34. params.keywords = state.search.keywords
  35. state.loading = true
  36. const { data } = await getUserByPage(params)
  37. state.loading = false
  38. state.userList = data.data
  39. state.loading = false
  40. }
  41. }
  42. // 查询部门数据
  43. const getGroupData = async () => {
  44. const { data } = await getGroupByList()
  45. state.groups = packageTreeData({
  46. data,
  47. id: 'groupId',
  48. })
  49. if (data && data.length > 0) {
  50. state.curGroupId = data[0].groupId
  51. await getUserData()
  52. }
  53. }
  54. onMounted(() => {
  55. getGroupData()
  56. })
  57. // 每页数量切换
  58. function sizeChange(size: number) {
  59. onSizeChange(size).then(() => getUserData())
  60. }
  61. // 当前页码切换(翻页)
  62. function currentChange(page = 1) {
  63. onCurrentChange(page).then(() => getUserData())
  64. }
  65. // 部门点击
  66. const onTreeNodeClick = (node: TreeNode) => {
  67. state.curGroupId = node.groupId
  68. getUserData()
  69. }
  70. const groupRef = ref()
  71. // 新增部门
  72. const onGroupAdd = (data: any) => {
  73. const { groupId, groupName } = data
  74. groupRef.value.showAddModel(groupId, groupName)
  75. }
  76. // 编辑部门
  77. const onGroupEdit = (data?: any) => {
  78. const { groupId } = data
  79. groupRef.value.showEditModel(groupId)
  80. }
  81. // 删除部门
  82. const onGroupDelete = (node: Node, data: any) => {
  83. ElMessageBox.confirm(`确认删除「${data.label}」吗?`, '确认信息').then(async () => {
  84. const { msg } = await deleteGroupById(data.groupId)
  85. ElMessage.success(msg)
  86. await getGroupData()
  87. }).catch(() => {})
  88. }
  89. const accountTableRef = ref()
  90. const userRef = ref()
  91. // 查询
  92. const onSearch = () => {
  93. getUserData()
  94. }
  95. // 新增账号
  96. const onUserAdd = () => {
  97. userRef.value.showAddModel()
  98. }
  99. // 修改账号
  100. const onUserEdit = (row: any) => {
  101. userRef.value.showEditModel(row.groupId, row.accountId)
  102. }
  103. // 密码重置
  104. const onPasswordReset = (data?: any) => {
  105. ElMessageBox.confirm('温馨提示:系统默认重置密码为 888888?', '确认').then(async () => {
  106. const { msg } = await resetPassword(data.accountId)
  107. ElMessage.success(msg)
  108. }).catch(() => {})
  109. }
  110. // 修改状态
  111. const onChangeStatus = async (status: number, row: any) => {
  112. const { msg } = await updateUserStatus(row.accountId, status)
  113. ElMessage.success(msg)
  114. }
  115. // 删除用户账号
  116. const onUserDelete = (row: any) => {
  117. ElMessageBox.confirm('温馨提示:系统默认重置密码为 888888?', '确认').then(async () => {
  118. const { msg } = await deleteUserById(row.accountId)
  119. ElMessage.success(msg)
  120. }).catch(() => {})
  121. }
  122. // "更多"处理
  123. const onCommand = (command: string, row: any) => {
  124. switch (command) {
  125. case 'GrantGroupAdd':
  126. window.console.log(row)
  127. break
  128. case 'GrantGroupEdit':
  129. break
  130. case 'GrantGroupDelete':
  131. break
  132. case 'ResetPwd':
  133. onPasswordReset(row)
  134. break
  135. case 'Permit':
  136. break
  137. }
  138. }
  139. const getUserList = () => {}
  140. const getGroupList = () => {}
  141. </script>
  142. <template>
  143. <div class="absolute-container">
  144. <page-header title="帐号管理" content="维护组织部门及账号信息" />
  145. <div class="page-main">
  146. <LayoutContainer left-side-width="300px" hide-left-side-toggle>
  147. <template #leftSide>
  148. <el-scrollbar class="tree">
  149. <ElTree ref="groupTreeRef" :data="state.groups" :current-node-key="state.curGroupId" default-expand-all @node-click="onTreeNodeClick">
  150. <template #default="{ node, data }">
  151. <div class="custom-tree-node">
  152. <div class="label" :title="node.label">
  153. <div class="text">
  154. {{ data.groupName }}
  155. </div>
  156. </div>
  157. <div class="actions">
  158. <el-button-group>
  159. <el-button type="primary" plain size="small" @click.stop="onGroupAdd(data)">
  160. <template #icon>
  161. <el-icon>
  162. <svg-icon name="i-ep:plus" />
  163. </el-icon>
  164. </template>
  165. </el-button>
  166. <el-button type="info" plain size="small" @click.stop="onGroupEdit(data)">
  167. <template #icon>
  168. <el-icon>
  169. <svg-icon name="i-ep:edit" />
  170. </el-icon>
  171. </template>
  172. </el-button>
  173. <el-button v-if="data.groupId !== userData.ocId" type="danger" plain size="small" @click.stop="onGroupDelete(node, data)">
  174. <template #icon>
  175. <el-icon>
  176. <svg-icon name="i-ep:delete" />
  177. </el-icon>
  178. </template>
  179. </el-button>
  180. </el-button-group>
  181. </div>
  182. </div>
  183. </template>
  184. </ElTree>
  185. </el-scrollbar>
  186. </template>
  187. <div class="container">
  188. <tool-bar>
  189. <template #left>
  190. <span />
  191. </template>
  192. <template #right>
  193. <el-input v-model="state.search.keywords" placeholder="请输入名称,支持模糊查询" style="padding-right: 10px;" clearable />
  194. <el-button type="primary" @click="onSearch">
  195. <template #icon>
  196. <el-icon>
  197. <svg-icon name="i-ep:search" />
  198. </el-icon>
  199. </template>
  200. </el-button>
  201. <el-button type="primary" @click="onUserAdd">
  202. 新增用户
  203. </el-button>
  204. </template>
  205. </tool-bar>
  206. <el-table ref="accountTableRef" v-loading="state.loading" class="list-table" :data="state.userList" border stripe highlight-current-row>
  207. <el-table-column type="index" align="center" label="序号" width="60" />
  208. <el-table-column align="center" header-align="center" label="头像" width="60">
  209. <template #default="{ row }">
  210. <el-avatar :size="30" :src="row.accountAvatar" />
  211. </template>
  212. </el-table-column>
  213. <el-table-column align="center" width="100" label="账号">
  214. <template #default="{ row }">
  215. <span>{{ row.accountName }}</span>
  216. </template>
  217. </el-table-column>
  218. <el-table-column align="center" width="90" label="姓名">
  219. <template #default="{ row }">
  220. <span>{{ row.accountRealName }}</span>
  221. </template>
  222. </el-table-column>
  223. <el-table-column align="center" width="80" label="工号">
  224. <template #default="{ row }">
  225. <span>{{ row.accountStaffNo }}</span>
  226. </template>
  227. </el-table-column>
  228. <el-table-column align="center" width="125" label="联系方式">
  229. <template #default="{ row }">
  230. <span>{{ row.accountPhone }}</span>
  231. </template>
  232. </el-table-column>
  233. <el-table-column align="center" label="所在部门">
  234. <template #default="{ row }">
  235. <span>{{ row.groupName }}</span>
  236. </template>
  237. </el-table-column>
  238. <el-table-column align="center" width="100" label="岗位">
  239. <template #default="{ row }">
  240. <span>{{ row.positionName }}</span>
  241. </template>
  242. </el-table-column>
  243. <el-table-column align="center" label="状态" width="80">
  244. <template #default="scope">
  245. <div v-if="scope.row.isFixed !== 1">
  246. <el-switch
  247. v-model="scope.row.status"
  248. :active-value="1"
  249. :inactive-value="2"
  250. :loading="scope.row.loading"
  251. inline-prompt
  252. active-text="启用"
  253. inactive-text="禁用"
  254. @change="(status) => onChangeStatus(scope.row.status, scope.row)"
  255. />
  256. </div>
  257. </template>
  258. </el-table-column>
  259. <el-table-column label="操作" header-align="center" align="center" width="220">
  260. <template #default="scope">
  261. <el-button size="small" type="primary" @click="onUserEdit(scope.row)">
  262. 修改
  263. </el-button>
  264. <el-button v-if="scope.row.isFixed !== 1" size="small" type="danger" @click="onUserDelete(scope.row)">
  265. 删除
  266. </el-button>
  267. <el-dropdown v-if="scope.row.isFixed !== 1" @command="onCommand($event, scope.row)">
  268. <el-button size="small">
  269. 更多
  270. <el-icon class="el-icon--right">
  271. <svg-icon name="i-ep:arrow-down" />
  272. </el-icon>
  273. </el-button>
  274. <template #dropdown="{ row }">
  275. <el-dropdown-menu>
  276. <template v-if="row && row.grantGroupId > 0">
  277. <el-dropdown-item command="GrantGroupEdit">
  278. 编辑授权
  279. </el-dropdown-item>
  280. <el-dropdown-item command="GrantGroupDelete">
  281. 解除授权
  282. </el-dropdown-item>
  283. </template>
  284. <template v-else>
  285. <el-dropdown-item command="GrantGroupAdd">
  286. 添加授权
  287. </el-dropdown-item>
  288. </template>
  289. <el-dropdown-item command="ResetPwd">
  290. 重置密码
  291. </el-dropdown-item>
  292. <el-dropdown-item command="Permit">
  293. 权限配置
  294. </el-dropdown-item>
  295. </el-dropdown-menu>
  296. </template>
  297. </el-dropdown>
  298. </template>
  299. </el-table-column>
  300. </el-table>
  301. <el-pagination :current-page="pagination.page" :total="pagination.total" :page-size="pagination.size" :page-sizes="pagination.sizes" :layout="pagination.layout" :hide-on-single-page="false" class="pagination" background @current-change="currentChange" @size-change="sizeChange" />
  302. </div>
  303. </LayoutContainer>
  304. </div>
  305. <Group ref="groupRef" @success="getGroupList" />
  306. <User ref="userRef" @success="getUserList" />
  307. </div>
  308. </template>
  309. <style lang="scss" scoped>
  310. .absolute-container {
  311. position: absolute;
  312. width: 100%;
  313. height: 100%;
  314. display: flex;
  315. flex-direction: column;
  316. .page-header {
  317. margin-bottom: 0;
  318. }
  319. .page-main {
  320. flex: 1;
  321. overflow: auto;
  322. display: flex;
  323. flex-direction: column;
  324. .flex-container {
  325. position: static;
  326. }
  327. }
  328. }
  329. .flex-container {
  330. :deep(.left-side) {
  331. display: flex;
  332. flex-direction: column;
  333. height: 100%;
  334. .btns {
  335. display: inline-flex;
  336. width: 100%;
  337. margin-bottom: var(--container-padding);
  338. .add {
  339. width: 100%;
  340. }
  341. }
  342. .tree {
  343. flex: 1;
  344. overflow-y: auto;
  345. .el-tree {
  346. .el-tree-node__content {
  347. height: 40px;
  348. }
  349. .is-current > .el-tree-node__content {
  350. background-color: var(--el-color-primary-light-9);
  351. }
  352. .custom-tree-node {
  353. flex: 1;
  354. position: relative;
  355. width: 0;
  356. height: 100%;
  357. display: flex;
  358. flex-direction: column;
  359. justify-content: center;
  360. .label {
  361. display: inline-flex;
  362. align-items: center;
  363. width: calc(100% - 10px);
  364. color: var(--el-text-color-primary);
  365. .text {
  366. @include text-overflow;
  367. }
  368. }
  369. &:hover {
  370. .actions {
  371. display: block;
  372. }
  373. }
  374. .actions {
  375. display: none;
  376. position: absolute;
  377. right: 10px;
  378. top: 50%;
  379. transform: translateY(-50%);
  380. .el-button {
  381. padding: 5px 8px;
  382. }
  383. }
  384. }
  385. }
  386. }
  387. }
  388. :deep(.main) {
  389. .main-container {
  390. width: 100%;
  391. height: 100%;
  392. }
  393. }
  394. .empty {
  395. flex: 1;
  396. display: flex;
  397. align-items: center;
  398. justify-content: center;
  399. font-size: 32px;
  400. color: var(--el-text-color-placeholder);
  401. }
  402. }
  403. </style>