瀏覽代碼

zoom对接

jackson 11 月之前
父節點
當前提交
1aa1093f9d

文件差異過大導致無法顯示
+ 1 - 2397
package-lock.json


+ 1 - 0
package.json

@@ -12,6 +12,7 @@
     "axios": "^1.7.2",
     "vant": "^3.5.2",
     "vue": "^3.2.25",
+    "vue-clipboard3": "^2.0.0",
     "vue-router": "^4.1.2",
     "vue3-emoji": "^1.3.0",
     "vuex": "^4.0.2"

+ 14 - 0
src/api/index.ts

@@ -104,3 +104,17 @@ export function noReadNum(data: Obj) {
     data,
   })
 }
+
+export function creatZoom(data: Obj) {
+  return request({
+    url: '/goim/zoom/creatZoom',
+    data
+  })
+}
+
+export function get_zoom_token(data: Obj) {
+  return request({
+    url: '/goim/zoom/token',
+    data
+  })
+}

+ 16 - 0
src/api/tmp.txt

@@ -92,3 +92,19 @@ nickname
   fromId  int
   toId    int
   messageType  int
+
+
+先创建room
+/goim/zoom/creatZoom?token
+ 参数json
+ zoomName
+
+获取accsess_token
+/goim/zoom/token?token
+ 参数json
+ zoomId   creatZoom返回的uuid
+
+用户加人聊天
+/goim/zoom/token?token
+ 参数json
+ zoomId   creatZoom返回的uuid

+ 8 - 3
src/assets/styles/common.less

@@ -23,6 +23,11 @@ body {
   color: #222;
 }
 
+a {
+  cursor: pointer;
+  color: var(--van-button-primary-background-color);
+}
+
 #app {
   height: 100%;
   display: flex;
@@ -49,11 +54,11 @@ body {
   }
 }
 
-.common-pop{
+.common-pop {
   min-width: 300px;
   border-radius: 8px;
 
-  .close{
+  .close {
     position: absolute;
     font-size: 22px;
     right: 12px;
@@ -78,7 +83,7 @@ body {
     text-align: center;
   }
 
-  img{
+  img {
     max-width: 100%;
     max-height: 100%;
   }

+ 1 - 2
src/components/V3Emoji.vue

@@ -117,7 +117,7 @@ const props = withDefaults(
           cols: 30,
           resize: 'none'
         };
-      }
+      },
     }
 );
 const textValue = ref(props.modelValue);
@@ -160,7 +160,6 @@ const recordCursor = (focus: boolean) => {
   focus && (isPollupShow.value = false);
 };
 watchEffect(() => {
-  emit('update:modelValue', textValue.value);
   emit('update:modelValue', textValue.value);
   emit('changeText', textValue.value);
 });

+ 10 - 3
src/config/index.ts

@@ -1,5 +1,12 @@
-export default {
-  baseUrl: import.meta.env.MODE === 'production' ? '' : 'http://20.189.74.163:3111',
+const isProduction = import.meta.env.MODE === 'production'
 
-  socketUrl: import.meta.env.MODE === 'production' ? 'wss://www.ops66.cc:3103/sub' : 'ws://20.189.74.163:3102/sub'
+export default {
+  // api基础地址
+  baseUrl: isProduction ? '' : 'http://20.189.74.163:3111',
+  // websocket地址
+  socketUrl: isProduction ? 'wss://www.ops66.cc:3103/sub' : 'ws://20.189.74.163:3102/sub',
+  // zoom域名
+  zoomDomain: isProduction ? 'https://www.ops777777.cc' : 'http://localhost:3000',
+  // zoom的websocket地址
+  zoomSocketUrl: isProduction ? 'wss://m.ops777777.cc' : 'ws://20.189.74.163:7880',
 }

+ 5 - 0
src/router/index.ts

@@ -16,6 +16,11 @@ const routes: Array<RouteRecordRaw> = [
     name: "Register",
     component: () => import("@/views/Register.vue"),
   },
+  {
+    path: '/zoomLoading',
+    name: "ZoomLoading",
+    component: () => import("@/views/ZoomLoading.vue"),
+  },
   {
     path: '/:pathMatch(.*)',
     redirect: '/',

+ 3 - 3
src/utils/request.ts

@@ -1,4 +1,4 @@
-import axios from 'axios'
+import axios, {AxiosResponse, InternalAxiosRequestConfig} from 'axios'
 import Config from '../config'
 import {Obj} from "../interface"
 import {Toast} from 'vant'
@@ -16,7 +16,7 @@ const service = axios.create({
   method: 'post',
 })
 
-service.interceptors.request.use((config: Obj): Obj => {
+service.interceptors.request.use((config: InternalAxiosRequestConfig) => {
     if (store.state.userInfo.token) {
       config.params = {...config.params, token: store.state.userInfo.token}
     }
@@ -28,7 +28,7 @@ service.interceptors.request.use((config: Obj): Obj => {
   }
 )
 
-service.interceptors.response.use((response: Obj): Obj => {
+service.interceptors.response.use((response: AxiosResponse) => {
     const data = response.data
     if (data.code === 0) {
       return data

+ 22 - 0
src/views/ZoomLoading.vue

@@ -0,0 +1,22 @@
+<template>
+
+</template>
+
+<script setup lang="ts">
+import {Toast} from "vant";
+import {get_zoom_token} from "../api";
+import {useRoute} from "vue-router";
+import config from "../config";
+
+const route = useRoute()
+const joinZoom = async () => {
+  Toast.loading('加载中...')
+  let {data} = await get_zoom_token({zoomId: route.query.uuid})
+  window.location.href = `${config.zoomDomain}/#/room/?url=${config.zoomSocketUrl}&token=${data}`
+}
+joinZoom()
+</script>
+
+<style lang="less" scoped>
+
+</style>

+ 80 - 11
src/views/home/right/components/Chat.vue

@@ -5,7 +5,8 @@
                 @click="store.commit('setIsShowRight', false)"/>
       <div class="common-pic" @click="showInfo">{{ store.state.chatUserInfo.friendName.charAt(0) }}</div>
       <div class="username" @click="showInfo">{{ friendName }}</div>
-      <van-popover v-model:show="showPopover"
+      <van-popover class="chat-popover"
+                   v-model:show="showPopover"
                    :actions="actions[store.state.chatUserInfo.isGroup]"
                    placement="bottom-end"
                    :offset="[15, 5]"
@@ -50,25 +51,46 @@
           size="small"
           fix-pos="upleft"
           v-model="message"
+          :send-msg="sendMsg"
       />
       <van-button type="primary" size="small" :disabled="!message.trim()" class="send-btn" @click="sendMsg">
         <span class="text">发送</span>
       </van-button>
     </div>
+    <van-popup v-model:show="show" class="common-pop">
+      <van-icon name="close" class="close" @click="show=false"/>
+      <div class="title">创建会议链接</div>
+      <div class="form">
+        <van-cell-group inset>
+          <van-field v-model="room" label="房间编号"/>
+        </van-cell-group>
+      </div>
+      <div class="footer" @click="createRoom">确定</div>
+    </van-popup>
   </div>
 </template>
 
 <script lang="ts">
 import V3Emoji from '../../../../components/V3Emoji.vue'
-import {computed, defineComponent, reactive, ref, toRefs, watch, nextTick} from "vue";
+import {computed, defineComponent, reactive, ref, toRefs, watch, nextTick, onUnmounted} from "vue";
 import Client from "../../../../utils/client";
 import GroupClient from "../../../../utils/groupClient";
-import {messageList, sendMessageToUser, sendMessageToGroup, deleteFriend, deleteExitGroup} from "../../../../api";
+import {
+  messageList,
+  sendMessageToUser,
+  sendMessageToGroup,
+  deleteFriend,
+  deleteExitGroup, creatZoom
+} from "../../../../api";
 import {useStore} from "vuex";
 import {Obj, StrObj, StrNumObj} from "../../../../interface";
 import {formatDateTime} from "../../../../utils"
 import EmojiData from '../../../../assets/emojidata/emoji-data.json';
 import RE from '../../../../utils/regExp'
+import {Toast, Dialog} from "vant"
+import useClipboard from "vue-clipboard3";
+
+const {toClipboard} = useClipboard()
 
 const emojiData: Emoji.JsonData = EmojiData;
 const emojiMap: any = {}
@@ -101,7 +123,8 @@ interface State {
   showPopover: boolean,
   actions: Obj,
   currentAction: StrObj,
-  windowName: Window | null
+  show: boolean,
+  room: string
 }
 
 export default defineComponent({
@@ -117,11 +140,12 @@ export default defineComponent({
       client: null,
       showPopover: false,
       actions: {
-        1: [{value: 'joinVideo', text: '加入视频'}, {value: 'deleteFriend', text: '删除好友'}],
-        2: [{value: 'joinVideo', text: '加入视频'}, {value: 'exitGroup', text: '离开群'}],
+        1: [{value: 'createLink', text: '创建会议链接'}, {value: 'deleteFriend', text: '删除好友'}],
+        2: [{value: 'createLink', text: '创建会议链接'}, {value: 'exitGroup', text: '离开群'}],
       },
       currentAction: {},
-      windowName: null
+      show: false,
+      room: ''
     })
 
     const optionsName = {
@@ -281,6 +305,9 @@ export default defineComponent({
 
     // 把表情包的英文名字转成表情包
     const messageFormat = (msg: string) => {
+      if (/^https?:\/\//.test(msg)) {
+        return `<a href="${msg}" target="_blank">${msg}</a>`
+      }
       return msg.replace(/__([^_]+)?__/g, (a, name) => `<b class="chat-emoji">${emojiMap[name] || ''}</b>`)
     }
 
@@ -304,11 +331,46 @@ export default defineComponent({
         store.commit('setIsShowChat', false)
         store.commit('setIsShowRight', false)
       }
-      if (action.value === 'joinVideo') {
-        state.windowName = window.open('https://www.ops777777.cc/?url=https%3A%2F%2Fm.ops777777.cc&token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MTk0MDU1MDgsImlzcyI6IkFQSUdQeEhqVTlpQ2dHbyIsIm5hbWUiOiJqYWNrc29uIiwibmJmIjoxNzE5MzE5MTA4LCJzdWIiOiJqYWNrc29uIiwidmlkZW8iOnsicm9vbSI6Im15LWZpcnN0LXJvb20xIiwicm9vbUpvaW4iOnRydWV9fQ.WMuv_8iHb9gAucxbi9SxbXUW3SAaqQn-noBwF0uKCoU#/room?url=https%3A%2F%2Fm.ops777777.cc&token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MTk0MDU1MDgsImlzcyI6IkFQSUdQeEhqVTlpQ2dHbyIsIm5hbWUiOiJqYWNrc29uIiwibmJmIjoxNzE5MzE5MTA4LCJzdWIiOiJqYWNrc29uIiwidmlkZW8iOnsicm9vbSI6Im15LWZpcnN0LXJvb20xIiwicm9vbUpvaW4iOnRydWV9fQ.WMuv_8iHb9gAucxbi9SxbXUW3SAaqQn-noBwF0uKCoU&videoEnabled=1&audioEnabled=1&simulcast=0&dynacast=0&adaptiveStream=0&videoDeviceId=88cc2f5ccef42f15c7eed1f10d687cc4c7bc7c8a204a3eaa26ab619f676f2ba1')
+      if (action.value === 'createLink') {
+        let {data} = await creatZoom({zoomName: store.state.userInfo.username})
+        let message = window.location.origin + '/#/zoomLoading?uuid=' + data.uuid
+        Dialog.alert({
+          title: '会议链接创建成功',
+          message,
+          confirmButtonText: '复制链接'
+        }).then(() => {
+          toClipboard(message).then(() => {
+            Toast.success('复制成功')
+          })
+        })
+      }
+    }
+
+    const createRoom = async () => {
+      if (!state.room.trim()) {
+        return Toast('请输入房间编号')
       }
+      if (!/^\w+$/.test(state.room)) {
+        return Toast('房间编号由字母或数字组成')
+      }
+      Toast.loading('加载中...')
+      state.show = false
     }
 
+
+    const handleKeydown = (e: KeyboardEvent) => {
+      if (state.message.trim() && !e.shiftKey && e.key === 'Enter') {
+        document.getElementById('textarea')?.blur()
+        sendMsg()
+      }
+    }
+
+    window.addEventListener('keydown', handleKeydown)
+
+    onUnmounted(() => {
+      window.removeEventListener('keydown', handleKeydown)
+    })
+
     return {
       ...toRefs(state),
       store,
@@ -321,7 +383,8 @@ export default defineComponent({
       optionsName,
       messageFormat,
       selectAction,
-      clickEmoji
+      clickEmoji,
+      createRoom
     }
   }
 })
@@ -333,6 +396,12 @@ export default defineComponent({
   vertical-align: middle;
   margin: 0 2px;
 }
+
+.chat-popover {
+  .van-popover__action:hover {
+    background: #f1f1f1;
+  }
+}
 </style>
 
 <style lang="less" scoped>
@@ -430,7 +499,7 @@ export default defineComponent({
   }
 
   .send-btn {
-    margin-left: 8px;
+    margin-left: 6px;
     margin-bottom: 9px;
 
     .text {

+ 3 - 3
vite.config.ts

@@ -16,12 +16,12 @@ export default defineConfig({
   resolve: {
     alias: [{find: '@', replacement: '/src'}],
   },
-  // server: {
+  server: {
     // 更换ip
     // host: '192.168.2.27',
     // 更换端口号
-    //port: 8888
-  // },
+    port: 8888
+  },
   //生产环境打包配置,去除 console debugger
   build: {
     terserOptions: {

部分文件因文件數量過多而無法顯示