mirror of
https://github.com/kuaifan/dootask.git
synced 2026-03-17 03:03:41 +00:00
perf: 项目群、任务群可添加成员
This commit is contained in:
parent
bebef77e5c
commit
3aefe99bd9
@ -929,6 +929,8 @@ class DialogController extends AbstractController
|
|||||||
* @api {get} api/dialog/group/adduser 21. 添加群成员
|
* @api {get} api/dialog/group/adduser 21. 添加群成员
|
||||||
*
|
*
|
||||||
* @apiDescription 需要token身份
|
* @apiDescription 需要token身份
|
||||||
|
* - 有群主时:只有群主可以邀请
|
||||||
|
* - 没有群主时:群内成员都可以邀请
|
||||||
* @apiVersion 1.0.0
|
* @apiVersion 1.0.0
|
||||||
* @apiGroup dialog
|
* @apiGroup dialog
|
||||||
* @apiName group__adduser
|
* @apiName group__adduser
|
||||||
@ -951,7 +953,7 @@ class DialogController extends AbstractController
|
|||||||
return Base::retError('请选择群成员');
|
return Base::retError('请选择群成员');
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
$dialog = WebSocketDialog::checkDialog($dialog_id, true);
|
$dialog = WebSocketDialog::checkDialog($dialog_id, "auto");
|
||||||
//
|
//
|
||||||
$dialog->checkGroup();
|
$dialog->checkGroup();
|
||||||
$dialog->joinGroup($userids);
|
$dialog->joinGroup($userids);
|
||||||
@ -963,6 +965,8 @@ class DialogController extends AbstractController
|
|||||||
* @api {get} api/dialog/group/deluser 22. 移出(退出)群成员
|
* @api {get} api/dialog/group/deluser 22. 移出(退出)群成员
|
||||||
*
|
*
|
||||||
* @apiDescription 需要token身份
|
* @apiDescription 需要token身份
|
||||||
|
* - 只有群主、邀请人可以踢人
|
||||||
|
* - 群主、任务人员、项目人员不可被踢或退出
|
||||||
* @apiVersion 1.0.0
|
* @apiVersion 1.0.0
|
||||||
* @apiGroup dialog
|
* @apiGroup dialog
|
||||||
* @apiName group__adduser
|
* @apiName group__adduser
|
||||||
@ -993,10 +997,10 @@ class DialogController extends AbstractController
|
|||||||
return Base::retError('请选择群成员');
|
return Base::retError('请选择群成员');
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
$dialog = WebSocketDialog::checkDialog($dialog_id, $type === 'remove');
|
$dialog = WebSocketDialog::checkDialog($dialog_id);
|
||||||
//
|
//
|
||||||
$dialog->checkGroup();
|
$dialog->checkGroup();
|
||||||
$dialog->exitGroup($userids);
|
$dialog->exitGroup($userids, $type);
|
||||||
$dialog->pushMsg("groupExit", null, $userids);
|
$dialog->pushMsg("groupExit", null, $userids);
|
||||||
return Base::retSuccess($type === 'remove' ? '移出成功' : '退出成功');
|
return Base::retSuccess($type === 'remove' ? '移出成功' : '退出成功');
|
||||||
}
|
}
|
||||||
@ -1005,6 +1009,7 @@ class DialogController extends AbstractController
|
|||||||
* @api {get} api/dialog/group/disband 23. 解散群组
|
* @api {get} api/dialog/group/disband 23. 解散群组
|
||||||
*
|
*
|
||||||
* @apiDescription 需要token身份
|
* @apiDescription 需要token身份
|
||||||
|
* - 只有群主且是个人类型群可以解散
|
||||||
* @apiVersion 1.0.0
|
* @apiVersion 1.0.0
|
||||||
* @apiGroup dialog
|
* @apiGroup dialog
|
||||||
* @apiName group__disband
|
* @apiName group__disband
|
||||||
@ -1023,7 +1028,7 @@ class DialogController extends AbstractController
|
|||||||
//
|
//
|
||||||
$dialog = WebSocketDialog::checkDialog($dialog_id, true);
|
$dialog = WebSocketDialog::checkDialog($dialog_id, true);
|
||||||
//
|
//
|
||||||
$dialog->checkGroup();
|
$dialog->checkGroup('user');
|
||||||
$dialog->deleteDialog();
|
$dialog->deleteDialog();
|
||||||
$dialog->pushMsg("groupDelete");
|
$dialog->pushMsg("groupDelete");
|
||||||
return Base::retSuccess('解散成功');
|
return Base::retSuccess('解散成功');
|
||||||
|
|||||||
@ -207,9 +207,11 @@ class Project extends AbstractModel
|
|||||||
WebSocketDialogUser::updateInsert([
|
WebSocketDialogUser::updateInsert([
|
||||||
'dialog_id' => $this->dialog_id,
|
'dialog_id' => $this->dialog_id,
|
||||||
'userid' => $userid,
|
'userid' => $userid,
|
||||||
|
], [
|
||||||
|
'important' => 1
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
WebSocketDialogUser::whereDialogId($this->dialog_id)->whereNotIn('userid', $userids)->delete();
|
WebSocketDialogUser::whereDialogId($this->dialog_id)->whereNotIn('userid', $userids)->whereImportant(1)->delete();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -876,9 +876,11 @@ class ProjectTask extends AbstractModel
|
|||||||
WebSocketDialogUser::updateInsert([
|
WebSocketDialogUser::updateInsert([
|
||||||
'dialog_id' => $this->dialog_id,
|
'dialog_id' => $this->dialog_id,
|
||||||
'userid' => $userid,
|
'userid' => $userid,
|
||||||
|
], [
|
||||||
|
'important' => 1
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
WebSocketDialogUser::whereDialogId($this->dialog_id)->whereNotIn('userid', $userids)->delete();
|
WebSocketDialogUser::whereDialogId($this->dialog_id)->whereNotIn('userid', $userids)->whereImportant(1)->delete();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -134,6 +134,8 @@ class WebSocketDialog extends AbstractModel
|
|||||||
WebSocketDialogUser::updateInsert([
|
WebSocketDialogUser::updateInsert([
|
||||||
'dialog_id' => $this->id,
|
'dialog_id' => $this->id,
|
||||||
'userid' => $value,
|
'userid' => $value,
|
||||||
|
], [
|
||||||
|
'inviter' => User::userid(),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -144,27 +146,34 @@ class WebSocketDialog extends AbstractModel
|
|||||||
/**
|
/**
|
||||||
* 退出聊天室
|
* 退出聊天室
|
||||||
* @param int|array $userid 加入的会员ID或会员ID组
|
* @param int|array $userid 加入的会员ID或会员ID组
|
||||||
* @return bool
|
* @param $type
|
||||||
*/
|
*/
|
||||||
public function exitGroup($userid)
|
public function exitGroup($userid, $type = 'exit')
|
||||||
{
|
{
|
||||||
$builder = WebSocketDialogUser::whereDialogId($this->id);
|
$typeDesc = $type === 'remove' ? '移出' : '退出';
|
||||||
if (is_array($userid)) {
|
AbstractModel::transaction(function () use ($typeDesc, $type, $userid) {
|
||||||
$builder->whereIn('userid', $userid);
|
$builder = WebSocketDialogUser::whereDialogId($this->id);
|
||||||
} else {
|
if (is_array($userid)) {
|
||||||
$builder->whereUserid($userid);
|
$builder->whereIn('userid', $userid);
|
||||||
}
|
} else {
|
||||||
$builder->chunkById(100, function($list) {
|
$builder->whereUserid($userid);
|
||||||
/** @var WebSocketDialogUser $item */
|
|
||||||
foreach ($list as $item) {
|
|
||||||
if ($item->userid == $this->owner_id) {
|
|
||||||
// 群主不可退出
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$item->delete();
|
|
||||||
}
|
}
|
||||||
|
$builder->chunkById(100, function($list) use ($typeDesc, $type) {
|
||||||
|
/** @var WebSocketDialogUser $item */
|
||||||
|
foreach ($list as $item) {
|
||||||
|
if ($type === 'remove' && !in_array(User::userid(), [$this->owner_id, $item->inviter])) {
|
||||||
|
throw new ApiException('只有群主或邀请人可以移出成员');
|
||||||
|
}
|
||||||
|
if ($item->userid == $this->owner_id) {
|
||||||
|
throw new ApiException('群主不可' . $typeDesc);
|
||||||
|
}
|
||||||
|
if ($item->important) {
|
||||||
|
throw new ApiException('项目人员或任务人员不可' . $typeDesc);
|
||||||
|
}
|
||||||
|
$item->delete();
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -196,15 +205,19 @@ class WebSocketDialog extends AbstractModel
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 检查群组类型
|
* 检查群组类型
|
||||||
|
* @param string|array|null $groupType
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function checkGroup($groupType = 'user')
|
public function checkGroup($groupType = null)
|
||||||
{
|
{
|
||||||
if ($this->type !== 'group') {
|
if ($this->type !== 'group') {
|
||||||
throw new ApiException('仅限群组操作');
|
throw new ApiException('仅限群组操作');
|
||||||
}
|
}
|
||||||
if ($this->group_type !== $groupType) {
|
if ($groupType) {
|
||||||
throw new ApiException('操作的群组类型错误');
|
$groupTypes = is_array($groupType) ? $groupType : [$groupType];
|
||||||
|
if (!in_array($this->group_type, $groupTypes)) {
|
||||||
|
throw new ApiException('操作的群组类型错误');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -260,7 +273,7 @@ class WebSocketDialog extends AbstractModel
|
|||||||
/**
|
/**
|
||||||
* 获取对话(同时检验对话身份)
|
* 获取对话(同时检验对话身份)
|
||||||
* @param $dialog_id
|
* @param $dialog_id
|
||||||
* @param bool $checkOwner 是否校验群组身份
|
* @param bool|string $checkOwner 是否校验群组身份,'auto'时有群主为true无群主为false
|
||||||
* @return self
|
* @return self
|
||||||
*/
|
*/
|
||||||
public static function checkDialog($dialog_id, $checkOwner = false)
|
public static function checkDialog($dialog_id, $checkOwner = false)
|
||||||
@ -271,11 +284,14 @@ class WebSocketDialog extends AbstractModel
|
|||||||
}
|
}
|
||||||
//
|
//
|
||||||
$userid = User::userid();
|
$userid = User::userid();
|
||||||
|
if ($checkOwner === 'auto') {
|
||||||
|
$checkOwner = $dialog->owner_id > 0;
|
||||||
|
}
|
||||||
if ($checkOwner === true && $dialog->owner_id != $userid) {
|
if ($checkOwner === true && $dialog->owner_id != $userid) {
|
||||||
throw new ApiException('仅限群主操作');
|
throw new ApiException('仅限群主操作');
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
if ($dialog->type === 'group' && $dialog->group_type === 'task') {
|
if ($dialog->group_type === 'task') {
|
||||||
// 任务群对话校验是否在项目内
|
// 任务群对话校验是否在项目内
|
||||||
$project_id = intval(ProjectTask::whereDialogId($dialog->id)->value('project_id'));
|
$project_id = intval(ProjectTask::whereDialogId($dialog->id)->value('project_id'));
|
||||||
if ($project_id > 0) {
|
if ($project_id > 0) {
|
||||||
|
|||||||
@ -10,6 +10,8 @@ namespace App\Models;
|
|||||||
* @property int|null $userid 会员ID
|
* @property int|null $userid 会员ID
|
||||||
* @property string|null $top_at 置顶时间
|
* @property string|null $top_at 置顶时间
|
||||||
* @property int|null $mark_unread 是否标记为未读:0否,1是
|
* @property int|null $mark_unread 是否标记为未读:0否,1是
|
||||||
|
* @property int|null $inviter 邀请人
|
||||||
|
* @property int|null $important 是否不可移出(项目、任务人员)
|
||||||
* @property \Illuminate\Support\Carbon|null $created_at
|
* @property \Illuminate\Support\Carbon|null $created_at
|
||||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogUser newModelQuery()
|
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogUser newModelQuery()
|
||||||
@ -18,6 +20,8 @@ namespace App\Models;
|
|||||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogUser whereCreatedAt($value)
|
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogUser whereCreatedAt($value)
|
||||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogUser whereDialogId($value)
|
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogUser whereDialogId($value)
|
||||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogUser whereId($value)
|
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogUser whereId($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogUser whereImportant($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogUser whereInviter($value)
|
||||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogUser whereMarkUnread($value)
|
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogUser whereMarkUnread($value)
|
||||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogUser whereTopAt($value)
|
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogUser whereTopAt($value)
|
||||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogUser whereUpdatedAt($value)
|
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogUser whereUpdatedAt($value)
|
||||||
|
|||||||
@ -0,0 +1,48 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
class AddWebSocketDialogUsersInviterImportant extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
$isAdd = false;
|
||||||
|
Schema::table('web_socket_dialog_users', function (Blueprint $table) use (&$isAdd) {
|
||||||
|
if (!Schema::hasColumn('web_socket_dialog_users', 'important')) {
|
||||||
|
$isAdd = true;
|
||||||
|
$table->boolean('important')->default(0)->after('mark_unread')->nullable()->comment('是否不可移出(项目、任务人员)');
|
||||||
|
$table->bigInteger('inviter')->nullable()->default(0)->after('mark_unread')->comment('邀请人');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if ($isAdd) {
|
||||||
|
\App\Models\WebSocketDialog::whereIn('group_type', ['project', 'task'])->chunkById(100, function ($lists) {
|
||||||
|
/** @var \App\Models\WebSocketDialog $item */
|
||||||
|
foreach ($lists as $item) {
|
||||||
|
\App\Models\WebSocketDialogUser::whereDialogId($item->id)->update([
|
||||||
|
'important' => 1,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::table('web_socket_dialog_users', function (Blueprint $table) {
|
||||||
|
$table->dropColumn("important");
|
||||||
|
$table->dropColumn("inviter");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -19,9 +19,9 @@
|
|||||||
<div class="group-info-user">
|
<div class="group-info-user">
|
||||||
<ul>
|
<ul>
|
||||||
<li v-for="(item, index) in userList" :key="index">
|
<li v-for="(item, index) in userList" :key="index">
|
||||||
<UserAvatar :userid="item.userid" :size="32" :user-result="userResult" showName tooltipDisabled/>
|
<UserAvatar :userid="item.userid" :size="32" showName tooltipDisabled/>
|
||||||
<div v-if="item.userid === dialogData.owner_id" class="user-tag">{{ $L("群主") }}</div>
|
<div v-if="item.userid === dialogData.owner_id" class="user-tag">{{ $L("群主") }}</div>
|
||||||
<Icon v-else-if="dialogData.owner_id == userId" class="user-exit" type="md-exit" @click="onExit(item)"/>
|
<Icon v-else-if="dialogData.owner_id == userId || item.inviter == userId" class="user-exit" type="md-exit" @click="onExit(item)"/>
|
||||||
</li>
|
</li>
|
||||||
<li v-if="userList.length === 0" class="no">
|
<li v-if="userList.length === 0" class="no">
|
||||||
<Loading v-if="loadIng > 0"/>
|
<Loading v-if="loadIng > 0"/>
|
||||||
@ -30,12 +30,10 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="dialogData.owner_id == userId" class="group-info-button">
|
<div class="group-info-button">
|
||||||
<Button @click="openAdd" type="primary">{{ $L("添加成员") }}</Button>
|
<Button v-if="dialogData.owner_id == userId || dialogData.owner_id == 0" @click="openAdd" type="primary">{{ $L("添加成员") }}</Button>
|
||||||
<Button @click="onDisband" type="error" ghost>{{ $L("解散群组") }}</Button>
|
<Button v-if="dialogData.owner_id == userId" @click="onDisband" type="error" ghost>{{ $L("解散群组") }}</Button>
|
||||||
</div>
|
<Button v-else @click="onExit" type="error" ghost>{{ $L("退出群组") }}</Button>
|
||||||
<div v-else class="group-info-button">
|
|
||||||
<Button @click="onExit" type="error" ghost>{{ $L("退出群组") }}</Button>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!--添加成员-->
|
<!--添加成员-->
|
||||||
@ -85,7 +83,7 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
...mapState(['cacheDialogs']),
|
...mapState(['cacheDialogs', 'cacheUserBasic']),
|
||||||
|
|
||||||
dialogData() {
|
dialogData() {
|
||||||
return this.cacheDialogs.find(({id}) => id == this.dialogId) || {};
|
return this.cacheDialogs.find(({id}) => id == this.dialogId) || {};
|
||||||
@ -100,8 +98,15 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
userList() {
|
userList() {
|
||||||
const {dialogUser, searchKey, dialogData} = this;
|
const {dialogUser, searchKey, cacheUserBasic, dialogData} = this;
|
||||||
const list = dialogUser.filter(item => {
|
const list = dialogUser.map(item => {
|
||||||
|
const userBasic = cacheUserBasic.find(basic => basic.userid == item.userid)
|
||||||
|
if (userBasic) {
|
||||||
|
item.nickname = userBasic.nickname
|
||||||
|
item.email = userBasic.email
|
||||||
|
}
|
||||||
|
return item
|
||||||
|
}).filter(item => {
|
||||||
if (searchKey && item.nickname) {
|
if (searchKey && item.nickname) {
|
||||||
if (!$A.strExists(item.nickname, searchKey) && !$A.strExists(item.email, searchKey)) {
|
if (!$A.strExists(item.nickname, searchKey) && !$A.strExists(item.email, searchKey)) {
|
||||||
return false;
|
return false;
|
||||||
@ -171,16 +176,6 @@ export default {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
userResult(user) {
|
|
||||||
let index = this.dialogUser.findIndex(({userid}) => userid === user.userid);
|
|
||||||
if (index > -1) {
|
|
||||||
this.dialogUser.splice(index, 1, Object.assign(user, {
|
|
||||||
id: this.dialogUser[index].id,
|
|
||||||
created_at: this.dialogUser[index].created_at
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
openAdd() {
|
openAdd() {
|
||||||
this.addData = {
|
this.addData = {
|
||||||
dialog_id: this.dialogId,
|
dialog_id: this.dialogId,
|
||||||
|
|||||||
@ -53,7 +53,6 @@
|
|||||||
|
|
||||||
<template v-if="dialogData.type === 'group'">
|
<template v-if="dialogData.type === 'group'">
|
||||||
<ETooltip
|
<ETooltip
|
||||||
v-if="dialogData.group_type === 'user'"
|
|
||||||
placement="top"
|
placement="top"
|
||||||
:disabled="windowSmall"
|
:disabled="windowSmall"
|
||||||
:openDelay="600"
|
:openDelay="600"
|
||||||
@ -250,7 +249,7 @@
|
|||||||
<DrawerOverlay
|
<DrawerOverlay
|
||||||
v-model="groupInfoShow"
|
v-model="groupInfoShow"
|
||||||
placement="right"
|
placement="right"
|
||||||
:size="380">
|
:size="400">
|
||||||
<DialogGroupInfo v-if="groupInfoShow" :dialogId="dialogId"/>
|
<DialogGroupInfo v-if="groupInfoShow" :dialogId="dialogId"/>
|
||||||
</DrawerOverlay>
|
</DrawerOverlay>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user