安浩浩 1 жил өмнө
parent
commit
de27cfa8f6

+ 1 - 1
.vscode/settings.json

@@ -93,7 +93,7 @@
   "i18n-ally.sortKeys": true,
   "i18n-ally.namespace": false,
   "i18n-ally.enabledParsers": ["ts"],
-  "i18n-ally.sourceLanguage": "en",
+  "i18n-ally.sourceLanguage": "zh-CN",
   "i18n-ally.displayLanguage": "zh-CN",
   "i18n-ally.enabledFrameworks": ["vue", "react"],
   "cSpell.words": [

+ 2 - 1
package.json

@@ -39,6 +39,7 @@
     "benz-amr-recorder": "^1.1.5",
     "bpmn-js-token-simulation": "^0.10.0",
     "camunda-bpmn-moddle": "^7.0.1",
+    "components": "link:@/components",
     "cropperjs": "^1.6.1",
     "crypto-js": "^4.2.0",
     "dayjs": "^1.11.10",
@@ -83,8 +84,8 @@
     "@types/qs": "^6.9.12",
     "@typescript-eslint/eslint-plugin": "^7.1.0",
     "@typescript-eslint/parser": "^7.1.0",
-    "@unocss/transformer-variant-group": "^0.58.5",
     "@unocss/eslint-config": "^0.57.4",
+    "@unocss/transformer-variant-group": "^0.58.5",
     "@vitejs/plugin-legacy": "^5.3.1",
     "@vitejs/plugin-vue": "^5.0.4",
     "@vitejs/plugin-vue-jsx": "^3.1.0",

BIN
src/assets/imgs/tabbar/graycontacts.png


BIN
src/assets/imgs/tabbar/grayconversation.png


BIN
src/assets/imgs/tabbar/highlightconversation.png


BIN
src/assets/imgs/tabbar/higtlightcontacts.png


BIN
src/assets/imgs/welcome/Group 78@3x.png


BIN
src/assets/imgs/welcome/Mask_group.png


BIN
src/assets/imgs/welcome/Mask_group2.png


+ 173 - 0
src/components/SearchInput/index.vue

@@ -0,0 +1,173 @@
+<script setup lang="ts">
+import { Search } from '@element-plus/icons-vue'
+
+//搜索框value
+const inputValue = ref('')
+//控制搜索结果展示
+const isShowResultContent = ref(false)
+
+//搜索相匹配的值
+const querySearch = () => {
+  console.log('>>>>>>>>触发搜索')
+}
+</script>
+
+<template>
+  <div class="search_box" ref="searchBox">
+    <div>
+      <el-input
+        v-model.trim="inputValue"
+        placeholder="搜索"
+        @focus="isShowResultContent = true"
+        @clear="isShowResultContent = false"
+        @input="querySearch"
+        :prefix-icon="Search"
+        clearable
+      />
+    </div>
+  </div>
+</template>
+
+<style scoped lang="scss">
+::v-deep .el-input__wrapper {
+  box-shadow: none;
+}
+
+.search_box {
+  width: 100%;
+  height: 60px;
+  background: #f8f8f8;
+  padding: 14px 20px;
+  box-sizing: border-box;
+}
+
+.resultContent {
+  position: absolute;
+  top: 58px;
+  left: 0;
+  width: 100%;
+  height: calc(100% - 60px);
+  background-color: #ededed;
+  z-index: 888;
+  overflow-y: auto;
+
+  .search_history {
+    .search_history_item {
+      width: 100%;
+      font-family: 'PingFang SC';
+      font-style: normal;
+      font-weight: 400;
+      font-size: 12px;
+      line-height: 17px;
+      letter-spacing: 0.669643px;
+      color: #000000;
+
+      li {
+        display: flex;
+        flex-direction: row;
+        align-items: center;
+        justify-content: flex-start;
+        padding: 0 15px;
+        background: #fff;
+        margin: 1px 0;
+        height: 32px;
+        transition: all 0.5s;
+        cursor: pointer;
+
+        &:hover {
+          background: #e5e5e5;
+        }
+      }
+    }
+  }
+
+  .title {
+    height: 32px;
+    line-height: 32px;
+    padding: 0 15px;
+    background: #f2f2f2;
+    font-weight: 400;
+    font-size: 12px;
+    letter-spacing: 0.342857px;
+    color: #333333;
+  }
+
+  .search_history_title {
+    display: flex;
+    flex-direction: row;
+    justify-content: space-between;
+
+    .clear_search_history:hover {
+      color: #00a0fb;
+      cursor: pointer;
+    }
+  }
+
+  .search_result_item {
+    position: relative;
+    display: flex;
+    flex-direction: row;
+    align-items: center;
+    justify-content: flex-start;
+    height: 66px;
+    background: #fff;
+    // padding: 0 14px;
+    cursor: pointer;
+
+    .item_left {
+      padding: 0;
+      margin-right: 11px;
+      margin-left: 14px;
+    }
+
+    .item_main {
+      // width: 25%;
+      display: flex;
+      flex-direction: column;
+      align-items: flex-start;
+      justify-content: space-around;
+      height: 40px;
+      font-family: 'PingFang SC';
+      font-style: normal;
+      font-weight: 500;
+      font-size: 14px;
+
+      .name {
+        max-width: 100px;
+        height: 17px;
+        overflow: hidden;
+        text-overflow: ellipsis;
+        white-space: nowrap;
+      }
+
+      .last_msg_body {
+        max-width: 100px;
+        height: 17px;
+        font-family: 'PingFang SC';
+        font-style: normal;
+        font-weight: 400;
+        font-size: 12px;
+        line-height: 17px;
+        letter-spacing: 0.3px;
+        color: #a3a3a3;
+        overflow: hidden;
+        text-overflow: ellipsis;
+        white-space: nowrap;
+      }
+    }
+
+    .time {
+      position: absolute;
+      right: 15px;
+      top: 13px;
+      font-family: 'PingFang SC';
+      font-style: normal;
+      font-weight: 400;
+      font-size: 10px;
+      line-height: 14px;
+      letter-spacing: 0.25px;
+      color: #a3a3a3;
+    }
+  }
+}
+</style>

+ 73 - 0
src/components/Welcome/index.vue

@@ -0,0 +1,73 @@
+<script setup lang="ts">
+import tang from '@/assets/imgs/welcome/Group 78@3x.png'
+import maskGroup from '@/assets/imgs/welcome/Mask_group2.png'
+</script>
+<template>
+  <div class="app_contanier">
+    <div class="welcome_box">
+      <img class="tang" :src="tang" alt="" />
+      <h1 class="welcome_box_title">欢迎体验 芋道 即时通讯</h1>
+      <p class="welcome_box_text"
+        >包含单聊群聊,添加好友,创建群组等功能,更多其他功能等你发现,快去试试吧!
+      </p>
+    </div>
+    <img class="maskGroup" :src="maskGroup" alt="" />
+  </div>
+</template>
+
+<style scoped>
+.app_contanier {
+  position: absolute;
+  right: 0;
+  bottom: 0;
+  z-index: -1;
+  width: 100%;
+  height: 100%;
+  background-size: 100% 100%;
+  border-radius: 0 5px 5px 0;
+  overflow: hidden;
+}
+
+.welcome_box {
+  position: relative;
+  margin-top: 140px;
+  margin-left: 100px;
+  width: 637px;
+  height: 400px;
+}
+
+.tang {
+  position: absolute;
+  left: -30px;
+  top: 0;
+  width: 32px;
+  height: 32px;
+}
+
+.welcome_box_title {
+  font-family: 'PingFang SC', serif;
+  font-style: normal;
+  font-weight: 500;
+  font-size: 24px;
+  line-height: 34px;
+  letter-spacing: 1px;
+  color: #333333;
+}
+
+.welcome_box_text {
+  margin-top: 12px;
+  font-family: 'PingFang SC', serif;
+  font-style: normal;
+  font-weight: 300;
+  font-size: 16px;
+  line-height: 22px;
+  letter-spacing: 1.5px;
+  color: #a3a3a3;
+}
+
+.maskGroup {
+  position: absolute;
+  right: 0;
+  top: 25%;
+}
+</style>

+ 3 - 0
src/layout/components/Chat/index.ts

@@ -0,0 +1,3 @@
+import Chat from './src/Chat.vue'
+
+export { Chat }

+ 28 - 0
src/layout/components/Chat/src/Chat.vue

@@ -0,0 +1,28 @@
+<script setup lang="ts">
+import { Dialog } from '@/components/Dialog'
+import { ref } from 'vue'
+import IM from '@/views/im/index.vue'
+import { useRouter } from 'vue-router' // 导入 useRouter 方法
+
+defineOptions({ name: 'Chat' })
+
+const dialogVisible = ref(false)
+const router = useRouter() // 创建 router 实例
+
+// 添加点击事件处理函数
+function handleClick() {
+  dialogVisible.value = !dialogVisible.value
+  router.push('/im/conversation') // 设置路由为 /im/conversation
+}
+</script>
+
+<template>
+  <div class="custom-hover" v-bind="$attrs">
+    <ElBadge>
+      <Icon :size="18" class="cursor-pointer" icon="ep:chat-round" @click="handleClick" />
+    </ElBadge>
+  </div>
+  <Dialog v-model="dialogVisible" width="90%" top="10vh">
+    <IM />
+  </Dialog>
+</template>

+ 2 - 0
src/layout/components/ToolHeader.vue

@@ -1,6 +1,7 @@
 <script lang="tsx">
 import { defineComponent, computed } from 'vue'
 import { Message } from '@/layout/components//Message'
+import { Chat } from '@/layout/components/Chat'
 import { Collapse } from '@/layout/components/Collapse'
 import { UserInfo } from '@/layout/components/UserInfo'
 import { Screenfull } from '@/layout/components/Screenfull'
@@ -78,6 +79,7 @@ export default defineComponent({
           {message.value ? (
             <Message class="custom-hover" color="var(--top-header-text-color)"></Message>
           ) : undefined}
+          <Chat class="custom-hover" color="var(--top-header-text-color)"></Chat>
           <UserInfo></UserInfo>
         </div>
       </div>

+ 57 - 0
src/router/modules/remaining.ts

@@ -573,6 +573,63 @@ const remainingRouter: AppRouteRecordRaw[] = [
         component: () => import('@/views/crm/product/detail/index.vue')
       }
     ]
+  },
+  {
+    path: '/im',
+    component: Layout,
+    name: 'IM',
+    meta: { hidden: true },
+    children: [
+      {
+        path: 'conversation',
+        name: 'Conversation',
+        meta: {
+          title: '会话',
+          noCache: true,
+          hidden: true,
+          noTagsView: true
+        },
+        component: () => import('@/views/im/Conversation/index.vue'),
+        children: [
+          {
+            // 会话详情
+            path: 'informdetails',
+            name: 'InformDetails',
+            meta: {
+              title: '通知详情',
+              noCache: true,
+              hidden: true,
+              noTagsView: true
+            },
+            component: () => import('@/views/im/InformDetails/index.vue')
+          },
+          {
+            //聊天对话框
+            path: 'message',
+            name: 'Message',
+            meta: {
+              title: '聊天对话框',
+              noCache: true,
+              hidden: true,
+              noTagsView: true
+            },
+            component: () => import('@/views/im/Message/index.vue')
+          }
+        ]
+      },
+      {
+        path: 'contacts',
+        name: 'Contacts',
+        meta: {
+          title: '联系人',
+          noCache: true,
+          hidden: true,
+          noTagsView: true
+        },
+        component: () => import('@/views/im/Contacts/index.vue'),
+        children: []
+      }
+    ]
   }
 ]
 

+ 5 - 0
src/views/im/Contacts/index.vue

@@ -0,0 +1,5 @@
+<script setup lang="ts"></script>
+
+<template></template>
+
+<style scoped lang="scss"></style>

+ 263 - 0
src/views/im/Conversation/components/ConversationList.vue

@@ -0,0 +1,263 @@
+<script setup lang="ts">
+import { formatDate } from '@/utils/formatTime'
+import { reactive } from 'vue'
+//取好友列表(主要使用好友下的用户属性相关)
+const friendList = reactive([
+  {
+    friendKey: {
+      avatarurl: '',
+      nickName: ''
+    }
+  }
+])
+//取会话数据
+const conversationList = reactive({
+  conversationKey: {
+    conversationInfo: {
+      avatarUrl: '',
+      name: '',
+      conversationType: 0
+    },
+    latestMessage: {
+      msg: ''
+    },
+    latestSendTime: 0,
+    unreadMessageNum: 0,
+    isMention: false
+  }
+})
+
+//处理会话name
+const handleConversationName = computed(() => {
+  return ''
+})
+//处理lastmsg的from昵称
+const handleLastMsgNickName = computed(() => {
+  return ''
+})
+//普通会话
+const checkedConverItemIndex = ref(null)
+const toChatMessage = (item, itemKey, index) => {
+  checkedConverItemIndex.value = index
+}
+//删除某条会话
+const deleteConversation = (itemKey) => {}
+</script>
+<template>
+  <!-- 普通会话 -->
+  <template v-if="Object.keys(conversationList).length > 0">
+    <li
+      v-for="(item, itemKey, index) in conversationList"
+      :key="itemKey"
+      @click="toChatMessage(item, itemKey, index)"
+      :style="{
+        background: checkedConverItemIndex === index ? '#E5E5E5' : ''
+      }"
+    >
+      <el-popover
+        popper-class="conversation_popover"
+        placement="right-end"
+        trigger="contextmenu"
+        :show-arrow="false"
+        :offset="-10"
+      >
+        <template #reference>
+          <div class="session_list_item">
+            <div class="item_body item_left">
+              <div class="session_other_avatar">
+                <el-avatar
+                  :size="34"
+                  :src="
+                    friendList[item.conversationKey] && friendList[item.conversationKey].avatarurl
+                      ? friendList[item.conversationKey].avatarurl
+                      : item.conversationInfo.avatarUrl
+                  "
+                />
+              </div>
+            </div>
+            <div class="item_body item_main">
+              <div class="name"> 好友 </div>
+              <div class="last_msg_body">
+                <span class="last_msg_body_mention" v-if="item.isMention">[有人@我]</span>
+                <span v-show="item.conversationType === 2">好友</span>
+                {{ item.latestMessage.msg }}
+              </div>
+            </div>
+            <div class="item_body item_right">
+              <span class="time">{{ formatDate(item.latestSendTime, 'MM/DD/HH:mm') }}</span>
+              <span class="unReadNum_box" v-if="item.unreadMessageNum >= 1">
+                <sup
+                  class="unReadNum_count"
+                  v-text="item.unreadMessageNum >= 99 ? '99+' : item.unreadMessageNum"
+                ></sup>
+              </span>
+            </div>
+          </div>
+        </template>
+        <template #default>
+          <div class="session_list_delete" @click="deleteConversation(itemKey)"> 删除会话 </div>
+        </template>
+      </el-popover>
+    </li>
+  </template>
+  <template v-else>
+    <el-empty description="暂无最近会话" />
+  </template>
+</template>
+
+<style scoped lang="scss">
+.session_list {
+  position: relative;
+  height: 100%;
+  padding: 0;
+  margin: 0;
+}
+
+.offline_hint {
+  width: 100%;
+  height: 30px;
+  text-align: center;
+  line-height: 30px;
+  color: #f35f81;
+  background: #fce7e8;
+  font-size: 7px;
+
+  .plaint_icon {
+    display: inline-block;
+    width: 15px;
+    height: 15px;
+    color: #e5e5e5;
+    text-align: center;
+    line-height: 15px;
+    font-size: 7px;
+    font-weight: bold;
+    background: #e6686e;
+    border-radius: 50%;
+  }
+}
+
+.session_list .session_list_item {
+  display: flex;
+  flex-direction: row;
+  justify-content: flex-start;
+  align-items: center;
+  height: 66px;
+  background: #f0f0f0;
+  color: var(--el-color-primary);
+  border-bottom: 1px solid var(--el-border-color);
+  cursor: pointer;
+
+  &:hover {
+    background: #e5e5e5;
+  }
+
+  .item_body {
+    display: flex;
+    height: 100%;
+  }
+
+  .item_left {
+    flex-direction: row;
+    align-items: center;
+    justify-content: center;
+    margin-left: 14px;
+    margin-right: 10px;
+  }
+
+  .item_main {
+    width: 225px;
+    max-width: 225px;
+    height: 34px;
+    flex-direction: column;
+    justify-content: space-between;
+    align-items: flex-start;
+
+    .name {
+      min-width: 56px;
+      max-width: 180px;
+      height: 17px;
+      font-weight: 400;
+      font-size: 14px;
+      /* identical to box height */
+      color: #333333;
+      overflow: hidden;
+      text-overflow: ellipsis;
+      white-space: nowrap;
+    }
+
+    .last_msg_body {
+      max-width: 185px;
+      height: 17px;
+      font-weight: 400;
+      font-size: 12px;
+      line-height: 17px;
+      letter-spacing: 0.3px;
+      color: #a3a3a3;
+      overflow: hidden;
+      text-overflow: ellipsis;
+      white-space: nowrap;
+    }
+    .last_msg_body_mention {
+      font-size: 12px;
+      line-height: 17px;
+      font-weight: bold;
+      color: red;
+    }
+  }
+
+  .item_right {
+    width: 25%;
+    height: 34px;
+    flex-direction: column;
+    align-items: flex-end;
+    margin-right: 10px;
+
+    .time {
+      font-size: 10px;
+      font-weight: 400;
+      font-size: 10px;
+      line-height: 14px;
+      letter-spacing: 0.25px;
+      color: #a3a3a3;
+    }
+
+    .unReadNum_box {
+      margin-top: 10px;
+      vertical-align: middle;
+
+      .unReadNum_count {
+        display: inline-block;
+        min-width: 20px;
+        height: 20px;
+        padding: 0 6px;
+        color: #fff;
+        font-weight: normal;
+        font-size: 12px;
+        line-height: 20px;
+        white-space: nowrap;
+        text-align: center;
+        background: #f5222d;
+        border-radius: 10px;
+        box-sizing: border-box;
+      }
+    }
+  }
+}
+
+.session_list_item_active {
+  background: #d2d2d2;
+}
+
+.session_list .session_list_item + .list_item {
+  margin-top: 10px;
+}
+
+.session_list_delete {
+  cursor: pointer;
+  transition: all 0.5s;
+
+  &:hover {
+    background: #e1e1e1;
+  }
+}
+</style>

+ 42 - 0
src/views/im/Conversation/index.vue

@@ -0,0 +1,42 @@
+<script setup lang="ts">
+/* 搜索框组件 */
+import SearchInput from '@/components/SearchInput/index.vue'
+/* 欢迎页 */
+import Welcome from '@/components/Welcome/index.vue'
+import ConversationList from '../Conversation/components/ConversationList.vue'
+</script>
+<template>
+  <el-container style="height: 100%">
+    <el-aside class="chat_conversation_box">
+      <!-- 搜索组件 -->
+      <SearchInput :searchType="'conversation'" />
+      <div class="chat_conversation_list">
+        <ConversationList />
+      </div>
+    </el-aside>
+    <el-main class="chat_conversation_main_box">
+      <router-view />
+      <Welcome />
+    </el-main>
+  </el-container>
+</template>
+
+<style lang="scss" scoped>
+.chat_conversation_box {
+  position: relative;
+  background: #cfdbf171;
+  overflow: hidden;
+  min-width: 324px;
+
+  .chat_conversation_list {
+    height: calc(100% - 60px);
+  }
+}
+
+.chat_conversation_main_box {
+  position: relative;
+  width: 100%;
+  height: 100%;
+  padding: 0;
+}
+</style>

+ 11 - 0
src/views/im/InformDetails/index.vue

@@ -0,0 +1,11 @@
+<script setup lang="ts">
+
+</script>
+
+<template>
+
+</template>
+
+<style scoped lang="scss">
+
+</style>

+ 11 - 0
src/views/im/Message/index.vue

@@ -0,0 +1,11 @@
+<script setup lang="ts">
+
+</script>
+
+<template>
+
+</template>
+
+<style scoped lang="scss">
+
+</style>

+ 287 - 0
src/views/im/NavBar/index.vue

@@ -0,0 +1,287 @@
+<script setup lang="ts">
+/* route */
+import { useRoute } from 'vue-router'
+/* 取用户头像 */
+import router from '@/router'
+import highlightConversation from '@/assets/imgs/tabbar/highlightconversation.png'
+import grayConversation from '@/assets/imgs/tabbar/grayconversation.png'
+import highlightContacts from '@/assets/imgs/tabbar/higtlightcontacts.png'
+import grayContacts from '@/assets/imgs/tabbar/graycontacts.png'
+import avatarImg from '@/assets/imgs/avatar.gif'
+import { useUserStore } from '@/store/modules/user'
+
+const userStore = useUserStore()
+
+const avatar = computed(() => userStore.user.avatar ?? avatarImg)
+
+/* tabular icon 路由跳转 */
+const skipRouterName = ref('conversation')
+const changeSkipRouterName = (routerName: string) => {
+  router.push(`/im/${routerName}`)
+}
+const route = useRoute()
+// 监听路由变化
+watch(
+  () => route.path,
+  (newPath) => {
+    console.log('>>>>>newPath', newPath)
+    if (newPath.includes('/im/conversation')) {
+      skipRouterName.value = 'conversation'
+    }
+    if (newPath.includes('/im/contacts')) {
+      console.log('>>>>>存在赋值为联系人样式')
+      skipRouterName.value = 'contacts'
+    }
+  }
+)
+</script>
+
+<template>
+  <!-- 头像 -->
+  <div class="chat_avatar">
+    <ElAvatar :src="avatar" alt="" class="w-[calc(var(--logo-height)-25px)] rounded-[50%]" />
+  </div>
+  <!-- 去往会话 -->
+  <div class="chat_conversation chat_icon_box" @click="changeSkipRouterName('conversation')">
+    <div class="img_box">
+      <img
+        :src="skipRouterName === 'conversation' ? highlightConversation : grayConversation"
+        alt=""
+      />
+    </div>
+  </div>
+  <!-- 去往联系人 -->
+  <div class="chat_contacts chat_icon_box" @click="changeSkipRouterName('contacts')">
+    <img
+      class="chat_contacts_icon"
+      :src="skipRouterName === 'contacts' ? highlightContacts : grayContacts"
+      alt=""
+    />
+  </div>
+</template>
+
+<style lang="scss" scoped>
+.chat_avatar {
+  margin-top: 43px;
+  position: relative;
+  width: 44px;
+  height: 44px;
+  transition: all 0.3s;
+
+  &:hover {
+    transform: scale(1.3);
+  }
+
+  span {
+    display: inline-block;
+    width: 100%;
+    height: 100%;
+  }
+
+  .online_status {
+    position: absolute;
+    right: 2px;
+    bottom: 2px;
+    display: inline-block;
+    width: 6px;
+    height: 6px;
+    border: 2px solid #fff;
+    background: #fff;
+    border-radius: 50%;
+    transition: all 0.3s;
+    cursor: pointer;
+
+    &:hover {
+      transform: scale(1.2);
+    }
+  }
+}
+
+.chat_icon_box {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  width: 100%;
+  height: 67px;
+  text-align: center;
+  line-height: 67px;
+  margin: 4px 0;
+}
+
+.chat_conversation {
+  .img_box {
+    position: relative;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    width: 30px;
+    height: 30px;
+
+    img {
+      display: inline-block;
+      width: 27px;
+      height: 27px;
+      transition: all 0.5s;
+
+      &:hover {
+        transform: scale(1.3);
+      }
+    }
+
+    .badge {
+      position: absolute;
+      right: 0;
+      top: 8px;
+      display: inline-block;
+      width: 7px;
+      height: 7px;
+      border-radius: 50%;
+      background: red;
+    }
+  }
+}
+
+.chat_contacts {
+  img {
+    display: inline-block;
+    width: 27px;
+    height: 27px;
+    transition: all 0.5s;
+
+    &:hover {
+      transform: scale(1.3);
+    }
+  }
+}
+
+.chat_settings {
+  position: absolute;
+  bottom: 92px;
+  font-size: 30px;
+  color: #8e8e8e;
+  cursor: pointer;
+  transition: all 0.5s;
+
+  &:hover {
+    color: #1b83f9;
+    transform: scale(1.3);
+  }
+
+  .chat_setting_item {
+    width: 100%;
+    height: 30px;
+  }
+}
+
+.more_settings {
+  position: absolute;
+  bottom: 46px;
+  color: #8e8e8e;
+  cursor: pointer;
+  transition: all 0.5s;
+
+  &:hover {
+    transform: scale(1.3);
+  }
+}
+
+.setting_fun_list {
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  align-items: center;
+
+  .func_item {
+    display: flex;
+    flex-direction: row;
+    align-items: center;
+    // justify-content: space-around;
+    width: 101px;
+    height: 40px;
+    border-radius: 3px;
+
+    &:hover {
+      background-color: #f2f2f2;
+    }
+
+    .settting_fun_icon {
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      margin-left: 5px;
+
+      img {
+        width: 20px;
+        height: 20px;
+      }
+    }
+
+    .setting_fun_text {
+      display: inline-block;
+      text-align: center;
+      margin-left: 12px;
+      height: 20px;
+      width: 58px;
+      font-weight: 400;
+      font-size: 14px;
+      line-height: 20px;
+      letter-spacing: 0.4px;
+      color: #333333;
+      cursor: pointer;
+    }
+
+    .apply_groups {
+      display: flex;
+      flex-direction: column;
+    }
+  }
+}
+
+.settting_fun_icon {
+  font-size: 20px;
+}
+
+.line {
+  display: inline-block;
+  width: 69px;
+  height: 1px;
+  border: 1px solid rgba(0, 0, 0, 0.0462467);
+}
+
+.components {
+  ::v-deep .edit_userinfo_diglog {
+    border-radius: 4px;
+    overflow: hidden;
+  }
+
+  ::v-deep .setting_func_diglog > .el-dialog__body {
+    padding: 28px 24px 24px 24px;
+  }
+
+  ::v-deep .setting_func_diglog > .el-dialog__header {
+    background: #f2f2f2;
+    margin: 0;
+  }
+
+  ::v-deep .edit_userinfo_diglog > .el-dialog__header {
+    padding: 0;
+    margin-right: 0;
+  }
+
+  ::v-deep .edit_userinfo_diglog > .el-dialog__body {
+    padding: 0;
+    border-radius: 4px;
+  }
+
+  ::v-deep .login_diglog > .el-dialog__header {
+    background: #f2f2f2;
+    margin: 0;
+  }
+
+  ::v-deep .personal_setting_card > .el-dialog__header {
+    background: #f2f2f2;
+    margin: 0;
+  }
+}
+</style>

+ 53 - 0
src/views/im/index.vue

@@ -0,0 +1,53 @@
+<script lang="ts" setup>
+import NavBar from './NavBar/index.vue'
+
+defineOptions({ name: 'IM' })
+</script>
+<template>
+  <div class="app-container">
+    <el-container class="chat_container">
+      <el-aside class="chat_nav_bar" width="72px">
+        <NavBar />
+      </el-aside>
+      <el-main class="chat_main_box">
+        <router-view />
+      </el-main>
+    </el-container>
+  </div>
+</template>
+<style lang="scss" scoped>
+.app-container {
+  position: fixed;
+  left: 0;
+  top: 0;
+  width: 100vw;
+  height: 100vh;
+  background-size: cover;
+  backdrop-filter: blur(5px);
+
+  .chat_container {
+    width: 85%;
+    height: 95%;
+    background: #fff;
+    position: relative;
+    top: 50%;
+    transform: translateY(-50%);
+    margin: auto auto;
+    border-radius: 5px;
+
+    .chat_nav_bar {
+      display: flex;
+      flex-direction: column;
+      align-items: center;
+      border-radius: 5px 0 0 5px;
+      width: 80px;
+      background: #262626;
+      overflow: hidden;
+    }
+
+    .chat_main_box {
+      padding: 0;
+    }
+  }
+}
+</style>

+ 1 - 1
vite.config.ts

@@ -1,4 +1,4 @@
-import { resolve } from 'path'
+ import { resolve } from 'path'
 import { loadEnv } from 'vite'
 import type { UserConfig, ConfigEnv } from 'vite'
 import { createVitePlugins } from './build/vite'