index.vue 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. <template>
  2. <el-dialog v-model="visible" title="选择消息接收人" width="780px" append-to-body @close="closeDialog">
  3. <div class="container">
  4. <div class="left-content">
  5. <div>人员选择列表</div>
  6. <el-input v-model="filterText" placeholder="输入关键字进行搜索" class="input" />
  7. <el-tree
  8. ref="treeRef"
  9. class="filter-tree"
  10. :data="treeData"
  11. show-checkbox
  12. :props="defaultProps"
  13. :filter-node-method="filterNode"
  14. :default-checked-keys="defaultCheckData"
  15. node-key="uuid"
  16. @check-change="handleCheckChange"
  17. >
  18. <template #default="{ node, data }">
  19. <div class="custom-tree-node">
  20. <img class="icon" :src="getImage(data)" alt="" />
  21. <span>{{ node.label }}</span>
  22. </div>
  23. </template>
  24. </el-tree>
  25. </div>
  26. <div class="right-content">
  27. <div style="display: flex">
  28. 已选择:
  29. <div v-show="checkData.length > 0">{{ checkData.length }}人</div>
  30. </div>
  31. <div class="select-box">
  32. <div v-for="(item, index) in checkData" :key="index" class="select-item">
  33. <div class="item-left">
  34. <img class="icon" :src="getImage(item)" alt="" />
  35. {{ item.label }}
  36. </div>
  37. <i class="icon-close" @click="uncheckNodeById(item.id, index)" />
  38. </div>
  39. </div>
  40. </div>
  41. </div>
  42. <template #footer>
  43. <div class="dialog-footer">
  44. <el-button @click="closeDialog">取 消</el-button>
  45. <el-button type="primary" @click="confirm">确 定</el-button>
  46. </div>
  47. </template>
  48. </el-dialog>
  49. </template>
  50. <script setup name="Contact">
  51. import { deepClone } from '@/utils/index';
  52. import userImg from '@/assets/images/user.png';
  53. import fileImg from '@/assets/images/file.png';
  54. import { getPhoneList} from '@/api/informationissue/informationissue';
  55. const props = defineProps({
  56. modelValue: Boolean,
  57. treeData: Array,
  58. defaultCheckData: Array
  59. });
  60. const emits = defineEmits(['update:modelValue', 'confirm']);
  61. let visible = ref(false);
  62. const treeRef = ref();
  63. let filterText = ref('');
  64. let defaultProps = reactive({
  65. children: 'children',
  66. label: 'label'
  67. });
  68. let checkData = ref([]);
  69. watch(filterText, (val) => {
  70. treeRef.value.filter(val);
  71. });
  72. const initData = () => {
  73. if (!!props.defaultCheckData) {
  74. props.defaultCheckData.forEach((item) => {
  75. treeRef.value.setChecked(item.uuid, true, true);
  76. });
  77. checkData.value = deepClone(props.defaultCheckData);
  78. }
  79. };
  80. watch(
  81. () => props.modelValue,
  82. () => {
  83. if (!!props.modelValue) {
  84. initData();
  85. }
  86. visible.value = props.modelValue;
  87. },
  88. {
  89. immediate: true
  90. }
  91. );
  92. const filterNode = (value, data) => {
  93. if (!value) return true;
  94. return data.label.indexOf(value) !== -1;
  95. };
  96. const getImage = (item) => {
  97. if (item.img) {
  98. return item.img;
  99. } else if (item.deptType) {
  100. return fileImg;
  101. } else {
  102. return userImg;
  103. }
  104. };
  105. const handleCheckChange = () => {
  106. const data = [];
  107. const treeData = treeRef.value.getCheckedNodes(false, false);
  108. treeData.forEach((item) => {
  109. if (!item.deptType) {
  110. if (!data.some((obj) => obj.id === item.id)) {
  111. data.push(item);
  112. }
  113. }
  114. });
  115. checkData.value = data;
  116. };
  117. const uncheckNodeById = (nodeId, index) => {
  118. const nodes = treeRef.value.getCheckedNodes();
  119. checkData.value.splice(index, 1);
  120. nodes.forEach((item) => {
  121. if (item.id === nodeId) {
  122. treeRef.value.setChecked(item.uuid, false, true);
  123. }
  124. });
  125. };
  126. const closeDialog = () => {
  127. emits('update:modelValue', false);
  128. treeRef.value.setCheckedKeys([], false);
  129. checkData.value = [];
  130. };
  131. const confirm = () => {
  132. const data = deepClone(checkData.value);
  133. closeDialog();
  134. emits('confirm', data);
  135. };
  136. </script>
  137. <style lang="scss" scoped>
  138. .container {
  139. display: flex;
  140. .left-content {
  141. flex: 1;
  142. border: 1px solid #dcdfe6;
  143. border-radius: 5px;
  144. height: 400px;
  145. overflow-y: auto;
  146. padding: 10px;
  147. .input {
  148. margin: 15px 0 5px;
  149. }
  150. .filter-tree {
  151. :deep(.el-tree-node__content) {
  152. height: 45px;
  153. }
  154. .custom-tree-node {
  155. display: flex;
  156. width: 100%;
  157. }
  158. }
  159. }
  160. .right-content {
  161. margin-left: 20px;
  162. width: 300px;
  163. flex-shrink: 0;
  164. border: 1px solid #dcdfe6;
  165. border-radius: 5px;
  166. height: 400px;
  167. overflow-y: auto;
  168. padding: 10px;
  169. .select-box {
  170. .select-item {
  171. width: 100%;
  172. display: flex;
  173. justify-content: space-between;
  174. align-items: center;
  175. padding: 10px 0;
  176. .item-left {
  177. display: flex;
  178. align-items: center;
  179. }
  180. .icon-close {
  181. width: 12px;
  182. height: 12px;
  183. background: url('@/assets/images/close2.png') no-repeat;
  184. background-size: 100% 100%;
  185. cursor: pointer;
  186. &:hover {
  187. background: url('@/assets/images/close3.png') no-repeat;
  188. background-size: 100% 100%;
  189. }
  190. }
  191. }
  192. }
  193. }
  194. }
  195. .icon {
  196. width: 20px;
  197. height: 20px;
  198. margin-right: 8px;
  199. object-fit: cover;
  200. }
  201. </style>