index.vue 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. <template>
  2. <div
  3. class="transfer"
  4. :class="[!isPC ? 'transfer-h5' : '', isMobile ? 'transfer-h5-wechat' : '']"
  5. >
  6. <header
  7. v-if="!isPC"
  8. class="transfer-header transfer-h5-header"
  9. >
  10. <div
  11. v-if="!props.isHiddenBackIcon"
  12. @click="cancel"
  13. >
  14. <Icon
  15. class="icon"
  16. :file="backIcon"
  17. :width="'18px'"
  18. :height="'18px'"
  19. />
  20. </div>
  21. <span class="title">{{ transferTitle }}</span>
  22. <span class="space" />
  23. </header>
  24. <main class="main">
  25. <div class="left">
  26. <header class="transfer-header">
  27. <!-- PC triggers @keyup.enter -->
  28. <input
  29. v-if="isPC && isTransferSearch"
  30. type="text"
  31. :value="searchValue"
  32. :placeholder="TUITranslateService.t('component.请输入userID')"
  33. enterkeyhint="search"
  34. :class="[isUniFrameWork ? 'left-uniapp-input' : '']"
  35. @keyup.enter="handleInput"
  36. >
  37. <!-- not PC triggers blur -->
  38. <input
  39. v-if="!isPC && isTransferSearch"
  40. type="text"
  41. :placeholder="TUITranslateService.t('component.请输入userID')"
  42. enterkeyhint="search"
  43. :value="searchValue"
  44. :class="[isUniFrameWork ? 'left-uniapp-input' : '']"
  45. @blur="handleInput"
  46. @confirm="handleInput"
  47. >
  48. </header>
  49. <main class="transfer-left-main">
  50. <ul class="transfer-list">
  51. <li
  52. v-if="optional.length > 1 && !isRadio"
  53. class="transfer-list-item"
  54. @click="selectedAll"
  55. >
  56. <Icon
  57. v-if="transferSelectedList.length === optional.length"
  58. :file="selectedIcon"
  59. :width="'18px'"
  60. :height="'18px'"
  61. />
  62. <i
  63. v-else
  64. class="icon-unselected"
  65. />
  66. <span class="select-all">{{
  67. TUITranslateService.t("component.全选")
  68. }}</span>
  69. </li>
  70. <li
  71. v-for="item in transferList"
  72. :key="item.userID"
  73. class="transfer-list-item"
  74. @click="selected(item)"
  75. >
  76. <Icon
  77. v-if="transferSelectedList.indexOf(item) > -1"
  78. :file="selectedIcon"
  79. :class="[item.isDisabled && 'disabled']"
  80. :width="'18px'"
  81. :height="'18px'"
  82. />
  83. <i
  84. v-else
  85. :class="[item.isDisabled && 'disabled', 'icon-unselected']"
  86. />
  87. <template v-if="!isTransferCustomItem">
  88. <img
  89. class="avatar"
  90. :src="
  91. item.avatar ||
  92. 'https://web.sdk.qcloud.com/component/TUIKit/assets/avatar_21.png'
  93. "
  94. onerror="this.onerror=null;this.src='https://web.sdk.qcloud.com/component/TUIKit/assets/avatar_21.png'"
  95. >
  96. <span class="name">{{ item.nick || item.userID }}</span>
  97. <span v-if="item.isDisabled">({{ TUITranslateService.t("component.已在群中") }})</span>
  98. </template>
  99. <template v-else>
  100. <slot
  101. name="left"
  102. :data="item"
  103. />
  104. </template>
  105. </li>
  106. <li
  107. v-if="transferTotal > transferList.length"
  108. class="transfer-list-item more"
  109. @click="getMore"
  110. >
  111. {{ TUITranslateService.t("component.查看更多") }}
  112. </li>
  113. </ul>
  114. </main>
  115. </div>
  116. <div class="right">
  117. <header
  118. v-if="isPC"
  119. class="transfer-header"
  120. >
  121. {{ transferTitle }}
  122. </header>
  123. <ul
  124. v-if="resultShow"
  125. class="transfer-list"
  126. >
  127. <p
  128. v-if="transferSelectedList.length > 0 && isPC"
  129. class="transfer-text"
  130. >
  131. {{ TUITranslateService.t("component.已选中")
  132. }}{{ transferSelectedList.length
  133. }}{{ TUITranslateService.t("component.人") }}
  134. </p>
  135. <li
  136. v-for="(item, index) in transferSelectedList"
  137. :key="index"
  138. class="transfer-list-item space-between"
  139. >
  140. <aside class="transfer-list-item-content">
  141. <template v-if="!isTransferCustomItem">
  142. <img
  143. class="avatar"
  144. :src="
  145. item.avatar ||
  146. 'https://web.sdk.qcloud.com/component/TUIKit/assets/avatar_21.png'
  147. "
  148. onerror="this.onerror=null;this.src='https://web.sdk.qcloud.com/component/TUIKit/assets/avatar_21.png'"
  149. >
  150. <span
  151. v-if="isPC"
  152. class="name"
  153. >{{ item.nick || item.userID }}</span>
  154. </template>
  155. <template v-else>
  156. <slot
  157. name="right"
  158. :data="item"
  159. />
  160. </template>
  161. </aside>
  162. <span
  163. v-if="isPC"
  164. @click="selected(item)"
  165. >
  166. <Icon
  167. :file="cancelIcon"
  168. :width="'18px'"
  169. :height="'18px'"
  170. />
  171. </span>
  172. </li>
  173. </ul>
  174. <footer class="transfer-right-footer">
  175. <button
  176. class="btn btn-cancel"
  177. @click="cancel"
  178. >
  179. {{ TUITranslateService.t("component.取消") }}
  180. </button>
  181. <button
  182. v-if="transferSelectedList.length > 0"
  183. class="btn"
  184. @click="submit"
  185. >
  186. {{ TUITranslateService.t("component.完成") }}
  187. </button>
  188. <button
  189. v-else
  190. class="btn btn-no"
  191. @click="submit"
  192. >
  193. {{ TUITranslateService.t("component.完成") }}
  194. </button>
  195. </footer>
  196. </div>
  197. </main>
  198. </div>
  199. </template>
  200. <script lang="ts" setup>
  201. import { ref, watchEffect, computed } from '../../../adapter-vue';
  202. import { TUITranslateService } from '@tencentcloud/chat-uikit-engine';
  203. import { ITransferListItem } from '../../../interface';
  204. import Icon from '../Icon.vue';
  205. import selectedIcon from '../../../assets/icon/selected.svg';
  206. import backIcon from '../../../assets/icon/back.svg';
  207. import cancelIcon from '../../../assets/icon/cancel.svg';
  208. import { isPC, isUniFrameWork, isMobile } from '../../../utils/env';
  209. const props = defineProps({
  210. list: {
  211. type: Array,
  212. default: () => [],
  213. },
  214. selectedList: {
  215. type: Array,
  216. default: () => [],
  217. },
  218. isSearch: {
  219. type: Boolean,
  220. default: true,
  221. },
  222. isRadio: {
  223. type: Boolean,
  224. default: false,
  225. },
  226. isCustomItem: {
  227. type: Boolean,
  228. default: false,
  229. },
  230. title: {
  231. type: String,
  232. default: '',
  233. },
  234. type: {
  235. type: String,
  236. default: '',
  237. },
  238. resultShow: {
  239. type: Boolean,
  240. default: true,
  241. },
  242. total: {
  243. type: Number,
  244. default: 0,
  245. },
  246. isHiddenBackIcon: {
  247. type: Boolean,
  248. default: false,
  249. },
  250. });
  251. const transferList = ref<ITransferListItem[]>([]);
  252. const transferTotal = ref<number>(0);
  253. const transferSelectedList = ref<ITransferListItem[]>([]);
  254. const isTransferSearch = ref(true);
  255. const isTransferCustomItem = ref(false);
  256. const transferTitle = ref('');
  257. const searchValue = ref('');
  258. watchEffect(() => {
  259. if (props.isCustomItem) {
  260. for (let index = 0; index < props.list.length; index++) {
  261. if (
  262. (props.list[index] as any).conversationID.indexOf('@TIM#SYSTEM') > -1
  263. ) {
  264. // eslint-disable-next-line vue/no-mutating-props
  265. props.list.splice(index, 1);
  266. }
  267. transferList.value = props.list as ITransferListItem[];
  268. }
  269. } else {
  270. transferList.value = props.list as ITransferListItem[];
  271. }
  272. transferTotal.value = props.total ? props.total : props.list.length;
  273. transferSelectedList.value = (props.selectedList && props.selectedList.length > 0 ? props.selectedList : transferSelectedList.value) as any;
  274. isTransferSearch.value = props.isSearch;
  275. isTransferCustomItem.value = props.isCustomItem;
  276. transferTitle.value = props.title;
  277. });
  278. const emit = defineEmits(['search', 'submit', 'cancel', 'getMore']);
  279. const optional = computed(() =>
  280. transferList.value.filter((item: any) => !item.isDisabled),
  281. );
  282. const handleInput = (e: any) => {
  283. searchValue.value = e.target.value || e.detail.value;
  284. emit('search', searchValue.value);
  285. };
  286. const selected = (item: any) => {
  287. if (item.isDisabled) {
  288. return;
  289. }
  290. let list: ITransferListItem[] = transferSelectedList.value;
  291. const index: number = list.indexOf(item);
  292. if (index > -1) {
  293. return transferSelectedList.value.splice(index, 1);
  294. }
  295. if (props.isRadio) {
  296. list = [];
  297. }
  298. list.push(item);
  299. transferSelectedList.value = list;
  300. };
  301. const selectedAll = () => {
  302. if (transferSelectedList.value.length === optional.value.length) {
  303. transferSelectedList.value = [];
  304. } else {
  305. transferSelectedList.value = [...optional.value];
  306. }
  307. };
  308. const submit = () => {
  309. emit('submit', transferSelectedList.value);
  310. searchValue.value = '';
  311. };
  312. const cancel = () => {
  313. emit('cancel');
  314. searchValue.value = '';
  315. };
  316. const getMore = () => {
  317. emit('getMore');
  318. };
  319. </script>
  320. <style lang="scss" scoped src="./style/transfer.scss"></style>