Browse Source

init demo
Signed-off-by: Caner <5658514@qq.com>

Caner 2 years ago
parent
commit
bacccbf0a2

+ 1 - 0
.env

@@ -0,0 +1 @@
+VITE_PROXY_URL=http://sms_test.zkyxit.com:28181

+ 40 - 0
index.html

@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<html lang="zh">
+
+<head>
+  <meta charset="UTF-8" />
+  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+  <style>
+    html,
+    body {
+      user-select: none;
+      margin: 0;
+      padding: 0;
+      overflow: hidden;
+    }
+
+    *::-webkit-scrollbar {
+      width: 4px;
+    }
+
+    *::-webkit-scrollbar-thumb {
+      border-radius: 10px;
+      box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
+      background: rgba(0, 0, 0, 0.2);
+    }
+
+    *::-webkit-scrollbar-track {
+      box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
+      border-radius: 0;
+      background: rgba(0, 0, 0, 0.1);
+
+    }
+  </style>
+</head>
+
+<body>
+  <div id="app"></div>
+  <script type="module" src="./src/main.ts"></script>
+</body>
+
+</html>

+ 17 - 0
package.json

@@ -0,0 +1,17 @@
+{
+  "name": "sms_app_vide_chat",
+  "private": true,
+  "version": "0.0.1",
+  "scripts": {
+    "dev": "vite",
+    "build": "vite build;rm -Force -R ../../../sms/public/libs/metting;cp -Force -R ../../build/dist/metting ../../../sms/public/libs/metting"
+  },
+  "dependencies": {
+    "axios": "^1.4.0",
+    "livekit-client": "^1.9.7",
+    "naive-ui": "^2.33.3"
+  },
+  "devDependencies": {
+    "vite": "4.1.3"
+  }
+}

+ 431 - 0
src/App.vue

@@ -0,0 +1,431 @@
+
+<script setup lang="ts">
+import { NButton, NTooltip, NPopover, zhCN, dateZhCN, NConfigProvider } from 'naive-ui'
+import inviteFriends from '@/components/invite-friends.vue'
+import { computed, onMounted, onUnmounted, ref, nextTick } from 'vue'
+import overrides from './assets/theme/naive.js'
+import ChatComponent from '@/components/chat.vue'
+import { LocalParticipant, RemoteParticipant, RemoteTrack, LocalTrackPublication, Room, RoomEvent, DataPacket_Kind, Participant } from 'livekit-client';
+import ApiService from './services/api.service'
+
+const apiService = new ApiService()
+const live_url = computed(() => localStorage.getItem('live_url'))
+const live_token = computed(() => localStorage.getItem('live_token'))
+const live_yhid = computed(() => localStorage.getItem('live_yhid'))
+const live_hyid = computed(() => localStorage.getItem('live_hyid'))
+const isClient = window.electron
+const inviteShow = ref(false)
+const expanded = ref([1])
+const chatShow = ref(false)
+const localVideoDom = ref()
+const VideoDomList = ref([] as Any)
+const encoder = new TextEncoder()
+const decoder = new TextDecoder()
+const msgData = ref([])
+const currentClick = ref(0)
+
+apiService.getMettingPep({ yhid: live_yhid.value, hyid: live_hyid.value }).then(({ data }) => {
+  const newData = data || []
+  VideoDomList.value = newData.map(el => ({ ...el, yhtx: '/api/file/preview/' + el.yhtx, name: el.yhid == live_yhid.value ? '我' : el.yhmc, id: el.yhid == live_yhid.value ? 0 : el.yhid, audio: false, tracks: [] })).sort((a, b) => a.id - b.id)
+  console.log(66, VideoDomList.value);
+
+})
+
+
+// initRoom
+const videoCallRoom: Room | null = new Room()
+  .on(RoomEvent.TrackSubscribed, onRemoteTrack)
+  .on(RoomEvent.Disconnected, close)
+  .on(RoomEvent.Connected, () => console.log('房间已连接'))
+  .on(RoomEvent.Reconnected, () => console.log('房间已重新连接'))
+  .on(RoomEvent.ConnectionStateChanged, (e) => console.log('连接状态改变', e))
+  .on(RoomEvent.ParticipantConnected, (e) => console.log('参与者加入:', e.name))
+  .on(RoomEvent.ParticipantDisconnected, onRemoteLeave)
+  .on(RoomEvent.LocalTrackPublished, onLocalTrack)
+  .on(RoomEvent.DataReceived, onDataReceived)
+
+// 监听本地流程
+function onLocalTrack(localTrackPublication: LocalTrackPublication, localParticipant: LocalParticipant) {
+  VideoDomList.value[0].audio = true
+  VideoDomList.value[0].tracks.push(localTrackPublication.track)
+  const dom = document.getElementById('remote_' + VideoDomList.value[0].id) as HTMLVideoElement
+  if (localTrackPublication.kind === 'video') localTrackPublication.track.attach(dom)
+}
+
+// 监听远程流
+function onRemoteTrack(remoteTrack: RemoteTrack, _, remoteParticipant: RemoteParticipant) {
+  console.log('远程流', remoteParticipant)
+
+  // 远程保存
+  const _index = VideoDomList.value.findIndex(el => el.id == remoteParticipant.identity)
+  if (_index >= 0) {
+    VideoDomList.value[_index].tracks.push(remoteTrack)
+  } else {
+    VideoDomList.value.push({
+      id: remoteParticipant.identity,
+      name: remoteParticipant.name,
+      audio: remoteTrack.kind === 'audio' ? remoteTrack.isMuted ? false : true : true,
+      tracks: [remoteTrack]
+    })
+
+  }
+
+  // 远程流赋值
+  nextTick(() => {
+    const dom = document.getElementById('remote_' + remoteParticipant.identity) as HTMLVideoElement
+    remoteTrack.attach(dom)
+  })
+}
+
+// 参与者离开
+function onRemoteLeave(participant: RemoteParticipant) {
+  console.log('参与者离开', participant);
+  // 移除dom
+  VideoDomList.value.forEach(function (item) {
+    if (item.id == participant.identity) {
+      item.tracks[0].detach()
+      item.tracks[1].detach()
+      item.tracks = []
+    }
+  })
+}
+
+// 监听消息
+function onDataReceived(payload: Uint8Array, participant: Participant, kind: DataPacket_Kind) {
+  const strData = decoder.decode(payload)
+  console.log('消息', strData, participant, kind);
+  const { name, identity } = participant
+  const { yhtx } = VideoDomList.value.find(el => el.yhid == identity) || { yhtx: '' }
+  const obj = {
+    name,
+    yhtx,
+    time: new Date().toLocaleString(),
+    strData
+  }
+  msgData.value.push(obj)
+}
+
+// 连接房间=>发布本地流
+async function roomConnect(url: string, token: string) {
+  if (!videoCallRoom) console.error('未初始化')
+  // 连接房间
+  await videoCallRoom!.connect(url, token!)
+  // 发布本地视频和音频track
+  await videoCallRoom!.localParticipant.enableCameraAndMicrophone()
+  console.log('加入房间,发布本地流')
+}
+
+// 切换
+function fnEvent(type: number, item?: Any) {
+  if (type === 3) {
+    inviteShow.value = true
+  } else if (type === 4 || type === 5) {
+    if (currentClick.value === type) {
+      chatShow.value = !chatShow.value
+    } else {
+      expanded.value = type === 4 ? [1] : [2]
+      chatShow.value = true
+      currentClick.value = type
+    }
+  } else if (type === 1) {
+    const audioTrack = item.tracks.find(el => el.kind === 'audio')
+    if (!audioTrack) return
+    if (item.id) {
+      const dom = document.getElementById('remote_' + item.id) as HTMLVideoElement
+      dom.muted = item.audio
+    } else {
+      item.audio ? audioTrack.unmute() : audioTrack.mute()
+    }
+    item.audio = !item.audio
+  } else if (type === 2) {
+    const data = encoder.encode(item)
+    if (videoCallRoom.state === 'connected') {
+      videoCallRoom.localParticipant.publishData(data, DataPacket_Kind.RELIABLE)
+      const { yhtx } = VideoDomList.value.find(el => el.yhid == live_yhid.value) || { yhtx: '' }
+      const obj = {
+        name: '我',
+        yhtx,
+        time: new Date().toLocaleString(),
+        strData: item
+      }
+      msgData.value.push(obj)
+    }
+  }
+}
+
+// 关闭视频|及弹窗
+function close() {
+  videoCallRoom!.localParticipant.setCameraEnabled(false)
+  videoCallRoom!.localParticipant.setMicrophoneEnabled(false)
+  videoCallRoom!.disconnect()
+  localVideoDom.value = null
+  window.electron?.send('closeMetting')
+  console.log('断开连接')
+}
+
+// 最小化
+function minus() {
+  window.electron?.send('minusMetting')
+}
+
+// init
+onMounted(async () => {
+  await roomConnect(live_url.value!, live_token.value!)
+})
+
+// close
+onUnmounted(() => {
+  close()
+})
+</script>
+<template>
+  <n-config-provider preflight-style-disabled inline-theme-disabled :locale="zhCN" :date-locale="dateZhCN"
+    :theme-overrides="overrides">
+    <div class="metting">
+      <div class="metting-top" v-if="isClient">
+        <div class="metting-top-left">
+          <div class="metting-top-left-left">
+            <Icon name="signal" :size="18" />
+            <span>我的视频会议</span>
+            <span>|</span>
+            <span>00:00:00</span>
+            <span>|</span>
+            <span>3人参会中</span>
+          </div>
+          <div class="metting-top-left-right">
+            视频会议
+          </div>
+        </div>
+
+        <div class="metting-top-right">
+          <n-tooltip placement="bottom" trigger="hover">
+            <template #trigger>
+              <Icon name="minus" :size="25" color="white" @click="minus" />
+            </template>
+            最小化
+          </n-tooltip>
+          <n-tooltip placement="bottom" trigger="hover">
+            <template #trigger>
+              <Icon name="close" :size="23" color="white" @click="close" />
+            </template>
+            关闭
+          </n-tooltip>
+        </div>
+
+      </div>
+      <div class="metting-content">
+        <div class="metting-content-left">
+          <div class="metting-content-left-top">
+            <template v-for="(item, i) in VideoDomList" :key="i">
+              <div class="video-remote">
+                <video :id="'remote_' + item.id" autoplay playsinline></video>
+                <div class="video-remote-bottom">
+                  <div class="video-remote-bottom-left"> {{ item.name }}</div>
+                  <div class="video-remote-bottom-right">
+                    <Icon name="mic" :size="30" v-if="item.audio" @click="fnEvent(1, item)" />
+                    <icon name="prohibition" :size="30" v-else @click="fnEvent(1, item)" />
+                  </div>
+                </div>
+              </div>
+            </template>
+          </div>
+          <div class="metting-content-left-bottom">
+            <div class="metting-content-left-bottom-left" />
+            <div class="metting-content-left-bottom-center">
+              <div @click="fnEvent(3)" v-if="isClient">
+                <icon name="addPep" :size="30" />
+                <p>邀请</p>
+              </div>
+              <div>
+                <Icon name="pes" :size="30" @click="fnEvent(4)" />
+                <p>成员</p>
+              </div>
+              <div>
+                <Icon name="msg" :size="30" @click="fnEvent(5)" />
+                <p>聊天</p>
+              </div>
+            </div>
+            <div class="metting-content-left-bottom-right">
+              <n-popover trigger="click" v-if="isClient">
+                <template #trigger>
+                  <n-button type="error">结束会议</n-button>
+                </template>
+                <n-button type="error" block>离开会议</n-button>
+                <n-button type="error" block style="margin-top: 10px;">结束会议</n-button>
+              </n-popover>
+            </div>
+          </div>
+        </div>
+        <ChatComponent v-model:expanded="expanded" v-model="chatShow" :data="VideoDomList"
+          @changeAudio="(data: object) => fnEvent(1, data)" @sendMSG="(data: string) => fnEvent(2, data)"
+          :msgData="msgData" />
+      </div>
+      <!-- 邀请 -->
+      <inviteFriends v-model="inviteShow" />
+    </div>
+  </n-config-provider>
+</template>
+<style scoped lang="scss">
+.metting {
+  width: 100vw;
+  height: 100vh;
+  min-width: 1270px;
+  min-height: 770px;
+  background: black;
+  overflow: hidden;
+  display: flex;
+  flex-flow: column;
+
+  &-top {
+    height: 50px;
+    width: 100%;
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    -webkit-app-region: drag;
+    color: #D9D9D9;
+    font-size: 17px;
+    background: #212124;
+    position: relative;
+
+    &-left {
+      flex: 1;
+      display: flex;
+      align-items: center;
+      margin-left: 15px;
+
+      &-left {
+        width: 50%;
+        display: flex;
+        align-items: center;
+
+        &>span:nth-child(2n) {
+          margin: 0 10px;
+        }
+      }
+    }
+
+    &-right {
+      -webkit-app-region: no-drag;
+      margin-right: 10px;
+
+      &>svg {
+        cursor: pointer;
+
+        &:not(:first-child) {
+          margin-left: 10px;
+        }
+      }
+
+    }
+
+  }
+
+  &-content {
+    width: 100%;
+    display: flex;
+    flex: 1;
+    align-items: flex-start;
+    justify-content: space-between;
+    color: white;
+    overflow: hidden;
+
+    &-left {
+      flex: 1;
+      height: 100%;
+
+      &-top {
+        height: calc(100% - 77px);
+        display: flex;
+        overflow-y: auto;
+        overflow-x: hidden;
+        flex-flow: wrap;
+        align-content: baseline;
+        padding-bottom: 0.53%;
+
+        .video-remote {
+          position: relative;
+          width: 24.6%;
+          height: 28%;
+          border-radius: 5px;
+          overflow: hidden;
+          background-color: #2d2d31;
+
+          &:not(:nth-child(4n)) {
+            margin-right: 0.53%;
+          }
+
+          &:nth-child(n+5) {
+            margin-top: 0.53%;
+          }
+
+          video {
+            width: 100%;
+            height: 100%;
+            object-fit: fill;
+          }
+
+          &-bottom {
+            position: absolute;
+            bottom: 0;
+            left: 0;
+            right: 0;
+            display: flex;
+            align-items: center;
+            justify-content: space-between;
+            padding: 3px 10px;
+
+            &-left {
+              display: flex;
+              flex-direction: column;
+              justify-content: space-between;
+            }
+
+            &-right {
+              svg {
+                margin: 0 2px;
+                cursor: pointer;
+              }
+
+            }
+          }
+        }
+      }
+
+      &-bottom {
+        height: 76px;
+        display: flex;
+        align-items: center;
+        justify-content: space-between;
+        background: #212124;
+
+        &>div {
+          display: flex;
+
+          &>div {
+            text-align: center;
+            cursor: pointer;
+
+            p {
+              margin: 0;
+            }
+
+            &:not(:first-child) {
+              margin-left: 20px;
+            }
+          }
+
+        }
+
+        &-left {
+          margin-left: 40px;
+        }
+
+        &-right {
+          margin-right: 20px;
+        }
+      }
+    }
+  }
+}
+</style>

+ 13 - 0
src/assets/icons/addPep.svg

@@ -0,0 +1,13 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="38" height="38" viewBox="0 0 38 38">
+<defs>
+<style>.a,.b{fill:#fff;}.b{opacity:0;}.c{clip-path:url(#a);}</style>
+<clipPath id="a"><rect class="a" width="23.231" height="24.065"/></clipPath>
+</defs>
+<g transform="translate(-589 -834)">
+<rect class="b" width="38" height="38" transform="translate(589 834)"/><g transform="translate(596 840)">
+<g class="c" transform="translate(0 0)">
+<path class="a" d="M17.3,13.073A5.9,5.9,0,0,0,14.031,23.21q-1.689.165-3.368.165a36.446,36.446,0,0,1-9.6-1.32A1.092,1.092,0,0,1,0,20.934V20.9a.05.05,0,0,0,0-.021c0-.044.005-.083.011-.123a11.336,11.336,0,0,1,6.1-9.053,7.236,7.236,0,0,0,9.236.068A10.664,10.664,0,0,1,17.3,13.073ZM4.677,6.06a6.094,6.094,0,1,1,12.187.067q0,.073,0,.146A6.094,6.094,0,0,1,4.677,6.06M18.09,24.065a5.141,5.141,0,1,1,5.141-5.141,5.141,5.141,0,0,1-5.141,5.141m-.381-5.712H15.423a.571.571,0,1,0,0,1.142h2.285V21.78a.571.571,0,0,0,1.142,0V19.5h2.285a.571.571,0,1,0,0-1.142H18.851V16.068a.571.571,0,0,0-1.142,0Z" transform="translate(0 0)"/>
+</g>
+</g>
+</g>
+</svg>

+ 3 - 0
src/assets/icons/close.svg

@@ -0,0 +1,3 @@
+<svg width="12" height="12" viewBox="0 0 12 12" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M6.71148 6.00003L9.89087 2.82065L9.17852 2.10829L5.99916 5.28765L2.81978 2.10828L2.10743 2.82063L5.28677 5.99998L2.10742 9.17933L2.81978 9.89169L5.99913 6.71234L9.17849 9.8917L9.89081 9.17938L6.71148 6.00003Z" />
+</svg>

+ 1 - 0
src/assets/icons/mic.svg

@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="38" height="38" viewBox="0 0 38 38"><defs><style>.a{fill:#fff;stroke:#707070;opacity:0;}.b{fill:#ccc;}.c{stroke:none;}.d{fill:none;}</style></defs><g transform="translate(-38 -834)"><g class="a" transform="translate(38 834)"><rect class="c" width="38" height="38"/><rect class="d" x="0.5" y="0.5" width="37" height="37"/></g><path class="b" d="M221.345,70.5a5.133,5.133,0,0,0-5.291,4.958v8.716a5.3,5.3,0,0,0,10.583,0V75.458a5.133,5.133,0,0,0-5.291-4.958Zm-9.038,12.434a1.068,1.068,0,0,0-1.1,1.033.844.844,0,0,0,.023.207h-.023a9.733,9.733,0,0,0,8.819,9.413v2.568H218.26a1.243,1.243,0,1,0,0,2.48h6.173a1.243,1.243,0,1,0,0-2.48h-1.764V93.587a9.757,9.757,0,0,0,8.8-9,1.039,1.039,0,0,0,.023-.207c0-.025-.007-.047-.007-.069,0-.047.007-.091.007-.138h-.023a1.121,1.121,0,0,0-2.163,0h-.023a7.954,7.954,0,0,1-15.874,0h-.023a1.037,1.037,0,0,0,.023-.207,1.063,1.063,0,0,0-1.1-1.033Zm0,0" transform="translate(-164.205 769.607)"/></g></svg>

+ 1 - 0
src/assets/icons/minus.svg

@@ -0,0 +1 @@
+<svg t="1678256645098" class="icon" viewBox="0 0 1025 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4822" xmlns:xlink="http://www.w3.org/1999/xlink" width="200.1953125" height="200"><path d="M895.531061 534.934007 126.604444 534.934007c-13.5716 0-24.573248-11.001648-24.573248-24.573248s11.001648-24.573248 24.573248-24.573248l768.926616 0c13.5716 0 24.573248 11.001648 24.573248 24.573248S909.102661 534.934007 895.531061 534.934007z" p-id="4823"></path></svg>

+ 1 - 0
src/assets/icons/msg.svg

@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="38" height="38" viewBox="0 0 38 38"><defs><style>.a,.b{fill:#fff;}.a{opacity:0;}</style></defs><g transform="translate(-763 -834)"><rect class="a" width="38" height="38" transform="translate(763 834)"/><path class="b" d="M72.818,60.387a11,11,0,0,1,4.474.863,11.97,11.97,0,0,1,3.676,2.42,11.338,11.338,0,0,1,3.44,8.071,10.925,10.925,0,0,1-.772,4.238A11.27,11.27,0,0,1,81.412,79.5a12.178,12.178,0,0,1-3.349,2.525,11.607,11.607,0,0,1-4.147,1.23q-.576.078-1.23.131t-1.452.078q-.8.026-1.779,0t-2.211-.157a21.162,21.162,0,0,1-4.042-.68q-1.321-.419-1.06-.471a7.96,7.96,0,0,0,2.381-.759.738.738,0,0,0,.432-.824,2.021,2.021,0,0,0-.51-1.007,11.908,11.908,0,0,1-2.158-3.414,11.36,11.36,0,0,1-.876-4.2,11,11,0,0,1,.863-4.474,11.691,11.691,0,0,1,2.433-3.663,11.518,11.518,0,0,1,3.637-2.485A11.356,11.356,0,0,1,72.818,60.387ZM77.92,71.9a1.61,1.61,0,0,0,.471,1.164,1.545,1.545,0,0,0,1.151.484A1.652,1.652,0,0,0,81.19,71.9a1.544,1.544,0,0,0-.484-1.151,1.61,1.61,0,0,0-1.164-.471A1.608,1.608,0,0,0,77.92,71.9Zm-6.567,0a1.674,1.674,0,0,0,2.865,1.177,1.674,1.674,0,0,0-2.368-2.368A1.6,1.6,0,0,0,71.353,71.9Zm-6.488-.026a1.631,1.631,0,0,0,.484,1.177,1.567,1.567,0,0,0,1.164.5,1.6,1.6,0,0,0,1.19-.5,1.631,1.631,0,0,0,.484-1.177,1.587,1.587,0,0,0-.484-1.164,1.618,1.618,0,0,0-1.19-.484,1.652,1.652,0,0,0-1.648,1.648Z" transform="translate(709.589 779.613)"/></g></svg>

+ 1 - 0
src/assets/icons/openshow.svg

@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="20.428" height="17.208" viewBox="0 0 20.428 17.208"><defs><style>.a{fill:#fff;}</style></defs><path class="a" d="M97.194,164.014H93.822a.712.712,0,0,1-.712-.712V159.93a.712.712,0,0,1,.712-.712h3.372a.712.712,0,0,1,.712.712V163.3a.712.712,0,0,1-.712.712Zm15.632,0h-12.8a.714.714,0,0,1-.714-.712V159.93a.712.712,0,0,1,.714-.712h12.8a.712.712,0,0,1,.712.712V163.3A.712.712,0,0,1,112.826,164.014Zm0,6.2h-12.8a.714.714,0,0,1-.714-.714v-3.371a.714.714,0,0,1,.714-.714h12.8a.712.712,0,0,1,.712.714V169.5a.712.712,0,0,1-.712.714Zm0,6.208h-12.8a.714.714,0,0,1-.714-.714v-3.371a.712.712,0,0,1,.714-.712h12.8a.712.712,0,0,1,.712.712v3.371a.712.712,0,0,1-.712.714Zm-15.632-6.208H93.822a.712.712,0,0,1-.712-.714v-3.371a.712.712,0,0,1,.712-.714h3.372a.712.712,0,0,1,.712.714V169.5a.712.712,0,0,1-.712.714Zm0,6.2H93.822a.712.712,0,0,1-.712-.712v-3.372a.712.712,0,0,1,.712-.712h3.372a.712.712,0,0,1,.712.712v3.372a.712.712,0,0,1-.712.712Z" transform="translate(-93.11 -159.217)"/></svg>

+ 1 - 0
src/assets/icons/pes.svg

@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="38" height="38" viewBox="0 0 38 38"><defs><style>.a,.b{fill:#fff;}.a{opacity:0;}</style></defs><g transform="translate(-676 -834)"><rect class="a" width="38" height="38" transform="translate(676 834)"/><g transform="translate(683 840)"><path class="b" d="M212.555,124.155m-5.255,0a5.255,5.255,0,1,0,5.255-5.255A5.255,5.255,0,0,0,207.3,124.155Z" transform="translate(-203.398 -117.398)"/><path class="b" d="M81.717,84.371c0,4.591-18.317,4.591-18.317,0s4.1-7.354,9.157-7.354S81.717,79.78,81.717,84.371ZM79.163,63.5A5.234,5.234,0,0,0,75.8,64.718a6.1,6.1,0,0,1,2.226,9.168,5.2,5.2,0,0,0,1.133.125,5.255,5.255,0,0,0,0-10.51Z" transform="translate(-63.4 -63.5)"/><path class="b" d="M521.226,513.2a10.33,10.33,0,0,0-2.826.437c3.574.727,7.46,3.506,7.46,7.948a2.661,2.661,0,0,1-.778,1.841c2.986-.488,5.3-1.578,5.3-3.27C530.385,515.4,526.283,513.2,521.226,513.2Z" transform="translate(-506.062 -501.006)"/></g></g></svg>

+ 1 - 0
src/assets/icons/prohibition.svg

@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="27" height="27" viewBox="0 0 27 27"><defs><style>.a{fill:#b3b3b3;}.b{fill:#fff;opacity:0;}.c{clip-path:url(#a);}</style><clipPath id="a"><rect class="a" width="14.798" height="19.823"/></clipPath></defs><g transform="translate(-1615 -340)"><rect class="b" width="27" height="27" transform="translate(1615 340)"/><g transform="translate(1620.895 344)"><g class="c" transform="translate(0)"><path class="a" d="M73.08,0h0Z" transform="translate(-65.753)"/><path class="a" d="M7.382,28.238a3.518,3.518,0,0,0,3.463-3.464V21.818l3.737-3.738a.735.735,0,0,0-1.04-1.04L.215,30.368a.735.735,0,0,0,1.04,1.04l1.616-1.616a6.681,6.681,0,0,0,3.578,1.615v1.806H5.277a.874.874,0,0,0-.054,1.748H9.381a.874.874,0,0,0,.054-1.748H8.208V31.407a6.705,6.705,0,0,0,5.848-6.341.771.771,0,0,0,.016-.146c0-.018,0-.033,0-.049,0-.034,0-.064,0-.1h-.016a.736.736,0,0,0-1.438,0H12.6a5.275,5.275,0,0,1-8.715,4L5.168,27.5a3.5,3.5,0,0,0,2.214.743" transform="translate(0 -15.138)"/><path class="a" d="M44.983,2.913A3.519,3.519,0,0,0,38,3.494V9.636c0,.084.007.166.014.248Z" transform="translate(-34.188 0)"/><path class="a" d="M6.493,91.1l1.112-1.112a5.267,5.267,0,0,1-.292-1.73H7.3a.779.779,0,0,0,.015-.146.726.726,0,0,0-.725-.728H6.583a.73.73,0,0,0-.732.727h0a.63.63,0,0,0,.015.146H5.85A6.685,6.685,0,0,0,6.493,91.1" transform="translate(-5.264 -78.617)"/></g></g></g></svg>

+ 1 - 0
src/assets/icons/search.svg

@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><svg width="24" height="24" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M21 38C30.3888 38 38 30.3888 38 21C38 11.6112 30.3888 4 21 4C11.6112 4 4 11.6112 4 21C4 30.3888 11.6112 38 21 38Z" fill="none" stroke="#333" stroke-width="4" stroke-linejoin="round"/><path d="M26.657 14.3431C25.2093 12.8954 23.2093 12 21.0001 12C18.791 12 16.791 12.8954 15.3433 14.3431" stroke="#333" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/><path d="M33.2216 33.2217L41.7069 41.707" stroke="#333" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/></svg>

+ 1 - 0
src/assets/icons/signal.svg

@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><svg width="24" height="24" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M40 6V42" stroke="#333" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/><path d="M29 16V42" stroke="#333" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/><path d="M19 26V42" stroke="#333" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/><path d="M8 36V42" stroke="#333" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/></svg>

+ 1 - 0
src/assets/icons/video.svg

@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="38" height="38" viewBox="0 0 38 38"><defs><style>.a{fill:#fff;stroke:#707070;opacity:0;}.b{fill:#ccc;}.c{stroke:none;}.d{fill:none;}</style></defs><g transform="translate(-101 -834)"><g class="a" transform="translate(101 834)"><rect class="c" width="38" height="38"/><rect class="d" x="0.5" y="0.5" width="37" height="37"/></g><path class="b" d="M94.04,288.286a1.691,1.691,0,0,1-1.656,1.72H74.725a1.691,1.691,0,0,1-1.656-1.72V273.377a1.691,1.691,0,0,1,1.656-1.72h17.66a1.691,1.691,0,0,1,1.656,1.72v14.909Zm7.406-15.082L96.662,276.3v9.066l4.753,3.07a1.2,1.2,0,0,0,.759.262,1.08,1.08,0,0,0,1.042-1.112v-13.5a1.08,1.08,0,0,0-1.042-1.112A1.187,1.187,0,0,0,101.446,273.2Z" transform="translate(31.931 573.343)"/></g></svg>

+ 28 - 0
src/assets/theme/naive.js

@@ -0,0 +1,28 @@
+export default {
+    "common": {
+        "primaryColor": "#2791FEFF",
+        "primaryColorHover": "rgba(255,255,255,.5)",
+        "primaryColorPressed": "#1F74CBFF",
+        "primaryColorSuppl": "#93C8FEFF",
+        "textColor1": "#fff",
+        "textColor2": "#A6A6A6",
+        "textColor3": "#fff",
+        "borderColor": "#44474A",
+    },
+    "Icon": {
+        "color": "white"
+    },
+    "Input": {
+        "boxShadowFocus": "0 0 0 2px rgba(0,0,0,0)",
+        "borderHover": "1px solid rgba(255,255,255,0.2)"
+    },
+    "Collapse": {
+        "itemMargin": "0"
+    },
+    "Button": {
+        "borderPressed":"#A6A6A6",
+        "textColorPressed":"#A6A6A6",
+        "borderHover": "1px solid rgba(255,255,255,0.2)",
+        "rippleColor":"#A6A6A6"
+    }
+}

+ 252 - 0
src/components/chat.vue

@@ -0,0 +1,252 @@
+<script lang="ts" setup>
+import { NCollapse, NCollapseItem, NInput, NButton, NAvatar } from 'naive-ui'
+import { ref } from "vue"
+
+const props = defineProps<{
+    modelValue: boolean,
+    expanded: number[],
+    data: { name: string, zzmc: string, yhtx: string, audio: boolean, tracks: Any[] }[],
+    msgData: { name: string, yhtx: string, time: string, strData: string }[]
+}>()
+
+const emit = defineEmits<{
+    (evt: 'update:modelValue', value: boolean): void
+    (evt: 'update:expanded', value: number[]): void
+    (evt: 'changeAudio', value: object): void
+    (evt: 'sendMSG', value: string): void
+}>()
+
+const inputData = ref('')
+
+function handleItemHeaderClick(v: Any) {
+    if (v.expanded) {
+        emit('update:expanded', [...props.expanded, v.name])
+    }
+    else {
+        emit('update:expanded', [...props.expanded.filter(t => t !== v.name)])
+    }
+}
+
+function changeAudio(params: { name: string, zzmc: string, yhtx: string, audio: boolean, tracks: Any[] }) {
+    emit('changeAudio', params)
+}
+
+function countTrue() {
+    return props.data.filter(el => el.tracks.length).length
+}
+
+function sendMsg() {
+    if (inputData.value) emit('sendMSG', inputData.value)
+    inputData.value = ''
+}
+</script>
+<template>
+    <div class="chat-collapse" v-if="modelValue">
+        <n-collapse class="collapse-box" :expanded-names="expanded" @item-header-click="handleItemHeaderClick">
+            <n-collapse-item title="" :name="1" arrow-placement="left">
+                <template #header>
+                    <div class="collapse-box-resetHeader">
+                        <span>参会人({{ countTrue() }}/{{ data.length }})</span>
+                    </div>
+                </template>
+                <div class="member-list">
+                    <div class="member-list-item" v-for="(item, index) in data" :key="index">
+                        <div class="member-list-item-left">
+                            <n-avatar round size="large" :src="item.yhtx" />
+                            <div class="member-list-item-left-info">
+                                <span class="name">{{ item.name }}</span>
+                                <span class="organ">{{ item.zzmc }}</span>
+                            </div>
+                        </div>
+                        <div class="member-list-item-right">
+                            <div class="status"> {{ item.tracks.length ? '到场' : '未到场' }} </div>
+                            <Icon name="mic" :size="30" v-if="item.audio" @click="changeAudio(item)" />
+                            <Icon name="prohibition" :size="30" v-else @click="changeAudio(item)" />
+                        </div>
+                    </div>
+                </div>
+            </n-collapse-item>
+            <n-collapse-item title="聊天" :name="2" arrow-placement="right">
+                <div class="chat-list">
+                    <div class="chat-list-main">
+                        <div class="chat" v-for="(item, index) in msgData" :key="index + 'msg'">
+                            <div class="chat-top">
+                                <div class="user-info">
+                                    <n-avatar :size="32" :src="item.yhtx" />
+                                    <span class="name">{{ item.name }}</span>
+                                </div>
+                                <span class="time">{{ item.time }}</span>
+                            </div>
+                            <div class="chat-bottom">{{ item.strData }} </div>
+                        </div>
+                    </div>
+                    <div class="chat-list-foot" @keyup.enter="sendMsg">
+                        <n-input type="text" v-model:value="inputData" placeholder="请输入内容..." />
+                        <n-button color="#4B94FF" @click="sendMsg">发送</n-button>
+                    </div>
+                </div>
+            </n-collapse-item>
+        </n-collapse>
+    </div>
+</template>
+<style lang="scss" scoped>
+.chat-collapse {
+    height: 100%;
+    width: 330px;
+    box-sizing: border-box;
+    margin-left: 5px;
+    background: #212124;
+
+    &>button {
+        width: 100%;
+    }
+
+    :deep(.collapse-box) {
+        height: 100%;
+        display: flex;
+        flex-direction: column;
+
+        .n-collapse-item {
+            border: none;
+
+            .n-collapse-item__header {
+                padding: 0;
+
+                .n-collapse-item__header-main {
+                    padding: 12px 20px;
+                    background: #2F2F33;
+
+                    .collapse-box-resetHeader {
+                        width: 100%;
+                        display: flex;
+                        align-items: center;
+                        justify-content: space-between;
+
+                        &>button {
+                            font-size: 12px;
+                        }
+                    }
+                }
+            }
+
+            .n-collapse-item__content-wrapper {
+                height: calc(100% - 43px);
+
+                .n-collapse-item__content-inner {
+                    padding: 0;
+                    height: 100%;
+                }
+            }
+        }
+
+        .n-collapse-item--active {
+            flex: 1;
+            min-height: calc(50% - 1px);
+        }
+
+    }
+
+
+    .member-list {
+        height: 100%;
+        overflow-y: auto;
+
+        .member-list-item {
+            padding: 20px 20px 0;
+            display: flex;
+            align-items: center;
+            justify-content: space-between;
+
+            &-left {
+                display: flex;
+
+                &-info {
+                    margin-left: 10px;
+                    display: flex;
+                    flex-direction: column;
+                    justify-content: space-between;
+
+                    .name {
+                        font-size: 14px;
+                        color: #FFFFFF;
+                    }
+
+                    .organ {
+                        font-size: 12px;
+                    }
+                }
+            }
+
+            &-right {
+                display: flex;
+                align-items: center;
+
+                &>svg {
+                    cursor: pointer;
+                }
+
+                .status {
+                    margin-right: 20px;
+                }
+            }
+        }
+    }
+
+
+
+
+    .chat-list {
+        height: 100%;
+        display: flex;
+        flex-direction: column;
+
+        &-main {
+            overflow-y: auto;
+            flex: 1;
+            border-bottom: 1px solid #38383D;
+
+            .chat {
+                margin: 25px 15px 0;
+                display: flex;
+                flex-direction: column;
+
+                &-top {
+                    margin-bottom: 5px;
+                    display: flex;
+                    justify-content: space-between;
+                    align-items: center;
+
+                    .user-info {
+                        display: flex;
+                        align-items: center;
+
+                        .name {
+                            margin-left: 7px;
+                            color: #4B94FF;
+                        }
+                    }
+                }
+
+                &-bottom {
+                    padding-left: 40px;
+                    color: #FFFFFF;
+                }
+            }
+        }
+
+        &-foot {
+            padding: 0 15px;
+            height: 60px;
+            display: flex;
+            align-items: center;
+            justify-content: space-between;
+
+            .n-input {
+                background: transparent;
+                margin-right: 10px;
+            }
+        }
+    }
+
+}
+</style>

+ 25 - 0
src/components/icon.vue

@@ -0,0 +1,25 @@
+<script setup lang="ts">
+import { computed } from 'vue'
+const props = defineProps<{
+  name: string,
+  size?: number,
+  color?: string
+}>()
+const symbolId = computed(() => `#icon-${props.name}`)
+const newColor = computed(() => `${props.color ?? '#ccc'}`)
+const newSize = computed(() => `${props.size ?? 16}`)
+</script>
+<template>
+  <svg
+    aria-hidden="true"
+    :font-size="newSize"
+    :width="newSize"
+    :height="newSize"
+  >
+
+    <use
+      :href="symbolId"
+      :fill="newColor"
+    />
+  </svg>
+</template>

+ 181 - 0
src/components/invite-friends.vue

@@ -0,0 +1,181 @@
+<script lang="ts" setup>
+import { computed, ref, onMounted } from 'vue';
+import Model from './model.vue'
+import ApiService from '../services/api.service'
+import { NInput, NListItem, NAvatar, NList, NCheckboxGroup, NCheckbox, NSpace, NTag } from 'naive-ui'
+
+const apiService = new ApiService()
+
+const props = defineProps<{
+    modelValue: boolean
+}>()
+
+const emit = defineEmits<{
+    (evt: 'update:modelValue', value: boolean): void
+    (evt: 'close'): void
+    (evt: 'confirm'): void
+}>()
+
+const tagStyle = { color: '#49494F', textColor: '#D9D9D9' }
+const visible = computed(() => props.modelValue)
+const inviteListCheck = ref([])
+const friendsData = ref([])
+// apiService.ServeGetTalkList()
+
+function close() {
+    emit('update:modelValue', false)
+}
+
+function confirm() {
+    emit('update:modelValue', false)
+
+}
+
+onMounted(() => {
+    // apiService.ServeGetTalkList()
+})
+</script>
+<template>
+    <Model :model-value="visible" title="会议邀请" :width="650" @close="close" @confirm="confirm">
+        <div class="invite">
+            <div class="invite-left">
+                <n-list hoverable>
+                    <n-list-item>
+                        <n-input placeholder="搜索" round size="small" clearable>
+                            <template #prefix>
+                                <Icon name="search" />
+                            </template>
+                        </n-input>
+                    </n-list-item>
+                    <n-list-item>
+                        <template #prefix>
+                            <n-avatar>
+                                <Icon name="search" />
+                            </n-avatar>
+                        </template>
+                        我的好友
+                    </n-list-item>
+                    <n-list-item>
+                        <template #prefix>
+                            <n-avatar>
+                                <Icon name="search" />
+                            </n-avatar>
+                        </template>
+                        我的群组
+                    </n-list-item>
+                    <n-list-item>
+                        <template #prefix>
+                            <n-avatar>
+                                <Icon name="search" />
+                            </n-avatar>
+                        </template>
+                        组织架构
+                    </n-list-item>
+                    <n-list-item>
+                        <n-space>最近聊天</n-space>
+                        <br />
+                        <n-checkbox-group v-model:value="inviteListCheck">
+                            <n-checkbox :value="index" v-for="(item, index) in 100" :key="index">
+                                <n-avatar size="small">
+                                    <Icon name="search" />
+                                </n-avatar>
+                                张铁柱
+                            </n-checkbox>
+                        </n-checkbox-group>
+                    </n-list-item>
+                </n-list>
+            </div>
+
+            <div class="invite-right">
+                <n-tag closable :bordered="false" :color="tagStyle" v-for="(item, index) in inviteListCheck" :key="index"
+                    :on-close="() => inviteListCheck.splice(index, 1)">
+                    <template #avatar>
+                        <n-avatar size="small">
+                            <Icon name="search" />
+                        </n-avatar>
+                    </template>
+                    张铁柱
+                </n-tag>
+            </div>
+        </div>
+
+    </Model>
+</template>
+<style lang="scss" scoped>
+.invite {
+    display: flex;
+
+    &-right,
+    &-left {
+        width: 50%;
+    }
+
+    &-left {
+        border-right: solid 1px #38383D;
+
+        :deep(.n-input) {
+            outline: none;
+            background: #1D1D20;
+
+            input {
+                outline: none;
+            }
+
+            &:hover .n-input__state-border {
+                border: none;
+            }
+        }
+
+        :deep(.n-list) {
+            background: none;
+
+            .n-list-item {
+                padding: 15px 20px;
+                cursor: pointer;
+
+                .n-list-item__prefix {
+                    font-size: 0;
+                }
+
+                .n-checkbox-group {
+                    max-height: 300px;
+                    overflow: auto;
+
+                    .n-checkbox {
+                        align-items: center;
+                        width: 100%;
+                        margin-bottom: 10px;
+
+                        .n-checkbox__label {
+                            display: flex;
+                            align-items: center;
+
+                            &>span:first-child {
+                                margin-right: 10px;
+                            }
+                        }
+                    }
+                }
+            }
+
+            &.n-list--show-divider .n-list-item:not(:last-child) .n-list-item__divider {
+                background-color: #38383D;
+            }
+
+            &.n-list--hoverable .n-list-item:hover {
+                background-color: #1D1D20;
+            }
+        }
+    }
+
+    &-right {
+        max-height: 598px;
+        padding: 10px 18px;
+        overflow: auto;
+
+        &>div:not(:nth-child(3n)) {
+            margin-right: 3px;
+        }
+    }
+}
+</style>

+ 69 - 0
src/components/model.vue

@@ -0,0 +1,69 @@
+<script lang="ts" setup>
+import { NModal, NButton } from 'naive-ui'
+import { computed } from 'vue'
+
+const props = withDefaults(defineProps<{
+    modelValue: boolean, // 显示
+    title: string,
+    width?: number
+}>(), { modelValue: false, title: '', width: 0 })
+
+const emit = defineEmits<{
+    (evt: 'update:modelValue', value: boolean): void
+    (evt: 'close'): void
+    (evt: 'confirm'): void
+}>()
+
+const footerStyle = {
+    background: '#212124',
+    display: 'flex',
+    justifyContent: 'flex-end',
+    alignItems: 'center',
+    padding: '15px 10px',
+    borderTop: '1px solid #38383D',
+}
+const contentStyle = {
+    background: '#212124',
+    padding: '0'
+}
+const headerStyle = {
+    background: '#2F2F33',
+    padding: '8px 10px',
+    fontSize: '16px'
+}
+const visible = computed(() => props.modelValue)
+
+function close() {
+    emit('update:modelValue', false)
+    emit('close')
+}
+
+function sure() {
+    emit('update:modelValue', false)
+    emit('confirm')
+}
+</script>
+<template>
+    <n-modal v-model:show="visible" preset="card" :footer-style="footerStyle" :content-style="contentStyle"
+        :header-style="headerStyle" :style="`width: ${width}px;`" :title="title" :closable="false">
+        <slot></slot>
+        <template #footer>
+            <div class="footer">
+                <n-button @click="close">取消</n-button>
+                <n-button type="info" @click="sure"> 呼叫 </n-button>
+            </div>
+        </template>
+    </n-modal>
+</template>
+<style lang="scss" scoped>
+.footer {
+
+    &>button {
+        padding: 0 25px;
+    }
+
+    &>button:last-child {
+        margin-left: 10px;
+    }
+}
+</style>

+ 70 - 0
src/main.ts

@@ -0,0 +1,70 @@
+import { createApp } from 'vue'
+import App from './App.vue'
+import Icon from '@/components/icon.vue'
+import 'virtual:svg-icons-register'
+const app = createApp(App)
+
+// 提前存token
+if (window.electron) {
+  window.electron.on('getToken', (token: string) => {
+    localStorage.setItem('token', token || '')
+  })
+} else {
+  const p = window.location.search.split('?')[1]
+  const a = new URLSearchParams(p)
+  a.forEach((el, k) => {
+    localStorage.setItem(k, el)
+  })
+}
+
+// 自定义拖拽指令
+app.directive('drag', (el) => {
+  const oDiv = el // 当前元素
+  el.style.pointerEvents = null // 防止触发点击事件
+  oDiv.onmousedown = (e: Any) => {
+    // 找父级 是否是absolute来进行移动
+    let target = oDiv
+    while (window.getComputedStyle(target).position !== 'absolute' && target !== document.body) {
+      target = target.parentElement
+    }
+    // 找父级 是否是relative来进行宽度计算
+    let targetParent = target.parentElement
+    while (window.getComputedStyle(targetParent).position !== 'relative' && targetParent !== document.body) {
+      targetParent = targetParent.parentElement
+    }
+
+    document.onselectstart = () => {
+      return false
+    }
+
+    // 鼠标按下,计算当前元素距离可视区的距离
+    const disX = e.clientX - target.offsetLeft
+    const disY = e.clientY - target.offsetTop
+    const cW = +window.getComputedStyle(target).width.replace('px', '')
+    const cH = +window.getComputedStyle(target).height.replace('px', '')
+    const maxW = +window.getComputedStyle(targetParent).width.replace('px', '')
+    const maxH = +window.getComputedStyle(targetParent).height.replace('px', '')
+    document.onmousemove = e => {
+      // 通过事件委托,计算移动的距离
+      // 因为浏览器里并不能直接取到并且使用clientX、clientY,所以使用事件委托在内部做完赋值
+      el.style.pointerEvents = 'none'
+      const l = e.clientX - disX
+      const t = e.clientY - disY
+      const cl = maxW - cW
+      const ct = maxH - cH
+      // 计算移动当前元素的位置,并且给该元素样式中的left和top值赋值
+      target.style.left = (l < 0 ? 0 : l > cl ? cl : l) + 'px'
+      target.style.top = (t < 0 ? 0 : t > ct ? ct : t) + 'px'
+    }
+    document.onmouseup = e => {
+      el.style.pointerEvents = null
+      document.onmousemove = null
+      document.onmouseup = null
+      document.onselectstart = null
+    }
+    // return false不加的话可能导致黏连,拖到一个地方时div粘在鼠标上不下来,相当于onmouseup失效
+    return false
+  }
+})
+app.component('Icon', Icon)
+app.mount('#app')

+ 55 - 0
src/services/api.service.ts

@@ -0,0 +1,55 @@
+import AxiosService from './axios'
+
+export default class ApiService {
+    Axios = new AxiosService()
+
+    /**挂断视频 */
+    async ServeHungUpVideoTalk(data: { voip_id: string }) {
+        return await this.Axios.put('/lmim/v3/talk/message/voip/hung-up', data)
+    }
+
+    /**取消视频 */
+    async ServeCancelVideoTalk(data: { voip_id: string, invitee_user_id: string }) {
+        return await this.Axios.put('/lmim/v3/talk/message/voip/cancel', data)
+    }
+
+    /**拒绝视频 */
+    async ServeRejectVideoTalk(data: { voip_id: string }) {
+        return await this.Axios.put('/lmim/v3/talk/message/voip/reject', data)
+    }
+
+    /**接收视频 */
+    async ServeResiveVideoTalk(data: { voip_id: string }) {
+        return await this.Axios.put('/lmim/v3/talk/message/voip/accept', data)
+    }
+
+    /**获取最近会话列表 */
+    async ServeGetTalkList() {
+        return await this.Axios.get('/lmim/v3/talk/list')
+    }
+
+    /** 获取用户好友列表 */
+    async ServeGetContacts() {
+        return await this.Axios.get('/lmim/v3/contact/list')
+    }
+
+    /** 获取用户组列表 */
+    async ServeContactGroupList() {
+        return await this.Axios.get('/lmim/v3/contact/group/list')
+    }
+
+    /** 获取所有人员 */
+    async ServePersonnelList() {
+        return await this.Axios.get('/lmim/v3/organize/personnel/all')
+    }
+
+    /** 获取组织架构 */
+    async ServeDepartmentList (){
+        return await this.Axios.get('/lmim/v3/organize/department/all')
+    }
+
+    /** 获取参会人员 */
+    async getMettingPep(data){
+        return await this.Axios.get('/meeting/v3/meeting/member/list',data)
+    }
+}

+ 35 - 0
src/services/axios.ts

@@ -0,0 +1,35 @@
+import axios from 'axios'
+
+class AxiosService {
+
+    constructor() {
+        const url = window.electron ? window.electron.envs.VITE_PROXY_URL : '/api'
+        // http request 拦截
+        axios.interceptors.request.use(
+            (config) => {
+                config.baseURL = url
+                config.headers.Authorization = localStorage.getItem('token') || ''
+                return config
+            },
+            err => {
+                throw err
+            }
+        )
+        // http response 拦截
+        axios.interceptors.response.use(
+            (response) => response.data,
+            err => {
+                throw err
+            }
+        )
+    }
+
+    async put(url: string, data: object): Promise<{ success: boolean, data: Any }> {
+        return await axios.put(url, data)
+    }
+
+    async get(url: string, data?: object): Promise<{ success: boolean, data: Any }> {
+        return await axios.get(url, { params: data })
+    }
+}
+export default AxiosService

+ 42 - 0
vite.config.ts

@@ -0,0 +1,42 @@
+import vue from '@vitejs/plugin-vue'
+import { defineConfig, loadEnv } from 'vite'
+import { resolve } from 'path'
+import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
+
+export default ({ mode }) => {
+  return defineConfig({
+    base: './',
+    build: {
+      emptyOutDir: true,
+      outDir: '../../build/dist/metting'
+    },
+    server: {
+      host: '0.0.0.0',
+      port: 15438,
+      strictPort: true,
+      proxy: {
+        '/api': {
+          target: loadEnv(mode, process.cwd()).VITE_PROXY_URL,
+          changeOrigin: true,
+          rewrite: path => path.replace(/^\/api/, ''),
+          secure: false,
+          headers: {
+            Referer: 'https://example.com'
+          }
+        }
+      }
+    },
+    resolve: {
+      alias: {
+        '@': resolve(__dirname, 'src')
+      }
+    },
+    plugins: [
+      vue(),
+      createSvgIconsPlugin({
+        iconDirs: [resolve(__dirname, './src/assets/icons')],
+        symbolId: 'icon-[dir]-[name]'
+      })
+    ]
+  })
+}

+ 589 - 0
yarn.lock

@@ -0,0 +1,589 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+"@babel/runtime@^7.21.0":
+  version "7.21.5"
+  resolved "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.21.5.tgz#8492dddda9644ae3bda3b45eabe87382caee7200"
+  integrity sha512-8jI69toZqqcsnqGGqwGS4Qb1VwLOEp4hz+CXPywcvjs60u3B4Pom/U/7rm4W8tMOYEB+E9wgD0mW1l3r8qlI9Q==
+  dependencies:
+    regenerator-runtime "^0.13.11"
+
+"@css-render/plugin-bem@^0.15.10":
+  version "0.15.12"
+  resolved "https://registry.npmmirror.com/@css-render/plugin-bem/-/plugin-bem-0.15.12.tgz#cd88e46a388e4786436bd622414da0aa6019af3b"
+  integrity sha512-Lq2jSOZn+wYQtsyaFj6QRz2EzAnd3iW5fZeHO1WSXQdVYwvwGX0ZiH3X2JQgtgYLT1yeGtrwrqJdNdMEUD2xTw==
+
+"@css-render/vue3-ssr@^0.15.10":
+  version "0.15.12"
+  resolved "https://registry.npmmirror.com/@css-render/vue3-ssr/-/vue3-ssr-0.15.12.tgz#798d8dffadecd2bf8c80cbaab64e9df10be5626e"
+  integrity sha512-AQLGhhaE0F+rwybRCkKUdzBdTEM/5PZBYy+fSYe1T9z9+yxMuV/k7ZRqa4M69X+EI1W8pa4kc9Iq2VjQkZx4rg==
+
+"@emotion/hash@~0.8.0":
+  version "0.8.0"
+  resolved "https://registry.npmmirror.com/@emotion/hash/-/hash-0.8.0.tgz#bbbff68978fefdbe68ccb533bc8cbe1d1afb5413"
+  integrity sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==
+
+"@esbuild/android-arm64@0.16.17":
+  version "0.16.17"
+  resolved "https://registry.npmmirror.com/@esbuild/android-arm64/-/android-arm64-0.16.17.tgz#cf91e86df127aa3d141744edafcba0abdc577d23"
+  integrity sha512-MIGl6p5sc3RDTLLkYL1MyL8BMRN4tLMRCn+yRJJmEDvYZ2M7tmAf80hx1kbNEUX2KJ50RRtxZ4JHLvCfuB6kBg==
+
+"@esbuild/android-arm@0.16.17":
+  version "0.16.17"
+  resolved "https://registry.npmmirror.com/@esbuild/android-arm/-/android-arm-0.16.17.tgz#025b6246d3f68b7bbaa97069144fb5fb70f2fff2"
+  integrity sha512-N9x1CMXVhtWEAMS7pNNONyA14f71VPQN9Cnavj1XQh6T7bskqiLLrSca4O0Vr8Wdcga943eThxnVp3JLnBMYtw==
+
+"@esbuild/android-x64@0.16.17":
+  version "0.16.17"
+  resolved "https://registry.npmmirror.com/@esbuild/android-x64/-/android-x64-0.16.17.tgz#c820e0fef982f99a85c4b8bfdd582835f04cd96e"
+  integrity sha512-a3kTv3m0Ghh4z1DaFEuEDfz3OLONKuFvI4Xqczqx4BqLyuFaFkuaG4j2MtA6fuWEFeC5x9IvqnX7drmRq/fyAQ==
+
+"@esbuild/darwin-arm64@0.16.17":
+  version "0.16.17"
+  resolved "https://registry.npmmirror.com/@esbuild/darwin-arm64/-/darwin-arm64-0.16.17.tgz#edef4487af6b21afabba7be5132c26d22379b220"
+  integrity sha512-/2agbUEfmxWHi9ARTX6OQ/KgXnOWfsNlTeLcoV7HSuSTv63E4DqtAc+2XqGw1KHxKMHGZgbVCZge7HXWX9Vn+w==
+
+"@esbuild/darwin-x64@0.16.17":
+  version "0.16.17"
+  resolved "https://registry.npmmirror.com/@esbuild/darwin-x64/-/darwin-x64-0.16.17.tgz#42829168730071c41ef0d028d8319eea0e2904b4"
+  integrity sha512-2By45OBHulkd9Svy5IOCZt376Aa2oOkiE9QWUK9fe6Tb+WDr8hXL3dpqi+DeLiMed8tVXspzsTAvd0jUl96wmg==
+
+"@esbuild/freebsd-arm64@0.16.17":
+  version "0.16.17"
+  resolved "https://registry.npmmirror.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.16.17.tgz#1f4af488bfc7e9ced04207034d398e793b570a27"
+  integrity sha512-mt+cxZe1tVx489VTb4mBAOo2aKSnJ33L9fr25JXpqQqzbUIw/yzIzi+NHwAXK2qYV1lEFp4OoVeThGjUbmWmdw==
+
+"@esbuild/freebsd-x64@0.16.17":
+  version "0.16.17"
+  resolved "https://registry.npmmirror.com/@esbuild/freebsd-x64/-/freebsd-x64-0.16.17.tgz#636306f19e9bc981e06aa1d777302dad8fddaf72"
+  integrity sha512-8ScTdNJl5idAKjH8zGAsN7RuWcyHG3BAvMNpKOBaqqR7EbUhhVHOqXRdL7oZvz8WNHL2pr5+eIT5c65kA6NHug==
+
+"@esbuild/linux-arm64@0.16.17":
+  version "0.16.17"
+  resolved "https://registry.npmmirror.com/@esbuild/linux-arm64/-/linux-arm64-0.16.17.tgz#a003f7ff237c501e095d4f3a09e58fc7b25a4aca"
+  integrity sha512-7S8gJnSlqKGVJunnMCrXHU9Q8Q/tQIxk/xL8BqAP64wchPCTzuM6W3Ra8cIa1HIflAvDnNOt2jaL17vaW+1V0g==
+
+"@esbuild/linux-arm@0.16.17":
+  version "0.16.17"
+  resolved "https://registry.npmmirror.com/@esbuild/linux-arm/-/linux-arm-0.16.17.tgz#b591e6a59d9c4fe0eeadd4874b157ab78cf5f196"
+  integrity sha512-iihzrWbD4gIT7j3caMzKb/RsFFHCwqqbrbH9SqUSRrdXkXaygSZCZg1FybsZz57Ju7N/SHEgPyaR0LZ8Zbe9gQ==
+
+"@esbuild/linux-ia32@0.16.17":
+  version "0.16.17"
+  resolved "https://registry.npmmirror.com/@esbuild/linux-ia32/-/linux-ia32-0.16.17.tgz#24333a11027ef46a18f57019450a5188918e2a54"
+  integrity sha512-kiX69+wcPAdgl3Lonh1VI7MBr16nktEvOfViszBSxygRQqSpzv7BffMKRPMFwzeJGPxcio0pdD3kYQGpqQ2SSg==
+
+"@esbuild/linux-loong64@0.16.17":
+  version "0.16.17"
+  resolved "https://registry.npmmirror.com/@esbuild/linux-loong64/-/linux-loong64-0.16.17.tgz#d5ad459d41ed42bbd4d005256b31882ec52227d8"
+  integrity sha512-dTzNnQwembNDhd654cA4QhbS9uDdXC3TKqMJjgOWsC0yNCbpzfWoXdZvp0mY7HU6nzk5E0zpRGGx3qoQg8T2DQ==
+
+"@esbuild/linux-mips64el@0.16.17":
+  version "0.16.17"
+  resolved "https://registry.npmmirror.com/@esbuild/linux-mips64el/-/linux-mips64el-0.16.17.tgz#4e5967a665c38360b0a8205594377d4dcf9c3726"
+  integrity sha512-ezbDkp2nDl0PfIUn0CsQ30kxfcLTlcx4Foz2kYv8qdC6ia2oX5Q3E/8m6lq84Dj/6b0FrkgD582fJMIfHhJfSw==
+
+"@esbuild/linux-ppc64@0.16.17":
+  version "0.16.17"
+  resolved "https://registry.npmmirror.com/@esbuild/linux-ppc64/-/linux-ppc64-0.16.17.tgz#206443a02eb568f9fdf0b438fbd47d26e735afc8"
+  integrity sha512-dzS678gYD1lJsW73zrFhDApLVdM3cUF2MvAa1D8K8KtcSKdLBPP4zZSLy6LFZ0jYqQdQ29bjAHJDgz0rVbLB3g==
+
+"@esbuild/linux-riscv64@0.16.17":
+  version "0.16.17"
+  resolved "https://registry.npmmirror.com/@esbuild/linux-riscv64/-/linux-riscv64-0.16.17.tgz#c351e433d009bf256e798ad048152c8d76da2fc9"
+  integrity sha512-ylNlVsxuFjZK8DQtNUwiMskh6nT0vI7kYl/4fZgV1llP5d6+HIeL/vmmm3jpuoo8+NuXjQVZxmKuhDApK0/cKw==
+
+"@esbuild/linux-s390x@0.16.17":
+  version "0.16.17"
+  resolved "https://registry.npmmirror.com/@esbuild/linux-s390x/-/linux-s390x-0.16.17.tgz#661f271e5d59615b84b6801d1c2123ad13d9bd87"
+  integrity sha512-gzy7nUTO4UA4oZ2wAMXPNBGTzZFP7mss3aKR2hH+/4UUkCOyqmjXiKpzGrY2TlEUhbbejzXVKKGazYcQTZWA/w==
+
+"@esbuild/linux-x64@0.16.17":
+  version "0.16.17"
+  resolved "https://registry.npmmirror.com/@esbuild/linux-x64/-/linux-x64-0.16.17.tgz#e4ba18e8b149a89c982351443a377c723762b85f"
+  integrity sha512-mdPjPxfnmoqhgpiEArqi4egmBAMYvaObgn4poorpUaqmvzzbvqbowRllQ+ZgzGVMGKaPkqUmPDOOFQRUFDmeUw==
+
+"@esbuild/netbsd-x64@0.16.17":
+  version "0.16.17"
+  resolved "https://registry.npmmirror.com/@esbuild/netbsd-x64/-/netbsd-x64-0.16.17.tgz#7d4f4041e30c5c07dd24ffa295c73f06038ec775"
+  integrity sha512-/PzmzD/zyAeTUsduZa32bn0ORug+Jd1EGGAUJvqfeixoEISYpGnAezN6lnJoskauoai0Jrs+XSyvDhppCPoKOA==
+
+"@esbuild/openbsd-x64@0.16.17":
+  version "0.16.17"
+  resolved "https://registry.npmmirror.com/@esbuild/openbsd-x64/-/openbsd-x64-0.16.17.tgz#970fa7f8470681f3e6b1db0cc421a4af8060ec35"
+  integrity sha512-2yaWJhvxGEz2RiftSk0UObqJa/b+rIAjnODJgv2GbGGpRwAfpgzyrg1WLK8rqA24mfZa9GvpjLcBBg8JHkoodg==
+
+"@esbuild/sunos-x64@0.16.17":
+  version "0.16.17"
+  resolved "https://registry.npmmirror.com/@esbuild/sunos-x64/-/sunos-x64-0.16.17.tgz#abc60e7c4abf8b89fb7a4fe69a1484132238022c"
+  integrity sha512-xtVUiev38tN0R3g8VhRfN7Zl42YCJvyBhRKw1RJjwE1d2emWTVToPLNEQj/5Qxc6lVFATDiy6LjVHYhIPrLxzw==
+
+"@esbuild/win32-arm64@0.16.17":
+  version "0.16.17"
+  resolved "https://registry.npmmirror.com/@esbuild/win32-arm64/-/win32-arm64-0.16.17.tgz#7b0ff9e8c3265537a7a7b1fd9a24e7bd39fcd87a"
+  integrity sha512-ga8+JqBDHY4b6fQAmOgtJJue36scANy4l/rL97W+0wYmijhxKetzZdKOJI7olaBaMhWt8Pac2McJdZLxXWUEQw==
+
+"@esbuild/win32-ia32@0.16.17":
+  version "0.16.17"
+  resolved "https://registry.npmmirror.com/@esbuild/win32-ia32/-/win32-ia32-0.16.17.tgz#e90fe5267d71a7b7567afdc403dfd198c292eb09"
+  integrity sha512-WnsKaf46uSSF/sZhwnqE4L/F89AYNMiD4YtEcYekBt9Q7nj0DiId2XH2Ng2PHM54qi5oPrQ8luuzGszqi/veig==
+
+"@esbuild/win32-x64@0.16.17":
+  version "0.16.17"
+  resolved "https://registry.npmmirror.com/@esbuild/win32-x64/-/win32-x64-0.16.17.tgz#c5a1a4bfe1b57f0c3e61b29883525c6da3e5c091"
+  integrity sha512-y+EHuSchhL7FjHgvQL/0fnnFmO4T1bhvWANX6gcnqTjtnKWbTvUMCpGnv2+t+31d7RzyEAYAd4u2fnIhHL6N/Q==
+
+"@juggle/resize-observer@^3.3.1":
+  version "3.4.0"
+  resolved "https://registry.npmmirror.com/@juggle/resize-observer/-/resize-observer-3.4.0.tgz#08d6c5e20cf7e4cc02fd181c4b0c225cd31dbb60"
+  integrity sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA==
+
+"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2":
+  version "1.1.2"
+  resolved "https://registry.npmmirror.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf"
+  integrity sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==
+
+"@protobufjs/base64@^1.1.2":
+  version "1.1.2"
+  resolved "https://registry.npmmirror.com/@protobufjs/base64/-/base64-1.1.2.tgz#4c85730e59b9a1f1f349047dbf24296034bb2735"
+  integrity sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==
+
+"@protobufjs/codegen@^2.0.4":
+  version "2.0.4"
+  resolved "https://registry.npmmirror.com/@protobufjs/codegen/-/codegen-2.0.4.tgz#7ef37f0d010fb028ad1ad59722e506d9262815cb"
+  integrity sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==
+
+"@protobufjs/eventemitter@^1.1.0":
+  version "1.1.0"
+  resolved "https://registry.npmmirror.com/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz#355cbc98bafad5978f9ed095f397621f1d066b70"
+  integrity sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==
+
+"@protobufjs/fetch@^1.1.0":
+  version "1.1.0"
+  resolved "https://registry.npmmirror.com/@protobufjs/fetch/-/fetch-1.1.0.tgz#ba99fb598614af65700c1619ff06d454b0d84c45"
+  integrity sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==
+  dependencies:
+    "@protobufjs/aspromise" "^1.1.1"
+    "@protobufjs/inquire" "^1.1.0"
+
+"@protobufjs/float@^1.0.2":
+  version "1.0.2"
+  resolved "https://registry.npmmirror.com/@protobufjs/float/-/float-1.0.2.tgz#5e9e1abdcb73fc0a7cb8b291df78c8cbd97b87d1"
+  integrity sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==
+
+"@protobufjs/inquire@^1.1.0":
+  version "1.1.0"
+  resolved "https://registry.npmmirror.com/@protobufjs/inquire/-/inquire-1.1.0.tgz#ff200e3e7cf2429e2dcafc1140828e8cc638f089"
+  integrity sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==
+
+"@protobufjs/path@^1.1.2":
+  version "1.1.2"
+  resolved "https://registry.npmmirror.com/@protobufjs/path/-/path-1.1.2.tgz#6cc2b20c5c9ad6ad0dccfd21ca7673d8d7fbf68d"
+  integrity sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==
+
+"@protobufjs/pool@^1.1.0":
+  version "1.1.0"
+  resolved "https://registry.npmmirror.com/@protobufjs/pool/-/pool-1.1.0.tgz#09fd15f2d6d3abfa9b65bc366506d6ad7846ff54"
+  integrity sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==
+
+"@protobufjs/utf8@^1.1.0":
+  version "1.1.0"
+  resolved "https://registry.npmmirror.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570"
+  integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==
+
+"@types/katex@^0.14.0":
+  version "0.14.0"
+  resolved "https://registry.npmmirror.com/@types/katex/-/katex-0.14.0.tgz#b84c0afc3218069a5ad64fe2a95321881021b5fe"
+  integrity sha512-+2FW2CcT0K3P+JMR8YG846bmDwplKUTsWgT2ENwdQ1UdVfRk3GQrh6Mi4sTopy30gI8Uau5CEqHTDZ6YvWIUPA==
+
+"@types/lodash-es@^4.17.6":
+  version "4.17.7"
+  resolved "https://registry.npmmirror.com/@types/lodash-es/-/lodash-es-4.17.7.tgz#22edcae9f44aff08546e71db8925f05b33c7cc40"
+  integrity sha512-z0ptr6UI10VlU6l5MYhGwS4mC8DZyYer2mCoyysZtSF7p26zOX8UpbrV0YpNYLGS8K4PUFIyEr62IMFFjveSiQ==
+  dependencies:
+    "@types/lodash" "*"
+
+"@types/lodash@*", "@types/lodash@^4.14.181":
+  version "4.14.194"
+  resolved "https://registry.npmmirror.com/@types/lodash/-/lodash-4.14.194.tgz#b71eb6f7a0ff11bff59fc987134a093029258a76"
+  integrity sha512-r22s9tAS7imvBt2lyHC9B8AGwWnXaYb1tY09oyLkXDs4vArpYJzw09nj8MLx5VfciBPGIb+ZwG0ssYnEPJxn/g==
+
+"@types/node@>=13.7.0":
+  version "20.2.0"
+  resolved "https://registry.npmmirror.com/@types/node/-/node-20.2.0.tgz#e33da33171ac4eba79b9cfe30b68a4f1561e74ec"
+  integrity sha512-3iD2jaCCziTx04uudpJKwe39QxXgSUnpxXSvRQjRvHPxFQfmfP4NXIm/NURVeNlTCc+ru4WqjYGTmpXrW9uMlw==
+
+async-validator@^4.0.7:
+  version "4.2.5"
+  resolved "https://registry.npmmirror.com/async-validator/-/async-validator-4.2.5.tgz#c96ea3332a521699d0afaaceed510a54656c6339"
+  integrity sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==
+
+asynckit@^0.4.0:
+  version "0.4.0"
+  resolved "https://registry.npmmirror.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
+  integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==
+
+axios@^1.4.0:
+  version "1.4.0"
+  resolved "https://registry.npmmirror.com/axios/-/axios-1.4.0.tgz#38a7bf1224cd308de271146038b551d725f0be1f"
+  integrity sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==
+  dependencies:
+    follow-redirects "^1.15.0"
+    form-data "^4.0.0"
+    proxy-from-env "^1.1.0"
+
+combined-stream@^1.0.8:
+  version "1.0.8"
+  resolved "https://registry.npmmirror.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
+  integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
+  dependencies:
+    delayed-stream "~1.0.0"
+
+css-render@^0.15.10:
+  version "0.15.12"
+  resolved "https://registry.npmmirror.com/css-render/-/css-render-0.15.12.tgz#76be94066897bd3231a9b9412971ffc258ada66e"
+  integrity sha512-eWzS66patiGkTTik+ipO9qNGZ+uNuGyTmnz6/+EJIiFg8+3yZRpnMwgFo8YdXhQRsiePzehnusrxVvugNjXzbw==
+  dependencies:
+    "@emotion/hash" "~0.8.0"
+    csstype "~3.0.5"
+
+csstype@~3.0.5:
+  version "3.0.11"
+  resolved "https://registry.npmmirror.com/csstype/-/csstype-3.0.11.tgz#d66700c5eacfac1940deb4e3ee5642792d85cd33"
+  integrity sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw==
+
+date-fns-tz@^1.3.3:
+  version "1.3.8"
+  resolved "https://registry.npmmirror.com/date-fns-tz/-/date-fns-tz-1.3.8.tgz#083e3a4e1f19b7857fa0c18deea6c2bc46ded7b9"
+  integrity sha512-qwNXUFtMHTTU6CFSFjoJ80W8Fzzp24LntbjFFBgL/faqds4e5mo9mftoRLgr3Vi1trISsg4awSpYVsOQCRnapQ==
+
+date-fns@^2.28.0:
+  version "2.30.0"
+  resolved "https://registry.npmmirror.com/date-fns/-/date-fns-2.30.0.tgz#f367e644839ff57894ec6ac480de40cae4b0f4d0"
+  integrity sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==
+  dependencies:
+    "@babel/runtime" "^7.21.0"
+
+delayed-stream@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.npmmirror.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
+  integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==
+
+esbuild@^0.16.14:
+  version "0.16.17"
+  resolved "https://registry.npmmirror.com/esbuild/-/esbuild-0.16.17.tgz#fc2c3914c57ee750635fee71b89f615f25065259"
+  integrity sha512-G8LEkV0XzDMNwXKgM0Jwu3nY3lSTwSGY6XbxM9cr9+s0T/qSV1q1JVPBGzm3dcjhCic9+emZDmMffkwgPeOeLg==
+  optionalDependencies:
+    "@esbuild/android-arm" "0.16.17"
+    "@esbuild/android-arm64" "0.16.17"
+    "@esbuild/android-x64" "0.16.17"
+    "@esbuild/darwin-arm64" "0.16.17"
+    "@esbuild/darwin-x64" "0.16.17"
+    "@esbuild/freebsd-arm64" "0.16.17"
+    "@esbuild/freebsd-x64" "0.16.17"
+    "@esbuild/linux-arm" "0.16.17"
+    "@esbuild/linux-arm64" "0.16.17"
+    "@esbuild/linux-ia32" "0.16.17"
+    "@esbuild/linux-loong64" "0.16.17"
+    "@esbuild/linux-mips64el" "0.16.17"
+    "@esbuild/linux-ppc64" "0.16.17"
+    "@esbuild/linux-riscv64" "0.16.17"
+    "@esbuild/linux-s390x" "0.16.17"
+    "@esbuild/linux-x64" "0.16.17"
+    "@esbuild/netbsd-x64" "0.16.17"
+    "@esbuild/openbsd-x64" "0.16.17"
+    "@esbuild/sunos-x64" "0.16.17"
+    "@esbuild/win32-arm64" "0.16.17"
+    "@esbuild/win32-ia32" "0.16.17"
+    "@esbuild/win32-x64" "0.16.17"
+
+events@^3.3.0:
+  version "3.3.0"
+  resolved "https://registry.npmmirror.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400"
+  integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==
+
+evtd@^0.2.2, evtd@^0.2.4:
+  version "0.2.4"
+  resolved "https://registry.npmmirror.com/evtd/-/evtd-0.2.4.tgz#0aac39ba44d6926e6668948ac27618e0795b9d07"
+  integrity sha512-qaeGN5bx63s/AXgQo8gj6fBkxge+OoLddLniox5qtLAEY5HSnuSlISXVPxnSae1dWblvTh4/HoMIB+mbMsvZzw==
+
+follow-redirects@^1.15.0:
+  version "1.15.2"
+  resolved "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13"
+  integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==
+
+form-data@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.npmmirror.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452"
+  integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==
+  dependencies:
+    asynckit "^0.4.0"
+    combined-stream "^1.0.8"
+    mime-types "^2.1.12"
+
+fsevents@~2.3.2:
+  version "2.3.2"
+  resolved "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
+  integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
+
+function-bind@^1.1.1:
+  version "1.1.1"
+  resolved "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
+  integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
+
+has@^1.0.3:
+  version "1.0.3"
+  resolved "https://registry.npmmirror.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
+  integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==
+  dependencies:
+    function-bind "^1.1.1"
+
+highlight.js@^11.5.0:
+  version "11.8.0"
+  resolved "https://registry.npmmirror.com/highlight.js/-/highlight.js-11.8.0.tgz#966518ea83257bae2e7c9a48596231856555bb65"
+  integrity sha512-MedQhoqVdr0U6SSnWPzfiadUcDHfN/Wzq25AkXiQv9oiOO/sG0S7XkvpFIqWBl9Yq1UYyYOOVORs5UW2XlPyzg==
+
+is-core-module@^2.11.0:
+  version "2.12.1"
+  resolved "https://registry.npmmirror.com/is-core-module/-/is-core-module-2.12.1.tgz#0c0b6885b6f80011c71541ce15c8d66cf5a4f9fd"
+  integrity sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==
+  dependencies:
+    has "^1.0.3"
+
+livekit-client@^1.9.7:
+  version "1.9.7"
+  resolved "https://registry.npmmirror.com/livekit-client/-/livekit-client-1.9.7.tgz#51e7d8975ce7dcbfd51e91a8f9221f5868a1e606"
+  integrity sha512-w0WjLat0qF76l71esjTXam5JE+7vCpBF6WW+oloHFNBIVtEzEnBZa2JUo/e2oWN2YypEO5MjCIDPo7Tuvo9clA==
+  dependencies:
+    events "^3.3.0"
+    loglevel "^1.8.0"
+    protobufjs "^7.0.0"
+    sdp-transform "^2.14.1"
+    ts-debounce "^4.0.0"
+    typed-emitter "^2.1.0"
+    webrtc-adapter "^8.1.1"
+
+lodash-es@^4.17.21:
+  version "4.17.21"
+  resolved "https://registry.npmmirror.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee"
+  integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==
+
+lodash@^4.17.21:
+  version "4.17.21"
+  resolved "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
+  integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
+
+loglevel@^1.8.0:
+  version "1.8.1"
+  resolved "https://registry.npmmirror.com/loglevel/-/loglevel-1.8.1.tgz#5c621f83d5b48c54ae93b6156353f555963377b4"
+  integrity sha512-tCRIJM51SHjAayKwC+QAg8hT8vg6z7GSgLJKGvzuPb1Wc+hLzqtuVLxp6/HzSPOozuK+8ErAhy7U/sVzw8Dgfg==
+
+long@^5.0.0:
+  version "5.2.3"
+  resolved "https://registry.npmmirror.com/long/-/long-5.2.3.tgz#a3ba97f3877cf1d778eccbcb048525ebb77499e1"
+  integrity sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==
+
+mime-db@1.52.0:
+  version "1.52.0"
+  resolved "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
+  integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
+
+mime-types@^2.1.12:
+  version "2.1.35"
+  resolved "https://registry.npmmirror.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a"
+  integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
+  dependencies:
+    mime-db "1.52.0"
+
+naive-ui@^2.33.3:
+  version "2.34.3"
+  resolved "https://registry.npmmirror.com/naive-ui/-/naive-ui-2.34.3.tgz#96fb0717aedd22b6943b947efc7f5cd58e9d29df"
+  integrity sha512-fUMr0dzb/iGsOTWgoblPVobY5X5dihQ1eam5dA+H74oyLYAvgX4pL96xQFPBLIYqvyRFBAsN85kHN5pLqdtpxA==
+  dependencies:
+    "@css-render/plugin-bem" "^0.15.10"
+    "@css-render/vue3-ssr" "^0.15.10"
+    "@types/katex" "^0.14.0"
+    "@types/lodash" "^4.14.181"
+    "@types/lodash-es" "^4.17.6"
+    async-validator "^4.0.7"
+    css-render "^0.15.10"
+    date-fns "^2.28.0"
+    date-fns-tz "^1.3.3"
+    evtd "^0.2.4"
+    highlight.js "^11.5.0"
+    lodash "^4.17.21"
+    lodash-es "^4.17.21"
+    seemly "^0.3.6"
+    treemate "^0.3.11"
+    vdirs "^0.1.8"
+    vooks "^0.2.12"
+    vueuc "^0.4.47"
+
+nanoid@^3.3.6:
+  version "3.3.6"
+  resolved "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.6.tgz#443380c856d6e9f9824267d960b4236ad583ea4c"
+  integrity sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==
+
+path-parse@^1.0.7:
+  version "1.0.7"
+  resolved "https://registry.npmmirror.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
+  integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
+
+picocolors@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.npmmirror.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
+  integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
+
+postcss@^8.4.21:
+  version "8.4.23"
+  resolved "https://registry.npmmirror.com/postcss/-/postcss-8.4.23.tgz#df0aee9ac7c5e53e1075c24a3613496f9e6552ab"
+  integrity sha512-bQ3qMcpF6A/YjR55xtoTr0jGOlnPOKAIMdOWiv0EIT6HVPEaJiJB4NLljSbiHoC2RX7DN5Uvjtpbg1NPdwv1oA==
+  dependencies:
+    nanoid "^3.3.6"
+    picocolors "^1.0.0"
+    source-map-js "^1.0.2"
+
+protobufjs@^7.0.0:
+  version "7.2.3"
+  resolved "https://registry.npmmirror.com/protobufjs/-/protobufjs-7.2.3.tgz#01af019e40d9c6133c49acbb3ff9e30f4f0f70b2"
+  integrity sha512-TtpvOqwB5Gdz/PQmOjgsrGH1nHjAQVCN7JG4A6r1sXRWESL5rNMAiRcBQlCAdKxZcAbstExQePYG8xof/JVRgg==
+  dependencies:
+    "@protobufjs/aspromise" "^1.1.2"
+    "@protobufjs/base64" "^1.1.2"
+    "@protobufjs/codegen" "^2.0.4"
+    "@protobufjs/eventemitter" "^1.1.0"
+    "@protobufjs/fetch" "^1.1.0"
+    "@protobufjs/float" "^1.0.2"
+    "@protobufjs/inquire" "^1.1.0"
+    "@protobufjs/path" "^1.1.2"
+    "@protobufjs/pool" "^1.1.0"
+    "@protobufjs/utf8" "^1.1.0"
+    "@types/node" ">=13.7.0"
+    long "^5.0.0"
+
+proxy-from-env@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.npmmirror.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2"
+  integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==
+
+regenerator-runtime@^0.13.11:
+  version "0.13.11"
+  resolved "https://registry.npmmirror.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9"
+  integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==
+
+resolve@^1.22.1:
+  version "1.22.2"
+  resolved "https://registry.npmmirror.com/resolve/-/resolve-1.22.2.tgz#0ed0943d4e301867955766c9f3e1ae6d01c6845f"
+  integrity sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==
+  dependencies:
+    is-core-module "^2.11.0"
+    path-parse "^1.0.7"
+    supports-preserve-symlinks-flag "^1.0.0"
+
+rollup@^3.10.0:
+  version "3.22.0"
+  resolved "https://registry.npmmirror.com/rollup/-/rollup-3.22.0.tgz#e6671baebdd473154ac7998bbc57faabcd7bba20"
+  integrity sha512-imsigcWor5Y/dC0rz2q0bBt9PabcL3TORry2hAa6O6BuMvY71bqHyfReAz5qyAqiQATD1m70qdntqBfBQjVWpQ==
+  optionalDependencies:
+    fsevents "~2.3.2"
+
+rxjs@^7.5.2:
+  version "7.8.1"
+  resolved "https://registry.npmmirror.com/rxjs/-/rxjs-7.8.1.tgz#6f6f3d99ea8044291efd92e7c7fcf562c4057543"
+  integrity sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==
+  dependencies:
+    tslib "^2.1.0"
+
+sdp-transform@^2.14.1:
+  version "2.14.1"
+  resolved "https://registry.npmmirror.com/sdp-transform/-/sdp-transform-2.14.1.tgz#2bb443583d478dee217df4caa284c46b870d5827"
+  integrity sha512-RjZyX3nVwJyCuTo5tGPx+PZWkDMCg7oOLpSlhjDdZfwUoNqG1mM8nyj31IGHyaPWXhjbP7cdK3qZ2bmkJ1GzRw==
+
+sdp@^3.2.0:
+  version "3.2.0"
+  resolved "https://registry.npmmirror.com/sdp/-/sdp-3.2.0.tgz#8961420552b36663b4d13ddba6f478d1461896a5"
+  integrity sha512-d7wDPgDV3DDiqulJjKiV2865wKsJ34YI+NDREbm+FySq6WuKOikwyNQcm+doLAZ1O6ltdO0SeKle2xMpN3Brgw==
+
+seemly@^0.3.6:
+  version "0.3.6"
+  resolved "https://registry.npmmirror.com/seemly/-/seemly-0.3.6.tgz#7ef97e8083dea00804965e2662f572a5df9cb18e"
+  integrity sha512-lEV5VB8BUKTo/AfktXJcy+JeXns26ylbMkIUco8CYREsQijuz4mrXres2Q+vMLdwkuLxJdIPQ8IlCIxLYm71Yw==
+
+source-map-js@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c"
+  integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==
+
+supports-preserve-symlinks-flag@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.npmmirror.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
+  integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
+
+treemate@^0.3.11:
+  version "0.3.11"
+  resolved "https://registry.npmmirror.com/treemate/-/treemate-0.3.11.tgz#7d52f8f69ab9ce326f8d139e0a3d1ffb25e48222"
+  integrity sha512-M8RGFoKtZ8dF+iwJfAJTOH/SM4KluKOKRJpjCMhI8bG3qB74zrFoArKZ62ll0Fr3mqkMJiQOmWYkdYgDeITYQg==
+
+ts-debounce@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.npmmirror.com/ts-debounce/-/ts-debounce-4.0.0.tgz#33440ef64fab53793c3d546a8ca6ae539ec15841"
+  integrity sha512-+1iDGY6NmOGidq7i7xZGA4cm8DAa6fqdYcvO5Z6yBevH++Bdo9Qt/mN0TzHUgcCcKv1gmh9+W5dHqz8pMWbCbg==
+
+tslib@^2.1.0:
+  version "2.5.1"
+  resolved "https://registry.npmmirror.com/tslib/-/tslib-2.5.1.tgz#f2ad78c367857d54e49a0ef9def68737e1a67b21"
+  integrity sha512-KaI6gPil5m9vF7DKaoXxx1ia9fxS4qG5YveErRRVknPDXXriu5M8h48YRjB6h5ZUOKuAKlSJYb0GaDe8I39fRw==
+
+typed-emitter@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.npmmirror.com/typed-emitter/-/typed-emitter-2.1.0.tgz#ca78e3d8ef1476f228f548d62e04e3d4d3fd77fb"
+  integrity sha512-g/KzbYKbH5C2vPkaXGu8DJlHrGKHLsM25Zg9WuC9pMGfuvT+X25tZQWo5fK1BjBm8+UrVE9LDCvaY0CQk+fXDA==
+  optionalDependencies:
+    rxjs "^7.5.2"
+
+vdirs@^0.1.4, vdirs@^0.1.8:
+  version "0.1.8"
+  resolved "https://registry.npmmirror.com/vdirs/-/vdirs-0.1.8.tgz#a103bc43baca738f8dea912a7e9737154a19dbc2"
+  integrity sha512-H9V1zGRLQZg9b+GdMk8MXDN2Lva0zx72MPahDKc30v+DtwKjfyOSXWRIX4t2mhDubM1H09gPhWeth/BJWPHGUw==
+  dependencies:
+    evtd "^0.2.2"
+
+vite@4.1.3:
+  version "4.1.3"
+  resolved "https://registry.npmmirror.com/vite/-/vite-4.1.3.tgz#001a038c3a7757d532787c0de429b8368136ded5"
+  integrity sha512-0Zqo4/Fr/swSOBmbl+HAAhOjrqNwju+yTtoe4hQX9UsARdcuc9njyOdr6xU0DDnV7YP0RT6mgTTOiRtZgxfCxA==
+  dependencies:
+    esbuild "^0.16.14"
+    postcss "^8.4.21"
+    resolve "^1.22.1"
+    rollup "^3.10.0"
+  optionalDependencies:
+    fsevents "~2.3.2"
+
+vooks@^0.2.12, vooks@^0.2.4:
+  version "0.2.12"
+  resolved "https://registry.npmmirror.com/vooks/-/vooks-0.2.12.tgz#2b6e23330b77bac81c7f7a344c4ca3e9f4f6c373"
+  integrity sha512-iox0I3RZzxtKlcgYaStQYKEzWWGAduMmq+jS7OrNdQo1FgGfPMubGL3uGHOU9n97NIvfFDBGnpSvkWyb/NSn/Q==
+  dependencies:
+    evtd "^0.2.2"
+
+vueuc@^0.4.47:
+  version "0.4.51"
+  resolved "https://registry.npmmirror.com/vueuc/-/vueuc-0.4.51.tgz#35cd5364db4b71fc791a9823748711b91d910d49"
+  integrity sha512-pLiMChM4f+W8czlIClGvGBYo656lc2Y0/mXFSCydcSmnCR1izlKPGMgiYBGjbY9FDkFG8a2HEVz7t0DNzBWbDw==
+  dependencies:
+    "@css-render/vue3-ssr" "^0.15.10"
+    "@juggle/resize-observer" "^3.3.1"
+    css-render "^0.15.10"
+    evtd "^0.2.4"
+    seemly "^0.3.6"
+    vdirs "^0.1.4"
+    vooks "^0.2.4"
+
+webrtc-adapter@^8.1.1:
+  version "8.2.2"
+  resolved "https://registry.npmmirror.com/webrtc-adapter/-/webrtc-adapter-8.2.2.tgz#3497a7a57905b2ec0bf804278a775a348952ca16"
+  integrity sha512-jQWwqiAEAFZamWliJo0Q+dIC6ZMJ8BgCFvW/oXWVFby1Nw14dOUfPwZ3lVe4nafDXdTyCUT7xfLt5xXiioXUCQ==
+  dependencies:
+    sdp "^3.2.0"