feat:更新协作信息
This commit is contained in:
@@ -8,7 +8,7 @@ onMounted(() => {
|
||||
const userStore = useUserStore()
|
||||
} catch (error) {
|
||||
console.warn('App.vue: Pinia 初始化中...', error)
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
@@ -128,4 +128,13 @@ export function getParticipantsApi(roomId) {
|
||||
method: 'get',
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 获取当前房间中视频
|
||||
export function getvideoUrlApi(room_uid) {
|
||||
return request({
|
||||
url: `/api/v1/room/${ room_uid }/recordings`,
|
||||
method: 'get',
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -16,4 +16,23 @@ export function getDirectoriesUsers(directory_uuid,data) {
|
||||
method: 'get',
|
||||
params:data
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
//获取参与者历史参会记录
|
||||
export function getParticipantsHistoryApi(userId,data) {
|
||||
return request({
|
||||
url: `/api/v1/rooms/${ userId }/participants/history`,
|
||||
method: 'get',
|
||||
params:data
|
||||
})
|
||||
}
|
||||
|
||||
// 获取用户详细信息
|
||||
export function getInfo(userUid,type) {
|
||||
return request({
|
||||
url: `/api/v1/auth/users/${userUid}`,
|
||||
method: 'get',
|
||||
params:type
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,8 @@
|
||||
import iframeToggle from "./IframeToggle/index.vue";
|
||||
import useTagsViewStore from "@/stores/modules/tagsView.js";
|
||||
|
||||
const tagsViewStore = useTagsViewStore();
|
||||
const tagsViewStore = useTagsViewStore();
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
149
src/layout/components/InviteJoin/index.vue
Normal file
149
src/layout/components/InviteJoin/index.vue
Normal file
@@ -0,0 +1,149 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
v-model="inviteDialog"
|
||||
title="远程协作"
|
||||
width="400px"
|
||||
:close-on-press-escape="false"
|
||||
:close-on-click-modal="false"
|
||||
:show-close="false"
|
||||
>
|
||||
|
||||
<div style="width: 100%; margin-bottom: 30px; font-size: 20px">
|
||||
"
|
||||
{{
|
||||
socketInformation.room_name
|
||||
? socketInformation.room_name
|
||||
: ''
|
||||
}}
|
||||
" 邀请您参加远程协作
|
||||
</div>
|
||||
<div style="text-align: center">
|
||||
<el-button
|
||||
size="large"
|
||||
type="danger"
|
||||
style="font-size: 16px"
|
||||
@click="clickRefuseJoin"
|
||||
>
|
||||
拒 绝
|
||||
</el-button>
|
||||
<el-button
|
||||
size="large"
|
||||
type="primary"
|
||||
style="font-size: 16px"
|
||||
@click="clickJoin"
|
||||
>
|
||||
加 入
|
||||
</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref ,onMounted} from 'vue'
|
||||
import { getStatusApi } from '@/api/conferencingRoom.js'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { mqttClient } from "@/utils/mqtt.js";
|
||||
import { useUserStore } from '@/stores/modules/user.js'
|
||||
|
||||
const router = useRouter()
|
||||
const userStore = useUserStore()
|
||||
|
||||
const inviteDialog = ref(false)
|
||||
const socketInformation = ref(null)
|
||||
|
||||
|
||||
/** 拒绝加入 */
|
||||
const clickRefuseJoin = async () => {
|
||||
//status 1: 同意加入, 5: 拒绝加入
|
||||
try{
|
||||
const res = await getStatusApi(socketInformation.value.room_uid,{status:5})
|
||||
if(res.meta.code == 200){
|
||||
ElMessage({
|
||||
message: '已拒绝加入该协作',
|
||||
type: 'error',
|
||||
})
|
||||
inviteDialog.value = false
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error,'error')
|
||||
inviteDialog.value = false
|
||||
} finally {
|
||||
inviteDialog.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const clickJoin = async () => {
|
||||
const res = await getStatusApi(socketInformation.value.room_uid,{status:1})
|
||||
if(res.meta.code == 200){
|
||||
ElMessage({
|
||||
message: '成功加入该协作',
|
||||
type: 'success',
|
||||
})
|
||||
inviteDialog.value = false
|
||||
router.push({
|
||||
path: '/conferencingRoom',
|
||||
query:{
|
||||
type:2,//创建房间,加入房间 2
|
||||
room_uid:socketInformation.value.room_uid
|
||||
}
|
||||
})
|
||||
}
|
||||
inviteDialog.value = false
|
||||
|
||||
}
|
||||
|
||||
/** 浏览器通知 */
|
||||
const showNotification = (data) => {
|
||||
if ('Notification' in window) {
|
||||
Notification.requestPermission().then((permission) => {
|
||||
if (permission === 'granted') {
|
||||
const notification = new Notification('协作邀请', {
|
||||
// body: String(data.room_name) + '邀请您参加远程协作'
|
||||
body: '远程协作有新的邀请'
|
||||
// icon: logo,
|
||||
})
|
||||
notification.onclick = () => { clickJoin() }
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/** 处理加入房间和拒接房间 mqtt 消息 */
|
||||
const processingSocket = (message) => {
|
||||
const res = JSON.parse(message)
|
||||
console.log(res,'收到用户信息 邀请')
|
||||
if (!res?.status) {
|
||||
socketInformation.value = res
|
||||
inviteDialog.value = true
|
||||
showNotification(socketInformation.value)
|
||||
}else if(res.status == 5){
|
||||
ElMessage({
|
||||
message: `${res?.display_name}拒绝加入该协作`,
|
||||
type: 'error',
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
processingSocket,
|
||||
});
|
||||
|
||||
// onMounted(async () => {
|
||||
// await mqttClient.connect(`room${Math.random().toString(16).substr(2, 8)}`);
|
||||
// const res = await userStore.getInfo()
|
||||
// const topic = `xSynergy/ROOM/+/rooms/${res.uid}`;
|
||||
// mqttClient.subscribe(topic, async (shapeData) => {
|
||||
// // console.log(shapeData.toString(),'shapeData发送邀请')
|
||||
// processingSocket(shapeData.toString())
|
||||
// });
|
||||
// })
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
</style>
|
||||
|
||||
@@ -2,4 +2,5 @@ export { default as AppMain } from './AppMain.vue'
|
||||
export { default as Navbar } from './Navbar.vue'
|
||||
export { default as Settings } from './Settings/index.vue'
|
||||
export { default as TagsView } from './TagsView/index.vue'
|
||||
export { default as ResetPwd } from './ResetPwd/index.vue'
|
||||
export { default as ResetPwd } from './ResetPwd/index.vue'
|
||||
export { default as InviteJoin } from './InviteJoin/index.vue'
|
||||
@@ -37,23 +37,28 @@
|
||||
</div>
|
||||
</div>
|
||||
<ResetPwd ref="resetPwdRef"/>
|
||||
<InviteJoin ref="inviteJoinRef"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ElMessageBox } from 'element-plus'
|
||||
import { ElMessageBox ,ElMessage} from 'element-plus'
|
||||
import { useWindowSize } from '@vueuse/core'
|
||||
import Sidebar from './components/Sidebar/index.vue'
|
||||
import { AppMain, TagsView ,ResetPwd} from './components/index.js'
|
||||
import { AppMain, TagsView ,ResetPwd,InviteJoin} from './components/index.js'
|
||||
import { useAppStore } from '@/stores/modules/app.js'
|
||||
import { useSettingsStore } from '@/stores/modules/settings.js'
|
||||
import { useUserStore } from '@/stores/modules/user.js'
|
||||
import { removeToken } from '@/utils/auth.js'
|
||||
import { onMounted ,ref} from 'vue'
|
||||
import { mqttClient } from "@/utils/mqtt.js";
|
||||
|
||||
const settingsStore = useSettingsStore()
|
||||
const userStore = useUserStore()
|
||||
const useAppStoreStore = useAppStore()
|
||||
const router = useRouter()
|
||||
|
||||
const inviteJoinRef = ref(null)
|
||||
|
||||
const theme = computed(() => settingsStore.theme)
|
||||
const sidebar = computed(() => useAppStoreStore.sidebar)
|
||||
@@ -136,6 +141,18 @@ function handleClickOutside() {
|
||||
useAppStoreStore.closeSideBar({ withoutAnimation: false })
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
await mqttClient.connect(`room${Math.random().toString(16).substr(2, 8)}`);
|
||||
const res = await userStore.getInfo()
|
||||
const topic = `xSynergy/ROOM/+/rooms/${res.uid}`;
|
||||
mqttClient.subscribe(topic, async (shapeData) => {
|
||||
if(inviteJoinRef.value){
|
||||
inviteJoinRef.value.processingSocket(shapeData.toString())
|
||||
}
|
||||
|
||||
});
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@@ -68,6 +68,12 @@ export const constantRoutes = [
|
||||
hidden: true,
|
||||
meta: { title: "401未授权" }
|
||||
},
|
||||
{
|
||||
path: '/assistWx',
|
||||
component: () => import('@/views/coordinate/personnelList/components/assistWx/index.vue'),
|
||||
meta: { title: "白板" },
|
||||
hidden: true,
|
||||
},
|
||||
]
|
||||
|
||||
export const dynamicRoutes = [
|
||||
|
||||
@@ -7,6 +7,8 @@ export const useRoomStore = defineStore('room', {
|
||||
userUid: '',
|
||||
//邀请进入房间的用户uid
|
||||
detailUid: '',
|
||||
//邀请用户名称
|
||||
detailName: '',
|
||||
}),
|
||||
actions: {
|
||||
setUserUid(data) {
|
||||
@@ -14,6 +16,9 @@ export const useRoomStore = defineStore('room', {
|
||||
},
|
||||
setDetailUid(data) {
|
||||
this.detailUid = data
|
||||
},
|
||||
setDetailName(data) {
|
||||
this.detailName = data
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,9 +17,8 @@ export const useUserStore = defineStore(
|
||||
async login(userInfo) {
|
||||
try {
|
||||
const { username, password } = userInfo;
|
||||
const trimmedUsername = username.trim();
|
||||
|
||||
const res = await login(trimmedUsername, password);
|
||||
const trimmedUsername = username.trim();
|
||||
const res = await login(trimmedUsername, password);
|
||||
if (res.meta.code !== 200) {
|
||||
ElMessage({ message: res.meta?.message || '登录失败', type: 'error' });
|
||||
return Promise.reject(res);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
import Cookies from "js-cookie";
|
||||
|
||||
import router from '@/router';
|
||||
const TokenKey = "token";
|
||||
|
||||
export function getToken() {
|
||||
@@ -18,3 +18,54 @@ export function removeToken() {
|
||||
return sessionStorage.removeItem(TokenKey);
|
||||
}
|
||||
|
||||
//获取用户信息
|
||||
export function getUserInfo() {
|
||||
try {
|
||||
const userData = sessionStorage.getItem("userData");
|
||||
|
||||
// 如果userData不存在,执行未授权处理
|
||||
if (!userData) {
|
||||
handleUnauthorized();
|
||||
return null;
|
||||
}
|
||||
|
||||
// 尝试解析JSON数据
|
||||
try {
|
||||
const parsedData = JSON.parse(userData);
|
||||
return parsedData;
|
||||
} catch (parseError) {
|
||||
console.error('用户数据格式错误,无法解析JSON:', parseError);
|
||||
// 数据格式错误也视为未登录
|
||||
sessionStorage.removeItem("userData");
|
||||
handleUnauthorized();
|
||||
return null;
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('获取用户信息时发生错误:', error);
|
||||
handleUnauthorized();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function handleUnauthorized() {
|
||||
removeToken();
|
||||
|
||||
// 使用 nextTick 确保路由状态已更新
|
||||
import('vue').then(({ nextTick }) => {
|
||||
nextTick(() => {
|
||||
const currentPath = router.currentRoute.value.fullPath;
|
||||
if (router.currentRoute.value.path !== '/login') {
|
||||
router.push({
|
||||
path: '/login',
|
||||
query: {
|
||||
redirect: currentPath !== '/login' ? currentPath : undefined
|
||||
}
|
||||
});
|
||||
} else {
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -156,9 +156,10 @@ service.interceptors.response.use(
|
||||
// if(currentPath == 'ConferencingRoom'){
|
||||
// return Promise.resolve(responseData);
|
||||
// }else{
|
||||
return handleUnauthorized().then(() => {
|
||||
return Promise.reject({ code: 401, message: '未授权' });
|
||||
});
|
||||
return handleUnauthorized()
|
||||
// .then(() => {
|
||||
// return Promise.reject({ code: 401, message: '未授权' });
|
||||
// });
|
||||
// }
|
||||
case 500:
|
||||
const serverErrorMsg = responseData.meta?.message || '服务器内部错误';
|
||||
@@ -221,7 +222,7 @@ service.interceptors.response.use(
|
||||
// });
|
||||
// }
|
||||
|
||||
function handleUnauthorized() {
|
||||
function handleUnauthorized() {
|
||||
removeToken();
|
||||
|
||||
// 使用 nextTick 确保路由状态已更新
|
||||
|
||||
@@ -716,3 +716,26 @@ export function removeDuplicate(arr) {
|
||||
});
|
||||
return newArr; // 返回一个新数组
|
||||
}
|
||||
|
||||
|
||||
export function createThrottle(func, delay){
|
||||
let timeoutId;
|
||||
let lastExecTime = 0;
|
||||
|
||||
return (...args) => {
|
||||
const currentTime = Date.now();
|
||||
|
||||
// 立即执行第一次
|
||||
if (currentTime - lastExecTime > delay) {
|
||||
func.apply(this, args);
|
||||
lastExecTime = currentTime;
|
||||
} else {
|
||||
// 清除之前的定时器,设置新的定时器
|
||||
clearTimeout(timeoutId);
|
||||
timeoutId = setTimeout(() => {
|
||||
func.apply(this, args);
|
||||
lastExecTime = Date.now();
|
||||
}, delay);
|
||||
}
|
||||
};
|
||||
};
|
||||
@@ -157,4 +157,4 @@ function isValidBox(x1, y1, x2, y2, imgWidth, imgHeight) {
|
||||
x2 > x1 && y2 > y1 &&
|
||||
x2 <= imgWidth && y2 <= imgHeight
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import { ElMessage } from 'element-plus';
|
||||
export function errorHandling(error,type) {
|
||||
switch (error.name) {
|
||||
case 'NotAllowedError':
|
||||
ElMessage.error('用户拒绝了权限请求,请允许此网站使用摄像头');
|
||||
ElMessage.error(`用户拒绝了权限请求,请允许此网站使用${type}权限`);
|
||||
break;
|
||||
case 'NotFoundError':
|
||||
ElMessage.error(`未检测到可用的${type}设备,请检查${type}是否已正确连接`);
|
||||
|
||||
@@ -1,9 +1,17 @@
|
||||
<template>
|
||||
<template>
|
||||
<div v-if="showLogin">
|
||||
<!-- 登录界面 -->
|
||||
<Login @loginSuccess="handleLoginSuccess" />
|
||||
</div>
|
||||
<div v-else>
|
||||
<!-- 加载状态 -->
|
||||
<div v-if="loading" class="loading-container">
|
||||
<div class="loading-content">
|
||||
<el-icon class="loading-icon"><Loading /></el-icon>
|
||||
<p>正在创建房间,请稍候...</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 音频元素 -->
|
||||
<audio ref="localAudio" autoplay muted class="audio-element"></audio>
|
||||
<div id="audio"></div>
|
||||
@@ -100,8 +108,7 @@
|
||||
:ref="el => setScreenShareVideoRef(el)"
|
||||
autoplay
|
||||
playsinline
|
||||
class="screen-share-element"
|
||||
style='border:1px solid red'
|
||||
class="screen-share-element"
|
||||
@loadedmetadata="handleScreenShareLoaded">
|
||||
</video>
|
||||
<!-- 如果没有屏幕共享,显示提示 -->
|
||||
@@ -445,7 +452,7 @@ const enlargedLaserPointerCanvas = ref(null); // 放大视频激光笔 Canvas
|
||||
const enlargedLaserPointerContext = ref(null); // 放大视频激光笔上下文
|
||||
|
||||
const lastActivatedLayer = ref(''); // 记录最后激活的图层:'screenVideo' 或 'whiteboard'
|
||||
|
||||
const loading = ref(false);
|
||||
// 路径更新节流处理
|
||||
let lastPublishTime = 0;
|
||||
const publishThrottleTime = 100; // 100ms 节流
|
||||
@@ -1934,9 +1941,12 @@ async function handleConfirmSelection(userInfo){
|
||||
if(userInfo.length < 0){
|
||||
ElMessage.error('请选择加入房间的人员')
|
||||
return
|
||||
}
|
||||
const joinUserIds = userInfo.map(item => item.uid)
|
||||
await getInvite(room.name,{user_uids:joinUserIds, participant_role: "participant"})
|
||||
}
|
||||
const joinUserInfo = userInfo.map(item => ({
|
||||
user_uid: item.uid,
|
||||
display_name: item.name
|
||||
}));
|
||||
await getInvite(room.name,{participants:joinUserInfo, participant_role: "participant"})
|
||||
}
|
||||
|
||||
function publishWhiteboardMessage(type, payload = {}) {
|
||||
@@ -2832,9 +2842,13 @@ function handleScreenShareEnded() {
|
||||
|
||||
async function joinRoomBtn() {
|
||||
try {
|
||||
loading.value = true; // 开始加载
|
||||
status.value = true; // 确保显示加载状态
|
||||
|
||||
const res = await getRoomToken({max_participants: 20});
|
||||
if(res.meta.code != 200){
|
||||
ElMessage.error(res.meta.message);
|
||||
loading.value = false;
|
||||
return;
|
||||
}
|
||||
const token = res.data.access_token;
|
||||
@@ -2849,6 +2863,8 @@ async function joinRoomBtn() {
|
||||
} catch (error) {
|
||||
ElMessage.error(`连接失败: ${error.message}`);
|
||||
status.value = true;
|
||||
} finally {
|
||||
loading.value = false; // 无论成功失败都结束加载
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3094,7 +3110,7 @@ onMounted(async () => {
|
||||
hostUid.value = roomStore.userUid
|
||||
// 邀请用户参与房间
|
||||
if(room.name){
|
||||
await getInvite(room.name,{user_uids:[roomStore.detailUid], participant_role: "participant"})
|
||||
await getInvite(room.name,{participants:[{user_uid:roomStore.detailUid,display_name:roomStore.detailName}], participant_role: "participant"})
|
||||
}
|
||||
} else {
|
||||
const res = await getTokenApi(route.query.room_uid)
|
||||
@@ -3115,6 +3131,42 @@ onMounted(async () => {
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.loading-container {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(15, 15, 26, 0.95);
|
||||
backdrop-filter: blur(10px);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
.loading-content {
|
||||
text-align: center;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.loading-icon {
|
||||
font-size: 48px;
|
||||
color: #409eff;
|
||||
margin-bottom: 16px;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
.loading-content p {
|
||||
margin: 0;
|
||||
font-size: 16px;
|
||||
color: #a0a0b0;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
/* 内容层级容器 */
|
||||
.content-layers-container {
|
||||
position: relative;
|
||||
@@ -3145,7 +3197,7 @@ onMounted(async () => {
|
||||
.enlarged-video-wrapper,
|
||||
.screen-share-wrapper {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
height: 95%;
|
||||
}
|
||||
|
||||
.enlarged-video-element,
|
||||
@@ -3438,7 +3490,7 @@ body {
|
||||
}
|
||||
.screen-share-element {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
height: 96%;
|
||||
object-fit: contain;
|
||||
background: #000;
|
||||
border-radius: 8px;
|
||||
@@ -3733,7 +3785,7 @@ body {
|
||||
}
|
||||
.microphone-control-group .dropdown-btn {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
height: 40px;
|
||||
}
|
||||
.controls-container {
|
||||
gap: 6px;
|
||||
|
||||
@@ -1108,7 +1108,7 @@ async function handleConfirmSelection(userInfo){
|
||||
ElMessage.error('请选择加入房间的人员')
|
||||
return
|
||||
}
|
||||
const joinUserIds = userInfo.map(item => item.uid)
|
||||
const joinUserIds = userInfo.map(item => item.uid)
|
||||
await getInvite(room.name,{user_uids:joinUserIds, participant_role: "participant"})
|
||||
}
|
||||
|
||||
|
||||
@@ -1,34 +1,236 @@
|
||||
<template>
|
||||
<div class="wrapper-content">
|
||||
|
||||
<div>
|
||||
<el-dialog
|
||||
v-model="dialogFormVisible"
|
||||
width="80%"
|
||||
:show-close="false"
|
||||
:destroy-on-close="true"
|
||||
:modal="false"
|
||||
:lock-scroll="true"
|
||||
:before-close="handleClose"
|
||||
class="call-dialog"
|
||||
>
|
||||
<div class="call-wrapper">
|
||||
<!-- 上方头像与状态 -->
|
||||
<div class="avatar-section">
|
||||
<img class="avatar" :src="avatarUrl" alt="头像" />
|
||||
<div class="user-name">{{ userName }}</div>
|
||||
<div class="status-text">{{ statusText }}</div>
|
||||
</div>
|
||||
|
||||
<!-- 底部操作按钮 -->
|
||||
<div class="control-section">
|
||||
<!-- 呼叫模式 -->
|
||||
<template v-if="mode === 'call'">
|
||||
<el-button
|
||||
v-if="callStatus === 'calling'"
|
||||
type="danger"
|
||||
round
|
||||
class="control-btn hangup"
|
||||
@click="hangup"
|
||||
>
|
||||
挂断
|
||||
</el-button>
|
||||
<el-button
|
||||
v-else
|
||||
type="primary"
|
||||
round
|
||||
class="control-btn call"
|
||||
@click="startCall"
|
||||
>
|
||||
呼叫中...
|
||||
</el-button>
|
||||
</template>
|
||||
|
||||
<!-- 接听模式 -->
|
||||
<template v-else>
|
||||
<el-button
|
||||
type="success"
|
||||
round
|
||||
class="control-btn accept"
|
||||
@click="acceptCall"
|
||||
>
|
||||
接听
|
||||
</el-button>
|
||||
<el-button
|
||||
type="danger"
|
||||
round
|
||||
class="control-btn hangup"
|
||||
@click="hangup"
|
||||
>
|
||||
挂断
|
||||
</el-button>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, nextTick, onUnmounted, onMounted } from "vue";
|
||||
import { ElLoading, ElMessage } from "element-plus";
|
||||
import { useRoute } from "vue-router";
|
||||
import { mqttClient } from "@/utils/mqtt";
|
||||
|
||||
const props = defineProps({
|
||||
roomId: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
|
||||
})
|
||||
const route = useRoute();
|
||||
|
||||
|
||||
onMounted(async () => {
|
||||
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
<script setup>
|
||||
import { ref, computed } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
const props = defineProps({
|
||||
mode: { type: String, default: "call" }, // call: 呼叫模式, receive: 接听模式
|
||||
avatarUrl: {
|
||||
type: String,
|
||||
default: "https://cdn-icons-png.flaticon.com/512/1946/1946429.png",
|
||||
},
|
||||
userName: { type: String, default: "对方用户" },
|
||||
});
|
||||
|
||||
const dialogFormVisible = ref(false);
|
||||
const callStatus = ref("calling"); // calling | active | ended
|
||||
|
||||
const statusText = computed(() => {
|
||||
if (props.mode === "call") {
|
||||
if (callStatus.value === "calling") return "正在呼叫对方...";
|
||||
if (callStatus.value === "active") return "通话中";
|
||||
return "通话结束";
|
||||
} else {
|
||||
return callStatus.value === "active" ? "通话中" : "对方来电...";
|
||||
}
|
||||
});
|
||||
|
||||
function startCall() {
|
||||
callStatus.value = "active";
|
||||
ElMessage.success("开始通话");
|
||||
}
|
||||
|
||||
function acceptCall() {
|
||||
callStatus.value = "active";
|
||||
ElMessage.success("已接听");
|
||||
}
|
||||
|
||||
function hangup() {
|
||||
callStatus.value = "ended";
|
||||
ElMessage.error("通话已结束");
|
||||
}
|
||||
|
||||
function handleClose() {
|
||||
dialogFormVisible.value = false;
|
||||
}
|
||||
|
||||
function show() {
|
||||
dialogFormVisible.value = true;
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
show,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* ::v-deep .el-dialog__header{
|
||||
background-color:red;
|
||||
} */
|
||||
/* 去除 el-dialog 默认样式,让它全屏覆盖且透明 */
|
||||
.call-dialog :deep(.el-dialog) {
|
||||
background: transparent;
|
||||
box-shadow: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border-radius: 0;
|
||||
height: calc(100vh - 30vh);
|
||||
width: 100%;
|
||||
max-width: none;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.call-dialog :deep(.el-dialog__body) {
|
||||
padding: 0;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/* 通话主背景 */
|
||||
.call-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
height: calc(100vh - 30vh);
|
||||
width: 100%;
|
||||
background: linear-gradient(180deg, #0f2027, #203a43, #2c5364);
|
||||
color: #fff;
|
||||
box-sizing: border-box;
|
||||
padding: 80px 0;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* 头像部分 */
|
||||
.avatar-section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
width: 180px;
|
||||
height: 180px;
|
||||
border-radius: 50%;
|
||||
border: 6px solid rgba(255, 255, 255, 0.25);
|
||||
box-shadow: 0 0 40px rgba(0, 0, 0, 0.4);
|
||||
object-fit: cover;
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.avatar:hover {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
.user-name {
|
||||
margin-top: 24px;
|
||||
font-size: 26px;
|
||||
font-weight: 600;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.status-text {
|
||||
margin-top: 12px;
|
||||
font-size: 18px;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
/* 控制按钮部分 */
|
||||
.control-section {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 80px;
|
||||
}
|
||||
|
||||
.control-btn {
|
||||
width: 160px;
|
||||
height: 60px;
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
letter-spacing: 1px;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.control-btn:hover {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
.control-btn.accept {
|
||||
background: linear-gradient(135deg, #00c853, #4caf50);
|
||||
color: #fff;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.control-btn.hangup {
|
||||
background: linear-gradient(135deg, #ff1744, #d50000);
|
||||
color: #fff;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.control-btn.call {
|
||||
background: linear-gradient(135deg, #2196f3, #1976d2);
|
||||
color: #fff;
|
||||
border: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -19,14 +19,45 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="list-content">
|
||||
<div class="content-top-input">
|
||||
<div class="content-top-input" v-if="leftTab == 1">
|
||||
<!-- <el-input
|
||||
v-model="queryFrom.nickName"
|
||||
placeholder="搜索成员"
|
||||
type="text"
|
||||
prefix-icon="Search"
|
||||
@change="searchList"
|
||||
/> -->
|
||||
<el-select
|
||||
v-model="participant_user"
|
||||
multiple
|
||||
filterable
|
||||
clearable
|
||||
remote
|
||||
reserve-keyword
|
||||
placeholder="搜索成员"
|
||||
:remote-method="remoteMethod"
|
||||
:loading="loading"
|
||||
collapse-tags
|
||||
collapse-tags-tooltip
|
||||
style="width: 100%"
|
||||
@change="searchList"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in userList"
|
||||
:key="item.uid"
|
||||
:label="item.name"
|
||||
:value="item.uid"
|
||||
/>
|
||||
</el-select>
|
||||
</div>
|
||||
<div class="content-top-input" v-if="leftTab == 2">
|
||||
<el-input
|
||||
v-model="queryFrom.nickName"
|
||||
placeholder="搜索成员"
|
||||
type="text"
|
||||
prefix-icon="Search"
|
||||
@change="searchList"
|
||||
/>
|
||||
/>
|
||||
</div>
|
||||
<div class="content-datapicker" v-if="leftTab == 1">
|
||||
<el-date-picker
|
||||
@@ -47,49 +78,50 @@
|
||||
v-infinite-scroll="infinite"
|
||||
v-if="dataList?.length"
|
||||
>
|
||||
<!-- @click="updateDetail(item)" -->
|
||||
<div
|
||||
v-for="(item, index) in dataList"
|
||||
:key="index"
|
||||
class="content-list-item"
|
||||
@click="updateDetail(item)"
|
||||
:style="
|
||||
item.assistanceId == assistanceId
|
||||
item.id == assistanceId
|
||||
? 'border-color: #409EFF; '
|
||||
: ''
|
||||
"
|
||||
>
|
||||
<div class="list-item-top">
|
||||
<span>
|
||||
{{ parseTime(item.beginTime, '{m}月{d}日') }}
|
||||
{{ weekName[new Date(item.beginTime).getDay()] }}
|
||||
{{ parseTime(item.created_at, '{m}月{d}日') }}
|
||||
{{ weekName[new Date(item.created_at).getDay()] }}
|
||||
</span>
|
||||
<span>
|
||||
{{ parseTime(item.beginTime, '{y}年') }}
|
||||
{{ parseTime(item.created_at, '{y}年') }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="list-item-content">
|
||||
<div class="list-item-content-text">
|
||||
<div style="display: flex; flex-wrap: wrap">
|
||||
<span
|
||||
v-for="(items, indexs) in item.assistanceMemberList"
|
||||
v-for="(items, indexs) in item.all_participants"
|
||||
:key="indexs"
|
||||
>
|
||||
{{
|
||||
items.nickName +
|
||||
(indexs + 1 == item.assistanceMemberList.length
|
||||
items.display_name +
|
||||
(indexs + 1 == item.all_participants.length
|
||||
? ''
|
||||
: '、')
|
||||
}}
|
||||
</span>
|
||||
</div>
|
||||
<span>
|
||||
发起人:{{ item.initiatorName ? item.initiatorName : '' }}
|
||||
发起人:{{ item.all_participants.find(item => item.participant_role == 'moderator')?.display_name || ''}}
|
||||
</span>
|
||||
<span>
|
||||
时间:{{
|
||||
parseTime(item.beginTime, '{h}:{i}') +
|
||||
parseTime(item.created_at, '{h}:{i}') +
|
||||
' ~ ' +
|
||||
(item.endTime ? parseTime(item.endTime, '{h}:{i}') : '')
|
||||
(item.updated_at ? parseTime(item.updated_at, '{h}:{i}') : '')
|
||||
}}
|
||||
</span>
|
||||
</div>
|
||||
@@ -138,10 +170,14 @@
|
||||
<script setup>
|
||||
import {
|
||||
// getAssistanceList,
|
||||
getParticipantsHistoryApi,
|
||||
getDirectories,
|
||||
getDirectoriesUsers
|
||||
getDirectoriesUsers,
|
||||
getInfo,
|
||||
} from '@/api/coordinate.js'
|
||||
import { nextTick, reactive, toRefs, watch, onMounted } from 'vue'
|
||||
import { deepClone,parseTime ,createThrottle} from '@/utils/ruoyi.js'
|
||||
import { getUserInfo } from '@/utils/auth.js'
|
||||
|
||||
// 接收 props
|
||||
const props = defineProps({
|
||||
@@ -157,13 +193,15 @@ const emit = defineEmits(['updateDetail', 'updateTab'])
|
||||
// state
|
||||
const state = reactive({
|
||||
isFirst: true,
|
||||
leftTab: 2,
|
||||
leftTab: 1,
|
||||
queryFrom: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
page_size: 10,
|
||||
page: 1,
|
||||
nickName: '',
|
||||
leftDatePicker: null,
|
||||
leftDatePicker: null,
|
||||
participant_user_uids:''
|
||||
},
|
||||
participant_user:[],
|
||||
leftListLoading: true,
|
||||
loading: false,
|
||||
dataList: [],
|
||||
@@ -216,7 +254,22 @@ const state = reactive({
|
||||
},
|
||||
},
|
||||
assistanceId: '',
|
||||
})
|
||||
userList:[],
|
||||
})
|
||||
// state.loading = true;
|
||||
const remoteMethod = createThrottle(async (query) => {
|
||||
if (!query || query.trim() === '') {
|
||||
state.userList = [];
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const res = await getInfo(query, { search_type: 'name' });
|
||||
state.userList = res.data || [];
|
||||
} catch (error) {
|
||||
console.error('搜索用户失败:', error);
|
||||
state.userList = [];
|
||||
}
|
||||
}, 500);
|
||||
|
||||
/**
|
||||
* 树状列表筛选
|
||||
@@ -231,11 +284,11 @@ const filterNode = (value, data) => {
|
||||
*/
|
||||
const searchList = () => {
|
||||
if (state.leftTab == 1) {
|
||||
state.queryFrom.pageNum = 1
|
||||
state.dataList = []
|
||||
state.queryFrom.page = 1
|
||||
state.dataList = []
|
||||
state.queryFrom.participant_user_uids = state.participant_user.join(',')
|
||||
getList()
|
||||
} else {
|
||||
// console.log('treeRef.filter',state.treeRef)
|
||||
} else {
|
||||
state.treeRef.filter(state.queryFrom.nickName)
|
||||
}
|
||||
}
|
||||
@@ -244,8 +297,8 @@ const searchList = () => {
|
||||
* 变更详情
|
||||
*/
|
||||
const updateDetail = (item) => {
|
||||
if (state.leftTab == 1) {
|
||||
state.assistanceId = item.assistanceId
|
||||
if (state.leftTab == 1) {
|
||||
state.assistanceId = item.id
|
||||
emit('updateDetail', item)
|
||||
} else {
|
||||
if (item.uid) {
|
||||
@@ -257,43 +310,63 @@ const updateDetail = (item) => {
|
||||
/**
|
||||
* 触底加载
|
||||
*/
|
||||
// const infinite = () => {
|
||||
// if (state.more) {
|
||||
// state.queryFrom.pageNum++
|
||||
// getList()
|
||||
// }
|
||||
// }
|
||||
const infinite = () => {
|
||||
if (state.more) {
|
||||
state.queryFrom.page++
|
||||
getList()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 协作记录
|
||||
*/
|
||||
const getList = async () => {
|
||||
try {
|
||||
state.leftListLoading = true
|
||||
try {
|
||||
state.leftListLoading = true
|
||||
let query = deepClone(state.queryFrom)
|
||||
// if (query.leftDatePicker?.length) {
|
||||
// query.beginSignTime = query.leftDatePicker[0]
|
||||
// query.endSignTime = query.leftDatePicker[1]
|
||||
// }
|
||||
|
||||
let query = structuredClone(state.queryFrom)
|
||||
if (query.leftDatePicker?.length) {
|
||||
query.beginSignTime = query.leftDatePicker[0]
|
||||
query.endSignTime = query.leftDatePicker[1]
|
||||
if (query.leftDatePicker?.length) {
|
||||
const startTime = new Date(query.leftDatePicker[0]);
|
||||
const endTime = new Date(query.leftDatePicker[1]);
|
||||
|
||||
// 添加日期有效性验证
|
||||
if (!isNaN(startTime.getTime())) {
|
||||
query.start_time = Math.floor(startTime.getTime());
|
||||
} else {
|
||||
console.error('开始时间格式无效:', query.leftDatePicker[0]);
|
||||
query.start_time = '';
|
||||
}
|
||||
|
||||
if (!isNaN(endTime.getTime())) {
|
||||
query.end_time = Math.floor(endTime.getTime());
|
||||
} else {
|
||||
console.error('结束时间格式无效:', query.leftDatePicker[1]);
|
||||
query.end_time = '';
|
||||
}
|
||||
}
|
||||
delete query.leftDatePicker
|
||||
|
||||
let infoData = await getAssistanceList({ ...query })
|
||||
|
||||
state.dataList = infoData.rows.length
|
||||
? state.dataList.concat(infoData.rows)
|
||||
delete query.leftDatePicker
|
||||
const userData = await getUserInfo()
|
||||
if(!userData) return
|
||||
let infoData = await getParticipantsHistoryApi( userData?.uid ,{ ...query })
|
||||
state.dataList = infoData.data.history?.length
|
||||
? state.dataList.concat(infoData.data.history)
|
||||
: []
|
||||
|
||||
if (state.isFirst) {
|
||||
emit('updateDetail', state.dataList.length ? state.dataList[0] : null)
|
||||
state.assistanceId = state.dataList.length
|
||||
? state.dataList[0].assistanceId
|
||||
: ''
|
||||
emit('updateDetail', state.dataList?.length ? state.dataList[0] : null)
|
||||
state.assistanceId = state.dataList?.length
|
||||
? state.dataList[0].id
|
||||
: ''
|
||||
state.isFirst = false
|
||||
}
|
||||
|
||||
state.more = state.dataList.length < infoData.total
|
||||
state.isShow = Boolean(state.dataList.length)
|
||||
state.more = state.dataList?.length < infoData.data.total
|
||||
state.isShow = Boolean(state.dataList?.length)
|
||||
state.leftListLoading = false
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
@@ -350,20 +423,7 @@ const loadUserNode = async(resolve,id,level)=>{
|
||||
console.log(error)
|
||||
state.leftListLoading = false
|
||||
}
|
||||
}
|
||||
|
||||
// try {
|
||||
// if (userList.data.sub_units?.length) {
|
||||
// state.dataList = userList.data.sub_units
|
||||
// let user = getUser(state.dataList)
|
||||
// emit('updateDetail', user)
|
||||
// } else {
|
||||
// emit('updateDetail', null)
|
||||
// }
|
||||
// state.leftListLoading = false
|
||||
// }
|
||||
|
||||
|
||||
}
|
||||
|
||||
const getUser = (list) => {
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
@@ -398,15 +458,16 @@ watch(
|
||||
state.dataList = []
|
||||
state.isFirst = true
|
||||
state.queryFrom = {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
page_size: 10,
|
||||
page: 1,
|
||||
nickName: '',
|
||||
participant_user_uids:'',
|
||||
leftDatePicker: null,
|
||||
}
|
||||
|
||||
if (newValue == 1) {
|
||||
state.isShow = false
|
||||
// getList()
|
||||
getList()
|
||||
} else {
|
||||
HandleLoadNode()
|
||||
}
|
||||
@@ -416,7 +477,7 @@ watch(
|
||||
onMounted(() => {
|
||||
state.dataList = []
|
||||
state.isFirst = true
|
||||
// getList()
|
||||
getList()
|
||||
})
|
||||
|
||||
/**
|
||||
@@ -425,7 +486,7 @@ onMounted(() => {
|
||||
const {
|
||||
isFirst, leftTab, queryFrom, leftListLoading, loading,
|
||||
dataList, more, isShow, shortcuts, weekName,
|
||||
treeRef, treeProps, assistanceId
|
||||
treeRef, treeProps, assistanceId,userList,participant_user
|
||||
} = toRefs(state)
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,278 +1,278 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="app-container" v-loading="load" :element-loading-text="loadText">
|
||||
<el-row :gutter="6" style="padding: 0 10px; background: #fefefe">
|
||||
<el-col :xs="24" :sm="24" :md="8" :lg="6">
|
||||
<leftTab
|
||||
@updateDetail="updateDetail"
|
||||
@updateTab="updateTab"
|
||||
:loading="!detail?.appId && !detail?.userId && isShow"
|
||||
/>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="24" :md="16" :lg="18">
|
||||
<div
|
||||
class="right-content"
|
||||
|
||||
>
|
||||
<!-- v-loading="!detail?.appId && !detail?.userId && isShow" -->
|
||||
<div class="right-content-title">
|
||||
{{ tabValue == 1 ? '协作信息' : '员工信息' }}
|
||||
</div>
|
||||
<el-row :gutter="6" style="padding: 0 10px; background: #fefefe">
|
||||
<el-col :xs="24" :sm="24" :md="8" :lg="6">
|
||||
<leftTab
|
||||
@updateDetail="updateDetail"
|
||||
@updateTab="updateTab"
|
||||
:loading="!detail?.appId && !detail?.userId && isShow"
|
||||
/>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="24" :md="16" :lg="18">
|
||||
<div
|
||||
class="agency-detail-massage-cont right-content-message"
|
||||
v-if="isShow && tabValue == 1"
|
||||
>
|
||||
<div class="agency-detail-cont-item">
|
||||
<span class="agency-detail-item-title">发起人</span>
|
||||
<span class="agency-detail-item-content">
|
||||
{{ detail.initiatorName }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="agency-detail-cont-item">
|
||||
<span class="agency-detail-item-title">协作时间</span>
|
||||
<span class="agency-detail-item-content">
|
||||
<!-- {{
|
||||
parseTime(detail.beginTime, '{y}年{m}月{d}日') +
|
||||
' ' +
|
||||
weekName[new Date(detail.beginTime).getDay()] +
|
||||
' ' +
|
||||
parseTime(detail.beginTime, '{h}:{i}')
|
||||
}} -->
|
||||
</span>
|
||||
</div>
|
||||
<div class="agency-detail-cont-item">
|
||||
<span class="agency-detail-item-title">成员</span>
|
||||
<span
|
||||
class="agency-detail-item-content"
|
||||
v-if="detail?.assistanceMemberList?.length"
|
||||
style="display: flex; flex-wrap: wrap"
|
||||
>
|
||||
<span
|
||||
v-for="(items, indexs) in detail.assistanceMemberList"
|
||||
:key="indexs"
|
||||
class="right-content"
|
||||
v-loading='isShowLoading'
|
||||
>
|
||||
<div class="right-content-title">
|
||||
{{ tabValue == 1 ? '协作信息' : '员工信息' }}
|
||||
</div>
|
||||
<div
|
||||
class="agency-detail-massage-cont right-content-message"
|
||||
v-if="isShow && tabValue == 1"
|
||||
>
|
||||
<div class="agency-detail-cont-item">
|
||||
<span class="agency-detail-item-title">发起人</span>
|
||||
<span class="agency-detail-item-content">
|
||||
{{ detail.initiator }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="agency-detail-cont-item">
|
||||
<span class="agency-detail-item-title">协作时间</span>
|
||||
<span class="agency-detail-item-content">
|
||||
{{
|
||||
items.nickName +
|
||||
(indexs + 1 == detail.assistanceMemberList.length
|
||||
? ''
|
||||
: '、')
|
||||
detail.created_at ?
|
||||
parseTime(detail.created_at, '{y}年{m}月{d}日') +
|
||||
' ' +
|
||||
weekName[new Date(detail.created_at).getDay()] +
|
||||
' ' +
|
||||
parseTime(detail.created_at, '{h}:{i}')
|
||||
: '暂无'
|
||||
}}
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="agency-detail-cont-item">
|
||||
<span class="agency-detail-item-title">协作时长</span>
|
||||
<span class="agency-detail-item-content">
|
||||
<!-- {{ getTime() }} -->
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="right-content-file" v-if="isShow && tabValue == 1">
|
||||
<el-row :gutter="15">
|
||||
<el-col :xs="24" :sm="24" :md="16" :lg="18">
|
||||
<div class="content-file-video">
|
||||
<div class="file-top">协作视频</div>
|
||||
<div class="file-video-bottom">
|
||||
<!-- autoplay="autoplay" -->
|
||||
<video
|
||||
v-if="
|
||||
detail.remoteVideoFile?.prefix &&
|
||||
detail.remoteVideoFile.path
|
||||
"
|
||||
:src="
|
||||
detail.remoteVideoFile.prefix +
|
||||
detail.remoteVideoFile.path
|
||||
"
|
||||
id="videoPlayer"
|
||||
loop
|
||||
controls
|
||||
></video>
|
||||
<div v-else class="video-null">暂无视频</div>
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="24" :md="8" :lg="6">
|
||||
<div>
|
||||
<div class="file-top">
|
||||
附件({{
|
||||
detail?.fileList?.length ? detail.fileList.length : 0
|
||||
}})
|
||||
</div>
|
||||
<div class="content-file-list">
|
||||
<el-scrollbar
|
||||
class="file-list"
|
||||
height="calc(100vh - 380px)"
|
||||
<div class="agency-detail-cont-item">
|
||||
<span class="agency-detail-item-title">成员</span>
|
||||
<span
|
||||
class="agency-detail-item-content"
|
||||
v-if="detail?.all_participants?.length"
|
||||
style="display: flex; flex-wrap: wrap"
|
||||
>
|
||||
<div
|
||||
class="file-list-content"
|
||||
v-if="detail?.fileList?.length"
|
||||
<span
|
||||
v-for="(items, indexs) in detail.all_participants"
|
||||
:key="indexs"
|
||||
>
|
||||
{{
|
||||
items.display_name +
|
||||
(indexs + 1 == detail.all_participants.length
|
||||
? ''
|
||||
: '、')
|
||||
}}
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="agency-detail-cont-item">
|
||||
<span class="agency-detail-item-title">协作时长</span>
|
||||
<span class="agency-detail-item-content">
|
||||
{{ getTime() }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="right-content-file" v-if="isShow && tabValue == 1">
|
||||
<el-row :gutter="15">
|
||||
<el-col :xs="24" :sm="24" :md="16" :lg="18">
|
||||
<div class="content-file-video">
|
||||
<div class="file-top">协作视频</div>
|
||||
<div class="file-video-bottom">
|
||||
<!-- autoplay="autoplay" -->
|
||||
<video
|
||||
v-if="detail.remoteVideoFile?.storage_url"
|
||||
:src="detail.remoteVideoFile.storage_url"
|
||||
id="videoPlayer"
|
||||
loop
|
||||
autoplay
|
||||
controls
|
||||
></video>
|
||||
<div v-else class="video-null">暂无视频</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="24" :md="8" :lg="6">
|
||||
<div>
|
||||
<div class="file-top">
|
||||
附件({{
|
||||
detail?.fileList?.length ? detail.fileList.length : 0
|
||||
}})
|
||||
</div>
|
||||
<div class="content-file-list">
|
||||
<el-scrollbar
|
||||
class="file-list"
|
||||
height="calc(100vh - 380px)"
|
||||
>
|
||||
<div
|
||||
class="file-list-item"
|
||||
v-for="(item, index) in detail.fileList"
|
||||
:key="index"
|
||||
>
|
||||
<div class="file-list-item-icon"></div>
|
||||
<div class="file-list-item-text">
|
||||
<div class="list-item-text text-out-of-hiding-1">
|
||||
{{ item.name }}
|
||||
</div>
|
||||
<el-link
|
||||
:href="item.prefix + item.path"
|
||||
type="primary"
|
||||
target="_blank"
|
||||
:underline="false"
|
||||
<div
|
||||
class="file-list-content"
|
||||
v-if="detail?.fileList?.length"
|
||||
>
|
||||
<div
|
||||
class="file-list-item"
|
||||
v-for="(item, index) in detail.fileList"
|
||||
:key="index"
|
||||
>
|
||||
<div class="file-list-item-icon"></div>
|
||||
<div class="file-list-item-text">
|
||||
<div class="list-item-text text-out-of-hiding-1">
|
||||
{{ item.file_name }}
|
||||
</div>
|
||||
<el-icon
|
||||
:size="18"
|
||||
color="#0d74ff"
|
||||
style="cursor: pointer"
|
||||
>
|
||||
<Download />
|
||||
:size="18"
|
||||
color="#0d74ff"
|
||||
style="cursor: pointer"
|
||||
@click="handlePreview(item)"
|
||||
>
|
||||
<View />
|
||||
</el-icon>
|
||||
</el-link>
|
||||
<el-icon
|
||||
:size="18"
|
||||
color="#FF4646"
|
||||
style="cursor: pointer"
|
||||
@click="clickDeleteFile(item)"
|
||||
>
|
||||
<Delete />
|
||||
</el-icon>
|
||||
<el-link
|
||||
:href="item.source_url"
|
||||
type="primary"
|
||||
target="_blank"
|
||||
:underline="false"
|
||||
>
|
||||
<el-icon
|
||||
:size="18"
|
||||
color="#0d74ff"
|
||||
style="cursor: pointer"
|
||||
>
|
||||
<Download />
|
||||
</el-icon>
|
||||
</el-link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
<div
|
||||
class="message-user"
|
||||
v-else-if="isShow && tabValue == 2"
|
||||
style="height: calc(100vh - 90px)"
|
||||
v-loading="userLoading"
|
||||
>
|
||||
<div class="message-user-card">
|
||||
<div class="user-card-nickName">
|
||||
<img v-if="detail.avatar" :src="detail.avatar" />
|
||||
<img v-else src="@/assets/images/profile.jpg" />
|
||||
<span>{{ detail.nickName || detail.name || '暂无信息' }}</span>
|
||||
</div>
|
||||
<div class="user-card-information">
|
||||
<div class="user-information-item">
|
||||
<div class="user-information-title">
|
||||
<img src="@/assets/images/user-information1.png" alt="" />
|
||||
<span>性别</span>
|
||||
</div>
|
||||
<div class="user-information-text">
|
||||
<!-- <dict-tag
|
||||
v-if="detail.sex"
|
||||
:options="sys_user_sex"
|
||||
:value="detail.sex"
|
||||
/>
|
||||
<div v-else>
|
||||
{{ '暂无' }}
|
||||
</div> -->
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
<div class="user-information-item">
|
||||
<div class="user-information-title">
|
||||
<img src="@/assets/images/user-information2.png" alt="" />
|
||||
<span>手机号</span>
|
||||
</div>
|
||||
<div class="user-information-text">
|
||||
{{ detail.phonenumber || '暂无' }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="user-information-item">
|
||||
<div class="user-information-title">
|
||||
<img src="@/assets/images/user-information3.png" alt="" />
|
||||
<span>邮箱</span>
|
||||
</div>
|
||||
<div class="user-information-text">
|
||||
{{ detail.email || '暂无' }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="user-information-item">
|
||||
<div class="user-information-title">
|
||||
<img src="@/assets/images/user-information4.png" alt="" />
|
||||
<span>所属部门</span>
|
||||
</div>
|
||||
<div class="user-information-text">
|
||||
{{ detail.organization || '暂无' }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="user-card-btn">
|
||||
<el-button type="info" @click="clickInitiate">
|
||||
发起协作
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="message-null">
|
||||
<el-empty description="暂无内容" />
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
<div
|
||||
class="message-user"
|
||||
v-else-if="isShow && tabValue == 2"
|
||||
style="height: calc(100vh - 90px)"
|
||||
v-loading="userLoading"
|
||||
>
|
||||
<div class="message-user-card">
|
||||
<div class="user-card-nickName">
|
||||
<img v-if="detail.avatar" :src="detail.avatar" />
|
||||
<img v-else src="@/assets/images/profile.jpg" />
|
||||
<span>{{ detail.nickName || detail.name || '暂无信息' }}</span>
|
||||
</div>
|
||||
<div class="user-card-information">
|
||||
<div class="user-information-item">
|
||||
<div class="user-information-title">
|
||||
<img src="@/assets/images/user-information1.png" alt="" />
|
||||
<span>性别</span>
|
||||
</div>
|
||||
<div class="user-information-text">
|
||||
<!-- <dict-tag
|
||||
v-if="detail.sex"
|
||||
:options="sys_user_sex"
|
||||
:value="detail.sex"
|
||||
/>
|
||||
<div v-else>
|
||||
{{ '暂无' }}
|
||||
</div> -->
|
||||
</div>
|
||||
</div>
|
||||
<div class="user-information-item">
|
||||
<div class="user-information-title">
|
||||
<img src="@/assets/images/user-information2.png" alt="" />
|
||||
<span>手机号</span>
|
||||
</div>
|
||||
<div class="user-information-text">
|
||||
{{ detail.phonenumber || '暂无' }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="user-information-item">
|
||||
<div class="user-information-title">
|
||||
<img src="@/assets/images/user-information3.png" alt="" />
|
||||
<span>邮箱</span>
|
||||
</div>
|
||||
<div class="user-information-text">
|
||||
{{ detail.email || '暂无' }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="user-information-item">
|
||||
<div class="user-information-title">
|
||||
<img src="@/assets/images/user-information4.png" alt="" />
|
||||
<span>所属部门</span>
|
||||
</div>
|
||||
<div class="user-information-text">
|
||||
{{ detail.organization || '暂无' }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="user-card-btn">
|
||||
<el-button type="info" @click="clickInitiate">
|
||||
发起协作
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="message-null">
|
||||
<el-empty description="暂无内容" />
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-dialog
|
||||
v-model="inviteDialog"
|
||||
title="远程协作"
|
||||
width="400px"
|
||||
:close-on-press-escape="false"
|
||||
:close-on-click-modal="false"
|
||||
:show-close="false"
|
||||
>
|
||||
<div>
|
||||
<div style="width: 100%; margin-bottom: 30px; font-size: 20px">
|
||||
"
|
||||
{{
|
||||
socketInformation.room_name
|
||||
? socketInformation.room_name
|
||||
: ''
|
||||
}}
|
||||
" 邀请您参加远程协作
|
||||
</div>
|
||||
<div style="text-align: center">
|
||||
<el-button
|
||||
size="large"
|
||||
type="danger"
|
||||
style="font-size: 16px"
|
||||
@click="clickRefuseJoin"
|
||||
>
|
||||
拒 绝
|
||||
</el-button>
|
||||
<el-button
|
||||
size="large"
|
||||
type="primary"
|
||||
style="font-size: 16px"
|
||||
@click="clickJoin"
|
||||
>
|
||||
加 入
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <el-dialog
|
||||
v-model="inviteDialog"
|
||||
title="远程协作"
|
||||
width="400px"
|
||||
:close-on-press-escape="false"
|
||||
:close-on-click-modal="false"
|
||||
:show-close="false"
|
||||
>
|
||||
|
||||
<div style="width: 100%; margin-bottom: 30px; font-size: 20px">
|
||||
"
|
||||
{{
|
||||
socketInformation.room_name
|
||||
? socketInformation.room_name
|
||||
: ''
|
||||
}}
|
||||
" 邀请您参加远程协作
|
||||
</div>
|
||||
<div style="text-align: center">
|
||||
<el-button
|
||||
size="large"
|
||||
type="danger"
|
||||
style="font-size: 16px"
|
||||
@click="clickRefuseJoin"
|
||||
>
|
||||
拒 绝
|
||||
</el-button>
|
||||
<el-button
|
||||
size="large"
|
||||
type="primary"
|
||||
style="font-size: 16px"
|
||||
@click="clickJoin"
|
||||
>
|
||||
加 入
|
||||
</el-button>
|
||||
</div>
|
||||
</el-dialog> -->
|
||||
</div>
|
||||
<!-- 文件预览 -->
|
||||
<BrowseFile ref="browseFileRef" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onActivated, onMounted, reactive, toRefs, watch, getCurrentInstance ,ref} from 'vue'
|
||||
import leftTab from './components/leftTab/index.vue'
|
||||
import AssistWx from './components/assistWx/index.vue'
|
||||
import BrowseFile from '@/views/conferencingRoom/components/fileUpload/browseFile.vue'
|
||||
import { getInfo } from '@/api/login.js'
|
||||
import { getStatusApi } from '@/api/conferencingRoom.js'
|
||||
import { getStatusApi ,getFileListApi ,getvideoUrlApi} from '@/api/conferencingRoom.js'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { useRoomStore } from '@/stores/modules/room'
|
||||
import { useUserStore } from '@/stores/modules/user.js'
|
||||
import { mqttClient } from "@/utils/mqtt.js";
|
||||
import { getToken } from '@/utils/auth.js'
|
||||
import { getToken ,getUserInfo} from '@/utils/auth.js';
|
||||
import { deepClone,parseTime } from '@/utils/ruoyi.js'
|
||||
const roomStore = useRoomStore()
|
||||
const userStore = useUserStore()
|
||||
const router = useRouter()
|
||||
@@ -280,8 +280,9 @@ const { proxy } = getCurrentInstance()
|
||||
const state = reactive({
|
||||
detail: {},
|
||||
weekName: ['周日', '周一', '周二', '周三', '周四', '周五', '周六'],
|
||||
tabValue: 2,
|
||||
tabValue: 1,
|
||||
isShow: true,
|
||||
isShowLoading: false,
|
||||
load: false,
|
||||
loadText: '数据加载中',
|
||||
isLinkKnow: 'F',
|
||||
@@ -289,7 +290,9 @@ const state = reactive({
|
||||
inviteDialog: false,
|
||||
cooperation: import.meta.env.VITE_APP_COOPERATION_TYPE,
|
||||
})
|
||||
const userLoading = ref(false); // 用户信息加载状态
|
||||
const userLoading = ref(false); // 用户信息加载状态
|
||||
//文件预览
|
||||
const browseFileRef = ref(null);
|
||||
|
||||
const isEmptyObject = (obj) => {
|
||||
return !obj || Object.keys(obj).length === 0
|
||||
@@ -302,7 +305,9 @@ const clickInitiate = () => {
|
||||
userData = JSON.parse(sessionStorage.getItem('userData')) || null
|
||||
} catch (e) {
|
||||
console.error('解析 userData 失败:', e)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (isEmptyObject(state.detail)) {
|
||||
ElMessage({
|
||||
message: '请先选择人员',
|
||||
@@ -318,13 +323,14 @@ const clickInitiate = () => {
|
||||
return
|
||||
}
|
||||
roomStore.setUserUid(userData.uid)
|
||||
roomStore.setDetailUid(state.detail.uid)
|
||||
roomStore.setDetailUid(state.detail.uid)
|
||||
roomStore.setDetailName(state.detail.name)
|
||||
router.push({
|
||||
path: '/conferencingRoom',
|
||||
query:{
|
||||
type:1//创建房间,加入房间 2
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/** 修改展示列表 */
|
||||
@@ -334,33 +340,49 @@ const updateTab = (newValue) => {
|
||||
}
|
||||
|
||||
/** 修改展示区内容 */
|
||||
const updateDetail = async (details) => {
|
||||
const updateDetail = async (details) => {
|
||||
userLoading.value = true
|
||||
if (details) {
|
||||
state.detail = {}
|
||||
if (state.tabValue == 1) {
|
||||
state.isShow = true
|
||||
state.isShowLoading = true
|
||||
getTheFileList(details)
|
||||
} else {
|
||||
const res = await getInfo(details.uid)
|
||||
state.detail = res.data
|
||||
userLoading.value = false
|
||||
// getInfo(details.uid)
|
||||
// .then((res) => {
|
||||
// console.log(res,'人员详细信息')
|
||||
// })
|
||||
// .finally(() => { state.isShow = true })
|
||||
|
||||
state.detail = res.data
|
||||
userLoading.value = false
|
||||
}
|
||||
}
|
||||
userLoading.value = false
|
||||
}
|
||||
|
||||
const getTheFileList = async (details) => {
|
||||
try {
|
||||
let detail = deepClone(details);
|
||||
const [fileResponse, videoResponse] = await Promise.all([
|
||||
getFileListApi(details.room_uid),
|
||||
getvideoUrlApi(details.room_uid)
|
||||
]);
|
||||
const processedDetail = {
|
||||
...details,
|
||||
fileList: fileResponse.data?.files || [],
|
||||
remoteVideoFile: videoResponse.data?.recordings?.[0] || {},
|
||||
initiator: details.all_participants?.find(item =>
|
||||
item.participant_role === 'moderator' // 使用严格相等
|
||||
)?.display_name || '未知发起人'
|
||||
};
|
||||
state.detail = processedDetail;
|
||||
state.isShowLoading = false;
|
||||
} catch (error) {
|
||||
console.error('获取文件列表失败:', error);
|
||||
// 可以根据需要添加错误处理逻辑
|
||||
}
|
||||
} else {
|
||||
state.isShow = false
|
||||
}
|
||||
userLoading.value = false
|
||||
}
|
||||
|
||||
/** 获取通话时长 */
|
||||
const getTime = () => {
|
||||
let begin = new Date(state.detail.beginTime).getTime()
|
||||
let end = new Date(state.detail.endTime).getTime()
|
||||
let begin = new Date(state.detail.created_at).getTime()
|
||||
let end = new Date(state.detail.updated_at).getTime()
|
||||
if (begin && end) {
|
||||
let diff = end - begin
|
||||
const h = Math.floor(diff / (1000 * 60 * 60))
|
||||
@@ -374,83 +396,92 @@ const getTime = () => {
|
||||
}
|
||||
}
|
||||
|
||||
/** 加入会议 */
|
||||
const clickJoin = async () => {
|
||||
const res = await getStatusApi(state.socketInformation.room_uid,{status:1})
|
||||
if(res.meta.code == 200){
|
||||
ElMessage({
|
||||
message: '成功加入该协作',
|
||||
type: 'success',
|
||||
})
|
||||
state.inviteDialog = false
|
||||
router.push({
|
||||
path: '/conferencingRoom',
|
||||
query:{
|
||||
type:2,//创建房间,加入房间 2
|
||||
room_uid:state.socketInformation.room_uid
|
||||
}
|
||||
})
|
||||
}
|
||||
state.inviteDialog = false
|
||||
|
||||
//文件预览
|
||||
function handlePreview(file) {
|
||||
if (!file.preview_url) {
|
||||
ElMessage.error('文件链接无效');
|
||||
return;
|
||||
}
|
||||
browseFileRef.value.showEdit(file)
|
||||
}
|
||||
|
||||
/** 加入会议 */
|
||||
// const clickJoin = async () => {
|
||||
// const res = await getStatusApi(state.socketInformation.room_uid,{status:1})
|
||||
// if(res.meta.code == 200){
|
||||
// ElMessage({
|
||||
// message: '成功加入该协作',
|
||||
// type: 'success',
|
||||
// })
|
||||
// state.inviteDialog = false
|
||||
// router.push({
|
||||
// path: '/conferencingRoom',
|
||||
// query:{
|
||||
// type:2,//创建房间,加入房间 2
|
||||
// room_uid:state.socketInformation.room_uid
|
||||
// }
|
||||
// })
|
||||
// }
|
||||
// state.inviteDialog = false
|
||||
|
||||
// }
|
||||
|
||||
/** 拒绝加入 */
|
||||
const clickRefuseJoin = async () => {
|
||||
//status 1: 同意加入, 5: 拒绝加入
|
||||
const res = await getStatusApi(state.socketInformation.room_uid,{status:5})
|
||||
if(res.meta.code == 200){
|
||||
ElMessage({
|
||||
message: '已拒绝加入该协作',
|
||||
type: 'error',
|
||||
})
|
||||
state.inviteDialog = false
|
||||
}
|
||||
}
|
||||
// const clickRefuseJoin = async () => {
|
||||
// //status 1: 同意加入, 5: 拒绝加入
|
||||
// const res = await getStatusApi(state.socketInformation.room_uid,{status:5})
|
||||
// if(res.meta.code == 200){
|
||||
// ElMessage({
|
||||
// message: '已拒绝加入该协作',
|
||||
// type: 'error',
|
||||
// })
|
||||
// state.inviteDialog = false
|
||||
// }
|
||||
// }
|
||||
|
||||
/** 处理加入房间和拒接房间 mqtt 消息 */
|
||||
const processingSocket = (message) => {
|
||||
const res = JSON.parse(message)
|
||||
if (!res?.status) {
|
||||
state.socketInformation = res
|
||||
state.inviteDialog = true
|
||||
showNotification(state.socketInformation)
|
||||
}else if(res.status == 5){
|
||||
ElMessage({
|
||||
message: `${res?.display_name}拒绝加入该协作`,
|
||||
type: 'error',
|
||||
})
|
||||
}
|
||||
}
|
||||
// const processingSocket = (message) => {
|
||||
// const res = JSON.parse(message)
|
||||
// if (!res?.status) {
|
||||
// state.socketInformation = res
|
||||
// state.inviteDialog = true
|
||||
// showNotification(state.socketInformation)
|
||||
// }else if(res.status == 5){
|
||||
// ElMessage({
|
||||
// message: `${res?.display_name}拒绝加入该协作`,
|
||||
// type: 'error',
|
||||
// })
|
||||
// }
|
||||
// }
|
||||
|
||||
/** 浏览器通知 */
|
||||
const showNotification = (data) => {
|
||||
if ('Notification' in window) {
|
||||
Notification.requestPermission().then((permission) => {
|
||||
if (permission === 'granted') {
|
||||
const notification = new Notification('协作邀请', {
|
||||
// body: String(data.room_name) + '邀请您参加远程协作'
|
||||
body: '远程协作有新的邀请'
|
||||
// icon: logo,
|
||||
})
|
||||
notification.onclick = () => { clickJoin() }
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
// const showNotification = (data) => {
|
||||
// if ('Notification' in window) {
|
||||
// Notification.requestPermission().then((permission) => {
|
||||
// if (permission === 'granted') {
|
||||
// const notification = new Notification('协作邀请', {
|
||||
// // body: String(data.room_name) + '邀请您参加远程协作'
|
||||
// body: '远程协作有新的邀请'
|
||||
// // icon: logo,
|
||||
// })
|
||||
// notification.onclick = () => { clickJoin() }
|
||||
// }
|
||||
// })
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
// 暴露给模板
|
||||
const { detail, weekName, tabValue, isShow, load, loadText, isLinkKnow, socketInformation, inviteDialog, cooperation } = toRefs(state)
|
||||
onMounted(async () => {
|
||||
await mqttClient.connect(`room${Math.random().toString(16).substr(2, 8)}`);
|
||||
const res = await userStore.getInfo()
|
||||
const topic = `xSynergy/ROOM/+/rooms/${res.uid}`;
|
||||
mqttClient.subscribe(topic, async (shapeData) => {
|
||||
// console.log(shapeData.toString(),'shapeData发送邀请')
|
||||
processingSocket(shapeData.toString())
|
||||
});
|
||||
})
|
||||
const { detail, weekName, tabValue, isShow, load, loadText, isLinkKnow, socketInformation, inviteDialog, cooperation,isShowLoading } = toRefs(state)
|
||||
// onMounted(async () => {
|
||||
// await mqttClient.connect(`room${Math.random().toString(16).substr(2, 8)}`);
|
||||
// const res = await userStore.getInfo()
|
||||
// const topic = `xSynergy/ROOM/+/rooms/${res.uid}`;
|
||||
// mqttClient.subscribe(topic, async (shapeData) => {
|
||||
// // console.log(shapeData.toString(),'shapeData发送邀请')
|
||||
// processingSocket(shapeData.toString())
|
||||
// });
|
||||
// })
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
@@ -89,7 +89,7 @@ const loading = ref(false)
|
||||
password: ciphertext,
|
||||
username: loginForm.value.username,
|
||||
})
|
||||
.then(async (res) => {
|
||||
.then(async (res) => {
|
||||
const userInfo = JSON.parse(sessionStorage.getItem('userData'))
|
||||
await handleLoginSuccess();
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user