index.vue 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. <template>
  2. <el-container class="is-vertical">
  3. <sc-page-header @add="table_add"></sc-page-header>
  4. <el-container class="user-container">
  5. <el-aside width="310px">
  6. <el-header>
  7. <el-input v-model="filterText" clearable placeholder="输入关键字进行过滤"></el-input>
  8. </el-header>
  9. <el-main class="nopadding">
  10. <el-scrollbar>
  11. <el-tree ref="treeRef" node-key="id" :data="deptTree" :expand-on-click-node="false" highlight-current check-strictly :filter-node-method="filterNode" @node-click="data => nodeClick(data)">
  12. <template #default="{ data }">
  13. <vxe-text-ellipsis :id="data.id" :title="data.name" class="custom-tree-node" :content="data.name"></vxe-text-ellipsis>
  14. </template>
  15. </el-tree>
  16. </el-scrollbar>
  17. </el-main>
  18. </el-aside>
  19. <scTable ref="xGridTable" :apiObj="$API.auth.user" :formConfig="formConfig" :paramsColums="paramsColums" :columns="columns">
  20. <template #action="{ row }">
  21. <el-button type="primary" link @click="password_rest(row)">
  22. <template #icon><sc-iconify icon="material-symbols:arrow-split"></sc-iconify></template>重置密码
  23. </el-button>
  24. <el-button type="primary" link @click="table_edit(row)">
  25. <template #icon><sc-iconify icon="ant-design:edit-outlined"></sc-iconify></template>修改
  26. </el-button>
  27. <el-button type="primary" link @click="table_del(row)">
  28. <template #icon><sc-iconify icon="ant-design:delete-outlined"></sc-iconify></template>删除
  29. </el-button>
  30. </template>
  31. </scTable>
  32. </el-container>
  33. </el-container>
  34. <user-detail v-if="dialog" ref="userRef" @success="refreshTable" @closed="dialog = false"></user-detail>
  35. </template>
  36. <script setup>
  37. import XEUtils from "xe-utils";
  38. import API from "@/api";
  39. import TOOL from "@/utils/tool";
  40. import { mapFormItemInput, mapFormItemTenant } from "@/components/scTable/helper";
  41. import userDetail from "./detail";
  42. import store from "@/store";
  43. watch(() => store.state.tenant.tenantId, () => (fetchDept(), refreshTable()));
  44. const filterText = ref("");
  45. const deptTree = ref([]);
  46. const treeRef = ref();
  47. watch(() => filterText.value, value => treeRef.value.filter(value));
  48. const filterNode = (value, data) => {
  49. if (!value) return true;
  50. return data.name.includes(value);
  51. }
  52. const nodeClick = data => {
  53. if (XEUtils.get(formConfig.data, "deptId", null) === data.id) {
  54. treeRef.value.setCurrentKey();
  55. XEUtils.set(formConfig.data, "deptId", null);
  56. } else XEUtils.set(formConfig.data, "deptId", data.id);
  57. refreshTable();
  58. }
  59. const formConfig = reactive({
  60. data: {},
  61. items: [
  62. mapFormItemTenant({ events: { change: data => XEUtils.merge(formConfig.data, data) } }),
  63. mapFormItemInput("usernameLike", "用户名"),
  64. mapFormItemInput("nickNameLike", "用户昵称"),
  65. mapFormItemInput("phoneLike", "手机号")
  66. ]
  67. });
  68. const paramsColums = reactive([
  69. { column: "orderBy", defaultValue: "id_desc" },
  70. { column: "tenantId" },
  71. { column: "deptId" },
  72. { column: "usernameLike" },
  73. { column: "nickNameLike" },
  74. { column: "phoneLike" }
  75. ]);
  76. const columns = reactive([
  77. { type: "seq", width: 60 },
  78. { visible: computed(() => store.state.tenant.tenantId === "0"), type: "html", field: "tenant.name", title: "所属租户", minWidth: 200, sortable: true },
  79. { type: "html", field: "username", title: "用户名", minWidth: 160, sortable: true },
  80. { type: "html", field: "nickName", title: "用户昵称", minWidth: 160, sortable: true },
  81. { type: "html", field: "roleNames", title: "角色", minWidth: 160, sortable: true, formatter: ({ cellValue, row }) => cellValue || XEUtils.map(row.roleList, item => item.name).join() },
  82. { type: "html", field: "dept.name", title: "所属部门", minWidth: 160, sortable: true },
  83. { type: "html", field: "gender", title: "性别", minWidth: 100, sortable: true },
  84. { type: "html", field: "phone", title: "手机号", minWidth: 120, sortable: true },
  85. { type: "html", field: "email", title: "邮箱", minWidth: 160, sortable: true },
  86. { visible: false, type: "html", field: "idcard", title: "身份证号", minWidth: 160, sortable: true, formatter: ({ cellValue, row }) => cellValue || XEUtils.get(XEUtils.toStringJSON(row.features), "idcard") },
  87. { title: "操作", fixed: "right", width: 220, slots: { default: "action" } }
  88. ]);
  89. // 显示隐藏 筛选表单
  90. const xGridTable = ref();
  91. const refreshTable = (mode = "add") => (xGridTable.value.searchData(mode), xGridTable.value.reloadColumn(columns));
  92. const userRef = ref();
  93. const dialog = ref(false);
  94. const table_add = () => {
  95. dialog.value = true;
  96. nextTick(() => userRef.value?.open());
  97. }
  98. const table_edit = row => {
  99. dialog.value = true;
  100. nextTick(() => userRef.value?.setData(row));
  101. }
  102. const table_del = ({ id }) => {
  103. ElMessageBox.confirm("是否确认删除该用户?", "删除警告", {
  104. type: "warning",
  105. confirmButtonText: "确定",
  106. cancelButtonText: "取消"
  107. }).then(() => {
  108. API.auth.user.del(({ id })).then(() => {
  109. ElMessage.success("操作成功");
  110. refreshTable();
  111. });
  112. }).catch(() => {});
  113. }
  114. const password_rest = ({ id, username }) => {
  115. ElMessageBox.confirm(`是否确认重置"${username}"密码?`, "重置密码", {
  116. type: "warning",
  117. confirmButtonText: "确定",
  118. cancelButtonText: "取消"
  119. }).then(() => {
  120. API.auth.user.resetPass(({ id })).then(() => {
  121. ElNotification.success({
  122. title: "提示",
  123. message: `密码已重置,密码为:123456`,
  124. duration: 1500
  125. });
  126. });
  127. }).catch(() => {});
  128. }
  129. const fetchDept = () => API.system.dept.get({ orderBy: "deptSort_asc" }).then(res => deptTree.value = XEUtils.toArrayTree(res, { parentKey: "pid" })).catch(() => deptTree.value = []);
  130. fetchDept();
  131. </script>
  132. <style lang="scss" scoped>
  133. .user-container {border-top: 1px solid var(--el-border-color-light);}
  134. .user-container .el-aside {display: flex;flex-direction: column;}
  135. .user-container .el-aside .el-main {padding-top: 15px;padding-left: 15px;}
  136. .user-container .el-aside + .el-main {padding-top: 15px;}
  137. @media (max-width: 992px) {
  138. .aminui-main > .el-container > .el-container.user-container {display: block;margin-top: 0;border: none;}
  139. .user-container .el-aside {width: 100%;}
  140. .user-container .el-aside .el-main {padding-bottom: 15px;}
  141. .user-container .el-aside + .el-main {margin-top: 15px;}
  142. }
  143. </style>