user-select.vue 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. <template>
  2. <el-dialog :title="title" :visible.sync="visible" width="600px" :close-on-click-modal="false">
  3. <div class="content">
  4. <div class="left">
  5. <el-scrollbar>
  6. <el-tree ref="tree" :data="treeItems" :props="navProps" node-key="_id" @node-click="handleNavClick" :highlight-current="true">
  7. <span class="custom-tree-node" slot-scope="{ node, data }">
  8. <span>
  9. <i class="prefix naf-icons naf-icon-user1" v-if="data.userid" />
  10. <i class="prefix naf-icons naf-icon-folder1" v-else />
  11. {{ node.label }}
  12. </span>
  13. <span>
  14. <i class="suffix naf-icons naf-icon-ok" v-show="inSelected(data)" />
  15. </span>
  16. </span>
  17. </el-tree>
  18. </el-scrollbar>
  19. </div>
  20. <div class="right">
  21. <el-scrollbar>
  22. <el-tree ref="selected" :data="selected" :props="navProps" node-key="id" :highlight-current="true">
  23. <span class="custom-tree-node" slot-scope="{ node, data }">
  24. <span>
  25. <i class="prefix naf-icons naf-icon-user1" v-if="data.userid" />
  26. <i class="prefix naf-icons naf-icon-folder1" v-else />
  27. {{ node.label }}
  28. </span>
  29. <span style="float: right">
  30. <i class="suffix naf-icons naf-icon-close" />
  31. </span>
  32. </span>
  33. </el-tree>
  34. </el-scrollbar>
  35. </div>
  36. </div>
  37. <div slot="footer" class="dialog-footer">
  38. <el-button @click="$emit('cancel')" :size="options.size">取 消</el-button>
  39. <el-button type="primary" @click="$emit('ok', selected)" :size="options.size">确 定</el-button>
  40. </div>
  41. </el-dialog>
  42. </template>
  43. <script>
  44. import { mapState } from 'vuex';
  45. import _ from 'lodash';
  46. export default {
  47. props: {
  48. options: {
  49. type: Object,
  50. default: () => ({ size: 'small' }),
  51. } /* form options */,
  52. title: String,
  53. visible: { type: Boolean, default: true },
  54. },
  55. data() {
  56. return {
  57. navProps: {
  58. children: 'children',
  59. label: 'name',
  60. },
  61. selected: [],
  62. };
  63. },
  64. methods: {
  65. handleNavClick(data) {
  66. // this.$emit('selected', data);
  67. const idx = this.selected.findIndex(p => (_.isNumber(data.id) && p.id === data.id) || (_.isString(data.userid) && p.userid === data.userid));
  68. console.log('idx:', idx);
  69. if (idx === -1) {
  70. this.selected.push(_.omit(data, ['children']));
  71. } else {
  72. this.selected.splice(idx, 1);
  73. }
  74. },
  75. inSelected(data) {
  76. return this.selected.some(p => (_.isNumber(data.id) && p.id === data.id) || (_.isString(data.userid) && p.userid === data.userid));
  77. },
  78. },
  79. computed: {
  80. ...mapState({
  81. deptItems: state => state.system.dept.items,
  82. userItems: state => state.system.user.items,
  83. }),
  84. treeItems() {
  85. if (this.navItems) return this.navItems;
  86. const items = this.deptItems || [];
  87. const root = items.filter(a => !items.some(b => b.id === a.parentid));
  88. const fetchChildren = item => {
  89. const children = items.filter(p => p.parentid === item.id).map(p => fetchChildren(p));
  90. const users = this.userItems.filter(p => p.department && p.department.includes(item.id));
  91. return { ...item, children: [...children, ...users] };
  92. };
  93. const rootUsers = this.userItems.filter(p => p.department && p.department.includes(0));
  94. return root.map(p => fetchChildren(p)).concat(rootUsers);
  95. },
  96. },
  97. };
  98. </script>
  99. <style lang="less" scoped>
  100. .nav-tree {
  101. /deep/ .el-tree-node.is-current > .el-tree-node__content {
  102. background-color: #409eff;
  103. color: white;
  104. .naf-icon-dian {
  105. display: inline;
  106. color: white;
  107. }
  108. }
  109. /deep/ .naf-icon-dian {
  110. display: none;
  111. }
  112. /deep/ .el-tree-node__content:hover .naf-icon-dian {
  113. display: inline;
  114. }
  115. }
  116. .content {
  117. display: flex;
  118. flex-direction: row;
  119. height: 340px;
  120. }
  121. .left {
  122. flex: 1;
  123. }
  124. .right {
  125. width: 240px;
  126. }
  127. .naf-icons.prefix {
  128. color: grey;
  129. }
  130. .naf-icons.suffix {
  131. color: lightgrey;
  132. }
  133. .custom-tree-node {
  134. flex: 1;
  135. display: flex;
  136. align-items: center;
  137. justify-content: space-between;
  138. font-size: 14px;
  139. padding-right: 8px;
  140. }
  141. .el-scrollbar {
  142. height: 100%;
  143. }
  144. </style>