index.vue 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. <template>
  2. <div class="transfer" :class="[isH5 ? 'transfer-h5' : '']">
  3. <header class="transfer-h5-header" v-if="isH5">
  4. <i class="icon icon-back" @click="cancel"></i>
  5. <span class="title">{{ title }}</span>
  6. </header>
  7. <main class="main">
  8. <div class="left">
  9. <header v-if="isSearch">
  10. <input
  11. type="text"
  12. @keyup.enter="handleInput"
  13. :placeholder="$t('component.请输入userID')"
  14. enterkeyhint="search"
  15. />
  16. </header>
  17. <main>
  18. <ul class="list">
  19. <li class="list-item" @click="selectedAll" v-if="optional.length > 1 && !isRadio">
  20. <i
  21. class="icon"
  22. :class="[selectedList.length === optional.length ? 'icon-selected' : 'icon-unselected']"
  23. ></i>
  24. <span class="all">{{ $t('component.全选') }}</span>
  25. </li>
  26. <li class="list-item" v-for="(item, index) in list" :key="index" @click="selected(item)">
  27. <i
  28. class="icon"
  29. :class="[
  30. item?.isDisabled && 'disabled',
  31. selectedList.indexOf(item) > -1 ? 'icon-selected' : 'icon-unselected',
  32. ]"
  33. ></i>
  34. <template v-if="!isCustomItem">
  35. <img
  36. class="avatar"
  37. :src="item?.avatar || 'https://news-info.ks3-cn-beijing.ksyuncs.com/07/1690787574969.png'"
  38. onerror="this.src='https://news-info.ks3-cn-beijing.ksyuncs.com/07/1690787574969.png'"
  39. />
  40. <span class="name">{{ item?.nick || item?.userID }}</span>
  41. <span v-if="item?.isDisabled">({{ $t('component.已在群聊中') }})</span>
  42. </template>
  43. <template v-else>
  44. <slot name="left" :data="item" />
  45. </template>
  46. </li>
  47. </ul>
  48. </main>
  49. </div>
  50. <div class="right">
  51. <header v-if="!isH5">{{ title }}</header>
  52. <ul class="list" v-show="resultShow">
  53. <p v-if="selectedList.length > 0 && !isH5">
  54. {{ $t('component.已选中') }}{{ selectedList.length }}{{ $t('component.人') }}
  55. </p>
  56. <li class="list-item space-between" v-for="(item, index) in selectedList" :key="index">
  57. <aside>
  58. <template v-if="!isCustomItem">
  59. <img
  60. class="avatar"
  61. :src="item?.avatar || 'https://news-info.ks3-cn-beijing.ksyuncs.com/07/1690787574969.png'"
  62. onerror="this.src='https://news-info.ks3-cn-beijing.ksyuncs.com/07/1690787574969.png'"
  63. />
  64. <span v-if="!isH5">{{ item.nick || item.userID }}</span>
  65. </template>
  66. <template v-else>
  67. <slot name="right" :data="item" />
  68. </template>
  69. </aside>
  70. <i class="icon icon-cancel" @click="selected(item)" v-if="!isH5"></i>
  71. </li>
  72. </ul>
  73. <footer>
  74. <button class="btn btn-cancel" @click="cancel">{{ $t('component.取消') }}</button>
  75. <button v-if="selectedList.length > 0" class="btn" @click="submit">{{ $t('component.完成') }}</button>
  76. <button v-else class="btn btn-no" @click="submit">{{ $t('component.完成') }}</button>
  77. </footer>
  78. </div>
  79. </main>
  80. </div>
  81. </template>
  82. <script lang="ts">
  83. import { defineComponent, reactive, watchEffect, toRefs, computed } from 'vue';
  84. export default defineComponent({
  85. props: {
  86. list: {
  87. type: Array,
  88. default: () => [],
  89. },
  90. selectedList: {
  91. type: Array,
  92. default: () => [],
  93. },
  94. isSearch: {
  95. type: Boolean,
  96. default: () => true,
  97. },
  98. isRadio: {
  99. type: Boolean,
  100. default: () => false,
  101. },
  102. isCustomItem: {
  103. type: Boolean,
  104. default: () => false,
  105. },
  106. title: {
  107. type: String,
  108. default: () => '',
  109. },
  110. type: {
  111. type: String,
  112. default: () => '',
  113. },
  114. isH5: {
  115. type: Boolean,
  116. default: () => false,
  117. },
  118. resultShow: {
  119. type: Boolean,
  120. default: () => true,
  121. },
  122. },
  123. setup(props: any, ctx: any) {
  124. const data = reactive({
  125. type: '',
  126. list: [],
  127. selectedList: [],
  128. isSearch: true,
  129. isCustomItem: false,
  130. title: '',
  131. });
  132. watchEffect(() => {
  133. if (props.isCustomItem) {
  134. for (let index = 0; index < props.list.length; index++) {
  135. if (props.list[index].conversationID.indexOf('@TIM#SYSTEM') > -1) {
  136. // eslint-disable-next-line vue/no-mutating-props
  137. props.list.splice(index, 1);
  138. }
  139. data.list = props.list;
  140. }
  141. } else {
  142. data.list = props.list;
  143. }
  144. data.selectedList = props.selectedList;
  145. data.isSearch = props.isSearch;
  146. data.isCustomItem = props.isCustomItem;
  147. data.title = props.title;
  148. data.type = props.type;
  149. });
  150. // 可选项
  151. const optional = computed(() => data.list.filter((item: any) => !item.isDisabled));
  152. const handleInput = (e: any) => {
  153. ctx.emit('search', e.target.value);
  154. };
  155. const selected = (item: any) => {
  156. if (item.isDisabled) {
  157. return;
  158. }
  159. let list: any = data.selectedList;
  160. const index: number = list.indexOf(item);
  161. if (index > -1) {
  162. return data.selectedList.splice(index, 1);
  163. }
  164. if (props.isRadio) {
  165. list = [];
  166. }
  167. list.push(item);
  168. data.selectedList = list;
  169. };
  170. const selectedAll = () => {
  171. if (data.selectedList.length === optional.value.length) {
  172. data.selectedList = [];
  173. } else {
  174. data.selectedList = [...optional.value];
  175. }
  176. };
  177. const submit = () => {
  178. ctx.emit('submit', data.selectedList);
  179. };
  180. const cancel = () => {
  181. ctx.emit('cancel');
  182. };
  183. return {
  184. ...toRefs(data),
  185. optional,
  186. handleInput,
  187. selected,
  188. selectedAll,
  189. submit,
  190. cancel,
  191. };
  192. },
  193. });
  194. </script>
  195. <style lang="scss" scoped src="./style/transfer.scss"></style>