实时视频相关接口联调
This commit is contained in:
parent
31247fce3a
commit
f44044e0bd
219
src/pages/mediation-page/components/VideoInvitation.vue
Normal file
219
src/pages/mediation-page/components/VideoInvitation.vue
Normal file
@ -0,0 +1,219 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-dialog title="邀请" :visible="true" width="600px" append-to-body :close-on-click-modal="false"
|
||||
@close="handleClose">
|
||||
<div class="dialog-content dialog-office-batch">
|
||||
<div class="pt-8">
|
||||
<el-form ref="ruleFormRepayment"
|
||||
:model="repaymentObj"
|
||||
:rules="rulesClientRule"
|
||||
label-width="130px">
|
||||
<el-row :gutter="56">
|
||||
<el-col :span="24">
|
||||
<el-form-item label="当事人" prop="litigants">
|
||||
<el-select v-model="repaymentObj.litigants" multiple collapse-tags filterable
|
||||
placeholder="请选择" class="width100">
|
||||
<el-option
|
||||
v-for="(item,index) in litigantsOptions"
|
||||
:key="index"
|
||||
:label="item.name+ ' ' +'('+ item.phone +')'"
|
||||
:value="item.identity">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="邀请其他人" prop="members">
|
||||
<el-button
|
||||
icon="el-icon-plus"
|
||||
size="small"
|
||||
type="text"
|
||||
@click="addForm">邀请其他人
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24" v-for="(item,index) in repaymentObj.members" :key="index">
|
||||
<el-form-item label="" prop="" label-width="0">
|
||||
<el-row :gutter="20" style="background-color: rgb(245, 246, 250);margin-bottom: 5px;">
|
||||
<el-col :span="7">
|
||||
<div>身份</div>
|
||||
</el-col>
|
||||
<el-col :span="7">
|
||||
<div>姓名</div>
|
||||
</el-col>
|
||||
<el-col :span="7">
|
||||
<div>电话</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="7">
|
||||
<el-form-item
|
||||
:prop="`members[${index}].identity`"
|
||||
:rules="[
|
||||
{ required: true, message: '请选择', trigger: ['blur','change'],},
|
||||
]">
|
||||
<el-select v-model="item.identity" placeholder="请选择">
|
||||
<el-option
|
||||
v-for="(item,index) in identityOptions"
|
||||
:key="index"
|
||||
:label="item.label"
|
||||
:value="item.value">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="7">
|
||||
<el-form-item
|
||||
:prop="`members[${index}].name`"
|
||||
:rules="{ required: true, message: '请输入', trigger: ['blur','change'] }">
|
||||
<el-input
|
||||
v-model="item.name"
|
||||
placeholder="请输入"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="7">
|
||||
<el-form-item
|
||||
:prop="`members[${index}].phone`"
|
||||
:rules="[
|
||||
{ required: true, message: '请输入', trigger: ['blur','change'],},
|
||||
{ pattern: /^(13[0-9]{9})|(18[0-9]{9})|(14[0-9]{9})|(17[0-9]{9})|(15[0-9]{9})|(19[0-9]{9})$/, message: '请输入正确的手机号码', trigger: ['blur', 'change']}
|
||||
]">
|
||||
<el-input
|
||||
v-model="item.phone"
|
||||
placeholder="请输入"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="3">
|
||||
<div class="">
|
||||
<el-button
|
||||
icon="el-icon-delete"
|
||||
size="small"
|
||||
type="text"
|
||||
@click="deleteForm(index)">删除
|
||||
</el-button>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="handleClose()">取消</el-button>
|
||||
<el-button type="primary" @click="handleSubmit()">立即邀请</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import videoTelephone from "@/services/videoTelephone";
|
||||
|
||||
export default {
|
||||
components: {},
|
||||
props: {
|
||||
eventDialog: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {}
|
||||
},
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
litigantsOptions: [],
|
||||
identityOptions: [
|
||||
{ label: '法官', value: '法官' },
|
||||
{ label: '调解专家', value: '调解专家' },
|
||||
{ label: '律师', value: '律师' },
|
||||
{ label: '民警', value: '民警' },
|
||||
{ label: '其他', value: '其他' }
|
||||
],
|
||||
repaymentObj: {
|
||||
litigants: [], //{name: xx, phone: xx, identity: xx} 当事人
|
||||
members: [], //{name: xx, phone: xx, identity: xx} 邀请人
|
||||
id: '', // 案件ID
|
||||
},
|
||||
rulesClientRule: {
|
||||
litigants: [
|
||||
{ type: 'array', required: true, message: '请选择', trigger: 'change' }
|
||||
],
|
||||
},
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.getLitigantByCaseId();
|
||||
},
|
||||
methods: {
|
||||
getLitigantByCaseId() {
|
||||
videoTelephone.getLitigantByCaseId(this.eventDialog.caseId).then(res => {
|
||||
if (!res.code) {
|
||||
this.litigantsOptions = res;
|
||||
}
|
||||
})
|
||||
},
|
||||
addForm() {
|
||||
this.repaymentObj.members.push({ identity: '', name: '', phone: ''})
|
||||
},
|
||||
deleteForm(index) {
|
||||
this.repaymentObj.members.splice(index, 1)
|
||||
},
|
||||
handleClose() {
|
||||
this.$emit('update:eventDialog', null)
|
||||
},
|
||||
handleSubmit() {
|
||||
if(!this.$clickThrottle()) { return }//防止重复点击
|
||||
this.$refs.ruleFormRepayment.validate((valid) => {
|
||||
if (valid) {
|
||||
const resultArr = this.litigantsOptions
|
||||
.filter(item => this.repaymentObj.litigants.includes(item.identity))
|
||||
.map(({name, phone, identity}) => ({name, phone, identity}));
|
||||
this.repaymentObj.id = this.eventDialog.id;
|
||||
videoTelephone.videoInvite({...this.repaymentObj, litigants: resultArr}).then(res => {
|
||||
this.handleClose()
|
||||
this.$message.success("邀请成功");
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.dialog-office-batch {
|
||||
padding: 16px 30px;
|
||||
|
||||
.tabs__search-criteria-title {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.case-batch-num {
|
||||
background-color: rgba(236, 238, 241, 0.8196078431);
|
||||
padding: 15px 20px;
|
||||
border-radius: 4px;
|
||||
|
||||
a {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: #C66A5B;
|
||||
}
|
||||
}
|
||||
|
||||
.officelist {
|
||||
background-color: rgba(236, 238, 241, 0.8196078431);
|
||||
padding: 20px 20px;
|
||||
|
||||
.el-checkbox {
|
||||
width: 230px;
|
||||
margin: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
@ -1,102 +0,0 @@
|
||||
<template>
|
||||
<div
|
||||
:style="contentStyle"
|
||||
class="content"
|
||||
@mousedown="startDrag"
|
||||
@mouseup="stopDrag"
|
||||
@mouseleave="stopDrag">
|
||||
<div class="drag-div" @mousedown.stop="startDrag"></div>
|
||||
<div>Other content</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
position: { x: 0, y: 0 },
|
||||
dragging: false,
|
||||
offsetX: 0,
|
||||
offsetY: 0,
|
||||
mouseMoveHandler: null,
|
||||
mouseUpHandler: null
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
contentStyle() {
|
||||
return {
|
||||
left: `${this.position.x}px`,
|
||||
top: `${this.position.y}px`,
|
||||
};
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
startDrag(event) {
|
||||
event.preventDefault();
|
||||
|
||||
if (!event.target.closest('.drag-div')) return;
|
||||
|
||||
this.dragging = true;
|
||||
this.offsetX = event.clientX - this.position.x;
|
||||
this.offsetY = event.clientY - this.position.y;
|
||||
|
||||
this.removeEventListeners();
|
||||
|
||||
this.mouseMoveHandler = this.onMouseMove.bind(this);
|
||||
this.mouseUpHandler = this.stopDrag.bind(this);
|
||||
|
||||
document.addEventListener('mousemove', this.mouseMoveHandler, true);
|
||||
document.addEventListener('mouseup', this.mouseUpHandler, true);
|
||||
},
|
||||
onMouseMove(event) {
|
||||
if (this.dragging) {
|
||||
requestAnimationFrame(() => {
|
||||
this.updatePosition(event.clientX, event.clientY);
|
||||
});
|
||||
}
|
||||
},
|
||||
updatePosition(clientX, clientY) {
|
||||
this.position.x = clientX - this.offsetX;
|
||||
this.position.y = clientY - this.offsetY;
|
||||
|
||||
this.$forceUpdate();
|
||||
},
|
||||
stopDrag() {
|
||||
this.dragging = false;
|
||||
this.removeEventListeners();
|
||||
},
|
||||
removeEventListeners() {
|
||||
if (this.mouseMoveHandler) {
|
||||
document.removeEventListener('mousemove', this.mouseMoveHandler, true);
|
||||
}
|
||||
if (this.mouseUpHandler) {
|
||||
document.removeEventListener('mouseup', this.mouseUpHandler, true);
|
||||
}
|
||||
}
|
||||
},
|
||||
destroyed() {
|
||||
this.removeEventListeners();
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.content {
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
position: absolute;
|
||||
border: 1px solid #ccc;
|
||||
box-sizing: border-box;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.drag-div {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
background-color: #f00;
|
||||
text-align: center;
|
||||
line-height: 50px;
|
||||
color: white;
|
||||
cursor: grab;
|
||||
}
|
||||
</style>
|
||||
@ -1,7 +1,10 @@
|
||||
<template>
|
||||
<div ref="videoRoom" class="room-content border-radius-8" v-vdrag :class="zoomActive ? `room-content-big` : 'room-content-small'">
|
||||
<div class="room-top flex-row justify-content-between align-items-center">
|
||||
<div class="f16 f-weight600">调解视频画面</div>
|
||||
<div class="f16 f-weight600 flex-row">
|
||||
<div class="mr-8">调解视频画面</div>
|
||||
<div class="color-F53F3F" v-if="videoRecordingSts">{{ formattedTime }}</div>
|
||||
</div>
|
||||
<div class="room-top-btn background-color-fff flex-row align-items-center border-radius-4 cursor-pointer"
|
||||
@click="toggleZoom">
|
||||
<span class="mr-4">{{ zoomActive ? '缩小' : '放大' }}</span>
|
||||
@ -35,9 +38,9 @@
|
||||
<div v-if="zoomActive" class="room-bottom border-radius-8 background-color-fff flex-row justify-content-between align-items-center">
|
||||
<div class="flex-row align-items-center cursor-pointer" @click="handleVideoRecording">
|
||||
<svg-icon :icon-class="videoRecordingSts ? 'video-recording-2' : 'video-recording-1'" className="tabs-svg" />
|
||||
<div class="pl-4 f14">{{ videoRecordingSts ? '录制中': '录制' }}</div>
|
||||
<div class="pl-4 f14" :class="videoRecordingSts ? 'color-F53F3F' : ''">{{ videoRecordingSts ? '结束': '录制' }}</div>
|
||||
</div>
|
||||
<div class="flex-row align-items-center cursor-pointer">
|
||||
<div class="flex-row align-items-center cursor-pointer" @click="InviteDialog={caseId:caseId,id:eventDialog.id}">
|
||||
<svg-icon icon-class="Invite-room" className="tabs-svg" />
|
||||
<div class="pl-4 f14">邀请</div>
|
||||
</div>
|
||||
@ -49,14 +52,17 @@
|
||||
<i class="f24 el-icon-turn-off-microphone color-4E5969"></i>
|
||||
<div class="pl-4 f14">开启语音</div>
|
||||
</div>
|
||||
<div class="flex-row align-items-center cursor-pointer" @click="handleOffRemoteAudio('')">
|
||||
<div class="flex-row align-items-center cursor-pointer"
|
||||
@click="audioRecordingSts ? handleOffRemoteAudio('') : handleOnRemoteAudio('')">
|
||||
<svg-icon icon-class="mute-all" className="tabs-svg" />
|
||||
<div class="pl-4 f14">全部静音</div>
|
||||
<div class="pl-4 f14">{{audioRecordingSts ? '全部静音' : '全部开启'}}</div>
|
||||
</div>
|
||||
<div class="room-bottom-btn-finish cursor-pointer border-radius-4 f14 color-fff" @click="handleStopMediate">
|
||||
结束调解
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<VideoInvitation v-if="InviteDialog" :eventDialog.sync="InviteDialog" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -64,6 +70,9 @@
|
||||
import TRTC from 'trtc-sdk-v5';
|
||||
import videoTelephone from "@/services/videoTelephone";
|
||||
export default {
|
||||
components: {
|
||||
VideoInvitation: () => import('./VideoInvitation'),//邀请视频
|
||||
},
|
||||
props: {
|
||||
eventDialog: {
|
||||
type: Object,
|
||||
@ -76,6 +85,7 @@ export default {
|
||||
return {
|
||||
zoomActive: true,// true 放大状态、false 缩小状态
|
||||
|
||||
caseId: '',
|
||||
arrPersonnel: [],
|
||||
roomId: 0,
|
||||
sdkAppId: 0,
|
||||
@ -91,7 +101,13 @@ export default {
|
||||
personnelNumber: 1,
|
||||
remoteUsersViews: [],
|
||||
|
||||
videoRecordingSts: false
|
||||
audioRecordingSts: true, // 全部音频状态 true开启 false关闭
|
||||
videoRecordingSts: false, // 录制状态 true开启 false关闭
|
||||
startTime: null,
|
||||
timerId: null,
|
||||
duration: 0, // 记录录制时间(秒)
|
||||
|
||||
InviteDialog: null, // 邀请
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@ -105,7 +121,13 @@ export default {
|
||||
const itemsPerRow = 4;
|
||||
const rowHeight = 35.5;
|
||||
const numberOfRows = Math.ceil(this.personnelNumber / itemsPerRow);
|
||||
return `${numberOfRows * rowHeight + 35.5}px`;
|
||||
return `${numberOfRows * rowHeight + 37.5}px`;
|
||||
},
|
||||
formattedTime() {
|
||||
const hours = Math.floor(this.duration / 3600);
|
||||
const minutes = Math.floor((this.duration % 3600) / 60);
|
||||
const seconds = this.duration % 60;
|
||||
return `${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}:${String(Math.floor(seconds)).padStart(2, '0')}`;
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
@ -123,7 +145,7 @@ export default {
|
||||
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.videoRoom) {
|
||||
console.log(this.defaultTop, '---this.defaultTop')
|
||||
console.log(this.defaultTop, this.personnelNumber, '---this.defaultTop')
|
||||
this.$refs.videoRoom.style.left = this.zoomActive ? this.zoomedStyles.left : '157px';
|
||||
this.$refs.videoRoom.style.top = this.zoomActive ? this.zoomedStyles.top : this.defaultTop;
|
||||
}
|
||||
@ -134,7 +156,8 @@ export default {
|
||||
getVideoDetail() {
|
||||
videoTelephone.videoDetail({id: this.eventDialog.id}).then((res) => {
|
||||
// console.log(res, '---videoDetail')
|
||||
this.arrPersonnel = [...res.litigants, ...res.members]
|
||||
this.caseId = res.caseId;
|
||||
this.arrPersonnel = [...res.litigants, ...res.members];
|
||||
});
|
||||
},
|
||||
// 获取房间参数
|
||||
@ -344,7 +367,7 @@ export default {
|
||||
console.log(event, '---event远端退出房间')
|
||||
const { streamType } = event;
|
||||
this.trtc.stopRemoteVideo({ userId: event.userId, streamType });
|
||||
this.personnelNumber--;
|
||||
if (this.personnelNumber>1){this.personnelNumber--;}
|
||||
this.remoteUsersViews = this.remoteUsersViews.filter(item => item.userId !== event.userId);
|
||||
},
|
||||
// 接收远端消息
|
||||
@ -356,6 +379,16 @@ export default {
|
||||
async handleOffRemoteAudio(userId) {
|
||||
console.log(userId, '---关闭远端声音')
|
||||
try {
|
||||
if (!userId){
|
||||
this.audioRecordingSts = false;
|
||||
this.remoteUsersViews = this.remoteUsersViews.map(item => {
|
||||
item.microphone = false;
|
||||
return {
|
||||
...item,
|
||||
microphone: false
|
||||
}
|
||||
})
|
||||
}
|
||||
let jsonString = JSON.stringify({behavior: 'offAudio', userId: userId});
|
||||
let encoder = new TextEncoder();
|
||||
let encoded = encoder.encode(jsonString).buffer;
|
||||
@ -376,6 +409,16 @@ export default {
|
||||
async handleOnRemoteAudio(userId) {
|
||||
console.log(userId, '---开启远端声音')
|
||||
try {
|
||||
if (!userId){
|
||||
this.audioRecordingSts = true;
|
||||
this.remoteUsersViews = this.remoteUsersViews.map(item => {
|
||||
item.microphone = true;
|
||||
return {
|
||||
...item,
|
||||
microphone: true
|
||||
}
|
||||
})
|
||||
}
|
||||
let jsonString = JSON.stringify({behavior: 'onAudio', userId: userId});
|
||||
let encoder = new TextEncoder();
|
||||
let encoded = encoder.encode(jsonString).buffer;
|
||||
@ -404,15 +447,34 @@ export default {
|
||||
},
|
||||
|
||||
// 录制
|
||||
updateTimerDisplay() {
|
||||
if (!this.startTime) return;
|
||||
const currentTime = performance.now();
|
||||
this.duration = Math.floor((currentTime - this.startTime) / 1000); // 将毫秒转换为秒
|
||||
},
|
||||
handleVideoRecording(){
|
||||
if (this.videoRecordingSts){
|
||||
// clearInterval(this.timerId);
|
||||
// this.timerId = null;
|
||||
// this.videoRecordingSts = false;
|
||||
// return
|
||||
videoTelephone.stopRecord({id: this.eventDialog.id}).then((res) => {
|
||||
console.log('---视频已停止录制')
|
||||
clearInterval(this.timerId);
|
||||
this.timerId = null;
|
||||
this.videoRecordingSts = false;
|
||||
});
|
||||
}else {
|
||||
// this.startTime = performance.now();
|
||||
// this.updateTimerDisplay(); // 立即更新一次显示
|
||||
// this.timerId = setInterval(() => this.updateTimerDisplay(), 1000); // 每秒更新一次
|
||||
// this.videoRecordingSts = true;
|
||||
// return
|
||||
videoTelephone.startRecord({id: this.eventDialog.id}).then((res) => {
|
||||
console.log('---视频已开始录制')
|
||||
this.startTime = performance.now();
|
||||
this.updateTimerDisplay(); // 立即更新一次显示
|
||||
this.timerId = setInterval(() => this.updateTimerDisplay(), 1000); // 每秒更新一次
|
||||
this.videoRecordingSts = true;
|
||||
});
|
||||
}
|
||||
@ -428,12 +490,18 @@ export default {
|
||||
let data = {id:this.eventDialog.id}
|
||||
// if (this.videoRecordingSts){
|
||||
// this.handleVideoRecording();
|
||||
// }
|
||||
// } // 结束录制
|
||||
videoTelephone.stopMediate(data).then((res) => {
|
||||
this.handleClose();
|
||||
this.$parent.visiblePopover = null
|
||||
});
|
||||
}).catch(() => {});
|
||||
}
|
||||
},
|
||||
beforeDestroy() {
|
||||
if (this.timerId) {
|
||||
clearInterval(this.timerId);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
@ -27,7 +27,7 @@
|
||||
<div class="f12">{{item.content}}</div>
|
||||
<div class="flex-row align-items-center">
|
||||
<div class="f16 mr-8 cursor-pointer"
|
||||
v-if="item.roomId && item.sdkAppId && item.userId && item.userSig"
|
||||
v-if="item.roomId && item.sdkAppId && item.userId && item.userSig && item.status.code === 0"
|
||||
@click="handleVideoCall(item)">
|
||||
<i class="el-icon-video-camera"></i>
|
||||
</div>
|
||||
@ -37,7 +37,7 @@
|
||||
<i class="el-icon-edit-outline"></i>
|
||||
</div>
|
||||
<div class="f16 mr-8 cursor-pointer"
|
||||
v-if="item.status.code === 1"
|
||||
v-if="item.status.code === 0"
|
||||
@click="handleBackCase(item)">
|
||||
<i class="el-icon-delete"></i>
|
||||
</div>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user