index.vue 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. <template>
  2. <div
  3. :class="[
  4. 'message-input-toolbar',
  5. 'message-input-toolbar-h5',
  6. 'message-input-toolbar-uni',
  7. ]"
  8. >
  9. <div v-if="props.displayType === 'emojiPicker'">
  10. <EmojiPickerDialog />
  11. </div>
  12. <div v-else>
  13. <swiper
  14. :class="['message-input-toolbar-swiper']"
  15. :indicator-dots="isSwiperIndicatorDotsEnable"
  16. :autoplay="false"
  17. :circular="false"
  18. >
  19. <swiper-item
  20. :class="[
  21. 'message-input-toolbar-list',
  22. 'message-input-toolbar-h5-list',
  23. 'message-input-toolbar-uni-list',
  24. ]"
  25. >
  26. <ImageUpload imageSourceType="camera" />
  27. <ImageUpload imageSourceType="album" />
  28. <!-- <OtgoingCAll></OtgoingCAll> -->
  29. <!-- <VideoUpload videoSourceType="album" />
  30. <VideoUpload videoSourceType="camera" /> -->
  31. <!-- <template v-if="currentExtensionList[0]">
  32. <div
  33. v-for="(extension, index) in currentExtensionList.slice(0, 4)"
  34. :key="index"
  35. >
  36. <ToolbarItemContainer
  37. v-if="extension"
  38. :iconFile="genExtensionIcon(extension)"
  39. :title="genExtensionText(extension)"
  40. iconWidth="25px"
  41. iconHeight="25px"
  42. :needDialog="false"
  43. @onIconClick="onExtensionClick(extension)"
  44. />
  45. </div>
  46. </template> -->
  47. <!-- <Evaluate
  48. v-if="currentExtensionList.length < 4"
  49. @onDialogPopupShowOrHide="handleSwiperDotShow"
  50. /> -->
  51. <Words
  52. v-if="currentExtensionList.length < 3"
  53. @onDialogPopupShowOrHide="handleSwiperDotShow"
  54. />
  55. </swiper-item>
  56. <swiper-item
  57. v-if="currentExtensionList[2] && currentExtensionList.length >= 3"
  58. :class="[
  59. 'message-input-toolbar-list',
  60. 'message-input-toolbar-h5-list',
  61. 'message-input-toolbar-uni-list',
  62. ]"
  63. >
  64. <div
  65. v-for="(extension, index) in currentExtensionList.slice(4)"
  66. :key="index"
  67. >
  68. <ToolbarItemContainer
  69. v-if="extension"
  70. :iconFile="genExtensionIcon(extension)"
  71. :title="genExtensionText(extension)"
  72. iconWidth="25px"
  73. iconHeight="25px"
  74. :needDialog="false"
  75. @onIconClick="onExtensionClick(extension)"
  76. />
  77. </div>
  78. <Evaluate
  79. v-if="currentExtensionList.length >= 4"
  80. @onDialogPopupShowOrHide="handleSwiperDotShow"
  81. />
  82. <Words
  83. v-if="currentExtensionList.length >= 3"
  84. @onDialogPopupShowOrHide="handleSwiperDotShow"
  85. />
  86. </swiper-item>
  87. </swiper>
  88. </div>
  89. <UserSelector
  90. ref="userSelectorRef"
  91. :type="selectorShowType"
  92. :currentConversation="currentConversation"
  93. :isGroup="isGroup"
  94. @submit="onUserSelectorSubmit"
  95. @cancel="onUserSelectorCancel"
  96. />
  97. </div>
  98. </template>
  99. <script setup lang="ts">
  100. import { ref, onUnmounted, onMounted } from "../../../adapter-vue";
  101. import TUIChatEngine, {
  102. IConversationModel,
  103. TUIStore,
  104. StoreName,
  105. } from "@tencentcloud/chat-uikit-engine";
  106. import TUICore, { ExtensionInfo, TUIConstants } from "@tencentcloud/tui-core";
  107. import ImageUpload from "./image-upload/index.vue";
  108. import VideoUpload from "./video-upload/index.vue";
  109. import OtgoingCAll from "./otgoing-call/index.vue";
  110. import Evaluate from "./evaluate/index.vue";
  111. import Words from "./words/index.vue";
  112. import ToolbarItemContainer from "./toolbar-item-container/index.vue";
  113. import EmojiPickerDialog from "./emoji-picker/emoji-picker-dialog.vue";
  114. import UserSelector from "./user-selector/index.vue";
  115. import TUIChatConfig from "../config";
  116. import { enableSampleTaskStatus } from "../../../utils/enableSampleTaskStatus";
  117. import { ToolbarDisplayType } from "../../../interface";
  118. interface IProps {
  119. displayType: ToolbarDisplayType;
  120. }
  121. const props = withDefaults(defineProps<IProps>(), {});
  122. const currentConversation = ref<IConversationModel>();
  123. const isGroup = ref<boolean>(false);
  124. const selectorShowType = ref<string>("");
  125. const userSelectorRef = ref();
  126. const currentUserSelectorExtension = ref<ExtensionInfo | null>();
  127. const currentExtensionList = ref<ExtensionInfo[]>([]);
  128. const isSwiperIndicatorDotsEnable = ref<boolean>(false);
  129. // extensions
  130. const extensionList: ExtensionInfo[] = [
  131. ...TUICore.getExtensionList(TUIConstants.TUIChat.EXTENSION.INPUT_MORE.EXT_ID),
  132. ];
  133. const getExtensionList = (conversationID: string) => {
  134. if (!conversationID) {
  135. // uniapp build ios app has null in last index need to filter
  136. return (currentExtensionList.value = extensionList.filter(
  137. (extension) => extension
  138. ));
  139. }
  140. const chatType = TUIChatConfig.getChatType();
  141. const options: any = {
  142. chatType,
  143. };
  144. // 向下兼容,callkit 没有chatType 判断时,使用 filterVoice、filterVideo 过滤
  145. if (chatType === "customerService") {
  146. options.filterVoice = true;
  147. options.filterVideo = true;
  148. enableSampleTaskStatus("customerService");
  149. }
  150. // uniapp build ios app has null in last index need to filter
  151. currentExtensionList.value = [
  152. ...TUICore.getExtensionList(
  153. TUIConstants.TUIChat.EXTENSION.INPUT_MORE.EXT_ID,
  154. options
  155. ),
  156. ].filter((extension) => extension);
  157. };
  158. const onCurrentConversationUpdate = (conversation: IConversationModel) => {
  159. if (
  160. conversation?.conversationID &&
  161. currentConversation.value?.conversationID !== conversation?.conversationID
  162. ) {
  163. getExtensionList(conversation?.conversationID);
  164. if (currentExtensionList.value.length > 2) {
  165. isSwiperIndicatorDotsEnable.value = true;
  166. }
  167. }
  168. currentConversation.value = conversation;
  169. if (currentConversation?.value?.type === TUIChatEngine.TYPES.CONV_GROUP) {
  170. isGroup.value = true;
  171. } else {
  172. isGroup.value = false;
  173. }
  174. };
  175. onMounted(() => {
  176. TUIStore.watch(StoreName.CONV, {
  177. currentConversation: onCurrentConversationUpdate,
  178. });
  179. });
  180. onUnmounted(() => {
  181. TUIStore.unwatch(StoreName.CONV, {
  182. currentConversation: onCurrentConversationUpdate,
  183. });
  184. });
  185. // handle extensions onclick
  186. const onExtensionClick = (extension: ExtensionInfo) => {
  187. // uniapp vue2 build wx lose listener proto
  188. const extensionModel = currentExtensionList.value.find(
  189. (targetExtension) => targetExtension?.data?.name === extension?.data?.name
  190. );
  191. switch (extensionModel?.data?.name) {
  192. case "voiceCall":
  193. onCallExtensionClicked(extensionModel, 1);
  194. break;
  195. case "videoCall":
  196. onCallExtensionClicked(extensionModel, 2);
  197. break;
  198. case "search":
  199. extensionModel?.listener?.onClicked?.();
  200. break;
  201. default:
  202. break;
  203. }
  204. };
  205. const onCallExtensionClicked = (extension: ExtensionInfo, callType: number) => {
  206. selectorShowType.value = extension?.data?.name;
  207. if (currentConversation?.value?.type === TUIChatEngine.TYPES.CONV_C2C) {
  208. extension?.listener?.onClicked?.({
  209. userIDList: [currentConversation?.value?.conversationID?.slice(3)],
  210. type: callType,
  211. });
  212. } else if (isGroup.value) {
  213. currentUserSelectorExtension.value = extension;
  214. userSelectorRef?.value?.toggleShow &&
  215. userSelectorRef.value.toggleShow(true);
  216. }
  217. };
  218. const genExtensionIcon = (extension: any) => {
  219. return extension?.icon;
  220. };
  221. const genExtensionText = (extension: any) => {
  222. return extension?.text;
  223. };
  224. const onUserSelectorSubmit = (selectedInfo: any) => {
  225. currentUserSelectorExtension.value?.listener?.onClicked?.(selectedInfo);
  226. currentUserSelectorExtension.value = null;
  227. };
  228. const onUserSelectorCancel = () => {
  229. currentUserSelectorExtension.value = null;
  230. };
  231. const handleSwiperDotShow = (showStatus: boolean) => {
  232. isSwiperIndicatorDotsEnable.value =
  233. currentExtensionList.value.length > 2 ? !showStatus : false;
  234. };
  235. </script>
  236. <script lang="ts">
  237. export default {
  238. options: {
  239. styleIsolation: "shared",
  240. },
  241. };
  242. </script>
  243. <style lang="scss">
  244. @import "../../../assets/styles/common";
  245. @import "./style/uni";
  246. </style>