Quellcode durchsuchen

Update chat SDK integration and enhance IM component styling

- Replaced the @tencentcloud/chat package with @tencentcloud/lite-chat in multiple components for improved functionality.
- Refactored ConversationDetail.vue and Im.vue to utilize the new SDK, ensuring compatibility and better performance.
- Enhanced styling and structure of the IM component for a more cohesive user experience, including updated class names and layout adjustments.
- Updated useChat composable to reflect changes in SDK imports and types, maintaining type safety and functionality.
0es vor 3 Monaten
Ursprung
Commit
5ed0dc5b7f
5 geänderte Dateien mit 644 neuen und 409 gelöschten Zeilen
  1. 207 99
      app/components/im/ConversationDetail.vue
  2. 1 1
      app/components/popup/Im.vue
  3. 3 3
      app/composables/useChat.ts
  4. 1 1
      package.json
  5. 432 305
      yarn.lock

+ 207 - 99
app/components/im/ConversationDetail.vue

@@ -1,7 +1,6 @@
 <script setup lang="ts">
-import type { Conversation } from '@tencentcloud/chat'
+import type { Conversation } from '@tencentcloud/lite-chat'
 import type { UserInfoItemVO } from '~/types/api'
-import TitleIcon from '~/assets/icons/tab-active.svg'
 import CloseListIcon from '~/assets/icons/im/close-list.svg'
 import ArrowSvg from '~/assets/icons/mine/arrow-temp.svg'
 
@@ -22,131 +21,240 @@ const emit = defineEmits<{
 </script>
 
 <template>
-  <div class="im-detail-page">
-    <div class="im-detail-page__bg" />
-
-    <div class="im-detail-page__header">
-      <div class="im-detail-page__header-left">
+  <div class="im-detail">
+    <header class="im-detail__header">
+      <div class="im-detail__header-left">
         <button
-          class="im-detail-page__back"
+          class="im-detail__back"
           type="button"
+          aria-label="back"
           @click="emit('back')"
         >
-          <ArrowSvg class="im-detail-page__back-icon" />
-          <span class="im-detail-page__back-text">Back</span>
+          <ArrowSvg class="im-detail__back-icon" />
         </button>
 
-        <div class="im-detail-page__title">
-          <TitleIcon class="im-detail-page__title-icon" />
-          <span class="im-detail-page__title-text">
+        <div class="im-detail__avatar">
+          <img
+            class="im-detail__avatar-img"
+            :src="props.avatar"
+            alt=""
+            loading="lazy"
+          >
+        </div>
+
+        <div class="im-detail__title">
+          <p class="im-detail__name">
             {{ props.name || 'Conversation' }}
-          </span>
+          </p>
+          <p class="im-detail__status">
+            online
+          </p>
         </div>
       </div>
 
+      <div class="im-detail__header-right">
+        <!-- Icon can be empty (placeholder) -->
+        <button
+          class="im-detail__close"
+          type="button"
+          aria-label="close"
+          @click="emit('close')"
+        >
+          <CloseListIcon />
+        </button>
+      </div>
+    </header>
+
+    <main class="im-detail__content">
+      <div class="im-detail__placeholder">
+        消息内容待接入
+      </div>
+    </main>
+
+    <footer class="im-detail__composer">
+      <div class="im-detail__input">
+        <input
+          class="im-detail__input-el"
+          type="text"
+          inputmode="text"
+          autocomplete="off"
+          placeholder="发送消息"
+        >
+      </div>
       <button
-        class="im-detail-page__close"
+        class="im-detail__send"
         type="button"
-        @click="emit('close')"
-      >
-        <CloseListIcon />
-      </button>
-    </div>
-
-    <div class="im-detail-page__content" />
+        aria-label="send"
+      />
+    </footer>
   </div>
 </template>
 
 <style scoped lang="scss">
-.im-detail-page {
+.im-detail {
   height: 100vh;
-  padding: 16px 16px 20px;
-  position: relative;
   display: flex;
   flex-direction: column;
+  background: #F1F2F5;
+}
 
-  &__bg {
-    @include size(100%, 173px);
-    @include bg('~/assets/images/home/header-bg.png', 100% 173px);
-    position: absolute;
-    inset: 0;
-    z-index: 0;
-  }
+.im-detail__header {
+  background: #fff;
+  padding: calc(env(safe-area-inset-top, 0px) + 10px) 12px 10px;
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+}
 
-  &__header {
-    display: flex;
-    align-items: center;
-    justify-content: space-between;
-    position: relative;
-    z-index: 1;
-  }
+.im-detail__header-left {
+  display: flex;
+  align-items: center;
+  gap: 12px;
+  min-width: 0;
+}
 
-  &__header-left {
-    display: flex;
-    align-items: center;
-    gap: 10px;
-    min-width: 0;
-  }
+.im-detail__back {
+  border: none;
+  background: transparent;
+  padding: 0;
+  display: inline-flex;
+  align-items: center;
+  justify-content: center;
+  cursor: pointer;
+  -webkit-tap-highlight-color: transparent;
+  opacity: 0.9;
+  flex: 0 0 auto;
+}
 
-  &__back {
-    border: none;
-    background: transparent;
-    display: inline-flex;
-    align-items: center;
-    gap: 4px;
-    padding: 6px 0;
-    cursor: pointer;
-    -webkit-tap-highlight-color: transparent;
-    flex: 0 0 auto;
-  }
+.im-detail__back-icon {
+  @include size(24px);
+  transform: rotate(180deg);
+}
 
-  &__back-icon {
-    transform: rotate(180deg);
-  }
+.im-detail__avatar {
+  @include size(34px);
+  border-radius: 999px;
+  overflow: hidden;
+  background: #eee;
+  flex: 0 0 auto;
+}
 
-  &__back-text {
-    font-size: 12px;
-    color: rgba(0, 0, 0, 0.70);
-  }
+.im-detail__avatar-img {
+  @include size(100%);
+  object-fit: cover;
+  object-position: 50% 50%;
+  display: block;
+}
 
-  &__title {
-    font-size: 24px;
-    font-family: var(--font-title);
-    font-weight: 600;
-    color: #000;
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    min-width: 0;
-
-    &-icon {
-      position: absolute;
-      z-index: 0;
-    }
-    &-text {
-      position: relative;
-      z-index: 1;
-      max-width: 60vw;
-      overflow: hidden;
-      text-overflow: ellipsis;
-      white-space: nowrap;
-    }
-  }
+.im-detail__title {
+  min-width: 0;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  gap: 2px;
+}
 
-  &__close {
-    border: none;
-    background: transparent;
-  }
+.im-detail__name {
+  margin: 0;
+  font-family: var(--font-title, 'Poppins', sans-serif);
+  font-weight: 600;
+  font-size: 16px;
+  line-height: 17px;
+  color: #1D2129;
+  max-width: 60vw;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+
+.im-detail__status {
+  margin: 0;
+  font-family: 'Inter', sans-serif;
+  font-weight: 400;
+  font-size: 11px;
+  line-height: 14px;
+  color: #86909C;
+}
+
+.im-detail__header-right {
+  display: flex;
+  align-items: center;
+  gap: 8px;
+  flex: 0 0 auto;
+}
+
+.im-detail__close {
+  border: none;
+  background: transparent;
+  padding: 0;
+  display: inline-flex;
+  align-items: center;
+  justify-content: center;
+  cursor: pointer;
+  -webkit-tap-highlight-color: transparent;
+}
 
-  &__content {
-    display: flex;
-    flex-direction: column;
-    gap: 10px;
-    position: relative;
-    z-index: 1;
-    flex: 1 1 auto;
-    min-height: 0;
-    overflow: auto;
+.im-detail__content {
+  flex: 1 1 auto;
+  min-height: 0;
+  overflow: auto;
+  padding: 16px;
+}
+
+.im-detail__placeholder {
+  width: fit-content;
+  max-width: 100%;
+  margin: 0 auto;
+  padding: 4px 8px;
+  border-radius: 999px;
+  background: #fff;
+  font-size: 11px;
+  line-height: 14px;
+  color: #86909C;
+}
+
+.im-detail__composer {
+  background: #fff;
+  padding: 8px 12px calc(env(safe-area-inset-bottom, 0px) + 8px);
+  display: flex;
+  align-items: center;
+  gap: 10px;
+}
+
+.im-detail__input {
+  flex: 1 1 auto;
+  min-width: 0;
+  background: #F2F3F5;
+  border-radius: 999px;
+  padding: 8px 10px;
+  min-height: 36px;
+  display: flex;
+  align-items: center;
+}
+
+.im-detail__input-el {
+  width: 100%;
+  border: none;
+  outline: none;
+  background: transparent;
+  font-family: 'Inter', sans-serif;
+  font-weight: 400;
+  font-size: 14px;
+  line-height: 20px;
+  color: #1D2129;
+
+  &::placeholder {
+    color: #86909C;
   }
 }
+
+.im-detail__send {
+  @include size(40px);
+  border: none;
+  background: #15E5E2;
+  border-radius: 20px;
+  flex: 0 0 auto;
+  cursor: pointer;
+  -webkit-tap-highlight-color: transparent;
+}
 </style>

+ 1 - 1
app/components/popup/Im.vue

@@ -1,7 +1,7 @@
 <script setup lang="ts">
 import dayjs from 'dayjs'
 import { computed, ref, watch } from 'vue'
-import type { Conversation } from '@tencentcloud/chat'
+import type { Conversation } from '@tencentcloud/lite-chat'
 import { useImPopup } from '~/composables/useImPopup'
 import TitleIcon from '~/assets/icons/tab-active.svg'
 import CloseListIcon from '~/assets/icons/im/close-list.svg'

+ 3 - 3
app/composables/useChat.ts

@@ -1,8 +1,8 @@
-import type { ChatSDK, Conversation } from '@tencentcloud/chat'
+import type { ChatSDK, Conversation } from '@tencentcloud/lite-chat'
 import { userApi } from '~/api/user'
 import type { UserInfoItemVO } from '~/types/api'
 
-type TencentCloudChatStatic = typeof import('@tencentcloud/chat').default
+type TencentCloudChatStatic = typeof import('@tencentcloud/lite-chat').default
 
 export type GetConversationListOptions = Parameters<ChatSDK['getConversationList']>[0]
 
@@ -135,7 +135,7 @@ export function useChat() {
       const sdkAppId = Number(runtimeConfig.public.imAppId)
       if (!sdkAppId) throw new Error('Missing runtimeConfig.public.imAppId')
 
-      const { default: TencentCloudChat } = await import('@tencentcloud/chat')
+      const { default: TencentCloudChat } = await import('@tencentcloud/lite-chat')
       _sdk = TencentCloudChat
 
       const instance: ChatSDK = TencentCloudChat.create({ SDKAppID: sdkAppId })

+ 1 - 1
package.json

@@ -18,7 +18,7 @@
     "@nuxtjs/i18n": "10.2.1",
     "@pinia/nuxt": "0.11.3",
     "@sentry/nuxt": "^10",
-    "@tencentcloud/chat": "^3.6.1",
+    "@tencentcloud/lite-chat": "^4.2.0",
     "@vant/nuxt": "^1.0.7",
     "@vueuse/nuxt": "14.1.0",
     "apng-js": "^1.1.5",

Datei-Diff unterdrückt, da er zu groß ist
+ 432 - 305
yarn.lock


Einige Dateien werden nicht angezeigt, da zu viele Dateien in diesem Diff geändert wurden.