feat(multi-owner): 群/项目/部门支持主+副双负责人体系
- 群组:新增 web_socket_dialog_users.role(1=主、2=副),主可任命/罢免副群主,副可邀请/移出普通成员 - 项目:project_users.owner 扩展为 0/1/2(成员/主/副),主独占转让和删除,副共享日常管理;任务可见性、通知、分配等下游逻辑统一用「主+副」 - 部门:新增 user_department_owners 表存储副负责人;部门群同步副群主,赋予群管理员权限 - 转移用户时副身份不替补、降级为普通成员 - 配套 migration/backfill、API、前端 UI、i18n 词条与三项 Feature 测试 - .gitignore 忽略 .playwright-mcp/
This commit is contained in:
@@ -1755,8 +1755,10 @@ class DialogController extends AbstractController
|
||||
}
|
||||
// 任务可见性校验(与 task__one 一致)
|
||||
if ($task->visibility != 1) {
|
||||
$project_userid = ProjectUser::whereProjectId($task->project_id)->whereOwner(1)->value('userid');
|
||||
if ($user->userid != $project_userid) {
|
||||
$projectOwnerids = ProjectUser::whereProjectId($task->project_id)
|
||||
->whereIn('owner', [ProjectUser::OWNER_PRIMARY, ProjectUser::OWNER_DEPUTY])
|
||||
->pluck('userid')->map(fn($v) => (int)$v)->toArray();
|
||||
if (!in_array($user->userid, $projectOwnerids)) {
|
||||
$visibleUserids = array_merge(
|
||||
ProjectTaskUser::whereTaskId($task_id)->pluck('userid')->toArray(),
|
||||
ProjectTaskUser::whereTaskPid($task_id)->pluck('userid')->toArray(),
|
||||
@@ -2832,7 +2834,10 @@ class DialogController extends AbstractController
|
||||
return Base::retError('对话不存在或已被删除', ['dialog_id' => $dialog_id], -4003);
|
||||
}
|
||||
} else {
|
||||
$dialog = WebSocketDialog::checkDialog($dialog_id, true);
|
||||
$dialog = WebSocketDialog::checkDialog($dialog_id);
|
||||
if (!$dialog->isOwner(User::userid())) {
|
||||
throw new \App\Exceptions\ApiException('仅群主或群管理员可操作');
|
||||
}
|
||||
}
|
||||
//
|
||||
$data = ['id' => $dialog->id];
|
||||
@@ -2891,7 +2896,11 @@ class DialogController extends AbstractController
|
||||
return Base::retError('请选择群成员');
|
||||
}
|
||||
//
|
||||
$dialog = WebSocketDialog::checkDialog($dialog_id, "auto");
|
||||
$dialog = WebSocketDialog::checkDialog($dialog_id);
|
||||
// 有群主(主或副)时,仅群主/副群主可邀请;无群主时,任意成员可邀请
|
||||
if ($dialog->owner_id > 0 && !$dialog->isOwner($user->userid)) {
|
||||
throw new \App\Exceptions\ApiException('仅限群主或群管理员操作');
|
||||
}
|
||||
//
|
||||
$dialog->checkGroup();
|
||||
$dialog->joinGroup($userids, $user->userid);
|
||||
@@ -2981,17 +2990,107 @@ class DialogController extends AbstractController
|
||||
$dialog = WebSocketDialog::checkDialog($dialog_id, $check_owner);
|
||||
//
|
||||
$dialog->checkGroup($check_owner ? 'user' : null);
|
||||
$oldOwnerId = (int)$dialog->owner_id;
|
||||
$dialog->owner_id = $userid;
|
||||
if ($dialog->save()) {
|
||||
$dialog->joinGroup($userid, 0);
|
||||
// 同步 role:原主 role=0、新主 role=1(覆盖即可)
|
||||
if ($oldOwnerId > 0 && $oldOwnerId !== (int)$userid) {
|
||||
WebSocketDialogUser::where('dialog_id', $dialog->id)
|
||||
->where('userid', $oldOwnerId)
|
||||
->update(['role' => 0]);
|
||||
}
|
||||
WebSocketDialogUser::where('dialog_id', $dialog->id)
|
||||
->where('userid', $userid)
|
||||
->update(['role' => 1]);
|
||||
$dialog->pushMsg("groupUpdate", [
|
||||
'id' => $dialog->id,
|
||||
'owner_id' => $dialog->owner_id,
|
||||
'deputy_ids' => $dialog->deputy_ids,
|
||||
]);
|
||||
}
|
||||
return Base::retSuccess('转让成功');
|
||||
}
|
||||
|
||||
/**
|
||||
* 任命副群主(仅主群主可操作)
|
||||
*
|
||||
* @apiParam {Number} dialog_id 群对话ID
|
||||
* @apiParam {Number} userid 要任命的群成员 userid
|
||||
*/
|
||||
public function group__adddeputy()
|
||||
{
|
||||
$user = User::auth();
|
||||
$dialog_id = intval(Request::input('dialog_id'));
|
||||
$userid = intval(Request::input('userid'));
|
||||
|
||||
if ($userid <= 0) {
|
||||
return Base::retError('请选择有效的成员');
|
||||
}
|
||||
|
||||
$dialog = WebSocketDialog::checkDialog($dialog_id, true); // checkOwner=true:仅主群主
|
||||
$dialog->checkGroup('user'); // 仅普通群
|
||||
|
||||
$member = WebSocketDialogUser::where('dialog_id', $dialog->id)
|
||||
->where('userid', $userid)
|
||||
->first();
|
||||
if (empty($member)) {
|
||||
return Base::retError('该用户不是群成员');
|
||||
}
|
||||
|
||||
if ((int)$member->role === 1) {
|
||||
return Base::retError('不能将群主任命为群管理员');
|
||||
}
|
||||
if ((int)$member->role !== 2) {
|
||||
$member->role = 2;
|
||||
$member->save();
|
||||
$dialog->pushMsg('groupUpdate', [
|
||||
'id' => $dialog->id,
|
||||
'deputy_ids' => $dialog->fresh()->deputy_ids,
|
||||
]);
|
||||
}
|
||||
|
||||
return Base::retSuccess('任命成功');
|
||||
}
|
||||
|
||||
/**
|
||||
* 罢免副群主(仅主群主可操作)
|
||||
*
|
||||
* @apiParam {Number} dialog_id 群对话ID
|
||||
* @apiParam {Number} userid 要罢免的副群主 userid
|
||||
*/
|
||||
public function group__deldeputy()
|
||||
{
|
||||
$user = User::auth();
|
||||
$dialog_id = intval(Request::input('dialog_id'));
|
||||
$userid = intval(Request::input('userid'));
|
||||
|
||||
if ($userid <= 0) {
|
||||
return Base::retError('请选择有效的成员');
|
||||
}
|
||||
|
||||
$dialog = WebSocketDialog::checkDialog($dialog_id, true);
|
||||
$dialog->checkGroup('user');
|
||||
|
||||
$member = WebSocketDialogUser::where('dialog_id', $dialog->id)
|
||||
->where('userid', $userid)
|
||||
->first();
|
||||
if (empty($member)) {
|
||||
return Base::retSuccess('罢免成功'); // 幂等:本来就不是成员
|
||||
}
|
||||
|
||||
if ((int)$member->role === 2) {
|
||||
$member->role = 0;
|
||||
$member->save();
|
||||
$dialog->pushMsg('groupUpdate', [
|
||||
'id' => $dialog->id,
|
||||
'deputy_ids' => $dialog->fresh()->deputy_ids,
|
||||
]);
|
||||
}
|
||||
|
||||
return Base::retSuccess('罢免成功');
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/dialog/group/disband 解散群组
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user