SelectUserDialog.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439
  1. <template>
  2. <el-dialog
  3. class="select-user-dialog"
  4. :visible.sync="modalIsShow"
  5. :title="title"
  6. top="10px"
  7. width="900px"
  8. :close-on-click-modal="false"
  9. :close-on-press-escape="false"
  10. append-to-body
  11. @opened="visibleChange"
  12. >
  13. <el-row type="flex" :gutter="10">
  14. <el-col :span="12">
  15. <div class="user-search">
  16. <el-input
  17. v-model.trim="filterLabel"
  18. placeholder="请输入角色名称"
  19. clearable
  20. size="mini"
  21. prefix-icon="el-icon-search"
  22. @input="labelChange"
  23. ></el-input>
  24. </div>
  25. <div class="user-types">
  26. <div
  27. :class="['user-type', { 'is-active': isOrgTab }]"
  28. @click="switchUserType('org')"
  29. >
  30. 组织架构
  31. </div>
  32. <div
  33. :class="['user-type', { 'is-active': !isOrgTab }]"
  34. @click="switchUserType('role')"
  35. >
  36. 角色
  37. </div>
  38. </div>
  39. <div class="user-tree">
  40. <el-tree
  41. ref="UserTree"
  42. :data="userTree"
  43. node-key="id"
  44. :default-checked-keys="selectedUserIds"
  45. :props="defaultProps"
  46. :default-expand-all="!isOrgTab"
  47. :default-expanded-keys="isOrgTab ? userOrgKeys : []"
  48. >
  49. <span class="custom-tree-node" slot-scope="{ node, data }">
  50. <el-checkbox
  51. v-if="data.isUser"
  52. v-model="node.checked"
  53. @change="(checked) => userChange(checked, data)"
  54. >
  55. {{ node.label }}({{ data.loginName }})
  56. </el-checkbox>
  57. <span v-else>{{ node.label }}</span>
  58. <el-checkbox
  59. v-if="!data.isUser && canSelectAll && data.children.length"
  60. v-model="data.selected"
  61. @change="(checked) => selectNodeAll(checked, data)"
  62. ></el-checkbox>
  63. </span>
  64. </el-tree>
  65. </div>
  66. </el-col>
  67. <el-col :span="12">
  68. <div class="user-part-title">已选范围</div>
  69. <div class="user-list">
  70. <div v-for="user in selectedUsers" :key="user.id" class="user-item">
  71. <p class="user-cont">
  72. <span>{{ user.label }}</span>
  73. </p>
  74. <el-button
  75. class="user-delete"
  76. type="text"
  77. icon="el-icon-remove"
  78. @click="toDeleteUser(user)"
  79. ></el-button>
  80. </div>
  81. </div>
  82. </el-col>
  83. </el-row>
  84. <p v-show="!selectValid" class="tips-info tips-error">
  85. 选择用户数不能超过{{ userLimitCount }}
  86. </p>
  87. <div slot="footer">
  88. <el-button type="primary" :disabled="!selectValid" @click="submit"
  89. >确认</el-button
  90. >
  91. <el-button @click="cancel">取消</el-button>
  92. </div>
  93. </el-dialog>
  94. </template>
  95. <script>
  96. import { organizationList } from "../api";
  97. export default {
  98. name: "select-user-dialog",
  99. props: {
  100. users: {
  101. type: Array,
  102. default() {
  103. return [];
  104. },
  105. },
  106. userLimitCount: {
  107. type: Number,
  108. default: 5,
  109. },
  110. canSelectAll: {
  111. type: Boolean,
  112. default: false,
  113. },
  114. filterRoles: {
  115. type: Array,
  116. default() {
  117. // id 数组
  118. return [];
  119. },
  120. },
  121. title: {
  122. type: String,
  123. default: "添加用户",
  124. },
  125. },
  126. data() {
  127. return {
  128. modalIsShow: false,
  129. filterLabel: "",
  130. userType: "org",
  131. orgData: [],
  132. orgUsers: [],
  133. roleUsers: [],
  134. userTree: [],
  135. userList: [],
  136. selectedUsers: [],
  137. selectedRoleUserIds: [],
  138. selectedUserIds: [],
  139. selectValid: true,
  140. userOrgKeys: [this.$ls.get("orgId")],
  141. defaultProps: {
  142. children: "children",
  143. label: "label",
  144. },
  145. };
  146. },
  147. computed: {
  148. isOrgTab() {
  149. return this.userType === "org";
  150. },
  151. },
  152. methods: {
  153. async getOrgData() {
  154. const data = await organizationList();
  155. this.orgData = data;
  156. },
  157. parseUserData(data) {
  158. let roleUserMap = {};
  159. const parseUser = (list) => {
  160. return list.map((item) => {
  161. // org
  162. let nitem = {
  163. id: item.id,
  164. label: item.name,
  165. isUser: false,
  166. selected: false,
  167. children: [],
  168. };
  169. if (item["children"] && item["children"].length) {
  170. nitem.children = [...nitem.children, ...parseUser(item.children)];
  171. }
  172. // user
  173. if (item["sysUserList"] && item["sysUserList"].length) {
  174. let sysUserList = item.sysUserList;
  175. // 过滤符合需求角色的用户
  176. if (this.filterRoles.length) {
  177. sysUserList = sysUserList.filter(
  178. (user) =>
  179. user.roleResultList &&
  180. user.roleResultList.some((role) =>
  181. this.filterRoles.includes(role.roleId)
  182. )
  183. );
  184. }
  185. const users = sysUserList.map((user) => {
  186. const nuser = {
  187. id: user.id,
  188. userId: user.id,
  189. label: user.realName,
  190. name: user.realName,
  191. loginName: user.loginName,
  192. orgName: item.name,
  193. selected: false,
  194. isUser: true,
  195. };
  196. if (user.roleResultList && user.roleResultList.length) {
  197. user.roleResultList.forEach((urole) => {
  198. if (
  199. this.filterRoles.length &&
  200. !this.filterRoles.includes(urole.roleId)
  201. )
  202. return;
  203. if (!roleUserMap[urole.roleId]) {
  204. roleUserMap[urole.roleId] = {
  205. id: urole.roleId,
  206. label: urole.roleName,
  207. selected: false,
  208. isUser: false,
  209. children: [],
  210. };
  211. }
  212. let ruser = { ...nuser };
  213. ruser.id = `${ruser.id}_${this.$randomCode()}`;
  214. ruser.label = `${ruser.name}(${ruser.orgName})`;
  215. roleUserMap[urole.roleId].children.push(ruser);
  216. });
  217. }
  218. return nuser;
  219. });
  220. nitem.children = [...nitem.children, ...users];
  221. }
  222. return nitem;
  223. });
  224. };
  225. this.orgUsers = parseUser(data);
  226. this.roleUsers = Object.values(roleUserMap);
  227. this.userTree = this.orgUsers;
  228. this.getUserList();
  229. },
  230. getUserList() {
  231. let userList = [];
  232. const fetchUser = (users) => {
  233. users.forEach((item) => {
  234. if (item["children"] && item["children"].length) {
  235. fetchUser(item.children);
  236. } else {
  237. if (item.isUser) {
  238. let nitem = { ...item };
  239. nitem.label = `${nitem.name}(${nitem.orgName})`;
  240. userList.push(nitem);
  241. }
  242. }
  243. });
  244. };
  245. fetchUser(this.orgUsers);
  246. this.userList = userList;
  247. },
  248. labelChange() {
  249. if (!this.filterLabel) {
  250. this.switchUserType(this.userType);
  251. } else {
  252. const escapeRegexpString = (value = "") =>
  253. String(value).replace(/[|\\{}()[\]^$+*?.]/g, "\\$&");
  254. const reg = new RegExp(escapeRegexpString(this.filterLabel), "i");
  255. this.userTree = this.userList.filter((item) => reg.test(item.name));
  256. this.$refs.UserTree.setCheckedKeys(this.selectedUserIds);
  257. }
  258. },
  259. checkValid() {
  260. this.selectValid =
  261. !this.userLimitCount ||
  262. this.selectedUsers.length <= this.userLimitCount;
  263. },
  264. async visibleChange() {
  265. if (!this.orgUsers.length) await this.getOrgData();
  266. this.parseUserData(this.orgData);
  267. this.filterLabel = "";
  268. this.userType = "org";
  269. this.userTree = this.orgUsers;
  270. this.selectedUsers = this.users.map((user) => {
  271. const luser = this.userList.find((item) => item.id === user.id);
  272. return {
  273. id: user.id,
  274. name: user.name,
  275. label: `${user.name}(${luser.orgName})`,
  276. };
  277. });
  278. this.selectedUserIds = this.users.map((item) => item.id);
  279. this.$refs.UserTree.setCheckedKeys(this.selectedUserIds);
  280. this.checkValid();
  281. },
  282. cancel() {
  283. this.modalIsShow = false;
  284. },
  285. open() {
  286. this.modalIsShow = true;
  287. },
  288. selectNodeAll(checked, data) {
  289. let userIds = [];
  290. const getUserIds = (list) => {
  291. list.forEach((item) => {
  292. item.selected = checked;
  293. if (item.children && item.children.length) {
  294. getUserIds(item.children);
  295. } else {
  296. if (item.isUser) userIds.push(item.userId);
  297. }
  298. });
  299. };
  300. getUserIds(data.children);
  301. userIds.forEach((userId) => {
  302. const userPos = this.selectedUserIds.indexOf(userId);
  303. const includeUser = userPos !== -1;
  304. if (checked) {
  305. if (!includeUser) this.selectedUserIds.push(userId);
  306. } else {
  307. if (includeUser) {
  308. this.selectedUserIds.splice(userPos, 1);
  309. }
  310. }
  311. });
  312. if (this.userType === "role") {
  313. this.updateSelectRoleUserIds();
  314. } else {
  315. this.$refs.UserTree.setCheckedKeys(this.selectedUserIds);
  316. }
  317. this.updateSelectedUsersFromUserIds();
  318. },
  319. switchUserType(type) {
  320. this.userType = type;
  321. this.userTree = type === "org" ? this.orgUsers : this.roleUsers;
  322. if (type === "role") {
  323. this.updateSelectRoleUserIds();
  324. }
  325. },
  326. updateSelectRoleUserIds() {
  327. let selectedRoleUserIds = [];
  328. this.roleUsers.forEach((role) => {
  329. role.children.forEach((user) => {
  330. if (this.selectedUserIds.includes(user.userId))
  331. selectedRoleUserIds.push(user.id);
  332. });
  333. });
  334. this.selectedRoleUserIds = selectedRoleUserIds;
  335. this.$refs.UserTree.setCheckedKeys(selectedRoleUserIds);
  336. },
  337. updateSelectedUsersFromUserIds() {
  338. this.selectedUsers = this.userList.filter((user) =>
  339. this.selectedUserIds.includes(user.id)
  340. );
  341. },
  342. userChange(checked, curUser) {
  343. if (this.filterLabel) {
  344. let prevSelectUserIds = this.selectedUsers.map((item) => item.id);
  345. const prevUserListSelectUserIds = this.userTree
  346. .filter((user) => prevSelectUserIds.includes(user.id))
  347. .map((user) => user.id);
  348. const selectedUsers = this.$refs.UserTree.getCheckedNodes(true);
  349. const sIds = selectedUsers.map((user) => user.id);
  350. const prevDeletedUserIds = prevUserListSelectUserIds.filter(
  351. (uid) => !sIds.includes(uid)
  352. );
  353. this.selectedUsers = this.selectedUsers.filter(
  354. (user) => !prevDeletedUserIds.includes(user.id)
  355. );
  356. prevSelectUserIds = this.selectedUsers.map((item) => item.id);
  357. selectedUsers.forEach((user) => {
  358. if (prevSelectUserIds.includes(user.id)) return;
  359. const nuser = {
  360. id: user.id,
  361. name: user.name,
  362. label: `${user.name}(${user.orgName})`,
  363. };
  364. this.selectedUsers.push(nuser);
  365. });
  366. this.selectedUserIds = this.selectedUsers.map((item) => item.id);
  367. this.checkValid();
  368. return;
  369. }
  370. if (this.userType === "org") {
  371. const selectedUsers = this.$refs.UserTree.getCheckedNodes(true);
  372. this.selectedUsers = selectedUsers.map((user) => {
  373. const nuser = {
  374. id: user.id,
  375. name: user.name,
  376. label: `${user.name}(${user.orgName})`,
  377. };
  378. return nuser;
  379. });
  380. this.selectedUserIds = this.selectedUsers.map((item) => item.id);
  381. this.checkValid();
  382. return;
  383. }
  384. if (this.userType === "role") {
  385. if (checked) {
  386. if (!this.selectedUserIds.includes(curUser.userId))
  387. this.selectedUserIds.push(curUser.userId);
  388. } else {
  389. this.selectedUserIds = this.selectedUserIds.filter(
  390. (userid) => userid !== curUser.userId
  391. );
  392. }
  393. this.updateSelectRoleUserIds();
  394. this.updateSelectedUsersFromUserIds();
  395. this.checkValid();
  396. }
  397. },
  398. toDeleteUser(user) {
  399. const pos = this.selectedUsers.findIndex((item) => item.id === user.id);
  400. this.selectedUsers.splice(pos, 1);
  401. this.selectedUserIds = this.selectedUsers.map((item) => item.id);
  402. if (this.userType === "role") {
  403. this.updateSelectRoleUserIds();
  404. } else {
  405. this.$refs.UserTree.setCheckedKeys(this.selectedUserIds);
  406. }
  407. this.checkValid();
  408. },
  409. submit() {
  410. if (!this.selectValid) return;
  411. this.$emit(
  412. "modified",
  413. this.selectedUsers.map((item) => {
  414. return {
  415. id: item.id,
  416. name: item.name,
  417. };
  418. })
  419. );
  420. this.cancel();
  421. },
  422. },
  423. };
  424. </script>