Commit 1c345c2e by wxl

x

parent 491d1c00
import { UserData } from "src/types/auth";
import { UserData } from "any-hooks/types/user";
import { useState } from "vue-vulcan";
/** 当前客户端用户的基本信息(含token) */
export function useAuthData() {
const [authData, setAuth] = useState<UserData>({}, {storage: 'custome', key: 'auth'});
const [authData, setAuth] = useState<UserData>(null, {storage: 'custome', key: 'auth'});
return {
authData,
......
import { useInjector, useRequest } from "vue-vulcan";
import { useAuthData } from "./useAuthData";
export function useLogOut() {
const [, request] = useRequest<any>('/loginOut', { auto: false });
const { setAuth } = useInjector(useAuthData);
const submitLogOut = (data: {login_id: string}) => {
return request(data).then( _ => setAuth(null));
}
return { submitLogOut }
}
\ No newline at end of file
import { AgoraAppStore } from "any-hooks/types/agora";
import { AgoraAppStore, StreamType } from "any-hooks/types/agora";
import { onMounted, watch } from "vue";
import { useInjector, useState } from "vue-vulcan";
import { AGORA_APP_SDK } from "../communication/token";
interface AgoraStreamItem {
url?: string;
uid: string;
uid: number; //agora仅支持类型为number的uid
}
// type AgoraState = 'unready' | 'inited' | 'joined';
/** 基于声网sdk封装,由于多平台特性,请在根组件将对应平台的声网SDK对象以及appid通过useProvider提供; */
/** 基于声网sdk封装,由于多平台特性,请在应用根组件将对应平台的声网SDK对象以及appid通过useProvider提供; */
export function useAgoraClient() {
const [agoraErr, setError] = useState(null);
const [streamList, setStream] = useState<AgoraStreamItem[]>([]);
const { appid, client } = useInjector<AgoraAppStore>(AGORA_APP_SDK);
onMounted(() => {
client.init(appid, subscribeRemoteStream, setError);
client.init(appid, () => {}, setError);
})
const joinChannelWithVideo = (token: string, cid: string, uid: string) => {
const joinChannelWithAgora = (token: string, cid: string, uid: number) => {
console.log('准备加入视频频道 cid:',cid)
client.join(
token,
cid,
uid,
pushVideoStream,
() => {pushVideoStream(); subscribeRemoteStream },
setError
);
}
......@@ -33,7 +32,7 @@ export function useAgoraClient() {
//推送本地视频流
const [localPushurl, setPushUrl] = useState('');
const pushVideoStream = () => {
client.publish( url => setPushUrl(url));
client.publish( url => {setPushUrl(url);console.log('成功生成推流地址'+url)});
}
//监听远程视频流
......@@ -41,36 +40,80 @@ export function useAgoraClient() {
client.on('stream-added', evt => {
client.subscribe(
evt.uid,
url => updateStremList('add', {uid: evt.uid, url}),
url => {updateStremList('add', {uid: evt.uid, url}); console.log(`用户${evt.uid}加入频道${url}`)},
setError
)
});
client.on('stream-removed', evt => updateStremList('remove', {uid: evt.uid}));
client.on('stream-removed', evt => updateStremList('remove', evt.uid));
}
watch(streamList, val => console.log(`远端流变化val`, val));
// 暂停本地流推送
const muteLocalStream = (type: StreamType) => {
return new Promise (resolve => {
client.muteLocal(type, () => resolve(null))
})
}
// 恢复本地流推送
const unmuteLocalStream = (type: StreamType) => {
return new Promise (resolve => {
client.unmuteLocal(type, () => resolve(null))
})
}
// 暂停远程流接收
const muteRemoteStream = (uid: number, type: StreamType) => {
return new Promise( resolve => {
client.mute(uid, type, () => resolve(null) )
})
}
// 恢复远程流接收
const unmuteRemoteStream = (uid: number, type: StreamType) => {
return new Promise( resolve => {
client.unmute(uid, type , () => resolve(null))
})
}
watch(streamList, console.log)
// 根据uid来新增或移除远端视频流列表
const updateStremList = (action: 'add' | 'remove', input: AgoraStreamItem) => {
function updateStremList(act: 'add', input: {uid: number, url: string}): void;
function updateStremList(act: 'remove', input: number[]): void;
function updateStremList (action, input) {
switch(action) {
case 'add':
setStream(streamList.value.concat(input));
break;
case 'remove':
const index = streamList.value.findIndex(item => item.uid === input.uid);
index && setStream(streamList.value.splice(index, 1));
console.log('remove', input)
const res = streamList.value.filter( item => {
!input.includes(item.uid)
});
setStream(res);
break;
}
}
// 退出频道
const leaveChannelWithAgora = () => {
return new Promise( resolve => {
client.leave(() => resolve(''), setError);
})
}
// 监听来自Agora Client的错误提示
watch(agoraErr, err => {
console.error(err)
})
return {
localPushurl,
streamList,
joinChannelWithVideo
joinChannelWithAgora,
leaveChannelWithAgora,
muteLocalStream,
muteRemoteStream,
unmuteLocalStream,
unmuteRemoteStream
}
}
\ No newline at end of file
import { Subject } from 'rxjs';
import { debounceTime } from 'rxjs/operators';
import { onUnmounted } from 'vue';
export function useDebounce(func: any, time: number) {
const trigger = new Subject();
trigger
.pipe(
debounceTime(time)
)
.subscribe(e => func(e))
const next = (e: any) => trigger.next(e);
onUnmounted(() => trigger.complete());
return next
}
\ No newline at end of file
......@@ -10,6 +10,7 @@ export function useSocket<S = any>() {
const socketSettings = useInjector<SocketSettings>(SOCKET_SETTINGS, 'optional');
let ws: CustomeSocket<S>;
const brokenTime = ref(0);
if(customeSocket) ws = customeSocket;
const connect = (url?: string) => {
......@@ -19,9 +20,12 @@ export function useSocket<S = any>() {
ws = new WebSocket(url) as unknown as CustomeSocket<S>
}
ws.addEventListener('message', event => setMsg(event.data));
ws.addEventListener('open', () => setStatus('opening'));
ws.addEventListener('open', () => socketSettings.heartData && startHeartConnect());
ws.addEventListener('close', () => setStatus('closed'));
ws.addEventListener('open', () => {
setStatus('opening');
brokenTime.value = 0;
socketSettings.heartData && startHeartConnect();
} );
ws.addEventListener('close', () => {setStatus('closed'); reconnect(url);});
ws.addEventListener('error', () => {
setStatus('onerror');
reconnect(url);
......@@ -35,7 +39,6 @@ export function useSocket<S = any>() {
}
// 重连功能
const brokenTime = ref(0);
const limit = socketSettings.retryLimit || 5;
const reconnect = (url: string) => {
brokenTime.value ++;
......
import { Subject } from 'rxjs';
import { throttleTime } from 'rxjs/operators';
import { onUnmounted } from 'vue';
export function useThrottle(func: any, time: number) {
const trigger = new Subject();
trigger
.pipe(
throttleTime(time)
)
.subscribe(e => func(e))
const next = (e: any) => trigger.next(e);
onUnmounted(() => trigger.complete());
return next
}
\ No newline at end of file
// import { BehaviorSubject, Observable, Subject } from 'rxjs';
// import { filter, tap } from 'rxjs/operators';
// import { useState, useInjector } from 'vue-vulcan';
// import { onMounted } from 'vue';
// import * as AgoraMiniappSDK from '../../src/libs/Agora_SDK_for_WeChat';
// // import { useChannelInfo } from './useChannelInfo';
// import { useAuthData } from '../auth/useAuthData';
// interface VideoItemData {
// url: string;
// uid?: string;
// rotation?: string;
// }
// AgoraMiniappSDK.LOG.onlog = (text) => {
// console.log(text);
// };
// const AGORA_APPID = '0a67966ff4ae4eb3b32446df0151e16a';
// const streamLog$ = new Subject<string>();
// const client = new AgoraMiniappSDK.Client();
// const agoraInit$ =
// new Observable<boolean>( observer => {
// client.init(AGORA_APPID, () => {
// streamLog$.next('初始化成功')
// observer.next(true);
// observer.complete();
// }, (e: any) => observer.error(e));
// })
// export function useAgoraClient() {
// const channelState$ = new BehaviorSubject<string>('leave');
// const [streamList, setStreamList] = useState<VideoItemData[]>([]);
// const { current, onReady } = useInjector(useChannelInfo, 'root');
// const { user } = useInjector(useAuthData);
// onMounted( () => {
// subscribeRemoteStream();
// })
// onReady( () => {
// agoraInit$
// .pipe(tap(_=>console.log('准备加入频道')))
// .subscribe(
// _ => client.join(current.value.agora_token, current.value.channel_id, user.value.id, () => {
// channelState$.next('joined');
// streamLog$.next('频道加入成功'+current.value.agora_token);
// pushLocalStream();
// }, console.log),
// console.log
// )
// })
// const leaveChannel = () => {
// client.leave( () => channelState$.next('leave'))
// }
// const subscribeRemoteStream = () => {
// client.on("update-url", e => {
// console.log('genx', e)
// })
// client.on("stream-added", (e: any) => {
// console.log('新人加入', e)
// const uid = e.uid
// client.subscribe(
// uid,
// (url: string) => {
// const newStream = {url, uid}
// setStreamList(streamList.value.concat([newStream]))
// }
// );
// });
// client.on("stream-removed", e => {
// console.log('有人退出', e)
// const uid = e.uid;
// const index = streamList.value.findIndex( item => item.uid === uid );
// const list = streamList.value.splice(index, 1);
// setStreamList(list);
// })
// }
// const pushLocalStream = () => {
// channelState$
// .pipe(
// filter( state => state === 'joined' )
// )
// .subscribe( _ => {
// console.log('推送本地流')
// client.publish( (url: string) => {
// console.log('推送成功', url)
// const list = streamList.value.concat([{ url }])
// setStreamList(list)
// } )
// })
// }
// return {
// streamList,
// leaveChannel,
// pushLocalStream
// }
// }
\ No newline at end of file
import { AnyRemoteSubFlag } from "any-hooks/types/socket";
import { AnyRemoteMainFlag, AnyRemoteSubFlag } from "any-hooks/types/socket";
import { UserData } from "any-hooks/types/user";
import { watch } from "vue";
import { useInjector, useState } from "vue-vulcan";
import { useChannelStore } from "./useChannelStore";
import { useNetSocketCenter } from "./useNetSocketCenter";
import { useNetSocketStore } from "./useNetSocketStore";
type CallingState = 'net_error' | 'calling' | 'call_successed' | 'call_accepted' | 'free';
type CallingState = 'net_error' | 'calling' | 'call_successed' | 'being_called' | 'call_accepted' | 'free';
interface Caller extends UserData {
action: AnyRemoteSubFlag | 'none';
members?: string[];
channel?: string;
}
/** 呼叫中心功能,可以主动呼叫联系人、回应对方的呼叫,以及监听双方呼叫人的信息和状态 */
/** 呼叫中心功能,可以主动呼叫联系人、回应对方的呼叫,以及监听相关用户的实时呼叫状态 */
export function useCallCenter() {
const { sendMsg, currentMsg } = useInjector(useNetSocketCenter);
const { sendMsg, currentMsg } = useInjector(useNetSocketStore);
/** 主动呼叫功能 */
const [target, setTarget] = useState<Caller>(null);
const [myCallState, setCallState] = useState<CallingState>('free');
const {currentChannel, createChannel, joinCallingChannel} = useInjector(useChannelStore);
const {currentChannel, channelMembers, createChannel, getTokenByChannel, updateMembers, clearChannel} = useInjector(useChannelStore);
const callContact = (user: UserData) => {
setTarget({...user, action: 'none'}); //保存呼叫目标的信息
setCallState('calling'); //主动呼叫别人时将自己的呼叫状态更改为‘calling’
......@@ -30,7 +31,10 @@ export function useCallCenter() {
toName: user.nickname,
channelID: currentChannel.value.channel_id,
msgMainFlag: 'CallOffer',
msgSubFlag: 'Request'
msgSubFlag: 'Request',
msgData: {
members: channelMembers.value
}
})
})
}
......@@ -39,7 +43,8 @@ export function useCallCenter() {
const answerCaller = (subFlag: AnyRemoteSubFlag) => {
if(subFlag === 'Connect') {
setCallState('call_accepted');
joinCallingChannel(caller.value.channel);
getTokenByChannel(caller.value.channel);
updateMembers(caller.value.members, 'join')
};
sendMsg({
toID: caller.value.id,
......@@ -54,13 +59,23 @@ export function useCallCenter() {
// 监听来自其他用户的呼叫请求
watch(currentMsg, msg => {
if(msg.msgMainFlag !== 'CallOffer') return;
if(myCallState.value !== 'free') answerCaller('Busying');
console.log(msg.msgSubFlag);
switch(msg.msgSubFlag) {
case 'Request':
// 本地呼叫状态为free时,变更为being_called;不为free,则发送繁忙的回应。
myCallState.value === 'free' ? setCallState('being_called') : answerCaller('Busying');
break;
case 'Hangup':
//对方中断呼叫,则将呼叫状态改为free
setCallState('free');
break;
}
setCaller({
id: currentMsg.value.fromID,
nickname: currentMsg.value.fromName,
action: msg.msgSubFlag,
channel: msg.channelID
channel: msg.channelID,
members: msg.msgData?.members || []
})
})
// 监听呼叫目标的回应
......@@ -69,10 +84,11 @@ export function useCallCenter() {
switch(msg.msgSubFlag) {
case 'Connect':
setCallState('call_successed');
updateMembers([msg.fromID], 'join');
break;
case 'Busying':
case 'Hangup':
console.log('对方拒绝呼叫请求')
console.log('对方拒绝呼叫请求')
setCallState('free');
setTarget({...target.value, action: msg.msgSubFlag});
break;
......@@ -81,15 +97,36 @@ export function useCallCenter() {
/** 呼叫挂断功能 */
const hangup = () => {
let flag: AnyRemoteMainFlag, toID: string;
switch(myCallState.value) {
default:
flag = 'ChannelChat';
toID = '-2'; // '-2'表示向频道发送消息
break;
case 'calling':
flag = 'CallOffer';
toID = target.value.id;
break;
case 'being_called':
flag = 'CallAnswer';
toID = caller.value.id;
break;
}
sendMsg({
channelID: currentChannel.value.channel_id,
msgMainFlag: myCallState.value === 'calling' ? 'CallOffer' : 'CallAnswer',
channelID: currentChannel.value?.channel_id,
msgMainFlag: flag,
msgSubFlag: 'Hangup',
toID: myCallState.value === 'calling' ? target.value.id : caller.value.id
toID
})
setCallState('free');
}
/** 监听呼叫状态,当状态变回free时,重置channel的信息 */
watch(myCallState, state => {
if(state === 'free') clearChannel()
})
return {
/** 呼叫远程联系人 @param UserData */
callContact,
......
import { useAuthData } from "any-hooks/auth/useAuthData";
import { watch } from "vue";
import { useRequest, useState } from "vue-vulcan";
import { UserData } from "any-hooks/types/user";
import { useInjector, useRequest, useState } from "vue-vulcan";
import { useNetSocketStore } from "./useNetSocketStore";
interface ChannelData {
channel_id: string;
agora_token: string;
members?: UserData[];
}
/** 频道中心功能,可以创建频道,并保存当前频道的信息,供呼叫中心、会议中心使用(目前只允许同一时间仅存在一个频道) */
/** 频道中心功能,可以创建频道,并保存当前频道的信息,供呼叫中心、会议中心使用(目前同一时间仅允许存在一个频道) */
export function useChannelStore() {
const [currentChannel, setCurrent] = useState<ChannelData>(null);
const [currentChannel, setChannel] = useState<ChannelData>(null);
const [channelMembers, setMembers] = useState<string[]>([]);
const [channelInfo, request] = useRequest<ChannelData>('/getAgoraToken', {auto: false});
const { authData } = useInjector(useAuthData);
const { currentMsg } = useInjector(useNetSocketStore);
const createChannel = () => {
return request()
return request();
}
const joinCallingChannel = (cid: string) => {
const getTokenByChannel = (cid: string) => {
request({channel_id: cid});
}
const updateMembers = (ids: string[], type: 'join' | 'leave') => {
const current = channelMembers.value;
if(type === 'join') {
setMembers([...new Set([...current, ...ids])])
} else {
setMembers(current.filter(item => !ids.includes(item)))
}
}
const clearChannel = () => {
setChannel(null);
setMembers([]);
}
watch(channelInfo, val => {
setCurrent(val);
setChannel(val);
updateMembers([authData.value.id], 'join');
})
//监听频道下的成员实时信息
watch(currentMsg, msg => {
if(msg.msgMainFlag !== 'ChannelChat') return;
switch(msg.msgSubFlag) {
case 'Hangup':
updateMembers([msg.fromID], 'leave');
break;
}
})
return {
currentChannel,
joinCallingChannel,
createChannel
channelMembers,
getTokenByChannel,
createChannel,
updateMembers,
clearChannel
}
}
\ No newline at end of file
import { setKeepScreenOn } from "@tarojs/taro";
import { useAuthData } from "any-hooks/auth/useAuthData";
import { useAgoraClient } from "any-hooks/common/useAgoraClient";
import { computed, watch } from "vue";
import { useInjector } from "vue-vulcan";
import { onMounted, watch } from "vue";
import { useInjector, useState } from "vue-vulcan";
import { useCallCenter } from "./useCallCenter";
import { useChannelStore } from "./useChannelStore";
/** 会议中心功能, 该功能在呼叫功能生效后使用,通过调用agoraSDK实现多人视频会议、语音会议的功能 */
export function useMeetingCenter() {
const { currentChannel } = useInjector(useChannelStore);
const { authData } = useInjector(useAuthData)
const {joinChannelWithVideo, streamList, localPushurl} = useAgoraClient();
const { authData } = useInjector(useAuthData);
const { hangup, myCallState } = useInjector(useCallCenter);
const {
joinChannelWithAgora,
leaveChannelWithAgora,
muteLocalStream,
unmuteLocalStream,
streamList,
localPushurl,
} = useAgoraClient();
// const meetingMembers = computed()
/** 监听频道信息,有值或变更后将agora通讯功能加入频道 */
watch(currentChannel, channel => {
joinChannelWithVideo(
if(!channel) return;
joinChannelWithAgora(
channel.agora_token,
channel.channel_id,
authData.value.id
parseInt(authData.value.id)
)
})
/** 离开会议(分两步:1.挂断当前呼叫, 2.退出agora音视频流) */
const leave = () => {
hangup();
leaveChannelWithAgora();
}
/** 保持屏幕常亮 */
onMounted(() => setKeepScreenOn({keepScreenOn: true}));
/** 监听频道人数,人数为1时,自动退出频道 (目前直接用agora stream替代)*/
watch(streamList, (current, last) => {
if(myCallState.value === 'free') return;
if(current.length > last.length) return;
if(current.length < 2) {
setTimeout(leave, 3000)
}
})
/** 切换麦克风使用状态 */
const [voiceMute, setVoiceMute] = useState(false);
const switchLocalMicState = () => {
if(!voiceMute.value) {
setVoiceMute(true)
muteLocalStream('audio');
} else {
setVoiceMute(false);
unmuteLocalStream('audio');
}
}
return {
streamList,
localPushurl
localPushurl,
voiceMute,
leave,
switchLocalMicState,
}
}
\ No newline at end of file
import { useAuthData } from "any-hooks/auth/useAuthData";
import { useSocket } from "any-hooks/common/useSocket";
import { AnyRemoteSocketMessage } from "any-hooks/types/socket";
import { AnyRemoteSocketMessage, SocketSettings } from "any-hooks/types/socket";
import { watch } from "vue";
import { useInjector, useState } from "vue-vulcan";
import { SOCKET_SETTINGS } from "./token";
enum NetStates {
off = 0,
......@@ -12,16 +13,19 @@ enum NetStates {
best
}
export function useNetSocketCenter() {
// 在线socket连接中心,会议中心、呼叫中心的基础
export function useNetSocketStore() {
const { authData } = useInjector(useAuthData);
const [ netState, setNetState ] = useState<NetStates>(0);
const { connect, send, currentMsg, startHeartConnect } = useSocket<AnyRemoteSocketMessage>();
const { baseUrl } = useInjector<SocketSettings>(SOCKET_SETTINGS, 'optional');
const { connect, send, currentMsg, startHeartConnect, status } = useSocket<AnyRemoteSocketMessage>();
watch(authData, data => {
console.log('authData', data)
if(!data) return;
connect(
`wss://www.if-ar.com:3009?fromID=${data.id}&fromName=${data.nickname}&signID=SA&companyID=${data.company_id}`
`${baseUrl}?fromID=${data.id}&fromName=${data.nickname}&signID=SA&companyID=${data.company_id}`
)
startHeartConnect({
fromID: authData.value.id,
......@@ -44,6 +48,7 @@ export function useNetSocketCenter() {
sendMsg,
setNetState,
currentMsg,
netState
netState,
status
}
}
\ No newline at end of file
import { UserData } from "../types/user";
import { useInjector, useRequest } from "vue-vulcan";
import { computed, onMounted, watch} from "vue";
import { useInjector, useRequest, useState } from "vue-vulcan";
import { computed, watch} from "vue";
import { useAuthData } from "../auth/useAuthData";
import { useNetSocketStore } from "any-hooks/communication/useNetSocketStore";
export function useContacts() {
const { authData } = useInjector(useAuthData);
const [ userList, getUserList ] = useRequest<UserData[]>('/getUserList', { auto: false });
const { currentMsg } = useInjector(useNetSocketStore);
const [keyword, setKeyWord] = useState('');
onMounted( () => {
if(authData) getUserList();
})
const contacts = computed( () => {
return userList.value?.filter( item => item.id !== authData.value?.id )
.filter( item => item.nickname.includes(keyword.value))
});
watch(authData, val => {
if(val) getUserList()
})
const getContactById = (id: string) => {
const index = userList.value.findIndex( user => user.id === id );
return userList.value[index];
}
const contacts = computed( () => userList.value?.filter( item => item.id !== authData.value.id ))
const getContactsByGroup = (groupId: string) => {
return userList.value.filter( item => item.diy_group === groupId )
}
// 监听socket的home类型消息 实时更新contacts联系人数据
watch(currentMsg, msg => {
if(msg.msgMainFlag !== 'Home') return;
if(msg.msgSubFlag === 'UpdateUserList') getUserList();
})
return {
contacts
contacts,
setKeyWord,
keyword,
getUserList,
getContactById,
getContactsByGroup
}
}
\ No newline at end of file
import { WorkGroupData } from "any-hooks/types/user";
import { useRequest } from "vue-vulcan";
export function useWorkGroups() {
const [groups, requestGroups] = useRequest<WorkGroupData[]>('/getWorkGroupList');
return {
groups,
requestGroups
}
}
\ No newline at end of file
type AgoraEventType = 'stream-added' | 'stream-removed' | 'update-url"'
export type StreamType = 'video' | 'audio' | 'all';
export interface AgoraSdkClient {
init: (appid: string, success?: any, err?: any) => void;
join: (token: string, cid: string, uid: string, success?: any, err?: any) => void;
join: (token: string, cid: string, uid: number, success?: any, err?: any) => void;
rejoin: (cb: any) => void;
publish(onSuccess: (url: string) => void, onFailure?: (err: { code: number; reason: string }) => void): void;
on(event: "error", callback: (evt: { code: number; reason: string }) => void): void;
on(event: AgoraEventType, callback: (evt: { uid: string, url?: string }) => void): void;
on(event: "stream-added", callback: (evt: { uid: number, url?: string }) => void): void;
on(event: "stream-removed", callback: (evt: { uid: number[] }) => void): void;
off: (cb: any) => void;
subscribe(uid: string, onSuccess: (url: string) => void, onFailure?: (err: any) => void): void
leave: (cb: any) => void;
subscribe(uid: number, onSuccess: (url: string) => void, onFailure?: (err: any) => void): void;
mute(uid: number, target: string, onSuccess?: () => void, onFailure?: (err: { code: number; reason: string }) => void): void;
unmute(uid: number, target: string, onSuccess?: () => void, onFailure?: (err: { code: number; reason: string }) => void): void;
muteLocal(target: StreamType, onSuccess?: () => void, onFailure?: (err: { code: number; reason: string }) => void): void;
unmuteLocal(target: string, onSuccess?: () => void, onFailure?: (err: { code: number; reason: string }) => void): void;
leave(onSuccess?: () => void, onFailure?: (err: { code: number; reason: string }) => void): void
destory: (cb: any) => void;
}
export interface AgoraAppStore {
appid: string;
platform: 'web' | 'mini-app' | 'electron';
client: AgoraSdkClient;
stream?: any;
}
......@@ -4,18 +4,20 @@ export interface CustomeSocket<S> {
send: (data: S) => void;
close: () => void;
addEventListener<K extends keyof WebSocketEventMap>(type: K, listener: (this: WebSocket, ev: WebSocketEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
removeEventListener<K extends keyof WebSocketEventMap>(type: K, listener?: (this: WebSocket, ev: WebSocketEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
}
export interface SocketSettings {
retryLimit?: number;
heartData?: any;
heartInterval?: number;
baseUrl: string;
}
export type ConnectStatus = 'ready' | 'opening' | 'onerror' | 'closed' | 'reconnect';
export type AnyRemoteMainFlag = 'Heart' | 'Login' | 'Broadcast' | 'Home' | 'CallOffer' | 'CallAnswer';
export type AnyRemoteSubFlag = 'Request' | 'Busying' | 'Connect' | 'Hangup';
export type AnyRemoteMainFlag = 'Heart' | 'Login' | 'Broadcast' | 'Home' | 'CallOffer' | 'CallAnswer' | 'ChannelChat';
export type AnyRemoteSubFlag = 'Request' | 'Busying' | 'Connect' | 'Hangup' | 'UpdateUserList';
export interface AnyRemoteSocketMessage {
fromID?: string;
......
......@@ -8,4 +8,24 @@ export interface UserData {
token?: string;
is_signin?: '1' | '2';
is_calling?: '1' | '0';
group_name?: string;
diy_group?: string;
phone?: string;
email?: string;
}
export interface WorkGroupData {
id: string;
title: string;
create_time: string;
update_time: string;
sort: string;
pid: string;
pid_list: string;
sid_list: string;
node_deep: string;
company_id: string;
progeny_ids: string;
ancestry_ids: string;
title_show: string;
}
\ No newline at end of file
......@@ -4,7 +4,8 @@ export default {
'pages/login/index',
'pages/meeting/index',
'pages/mine/index',
'pages/calling/index'
'pages/calling/index',
'pages/contact-detail/index'
],
window: {
backgroundTextStyle: 'light',
......
view,text,input{
padding: 0;
margin: 0;
font-size: 30px;
}
.top-bg{
background-image: url(./assets/bg2x.png);
background-size: 100% auto;
background-repeat: no-repeat;
background-position-x: left;
&.mine{
background-image: url(./assets/bg-big3x.png);
}
}
.top-header{
padding-top: 55px !important;
}
page, .page{
height: 100%;
overflow: hidden;
// background-color: #f7f7f7;
}
.col-page{
height: 100%;
display: flex;
flex-direction: column;
}
.layout {
height: 100%;
width: 100%;
}
.full{
height: 100%;
width: 100%;
}
.white-box{
padding: 15px;
background: #fff;
}
.pd-1{
padding: 15px;
}
.pd-2{
padding: 25px;
}
.avatar{
width: 120px;
height: 120px;
border-radius: 50%;
}
.info-item{
display: flex;
justify-content: space-between;
.title{
color: #333;
}
.value{
color: #999;
}
}
\ No newline at end of file
import './app.less';
import { authorize, } from '@tarojs/taro';
import { authorize } from '@tarojs/taro';
import { createApp } from 'vue';
import { useCustomeRequest } from './hooks/http/useCustomeRequest';
import { useProviders } from 'vue-vulcan';
......@@ -12,32 +12,55 @@ import { useCustomeSocket } from './hooks/socket/useCustomeSocket';
import { useSocketSetting } from './hooks/socket/useSocketSettings';
import { useCallCenter } from 'any-hooks/communication/useCallCenter';
import { useChannelStore } from 'any-hooks/communication/useChannelStore';
import { useNetSocketCenter } from 'any-hooks/communication/useNetSocketCenter';
import { useNetSocketStore } from 'any-hooks/communication/useNetSocketStore';
import { useCallerListener } from './hooks/call/useCallerListener';
import { useAgoraSDK } from './hooks/meeting/useAgoraSDK';
import { useMeetingCenter } from 'any-hooks/communication/useMeetingCenter';
import { useContacts } from 'any-hooks/contacts/useContacts';
import { useAppInitInfo } from './hooks/common/useAppInitInfo';
import { useSocketErrorHandle } from './hooks/socket/useSocketErrorHandle';
import dataEmpty from './components/data-empty.vue';
import MeetingBar from './components/mini-meeting-bar.vue';
const App = createApp({
onShow () {},
onShow () {
},
setup() {
/* 提供全局配置类hook */
useProviders(
useCustomeStorage, //自定义基于taro的storage的接口,覆盖useState默认的sessionStorage/localStorage方法
useCustomeRequest, //自定义基于taro.request的请求接口,覆盖useRequet默认的fetch方法
useAuthData, //全局的用户权限数据hook
useHttpIntercept, //提供http请求拦截器
useRequestOption, //提供http请求配置项
useSocketSetting, //提供小程序socket通讯的全局配置
useCustomeSocket, //自定义基于taro的socket通讯接口,覆盖useSocket默认的websokcet
useNetSocketCenter, //全局的socket连接中心
useChannelStore, //全局的频道信息
useCallCenter, //全局的多人呼叫
useCallerListener, //在整个APP生命周期内监听远程联系人的呼叫请求
useAgoraSDK, //提供声网skd配置信息
useMeetingCenter //全局的多人会议中心
useAppInitInfo
)
/* 提供用于覆盖原生api的hook(如 fetch/webSocket) */
useProviders(
useCustomeStorage, //自定义基于taro的storage的接口,覆盖useState内置的sessionStorage/localStorage接口
useCustomeRequest, //自定义基于taro.request的请求接口,覆盖useRequet内置的fetch接口
useCustomeSocket, //自定义基于taro的socket通讯接口,覆盖useSocket内置的websokcet接口
)
/* 提供全局共享的业务逻辑hook */
useProviders(
useAuthData, //用户权限数据
useHttpIntercept, //http请求拦截器
useNetSocketStore, //socket连接中心
useChannelStore, //频道信息中心
useCallCenter, //多人呼叫中心
useMeetingCenter, //多人会议中心
useContacts //实时联系人数据
);
authorize({ scope: 'scope.camera' });
useAuthCheck();
useCallerListener();
useSocketErrorHandle();
}
})
export default App
App.component('data-empty', dataEmpty);
App.component('meeting-bar', MeetingBar);
export default App;
src/assets/add.png

235 Bytes | W: | H:

src/assets/add.png

224 Bytes | W: | H:

src/assets/add.png
src/assets/add.png
src/assets/add.png
src/assets/add.png
  • 2-up
  • Swipe
  • Onion skin
src/assets/answer.png

2.27 KB | W: | H:

src/assets/answer.png

1.59 KB | W: | H:

src/assets/answer.png
src/assets/answer.png
src/assets/answer.png
src/assets/answer.png
  • 2-up
  • Swipe
  • Onion skin
src/assets/call.png

1.1 KB | W: | H:

src/assets/call.png

1.2 KB | W: | H:

src/assets/call.png
src/assets/call.png
src/assets/call.png
src/assets/call.png
  • 2-up
  • Swipe
  • Onion skin
src/assets/experience.png

828 Bytes | W: | H:

src/assets/experience.png

352 Bytes | W: | H:

src/assets/experience.png
src/assets/experience.png
src/assets/experience.png
src/assets/experience.png
  • 2-up
  • Swipe
  • Onion skin
src/assets/recording.png

2.62 KB | W: | H:

src/assets/recording.png

2.14 KB | W: | H:

src/assets/recording.png
src/assets/recording.png
src/assets/recording.png
src/assets/recording.png
  • 2-up
  • Swipe
  • Onion skin
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment