diff --git a/app/Http/Controllers/Api/ProjectController.php b/app/Http/Controllers/Api/ProjectController.php index e7a97e98..d6434c50 100755 --- a/app/Http/Controllers/Api/ProjectController.php +++ b/app/Http/Controllers/Api/ProjectController.php @@ -6,6 +6,7 @@ use App\Exceptions\ApiException; use App\Models\AbstractModel; use App\Models\Project; use App\Models\ProjectColumn; +use App\Models\ProjectInvite; use App\Models\ProjectLog; use App\Models\ProjectTask; use App\Models\ProjectTaskFile; @@ -258,6 +259,110 @@ class ProjectController extends AbstractController return Base::retSuccess('修改成功', ['id' => $project->id]); } + /** + * 获取邀请链接(限:项目负责人) + * + * @apiParam {Number} project_id 项目ID + * @apiParam {String} refresh 刷新链接 + * - no: 只获取(默认) + * - yes: 刷新链接,之前的将失效 + */ + public function invite() + { + User::auth(); + // + $project_id = intval(Request::input('project_id')); + $refresh = Request::input('refresh', 'no'); + // + $project = Project::userProject($project_id); + if (!$project->owner) { + return Base::retError('仅限项目负责人查看'); + } + // + $invite = Base::settingFind('system', 'project_invite'); + if ($invite == 'close') { + return Base::retError('未开放此功能'); + } + // + $projectInvite = ProjectInvite::whereProjectId($project->id)->first(); + if (empty($projectInvite)) { + $projectInvite = ProjectInvite::createInstance([ + 'project_id' => $project->id, + 'code' => Base::generatePassword(64), + ]); + $projectInvite->save(); + } else { + if ($refresh == 'yes') { + $projectInvite->code = Base::generatePassword(64); + $projectInvite->save(); + } + } + return Base::retSuccess('success', [ + 'url' => Base::fillUrl('manage/project/invite?code=' . $projectInvite->code), + 'num' => $projectInvite->num + ]); + } + + /** + * 通过邀请链接code获取项目信息 + * + * @apiParam {String} code + */ + public function invite__info() + { + User::auth(); + // + $code = Request::input('code'); + // + $invite = Base::settingFind('system', 'project_invite'); + if ($invite == 'close') { + return Base::retError('未开放此功能'); + } + // + $projectInvite = ProjectInvite::with(['project'])->whereCode($code)->first(); + if (empty($projectInvite)) { + return Base::retError('邀请code不存在'); + } + return Base::retSuccess('success', $projectInvite); + } + + /** + * 通过邀请链接code加入项目 + * + * @apiParam {String} code + */ + public function invite__join() + { + $user = User::auth(); + // + $code = Request::input('code'); + // + $invite = Base::settingFind('system', 'project_invite'); + if ($invite == 'close') { + return Base::retError('未开放此功能'); + } + // + $projectInvite = ProjectInvite::with(['project'])->whereCode($code)->first(); + if (empty($projectInvite)) { + return Base::retError('邀请code不存在'); + } + if ($projectInvite->already) { + return Base::retSuccess('已加入', $projectInvite); + } + if (!$projectInvite->project?->joinProject($user->userid)) { + return Base::retError('加入失败,请稍后再试'); + } + $projectInvite->num++; + $projectInvite->save(); + // + $projectInvite->project->syncDialogUser(); + $projectInvite->project->addLog("会员ID:" . $user->userid . " 通过邀请链接加入项目"); + // + $data = $projectInvite->toArray(); + $data['already'] = true; + return Base::retSuccess('加入成功', $data); + } + /** * 移交项目(限:项目负责人) * diff --git a/app/Http/Controllers/Api/SystemController.php b/app/Http/Controllers/Api/SystemController.php index c1a31a3f..66e80f91 100755 --- a/app/Http/Controllers/Api/SystemController.php +++ b/app/Http/Controllers/Api/SystemController.php @@ -24,7 +24,8 @@ class SystemController extends AbstractController * * @apiParam {String} type * - get: 获取(默认) - * - save: 保存设置(参数:reg、login_code、password_policy、chat_nickname) + * - all: 获取所有(需要管理员权限) + * - save: 保存设置(参数:reg、reg_invite、login_code、password_policy、project_invite、chat_nickname) * @apiSuccess {Number} ret 返回状态码(1正确、0错误) * @apiSuccess {String} msg 返回信息(错误描述) @@ -40,7 +41,7 @@ class SystemController extends AbstractController User::auth('admin'); $all = Request::input(); foreach ($all AS $key => $value) { - if (!in_array($key, ['reg', 'login_code', 'password_policy', 'chat_nickname'])) { + if (!in_array($key, ['reg', 'reg_invite', 'login_code', 'password_policy', 'project_invite', 'chat_nickname'])) { unset($all[$key]); } } @@ -49,9 +50,17 @@ class SystemController extends AbstractController $setting = Base::setting('system'); } // + if ($type == 'all') { + User::auth('admin'); + $setting['reg_invite'] = $setting['reg_invite'] ?: Base::generatePassword(8); + } else { + if (isset($setting['reg_invite'])) unset($setting['reg_invite']); + } + // $setting['reg'] = $setting['reg'] ?: 'open'; $setting['login_code'] = $setting['login_code'] ?: 'auto'; $setting['password_policy'] = $setting['password_policy'] ?: 'simple'; + $setting['project_invite'] = $setting['project_invite'] ?: 'open'; $setting['chat_nickname'] = $setting['chat_nickname'] ?: 'optional'; // return Base::retSuccess('success', $setting ?: json_decode('{}')); diff --git a/app/Models/ProjectInvite.php b/app/Models/ProjectInvite.php new file mode 100644 index 00000000..5c685316 --- /dev/null +++ b/app/Models/ProjectInvite.php @@ -0,0 +1,55 @@ +appendattrs['already'])) { + $this->appendattrs['already'] = false; + if (User::userid()) { + $this->appendattrs['already'] = (bool)$this->project?->projectUser?->where('userid', User::userid())->count(); + } + } + return $this->appendattrs['already']; + } + + /** + * @return \Illuminate\Database\Eloquent\Relations\HasOne + */ + public function project(): \Illuminate\Database\Eloquent\Relations\HasOne + { + return $this->hasOne(Project::class, 'id', 'project_id'); + } +} diff --git a/database/seeders/SettingsTableSeeder.php b/database/seeders/SettingsTableSeeder.php index a6ff5322..6b9b4b68 100644 --- a/database/seeders/SettingsTableSeeder.php +++ b/database/seeders/SettingsTableSeeder.php @@ -26,7 +26,7 @@ class SettingsTableSeeder extends Seeder 'id' => 1, 'name' => 'system', 'desc' => '', - 'setting' => '{"reg":"open","login_code":"auto"}', + 'setting' => '{"reg":"open","project_invite":"open","login_code":"auto"}', 'created_at' => seeders_at('2021-07-01 11:05:06'), 'updated_at' => seeders_at('2021-07-01 12:27:12'), ), diff --git a/resources/assets/js/pages/manage/components/ProjectList.vue b/resources/assets/js/pages/manage/components/ProjectList.vue index a90c094f..bac384d4 100644 --- a/resources/assets/js/pages/manage/components/ProjectList.vue +++ b/resources/assets/js/pages/manage/components/ProjectList.vue @@ -34,7 +34,8 @@ {{$L('项目设置')}} {{$L('成员管理')}} - {{$L('项目动态')}} + {{$L('邀请链接')}} + {{$L('项目动态')}} {{$L('已归档任务')}} {{$L('移交项目')}} {{$L('归档项目')}} @@ -320,7 +321,7 @@ v-model="settingShow" :title="$L('项目设置')" :mask-closable="false"> -
+ @@ -339,7 +340,7 @@ v-model="userShow" :title="$L('成员管理')" :mask-closable="false"> - + @@ -369,12 +370,39 @@ + + + + + +
{{$L('可通过此链接注册、加入项目。')}}
+
+ +
+ + +
+

{{$L('注意:刷新将导致原来的邀请链接失效!')}}

+
+ +
+
+
+ -
+ @@ -404,6 +432,10 @@ diff --git a/resources/assets/js/pages/manage/setting/system.vue b/resources/assets/js/pages/manage/setting/system.vue index 08691114..9db08a14 100644 --- a/resources/assets/js/pages/manage/setting/system.vue +++ b/resources/assets/js/pages/manage/setting/system.vue @@ -4,8 +4,16 @@ {{$L('允许')}} + {{$L('邀请码')}} {{$L('禁止')}} +
{{$L('允许:开放注册功能。')}}
+
@@ -23,6 +31,13 @@
{{$L('简单:大于或等于6个字符。')}}
{{$L('复杂:大于或等于6个字符,包含数字、字母大小写或者特殊字符。')}}
+ + + {{$L('开启')}} + {{$L('关闭')}} + +
{{$L('开启:项目管理员可生成链接邀请成员加入项目。')}}
+
{{$L('可选')}} @@ -68,7 +83,7 @@ export default { systemSetting(save) { this.loadIng++; this.$store.dispatch("call", { - url: 'system/setting?type=' + (save ? 'save' : 'get'), + url: 'system/setting?type=' + (save ? 'save' : 'all'), data: this.formDatum, }).then(({data}) => { if (save) { diff --git a/resources/assets/js/routes.js b/resources/assets/js/routes.js index b13d845c..4fc06dea 100755 --- a/resources/assets/js/routes.js +++ b/resources/assets/js/routes.js @@ -58,6 +58,11 @@ export default [ }, ] }, + { + name: 'manage-project-invite', + path: 'project/invite', + component: () => import('./pages/manage/projectInvite.vue'), + }, { name: 'manage-project', path: 'project/:id', diff --git a/resources/assets/sass/pages/common.scss b/resources/assets/sass/pages/common.scss index 8b5ac5f8..2122a774 100755 --- a/resources/assets/sass/pages/common.scss +++ b/resources/assets/sass/pages/common.scss @@ -1,5 +1,8 @@ body { overflow: hidden; + .form-tip { + color: #999999; + } .ivu-input, .ivu-select-selection { border-color: #e8e8e8; diff --git a/resources/assets/sass/pages/page-setting.scss b/resources/assets/sass/pages/page-setting.scss index 83d90b74..d9bb7685 100755 --- a/resources/assets/sass/pages/page-setting.scss +++ b/resources/assets/sass/pages/page-setting.scss @@ -106,9 +106,6 @@ .ivu-form { overflow: auto; } - .form-tip { - color: #999999; - } .setting-color { min-width: 400px; max-width: 600px;