no message

This commit is contained in:
kuaifan 2022-06-02 00:04:52 +08:00
parent dbee06179c
commit f2a618d0c9
16 changed files with 180 additions and 46 deletions

View File

@ -766,7 +766,7 @@ class UsersController extends AbstractController
}
/**
* @api {get} api/users/meeting/open 16. 【会议】会议
* @api {get} api/users/meeting/open 16. 【会议】创建会议、加入会议
*
* @apiDescription 需要token身份
* @apiVersion 1.0.0
@ -793,14 +793,14 @@ class UsersController extends AbstractController
$name = trim(Request::input('name'));
$userids = Request::input('userids');
$isCreate = false;
//
// 创建、加入
if ($type === 'join') {
$meeting = Meeting::whereMeetingid($meetingid)->first();
if (empty($meeting)) {
return Base::retError('频道ID不存在');
}
} elseif ($type === 'create') {
$meetingid = strtoupper(Base::generatePassword());
$meetingid = strtoupper(Base::generatePassword(11, 1));
$name = $name ?: "{$user->nickname} 发起的会议";
$channel = "DooTask:" . substr(md5($meetingid . env("APP_KEY")), 16);
$meeting = Meeting::createInstance([
@ -814,6 +814,7 @@ class UsersController extends AbstractController
} else {
return Base::retError('参数错误');
}
$data = $meeting->toArray();
// 创建令牌
$meetingSetting = Base::setting('meetingSetting');
if ($meetingSetting['open'] !== 'open') {
@ -841,7 +842,7 @@ class UsersController extends AbstractController
}
$dialog = WebSocketDialog::checkUserDialog($user->userid, $userid);
if ($dialog) {
$res = WebSocketDialogMsg::sendMsg($dialog->id, 'meeting', $meeting, $user->userid);
$res = WebSocketDialogMsg::sendMsg($dialog->id, 'meeting', $data, $user->userid);
if (Base::isSuccess($res)) {
$msgs[] = $res['data'];
}
@ -849,11 +850,56 @@ class UsersController extends AbstractController
}
}
//
$data = $meeting->toArray();
$data['appid'] = $meetingSetting['appid'];
$data['uid'] = $uid;
$data['token'] = $token;
$data['msgs'] = $msgs;
return Base::retSuccess('success', $data);
}
/**
* @api {get} api/users/meeting/invitation 17. 【会议】发送邀请
*
* @apiDescription 需要token身份
* @apiVersion 1.0.0
* @apiGroup users
* @apiName meeting__invitation
*
* @apiParam {String} meetingid 频道ID不是数字
* @apiParam {Array} userids 邀请成员
*
* @apiSuccess {Number} ret 返回状态码1正确、0错误
* @apiSuccess {String} msg 返回信息(错误描述)
* @apiSuccess {Object} data 返回数据
*/
public function meeting__invitation()
{
$user = User::auth();
//
$meetingid = trim(Request::input('meetingid'));
$userids = Request::input('userids');
//
$meeting = Meeting::whereMeetingid($meetingid)->first();
if (empty($meeting)) {
return Base::retError('频道ID不存在');
}
$data = $meeting->toArray();
// 发送给邀请人
$msgs = [];
foreach ($userids as $userid) {
if (!User::whereUserid($userid)->exists()) {
continue;
}
$dialog = WebSocketDialog::checkUserDialog($user->userid, $userid);
if ($dialog) {
$res = WebSocketDialogMsg::sendMsg($dialog->id, 'meeting', $data, $user->userid);
if (Base::isSuccess($res)) {
$msgs[] = $res['data'];
}
}
}
//
$data['msgs'] = $msgs;
return Base::retSuccess('发送邀请成功', $data);
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -61,6 +61,9 @@ export default {
if (typeof msg === "boolean") {
if (msg && !ended) {
audio.pause()
audio.src = null
this.audioSrc = null
this.audioPlay = false;
}
return
}
@ -71,6 +74,9 @@ export default {
audio.play()
} else {
audio.pause();
audio.src = null
this.audioSrc = null
this.audioPlay = false;
}
} else {
this.audioId = id;

View File

@ -36,6 +36,7 @@
<script>
import {mapGetters, mapState} from "vuex";
import {Store} from "le5le-store";
export default {
name: "MobileTabbar",
@ -60,6 +61,8 @@ export default {
[
{icon: '&#xe7b9;', name: 'addProject', label: '创建项目'},
{icon: '&#xe7b8;', name: 'addTask', label: '添加任务'},
{icon: '&#xe7c1;', name: 'createMeeting', label: '新会议'},
{icon: '&#xe794;', name: 'joinMeeting', label: '加入会议'},
]
],
};
@ -78,7 +81,7 @@ export default {
},
computed: {
...mapState(['cacheDialogs']),
...mapState(['cacheDialogs', 'userId']),
...mapGetters(['dashboardTask']),
routeName() {
@ -147,6 +150,19 @@ export default {
case 'addProject':
return;
case 'createMeeting':
Store.set('addMeeting', {
type: 'create',
userids: [this.userId],
});
break;
case 'joinMeeting':
Store.set('addMeeting', {
type: 'join',
});
break;
case 'project':
location = {name: 'manage-project', params: {projectId: 'all'}};
break;

View File

@ -39,12 +39,16 @@
<em>{{$L('会议主题')}}</em>
{{msgData.msg.name}}
</li>
<li>
<em>{{$L('会议创建人')}}</em>
<UserAvatar :userid="msgData.msg.userid" :show-icon="false" :show-name="true" tooltip-disabled/>
</li>
<li>
<em>{{$L('频道ID')}}</em>
{{msgData.msg.meetingid}}
{{msgData.msg.meetingid.replace(/^(.{3})(.{3})(.*)$/, '$1 $2 $3')}}
</li>
<li class="meeting-operation">
{{$L('点击入会议')}}
{{$L('点击入会议')}}
<i class="taskfont">&#xe68b;</i>
</li>
</ul>

View File

@ -1,5 +1,6 @@
<template>
<div v-show="false">
<!-- 加入/新建 -->
<Modal
v-model="addShow"
:title="$L(addData.type === 'join' ? '加入会议' : '新会议')"
@ -36,9 +37,10 @@
</Form>
<div slot="footer" class="adaption">
<Button type="default" @click="addShow=false">{{$L('取消')}}</Button>
<Button type="primary" :loading="loadIng > 0" @click="onSubmit">{{$L(addData.type === 'join' ? '入会议' : '开始会议')}}</Button>
<Button type="primary" :loading="loadIng > 0" @click="onSubmit">{{$L(addData.type === 'join' ? '入会议' : '开始会议')}}</Button>
</div>
</Modal>
<!-- 会议中 -->
<Modal
v-model="meetingShow"
:title="addData.name"
@ -64,7 +66,23 @@
<Button type="primary" :loading="videoLoad" @click="onVideo">
<i class="taskfont" v-html="localUser.videoTrack ? '&#xe7c1;' : '&#xe7c8;'"></i>
</Button>
<Button type="warning" :loading="loadIng > 0" @click="onClose">{{$L('退出会议')}}</Button>
<Button type="primary" @click="onInvitation('open')">{{$L('邀请')}}</Button>
<Button type="warning" :loading="loadIng > 0" @click="onClose">{{$L('离开会议')}}</Button>
</div>
</Modal>
<!-- 邀请 -->
<Modal
v-model="invitationShow"
:title="$L('邀请加入')"
:mask-closable="false">
<Form ref="invitationForm" :model="invitationData" label-width="auto" @submit.native.prevent>
<FormItem prop="userids" :label="$L('邀请成员')">
<UserInput v-model="invitationData.userids" :multiple-max="20" :placeholder="$L('选择邀请成员')"/>
</FormItem>
</Form>
<div slot="footer" class="adaption">
<Button type="default" @click="invitationShow=false">{{$L('取消')}}</Button>
<Button type="primary" :loading="invitationLoad" @click="onInvitation('submit')">{{$L('发送邀请')}}</Button>
</div>
</Modal>
</div>
@ -90,6 +108,12 @@ export default {
tracks: ['audio']
},
invitationShow: false,
invitationLoad: false,
invitationData: {
userids: [],
},
meetingShow: false,
audioLoad: false,
videoLoad: false,
@ -162,7 +186,9 @@ export default {
data: this.addData
}).then(({data}) => {
this.$set(this.addData, 'name', data.name);
this.$set(this.addData, 'meetingid', data.meetingid);
this.$store.dispatch("saveDialogMsg", data.msgs);
this.$store.dispatch("updateDialogLastMsg", data.msgs);
delete data.name;
delete data.msgs;
//
@ -199,10 +225,35 @@ export default {
}
},
onInvitation(type) {
if (type === 'open') {
this.invitationData = {
userids: [],
meetingid: this.addData.meetingid
};
this.invitationShow = true;
} else if (type === 'submit') {
this.invitationLoad = true;
this.$store.dispatch("call", {
url: 'users/meeting/invitation',
data: this.invitationData
}).then(({data, msg}) => {
this.invitationShow = false;
this.$store.dispatch("saveDialogMsg", data.msgs);
this.$store.dispatch("updateDialogLastMsg", data.msgs);
$A.messageSuccess(msg);
}).catch(({msg}) => {
$A.modalError(msg);
}).finally(_ => {
this.invitationLoad = false;
});
}
},
onClose() {
return new Promise(resolve => {
$A.modalConfirm({
content: '确定要退出会议吗?',
content: '确定要离开会议吗?',
cancelText: '继续',
okText: '退出',
onOk: async _ => {

View File

@ -1926,15 +1926,21 @@ export default {
updateDialogLastMsg({state, dispatch}, data) {
$A.execMainDispatch("updateDialogLastMsg", data)
//
let dialog = state.cacheDialogs.find(({id}) => id == data.dialog_id);
if (dialog) {
dispatch("saveDialog", {
id: data.dialog_id,
last_msg: data,
last_at: $A.formatDate("Y-m-d H:i:s")
if ($A.isArray(data)) {
data.forEach((msg) => {
dispatch("updateDialogLastMsg", msg)
});
} else {
dispatch("getDialogOne", data.dialog_id).catch(() => {})
} else if ($A.isJson(data)) {
let dialog = state.cacheDialogs.find(({id}) => id == data.dialog_id);
if (dialog) {
dispatch("saveDialog", {
id: data.dialog_id,
last_msg: data,
last_at: $A.formatDate("Y-m-d H:i:s")
});
} else {
dispatch("getDialogOne", data.dialog_id).catch(() => {})
}
}
},

View File

@ -181,7 +181,9 @@ body.dark-mode-reverse {
.dialog-head {
.dialog-content {
background-color: #e1e1e1;
.content-text {
.content-text,
.content-record,
.content-meeting {
color: #ffffff;
}
}

View File

@ -273,14 +273,6 @@ body {
display: flex;
align-items: center;
> .ivu-btn {
padding: 0;
> span {
padding: 0 15px;
}
}
.ivu-btn {
height: 38px;
line-height: 36px;

View File

@ -451,13 +451,13 @@
.content-record {
display: flex;
color: $primary-title-color;
.dialog-record {
display: flex;
flex-direction: row-reverse;
justify-content: flex-end;
align-content: center;
color: $primary-title-color;
line-height: 22px;
cursor: pointer;
@ -499,34 +499,44 @@
}
.content-meeting {
padding: 4px 6px;
color: $primary-title-color;
.dialog-meeting {
cursor: pointer;
min-width: 200px;
color: $primary-title-color;
min-width: 220px;
> li {
list-style: none;
display: flex;
flex-direction: column;
align-items: flex-start;
margin-bottom: 12px;
margin-bottom: 16px;
&.meeting-operation {
border-top: 1px solid #cccccc;
margin-bottom: 0;
padding: 8px 0 4px;
padding: 12px 0 0;
display: flex;
flex-direction: row;
align-items: center;
font-size: 12px;
opacity: 0.8;
position: relative;
&:before {
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
height: 1px;
background-color: rgba(204, 204, 204, 0.8);
transform: scaleY(0.5);
}
.taskfont {
font-size: 12px;
padding-left: 2px;
transform: scale(0.6);
transform: scale(0.8);
}
}
> em {
font-style: normal;
font-weight: 500;
font-weight: bold;
padding-bottom: 2px;
}
}
@ -729,10 +739,10 @@
}
.content-record {
color: #ffffff;
.dialog-record {
flex-direction: row;
color: #ffffff;
.record-time {
padding: 0 4px 0 0;
@ -745,13 +755,14 @@
}
.content-meeting {
color: #ffffff;
.dialog-meeting {
min-width: 200px;
color: #ffffff;
> li {
&.meeting-operation {
border-top: 1px solid #ffffff;
opacity: 1;
&:before {
background-color: rgba(255, 255, 255, 0.8);
}
}
}
}

View File

@ -30,10 +30,12 @@ body {
top: 4px;
right: 8px;
z-index: 2;
display: flex;
align-items: center;
.taskfont {
color: #ff0000;
font-size: 20px;
margin-left: 6px;
font-size: 18px;
margin-left: 8px;
}
}
.common-avatar {
@ -71,7 +73,6 @@ body {
font-size: 20px;
}
.ivu-btn {
padding: 0;
display: flex;
align-items: center;
justify-content: center;
@ -80,7 +81,6 @@ body {
display: flex;
align-items: center;
justify-content: center;
padding: 0 4px !important;
}
}
}