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身份 * @apiDescription 需要token身份
* @apiVersion 1.0.0 * @apiVersion 1.0.0
@ -793,14 +793,14 @@ class UsersController extends AbstractController
$name = trim(Request::input('name')); $name = trim(Request::input('name'));
$userids = Request::input('userids'); $userids = Request::input('userids');
$isCreate = false; $isCreate = false;
// // 创建、加入
if ($type === 'join') { if ($type === 'join') {
$meeting = Meeting::whereMeetingid($meetingid)->first(); $meeting = Meeting::whereMeetingid($meetingid)->first();
if (empty($meeting)) { if (empty($meeting)) {
return Base::retError('频道ID不存在'); return Base::retError('频道ID不存在');
} }
} elseif ($type === 'create') { } elseif ($type === 'create') {
$meetingid = strtoupper(Base::generatePassword()); $meetingid = strtoupper(Base::generatePassword(11, 1));
$name = $name ?: "{$user->nickname} 发起的会议"; $name = $name ?: "{$user->nickname} 发起的会议";
$channel = "DooTask:" . substr(md5($meetingid . env("APP_KEY")), 16); $channel = "DooTask:" . substr(md5($meetingid . env("APP_KEY")), 16);
$meeting = Meeting::createInstance([ $meeting = Meeting::createInstance([
@ -814,6 +814,7 @@ class UsersController extends AbstractController
} else { } else {
return Base::retError('参数错误'); return Base::retError('参数错误');
} }
$data = $meeting->toArray();
// 创建令牌 // 创建令牌
$meetingSetting = Base::setting('meetingSetting'); $meetingSetting = Base::setting('meetingSetting');
if ($meetingSetting['open'] !== 'open') { if ($meetingSetting['open'] !== 'open') {
@ -841,7 +842,7 @@ class UsersController extends AbstractController
} }
$dialog = WebSocketDialog::checkUserDialog($user->userid, $userid); $dialog = WebSocketDialog::checkUserDialog($user->userid, $userid);
if ($dialog) { if ($dialog) {
$res = WebSocketDialogMsg::sendMsg($dialog->id, 'meeting', $meeting, $user->userid); $res = WebSocketDialogMsg::sendMsg($dialog->id, 'meeting', $data, $user->userid);
if (Base::isSuccess($res)) { if (Base::isSuccess($res)) {
$msgs[] = $res['data']; $msgs[] = $res['data'];
} }
@ -849,11 +850,56 @@ class UsersController extends AbstractController
} }
} }
// //
$data = $meeting->toArray();
$data['appid'] = $meetingSetting['appid']; $data['appid'] = $meetingSetting['appid'];
$data['uid'] = $uid; $data['uid'] = $uid;
$data['token'] = $token; $data['token'] = $token;
$data['msgs'] = $msgs; $data['msgs'] = $msgs;
return Base::retSuccess('success', $data); 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 (typeof msg === "boolean") {
if (msg && !ended) { if (msg && !ended) {
audio.pause() audio.pause()
audio.src = null
this.audioSrc = null
this.audioPlay = false;
} }
return return
} }
@ -71,6 +74,9 @@ export default {
audio.play() audio.play()
} else { } else {
audio.pause(); audio.pause();
audio.src = null
this.audioSrc = null
this.audioPlay = false;
} }
} else { } else {
this.audioId = id; this.audioId = id;

View File

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

View File

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

View File

@ -1,5 +1,6 @@
<template> <template>
<div v-show="false"> <div v-show="false">
<!-- 加入/新建 -->
<Modal <Modal
v-model="addShow" v-model="addShow"
:title="$L(addData.type === 'join' ? '加入会议' : '新会议')" :title="$L(addData.type === 'join' ? '加入会议' : '新会议')"
@ -36,9 +37,10 @@
</Form> </Form>
<div slot="footer" class="adaption"> <div slot="footer" class="adaption">
<Button type="default" @click="addShow=false">{{$L('取消')}}</Button> <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> </div>
</Modal> </Modal>
<!-- 会议中 -->
<Modal <Modal
v-model="meetingShow" v-model="meetingShow"
:title="addData.name" :title="addData.name"
@ -64,7 +66,23 @@
<Button type="primary" :loading="videoLoad" @click="onVideo"> <Button type="primary" :loading="videoLoad" @click="onVideo">
<i class="taskfont" v-html="localUser.videoTrack ? '&#xe7c1;' : '&#xe7c8;'"></i> <i class="taskfont" v-html="localUser.videoTrack ? '&#xe7c1;' : '&#xe7c8;'"></i>
</Button> </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> </div>
</Modal> </Modal>
</div> </div>
@ -90,6 +108,12 @@ export default {
tracks: ['audio'] tracks: ['audio']
}, },
invitationShow: false,
invitationLoad: false,
invitationData: {
userids: [],
},
meetingShow: false, meetingShow: false,
audioLoad: false, audioLoad: false,
videoLoad: false, videoLoad: false,
@ -162,7 +186,9 @@ export default {
data: this.addData data: this.addData
}).then(({data}) => { }).then(({data}) => {
this.$set(this.addData, 'name', data.name); this.$set(this.addData, 'name', data.name);
this.$set(this.addData, 'meetingid', data.meetingid);
this.$store.dispatch("saveDialogMsg", data.msgs); this.$store.dispatch("saveDialogMsg", data.msgs);
this.$store.dispatch("updateDialogLastMsg", data.msgs);
delete data.name; delete data.name;
delete data.msgs; 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() { onClose() {
return new Promise(resolve => { return new Promise(resolve => {
$A.modalConfirm({ $A.modalConfirm({
content: '确定要退出会议吗?', content: '确定要离开会议吗?',
cancelText: '继续', cancelText: '继续',
okText: '退出', okText: '退出',
onOk: async _ => { onOk: async _ => {

View File

@ -1926,6 +1926,11 @@ export default {
updateDialogLastMsg({state, dispatch}, data) { updateDialogLastMsg({state, dispatch}, data) {
$A.execMainDispatch("updateDialogLastMsg", data) $A.execMainDispatch("updateDialogLastMsg", data)
// //
if ($A.isArray(data)) {
data.forEach((msg) => {
dispatch("updateDialogLastMsg", msg)
});
} else if ($A.isJson(data)) {
let dialog = state.cacheDialogs.find(({id}) => id == data.dialog_id); let dialog = state.cacheDialogs.find(({id}) => id == data.dialog_id);
if (dialog) { if (dialog) {
dispatch("saveDialog", { dispatch("saveDialog", {
@ -1936,6 +1941,7 @@ export default {
} else { } else {
dispatch("getDialogOne", data.dialog_id).catch(() => {}) dispatch("getDialogOne", data.dialog_id).catch(() => {})
} }
}
}, },
/** /**

View File

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

View File

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

View File

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

View File

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