no message
This commit is contained in:
parent
f3d4d3199f
commit
7405c5bba8
97
app/Http/Controllers/Api/DialogController.php
Executable file
97
app/Http/Controllers/Api/DialogController.php
Executable file
@ -0,0 +1,97 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Api;
|
||||||
|
|
||||||
|
use App\Models\User;
|
||||||
|
use App\Models\WebSocketDialog;
|
||||||
|
use App\Models\WebSocketDialogMsg;
|
||||||
|
use App\Models\WebSocketDialogUser;
|
||||||
|
use App\Module\Base;
|
||||||
|
use Request;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @apiDefine dialog
|
||||||
|
*
|
||||||
|
* 对话
|
||||||
|
*/
|
||||||
|
class DialogController extends AbstractController
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 消息列表
|
||||||
|
*
|
||||||
|
* @apiParam {Number} dialog_id 对话ID
|
||||||
|
*
|
||||||
|
* @apiParam {Number} [page] 当前页,默认:1
|
||||||
|
* @apiParam {Number} [pagesize] 每页显示数量,默认:50,最大:100
|
||||||
|
*/
|
||||||
|
public function msg__lists()
|
||||||
|
{
|
||||||
|
$user = User::authE();
|
||||||
|
if (Base::isError($user)) {
|
||||||
|
return $user;
|
||||||
|
} else {
|
||||||
|
$user = User::IDE($user['data']);
|
||||||
|
}
|
||||||
|
//
|
||||||
|
$dialog_id = intval(Request::input('dialog_id'));
|
||||||
|
//
|
||||||
|
if (!WebSocketDialogUser::whereDialogId($dialog_id)->whereUserid($user->userid)->exists()) {
|
||||||
|
return Base::retError('不在成员列表内');
|
||||||
|
}
|
||||||
|
$dialog = WebSocketDialog::whereId($dialog_id)->first();
|
||||||
|
if (empty($dialog)) {
|
||||||
|
return Base::retError('对话不存在或已被删除');
|
||||||
|
}
|
||||||
|
//
|
||||||
|
$list = WebSocketDialogMsg::whereDialogId($dialog_id)->orderByDesc('id')->paginate(Base::getPaginate(100, 50));
|
||||||
|
//
|
||||||
|
return Base::retSuccess('success', $list);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送消息
|
||||||
|
*
|
||||||
|
* @apiParam {Number} dialog_id 对话ID
|
||||||
|
* @apiParam {Number} [extra_int] 额外参数(数字)
|
||||||
|
* @apiParam {String} [extra_str] 额外参数(字符)
|
||||||
|
* @apiParam {String} text 消息内容
|
||||||
|
*/
|
||||||
|
public function msg__sendtext()
|
||||||
|
{
|
||||||
|
$user = User::authE();
|
||||||
|
if (Base::isError($user)) {
|
||||||
|
return $user;
|
||||||
|
} else {
|
||||||
|
$user = User::IDE($user['data']);
|
||||||
|
}
|
||||||
|
//
|
||||||
|
$dialog_id = intval(Request::input('dialog_id'));
|
||||||
|
$extra_int = intval(Request::input('extra_int'));
|
||||||
|
$extra_str = trim(Request::input('extra_str'));
|
||||||
|
$text = trim(Request::input('text'));
|
||||||
|
//
|
||||||
|
if (mb_strlen($text) < 1) {
|
||||||
|
return Base::retError('消息内容不能为空');
|
||||||
|
} elseif (mb_strlen($text) > 20000) {
|
||||||
|
return Base::retError('消息内容最大不能超过20000字');
|
||||||
|
}
|
||||||
|
//
|
||||||
|
if (!WebSocketDialogUser::whereDialogId($dialog_id)->whereUserid($user->userid)->exists()) {
|
||||||
|
return Base::retError('不在成员列表内');
|
||||||
|
}
|
||||||
|
$dialog = WebSocketDialog::whereId($dialog_id)->first();
|
||||||
|
if (empty($dialog)) {
|
||||||
|
return Base::retError('对话不存在或已被删除');
|
||||||
|
}
|
||||||
|
//
|
||||||
|
$msg = [
|
||||||
|
'text' => $text
|
||||||
|
];
|
||||||
|
//
|
||||||
|
if ($dialog->type == 'group') {
|
||||||
|
return WebSocketDialogMsg::addGroupMsg($dialog_id, 'text', $msg, $user->userid, $extra_int, $extra_str);
|
||||||
|
} else {
|
||||||
|
return WebSocketDialogMsg::addUserMsg($dialog_id, 'text', $msg, $user->userid, $extra_int, $extra_str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -9,9 +9,8 @@ use App\Models\ProjectLog;
|
|||||||
use App\Models\ProjectTask;
|
use App\Models\ProjectTask;
|
||||||
use App\Models\ProjectUser;
|
use App\Models\ProjectUser;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Models\WebSocketDialog;
|
use App\Models\WebSocketDialogMsg;
|
||||||
use App\Module\Base;
|
use App\Module\Base;
|
||||||
use Carbon\Carbon;
|
|
||||||
use Request;
|
use Request;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -209,6 +208,54 @@ class ProjectController extends AbstractController
|
|||||||
return Base::retSuccess('修改成功');
|
return Base::retSuccess('修改成功');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改项目成员
|
||||||
|
*
|
||||||
|
* @apiParam {Number} project_id 项目ID
|
||||||
|
* @apiParam {Number} userid 成员ID或成员ID组
|
||||||
|
*/
|
||||||
|
public function user()
|
||||||
|
{
|
||||||
|
$user = User::authE();
|
||||||
|
if (Base::isError($user)) {
|
||||||
|
return $user;
|
||||||
|
} else {
|
||||||
|
$user = User::IDE($user['data']);
|
||||||
|
}
|
||||||
|
//
|
||||||
|
$project_id = intval(Request::input('project_id'));
|
||||||
|
$userid = Request::input('userid');
|
||||||
|
$userid = is_array($userid) ? $userid : [$userid];
|
||||||
|
//
|
||||||
|
$project = Project::select($this->projectSelect)
|
||||||
|
->join('project_users', 'projects.id', '=', 'project_users.project_id')
|
||||||
|
->where('projects.id', $project_id)
|
||||||
|
->where('project_users.userid', $user->userid)
|
||||||
|
->first();
|
||||||
|
if (empty($project)) {
|
||||||
|
return Base::retError('项目不存在或不在成员列表内');
|
||||||
|
}
|
||||||
|
if (!$project->owner) {
|
||||||
|
return Base::retError('你不是项目负责人');
|
||||||
|
}
|
||||||
|
//
|
||||||
|
return AbstractModel::transaction(function() use ($project, $userid) {
|
||||||
|
$array = [];
|
||||||
|
foreach ($userid as $value) {
|
||||||
|
if ($value > 0 && $project->joinProject($value)) {
|
||||||
|
$array[] = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$delUser = ProjectUser::whereProjectId($project->id)->whereNotIn('userid', $array)->get();
|
||||||
|
if ($delUser->isNotEmpty()) {
|
||||||
|
foreach ($delUser as $value) {
|
||||||
|
$value->exitProject();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Base::retSuccess('修改成功');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 移交项目
|
* 移交项目
|
||||||
*
|
*
|
||||||
@ -256,6 +303,42 @@ class ProjectController extends AbstractController
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 退出项目
|
||||||
|
*
|
||||||
|
* @apiParam {Number} project_id 项目ID
|
||||||
|
*/
|
||||||
|
public function exit()
|
||||||
|
{
|
||||||
|
$user = User::authE();
|
||||||
|
if (Base::isError($user)) {
|
||||||
|
return $user;
|
||||||
|
} else {
|
||||||
|
$user = User::IDE($user['data']);
|
||||||
|
}
|
||||||
|
//
|
||||||
|
$project_id = intval(Request::input('project_id'));
|
||||||
|
//
|
||||||
|
$project = Project::select($this->projectSelect)
|
||||||
|
->join('project_users', 'projects.id', '=', 'project_users.project_id')
|
||||||
|
->where('projects.id', $project_id)
|
||||||
|
->where('project_users.userid', $user->userid)
|
||||||
|
->first();
|
||||||
|
if (empty($project)) {
|
||||||
|
return Base::retError('项目不存在或不在成员列表内');
|
||||||
|
}
|
||||||
|
//
|
||||||
|
if ($project->owner) {
|
||||||
|
return Base::retError('项目负责人无法退出项目');
|
||||||
|
}
|
||||||
|
//
|
||||||
|
$projectUser = ProjectUser::whereProjectId($project->id)->whereUserid($user->userid)->first();
|
||||||
|
if ($projectUser->exitProject()) {
|
||||||
|
return Base::retSuccess('退出成功');
|
||||||
|
}
|
||||||
|
return Base::retError('退出失败');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除项目
|
* 删除项目
|
||||||
*
|
*
|
||||||
@ -284,12 +367,91 @@ class ProjectController extends AbstractController
|
|||||||
return Base::retError('你不是项目负责人');
|
return Base::retError('你不是项目负责人');
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
return AbstractModel::transaction(function() use ($project) {
|
if ($project->deleteProject()) {
|
||||||
ProjectTask::whereProjectId($project->id)->delete();
|
|
||||||
$project->delete();
|
|
||||||
//
|
|
||||||
return Base::retSuccess('删除成功');
|
return Base::retSuccess('删除成功');
|
||||||
});
|
}
|
||||||
|
return Base::retError('删除失败');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 【消息】消息列表
|
||||||
|
*
|
||||||
|
* @apiParam {Number} project_id 项目ID
|
||||||
|
* @apiParam {Number} [task_id] 任务ID
|
||||||
|
*
|
||||||
|
* @apiParam {Number} [page] 当前页,默认:1
|
||||||
|
* @apiParam {Number} [pagesize] 每页显示数量,默认:30,最大:100
|
||||||
|
*/
|
||||||
|
public function msg__lists()
|
||||||
|
{
|
||||||
|
$user = User::authE();
|
||||||
|
if (Base::isError($user)) {
|
||||||
|
return $user;
|
||||||
|
} else {
|
||||||
|
$user = User::IDE($user['data']);
|
||||||
|
}
|
||||||
|
//
|
||||||
|
$project_id = intval(Request::input('project_id'));
|
||||||
|
$task_id = intval(Request::input('task_id'));
|
||||||
|
//
|
||||||
|
$project = Project::select($this->projectSelect)
|
||||||
|
->join('project_users', 'projects.id', '=', 'project_users.project_id')
|
||||||
|
->where('projects.id', $project_id)
|
||||||
|
->where('project_users.userid', $user->userid)
|
||||||
|
->first();
|
||||||
|
if (empty($project)) {
|
||||||
|
return Base::retError('项目不存在或不在成员列表内');
|
||||||
|
}
|
||||||
|
//
|
||||||
|
$builder = WebSocketDialogMsg::whereDialogId($project->dialog_id);
|
||||||
|
if ($task_id > 0) {
|
||||||
|
$builder->whereExtraInt($task_id);
|
||||||
|
}
|
||||||
|
$list = $builder->orderByDesc('id')->paginate(Base::getPaginate(100, 30));
|
||||||
|
//
|
||||||
|
return Base::retSuccess('success', $list);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 【消息】发送消息
|
||||||
|
*
|
||||||
|
* @apiParam {Number} project_id 项目ID
|
||||||
|
* @apiParam {Number} [task_id] 任务ID
|
||||||
|
* @apiParam {String} text 消息内容
|
||||||
|
*/
|
||||||
|
public function msg__sendtext()
|
||||||
|
{
|
||||||
|
$user = User::authE();
|
||||||
|
if (Base::isError($user)) {
|
||||||
|
return $user;
|
||||||
|
} else {
|
||||||
|
$user = User::IDE($user['data']);
|
||||||
|
}
|
||||||
|
//
|
||||||
|
$project_id = intval(Request::input('project_id'));
|
||||||
|
$task_id = intval(Request::input('task_id'));
|
||||||
|
$text = trim(Request::input('text'));
|
||||||
|
//
|
||||||
|
if (mb_strlen($text) < 1) {
|
||||||
|
return Base::retError('消息内容不能为空');
|
||||||
|
} elseif (mb_strlen($text) > 20000) {
|
||||||
|
return Base::retError('消息内容最大不能超过20000字');
|
||||||
|
}
|
||||||
|
//
|
||||||
|
$project = Project::select($this->projectSelect)
|
||||||
|
->join('project_users', 'projects.id', '=', 'project_users.project_id')
|
||||||
|
->where('projects.id', $project_id)
|
||||||
|
->where('project_users.userid', $user->userid)
|
||||||
|
->first();
|
||||||
|
if (empty($project)) {
|
||||||
|
return Base::retError('项目不存在或不在成员列表内');
|
||||||
|
}
|
||||||
|
//
|
||||||
|
$msg = [
|
||||||
|
'text' => $text
|
||||||
|
];
|
||||||
|
//
|
||||||
|
return WebSocketDialogMsg::addGroupMsg($project->dialog_id, 'text', $msg, $user->userid, $task_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
|
use App\Module\Base;
|
||||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -82,4 +83,41 @@ class Project extends AbstractModel
|
|||||||
{
|
{
|
||||||
return $this->hasMany(projectUser::class, 'project_id', 'id')->orderBy('id');
|
return $this->hasMany(projectUser::class, 'project_id', 'id')->orderBy('id');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加入项目
|
||||||
|
* @param int $userid 加入的会员ID
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function joinProject($userid) {
|
||||||
|
$result = AbstractModel::transaction(function () use ($userid) {
|
||||||
|
ProjectUser::updateInsert([
|
||||||
|
'project_id' => $this->id,
|
||||||
|
'userid' => $userid,
|
||||||
|
]);
|
||||||
|
WebSocketDialogUser::updateInsert([
|
||||||
|
'dialog_id' => $this->dialog_id,
|
||||||
|
'userid' => $userid,
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
return Base::isSuccess($result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除项目
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function deleteProject()
|
||||||
|
{
|
||||||
|
$result = AbstractModel::transaction(function () {
|
||||||
|
ProjectTask::whereProjectId($this->id)->delete();
|
||||||
|
WebSocketDialog::whereId($this->dialog_id)->delete();
|
||||||
|
if ($this->delete()) {
|
||||||
|
return Base::retSuccess('success');
|
||||||
|
} else {
|
||||||
|
return Base::retError('error');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return Base::isSuccess($result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,12 +27,14 @@ use Illuminate\Database\Eloquent\SoftDeletes;
|
|||||||
* @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
|
||||||
* @property \Illuminate\Support\Carbon|null $deleted_at
|
* @property \Illuminate\Support\Carbon|null $deleted_at
|
||||||
|
* @property-read int $dialog_id
|
||||||
* @property-read int $file_num
|
* @property-read int $file_num
|
||||||
* @property-read int $msg_num
|
* @property-read int $msg_num
|
||||||
* @property-read bool $overdue
|
* @property-read bool $overdue
|
||||||
* @property-read int $percent
|
* @property-read int $percent
|
||||||
* @property-read int $sub_num
|
* @property-read int $sub_num
|
||||||
* @property-read bool $today
|
* @property-read bool $today
|
||||||
|
* @property-read \App\Models\Project|null $project
|
||||||
* @property-read \Illuminate\Database\Eloquent\Collection|\App\Models\ProjectTaskTag[] $taskTag
|
* @property-read \Illuminate\Database\Eloquent\Collection|\App\Models\ProjectTaskTag[] $taskTag
|
||||||
* @property-read int|null $task_tag_count
|
* @property-read int|null $task_tag_count
|
||||||
* @property-read \Illuminate\Database\Eloquent\Collection|\App\Models\ProjectTaskUser[] $taskUser
|
* @property-read \Illuminate\Database\Eloquent\Collection|\App\Models\ProjectTaskUser[] $taskUser
|
||||||
@ -70,6 +72,7 @@ class ProjectTask extends AbstractModel
|
|||||||
'file_num',
|
'file_num',
|
||||||
'msg_num',
|
'msg_num',
|
||||||
'sub_num',
|
'sub_num',
|
||||||
|
'dialog_id',
|
||||||
'percent',
|
'percent',
|
||||||
'today',
|
'today',
|
||||||
'overdue',
|
'overdue',
|
||||||
@ -94,7 +97,7 @@ class ProjectTask extends AbstractModel
|
|||||||
public function getMsgNumAttribute()
|
public function getMsgNumAttribute()
|
||||||
{
|
{
|
||||||
if (!isset($this->attributes['msg_num'])) {
|
if (!isset($this->attributes['msg_num'])) {
|
||||||
$this->attributes['msg_num'] = ProjectTaskMsg::whereTaskId($this->id)->count();
|
$this->attributes['msg_num'] = WebSocketDialogMsg::whereDialogId($this->dialog_id)->whereExtraInt($this->id)->count();
|
||||||
}
|
}
|
||||||
return $this->attributes['msg_num'];
|
return $this->attributes['msg_num'];
|
||||||
}
|
}
|
||||||
@ -114,6 +117,18 @@ class ProjectTask extends AbstractModel
|
|||||||
return $this->attributes['sub_num'];
|
return $this->attributes['sub_num'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对话ID
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getDialogIdAttribute()
|
||||||
|
{
|
||||||
|
if (!isset($this->attributes['dialog_id'])) {
|
||||||
|
$this->attributes['dialog_id'] = intval(Project::whereId($this->project_id)->value('dialog_id'));
|
||||||
|
}
|
||||||
|
return $this->attributes['dialog_id'];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 进度(0-100)
|
* 进度(0-100)
|
||||||
* @return int
|
* @return int
|
||||||
@ -167,6 +182,14 @@ class ProjectTask extends AbstractModel
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \Illuminate\Database\Eloquent\Relations\HasOne
|
||||||
|
*/
|
||||||
|
public function project(): \Illuminate\Database\Eloquent\Relations\HasOne
|
||||||
|
{
|
||||||
|
return $this->hasOne(Project::class, 'id', 'project_id');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
||||||
*/
|
*/
|
||||||
|
@ -1,31 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Models;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class ProjectTaskMsg
|
|
||||||
*
|
|
||||||
* @package App\Models
|
|
||||||
* @property int $id
|
|
||||||
* @property int|null $project_id 项目ID
|
|
||||||
* @property int|null $task_id 任务ID
|
|
||||||
* @property string|null $msg 详细内容(JSON)
|
|
||||||
* @property int|null $userid 发送用户ID
|
|
||||||
* @property \Illuminate\Support\Carbon|null $created_at
|
|
||||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
|
||||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskMsg newModelQuery()
|
|
||||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskMsg newQuery()
|
|
||||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskMsg query()
|
|
||||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskMsg whereCreatedAt($value)
|
|
||||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskMsg whereId($value)
|
|
||||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskMsg whereMsg($value)
|
|
||||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskMsg whereProjectId($value)
|
|
||||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskMsg whereTaskId($value)
|
|
||||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskMsg whereUpdatedAt($value)
|
|
||||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskMsg whereUserid($value)
|
|
||||||
* @mixin \Eloquent
|
|
||||||
*/
|
|
||||||
class ProjectTaskMsg extends AbstractModel
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
|
use App\Module\Base;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class ProjectUser
|
* Class ProjectUser
|
||||||
*
|
*
|
||||||
@ -12,6 +14,7 @@ namespace App\Models;
|
|||||||
* @property int|null $owner 是否负责人
|
* @property int|null $owner 是否负责人
|
||||||
* @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
|
||||||
|
* @property-read \App\Models\Project|null $project
|
||||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectUser newModelQuery()
|
* @method static \Illuminate\Database\Eloquent\Builder|ProjectUser newModelQuery()
|
||||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectUser newQuery()
|
* @method static \Illuminate\Database\Eloquent\Builder|ProjectUser newQuery()
|
||||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectUser query()
|
* @method static \Illuminate\Database\Eloquent\Builder|ProjectUser query()
|
||||||
@ -26,4 +29,28 @@ namespace App\Models;
|
|||||||
class ProjectUser extends AbstractModel
|
class ProjectUser extends AbstractModel
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \Illuminate\Database\Eloquent\Relations\HasOne
|
||||||
|
*/
|
||||||
|
public function project(): \Illuminate\Database\Eloquent\Relations\HasOne
|
||||||
|
{
|
||||||
|
return $this->hasOne(Project::class, 'id', 'project_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 退出项目
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function exitProject() {
|
||||||
|
$result = AbstractModel::transaction(function () {
|
||||||
|
WebSocketDialogUser::whereDialogId($this->project->dialog_id)->whereUserid($this->userid)->delete();
|
||||||
|
if ($this->delete()) {
|
||||||
|
return Base::retSuccess('success');
|
||||||
|
} else {
|
||||||
|
return Base::retError('error');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return Base::isSuccess($result);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,8 @@ use App\Module\Base;
|
|||||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialog whereType($value)
|
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialog whereType($value)
|
||||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialog whereUpdatedAt($value)
|
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialog whereUpdatedAt($value)
|
||||||
* @mixin \Eloquent
|
* @mixin \Eloquent
|
||||||
|
* @property \Illuminate\Support\Carbon|null $deleted_at
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialog whereDeletedAt($value)
|
||||||
*/
|
*/
|
||||||
class WebSocketDialog extends AbstractModel
|
class WebSocketDialog extends AbstractModel
|
||||||
{
|
{
|
||||||
@ -89,7 +91,7 @@ class WebSocketDialog extends AbstractModel
|
|||||||
* @param int|array $userid 加入的会员ID或会员ID组
|
* @param int|array $userid 加入的会员ID或会员ID组
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public static function quitGroup($dialog_id, $userid)
|
public static function exitGroup($dialog_id, $userid)
|
||||||
{
|
{
|
||||||
if (is_array($userid)) {
|
if (is_array($userid)) {
|
||||||
WebSocketDialogUser::whereDialogId($dialog_id)->whereIn('userid', $userid)->delete();
|
WebSocketDialogUser::whereDialogId($dialog_id)->whereIn('userid', $userid)->delete();
|
||||||
|
@ -13,8 +13,11 @@ use Carbon\Carbon;
|
|||||||
* @property int $id
|
* @property int $id
|
||||||
* @property int|null $dialog_id 对话ID
|
* @property int|null $dialog_id 对话ID
|
||||||
* @property int|null $userid 发送会员ID
|
* @property int|null $userid 发送会员ID
|
||||||
* @property string|null $msg 详细消息
|
* @property string|null $type 消息类型
|
||||||
|
* @property array|mixed $msg 详细消息
|
||||||
* @property int|null $send 是否已送达
|
* @property int|null $send 是否已送达
|
||||||
|
* @property int|null $extra_int 额外数字参数
|
||||||
|
* @property string|null $extra_str 额外字符参数
|
||||||
* @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|WebSocketDialogMsg newModelQuery()
|
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg newModelQuery()
|
||||||
@ -22,27 +25,53 @@ use Carbon\Carbon;
|
|||||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg query()
|
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg query()
|
||||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereCreatedAt($value)
|
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereCreatedAt($value)
|
||||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereDialogId($value)
|
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereDialogId($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereExtraInt($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereExtraStr($value)
|
||||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereId($value)
|
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereId($value)
|
||||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereMsg($value)
|
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereMsg($value)
|
||||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereSend($value)
|
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereSend($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereType($value)
|
||||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereUpdatedAt($value)
|
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereUpdatedAt($value)
|
||||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereUserid($value)
|
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereUserid($value)
|
||||||
* @mixin \Eloquent
|
* @mixin \Eloquent
|
||||||
*/
|
*/
|
||||||
class WebSocketDialogMsg extends AbstractModel
|
class WebSocketDialogMsg extends AbstractModel
|
||||||
{
|
{
|
||||||
|
protected $hidden = [
|
||||||
|
'updated_at',
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消息
|
||||||
|
* @param $value
|
||||||
|
* @return array|mixed
|
||||||
|
*/
|
||||||
|
public function getMsgAttribute($value)
|
||||||
|
{
|
||||||
|
if (is_array($value)) {
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
return Base::json2array($value);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 给会员添加并发送消息
|
* 给会员添加并发送消息
|
||||||
* @param int $dialog_id 会话ID(即 聊天室ID)
|
* @param int $dialog_id 会话ID(即 聊天室ID)
|
||||||
|
* @param string $type 消息类型
|
||||||
* @param array $msg 发送的消息
|
* @param array $msg 发送的消息
|
||||||
* @param int $sender 发送的会员ID(默认自己,0为系统)
|
* @param int $sender 发送的会员ID(默认自己,0为系统)
|
||||||
|
* @param int $extra_int
|
||||||
|
* @param string $extra_str
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public static function addGroupMsg($dialog_id, $msg, $sender = 0)
|
public static function addGroupMsg($dialog_id, $type, $msg, $sender = 0, $extra_int = 0, $extra_str = '')
|
||||||
{
|
{
|
||||||
$dialogMsg = self::createInstance([
|
$dialogMsg = self::createInstance([
|
||||||
'userid' => $sender ?: User::token2userid(),
|
'userid' => $sender ?: User::token2userid(),
|
||||||
|
'type' => $type,
|
||||||
'msg' => $msg,
|
'msg' => $msg,
|
||||||
|
'extra_int' => $extra_int,
|
||||||
|
'extra_str' => $extra_str,
|
||||||
]);
|
]);
|
||||||
return AbstractModel::transaction(function () use ($dialog_id, $msg, $dialogMsg) {
|
return AbstractModel::transaction(function () use ($dialog_id, $msg, $dialogMsg) {
|
||||||
$dialog = WebSocketDialog::checkGroupDialog($dialogMsg->userid, $dialog_id);
|
$dialog = WebSocketDialog::checkGroupDialog($dialogMsg->userid, $dialog_id);
|
||||||
@ -60,11 +89,11 @@ class WebSocketDialogMsg extends AbstractModel
|
|||||||
'userid' => $userids,
|
'userid' => $userids,
|
||||||
'msg' => [
|
'msg' => [
|
||||||
'type' => 'dialog',
|
'type' => 'dialog',
|
||||||
'data' => $msg,
|
'data' => $dialogMsg->toArray(),
|
||||||
]
|
]
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
return Base::retSuccess('发送成功');
|
return Base::retSuccess('发送成功', $dialogMsg);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,15 +101,21 @@ class WebSocketDialogMsg extends AbstractModel
|
|||||||
/**
|
/**
|
||||||
* 给会员添加并发送消息
|
* 给会员添加并发送消息
|
||||||
* @param int $userid 接收的会员ID
|
* @param int $userid 接收的会员ID
|
||||||
|
* @param string $type 消息类型
|
||||||
* @param array $msg 发送的消息
|
* @param array $msg 发送的消息
|
||||||
* @param int $sender 发送的会员ID(默认自己,0为系统)
|
* @param int $sender 发送的会员ID(默认自己,0为系统)
|
||||||
|
* @param int $extra_int
|
||||||
|
* @param string $extra_str
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public static function addUserMsg($userid, $msg, $sender = 0)
|
public static function addUserMsg($userid, $type, $msg, $sender = 0, $extra_int = 0, $extra_str = '')
|
||||||
{
|
{
|
||||||
$dialogMsg = self::createInstance([
|
$dialogMsg = self::createInstance([
|
||||||
'userid' => $sender ?: User::token2userid(),
|
'userid' => $sender ?: User::token2userid(),
|
||||||
|
'type' => $type,
|
||||||
'msg' => $msg,
|
'msg' => $msg,
|
||||||
|
'extra_int' => $extra_int,
|
||||||
|
'extra_str' => $extra_str,
|
||||||
]);
|
]);
|
||||||
return AbstractModel::transaction(function () use ($userid, $msg, $dialogMsg) {
|
return AbstractModel::transaction(function () use ($userid, $msg, $dialogMsg) {
|
||||||
$dialog = WebSocketDialog::checkUserDialog($dialogMsg->userid, $userid);
|
$dialog = WebSocketDialog::checkUserDialog($dialogMsg->userid, $userid);
|
||||||
@ -96,10 +131,10 @@ class WebSocketDialogMsg extends AbstractModel
|
|||||||
'userid' => $userid,
|
'userid' => $userid,
|
||||||
'msg' => [
|
'msg' => [
|
||||||
'type' => 'dialog',
|
'type' => 'dialog',
|
||||||
'data' => $msg,
|
'data' => $dialogMsg->toArray(),
|
||||||
]
|
]
|
||||||
]);
|
]);
|
||||||
return Base::retSuccess('发送成功');
|
return Base::retSuccess('发送成功', $dialogMsg);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"echarts": "^5.1.1",
|
"echarts": "^5.1.1",
|
||||||
"tinymce": "^5.8.1",
|
"tinymce": "^5.8.1",
|
||||||
"view-design-hi": "^4.5.0-10",
|
"view-design-hi": "^4.5.0-11",
|
||||||
"vue-clipboard2": "^0.3.1",
|
"vue-clipboard2": "^0.3.1",
|
||||||
"vue-emoji-picker": "^1.0.1",
|
"vue-emoji-picker": "^1.0.1",
|
||||||
"vue-kityminder-gg": "^1.3.6",
|
"vue-kityminder-gg": "^1.3.6",
|
||||||
|
@ -91,6 +91,18 @@ export default {
|
|||||||
},
|
},
|
||||||
scrollToBottom(animate) {
|
scrollToBottom(animate) {
|
||||||
this.scrollTo(this.$refs.scrollerView.scrollHeight, animate);
|
this.scrollTo(this.$refs.scrollerView.scrollHeight, animate);
|
||||||
|
},
|
||||||
|
getScrollInfo() {
|
||||||
|
let scrollerView = $A(this.$refs.scrollerView);
|
||||||
|
let wInnerH = Math.round(scrollerView.innerHeight());
|
||||||
|
let wScrollY = scrollerView.scrollTop();
|
||||||
|
let bScrollH = this.$refs.scrollerView.scrollHeight;
|
||||||
|
this.scrollY = wScrollY;
|
||||||
|
return {
|
||||||
|
scale: wScrollY / (bScrollH - wInnerH), //已滚动比例
|
||||||
|
scrollY: wScrollY, //滚动的距离
|
||||||
|
scrollE: bScrollH - wInnerH - wScrollY, //与底部距离
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,9 +10,11 @@
|
|||||||
:default-label="value"
|
:default-label="value"
|
||||||
:default-event-object="true"
|
:default-event-object="true"
|
||||||
:multipleMax="multipleMax"
|
:multipleMax="multipleMax"
|
||||||
|
:multipleUncancelable="uncancelable"
|
||||||
multiple
|
multiple
|
||||||
filterable
|
filterable
|
||||||
transfer-class-name="common-user-transfer"
|
transfer-class-name="common-user-transfer"
|
||||||
|
@on-open-change="openChange"
|
||||||
@on-set-default-options="setDefaultOptions">
|
@on-set-default-options="setDefaultOptions">
|
||||||
<div v-if="multipleMax" slot="drop-prepend" class="user-drop-prepend">{{$L('最多只能选择' + multipleMax + '个')}}</div>
|
<div v-if="multipleMax" slot="drop-prepend" class="user-drop-prepend">{{$L('最多只能选择' + multipleMax + '个')}}</div>
|
||||||
<Option v-for="(item, key) in lists" :value="item.userid" :key="key" :label="item.nickname" :avatar="item.userimg">
|
<Option v-for="(item, key) in lists" :value="item.userid" :key="key" :label="item.nickname" :avatar="item.userimg">
|
||||||
@ -35,6 +37,12 @@
|
|||||||
type: [String, Number, Array],
|
type: [String, Number, Array],
|
||||||
default: ''
|
default: ''
|
||||||
},
|
},
|
||||||
|
uncancelable: {
|
||||||
|
type: Array,
|
||||||
|
default: () => {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
},
|
||||||
placeholder: {
|
placeholder: {
|
||||||
default: ''
|
default: ''
|
||||||
},
|
},
|
||||||
@ -55,6 +63,7 @@
|
|||||||
ready: false,
|
ready: false,
|
||||||
initialized: false,
|
initialized: false,
|
||||||
loading: false,
|
loading: false,
|
||||||
|
openLoad: false,
|
||||||
values: [],
|
values: [],
|
||||||
lists: []
|
lists: []
|
||||||
}
|
}
|
||||||
@ -89,6 +98,15 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
openChange(show) {
|
||||||
|
if (show && !this.openLoad) {
|
||||||
|
this.openLoad = true;
|
||||||
|
if (this.lists.length == this.values.length) {
|
||||||
|
this.$nextTick(this.searchUser);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
setDefaultOptions(options) {
|
setDefaultOptions(options) {
|
||||||
const userids = [];
|
const userids = [];
|
||||||
options.forEach(({value, label}) => {
|
options.forEach(({value, label}) => {
|
||||||
@ -126,7 +144,7 @@
|
|||||||
url: 'users/search',
|
url: 'users/search',
|
||||||
data: {
|
data: {
|
||||||
keys: {
|
keys: {
|
||||||
key: query
|
key: query || ''
|
||||||
},
|
},
|
||||||
take: 30
|
take: 30
|
||||||
},
|
},
|
||||||
|
49
resources/assets/js/pages/manage/components/message-view.vue
Normal file
49
resources/assets/js/pages/manage/components/message-view.vue
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
<template>
|
||||||
|
<div class="message-view">
|
||||||
|
|
||||||
|
<div v-if="msgData.type == 'text'" class="message-content" v-html="textMsg(msgData.msg.text)"></div>
|
||||||
|
<div v-else class="message-content message-unknown">{{$L("未知的消息类型")}}</div>
|
||||||
|
|
||||||
|
<div v-if="msgData.created_at" class="message-time">{{formatTime(msgData.created_at)}}</div>
|
||||||
|
<div v-else class="message-time"><Loading/></div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "MessageView",
|
||||||
|
props: {
|
||||||
|
msgData: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
formatTime(date) {
|
||||||
|
let time = Math.round(new Date(date).getTime() / 1000),
|
||||||
|
string = '';
|
||||||
|
if ($A.formatDate('Ymd') === $A.formatDate('Ymd', time)) {
|
||||||
|
string = $A.formatDate('H:i', time)
|
||||||
|
} else if ($A.formatDate('Y') === $A.formatDate('Y', time)) {
|
||||||
|
string = $A.formatDate('m-d', time)
|
||||||
|
} else {
|
||||||
|
string = $A.formatDate('Y-m-d', time)
|
||||||
|
}
|
||||||
|
return string || '';
|
||||||
|
},
|
||||||
|
|
||||||
|
textMsg(text) {
|
||||||
|
if (!text) {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
text = text.trim().replace(/(\n\x20*){3,}/g, "<br/><br/>");
|
||||||
|
text = text.trim().replace(/\n/g, "<br/>");
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
@ -31,10 +31,14 @@
|
|||||||
<li class="project-icon">
|
<li class="project-icon">
|
||||||
<Dropdown @on-click="projectDropdown" transfer>
|
<Dropdown @on-click="projectDropdown" transfer>
|
||||||
<Icon type="ios-more" />
|
<Icon type="ios-more" />
|
||||||
<DropdownMenu slot="list">
|
<DropdownMenu v-if="projectDetail.owner_userid === userId" slot="list">
|
||||||
<DropdownItem name="setting">{{$L('项目设置')}}</DropdownItem>
|
<DropdownItem name="setting">{{$L('项目设置')}}</DropdownItem>
|
||||||
<DropdownItem name="transfer">{{$L('移交项目')}}</DropdownItem>
|
<DropdownItem name="user">{{$L('成员管理')}}</DropdownItem>
|
||||||
<DropdownItem name="delete" style="color:#f40" divided>{{$L('删除项目')}}</DropdownItem>
|
<DropdownItem name="transfer" divided>{{$L('移交项目')}}</DropdownItem>
|
||||||
|
<DropdownItem name="delete" style="color:#f40">{{$L('删除项目')}}</DropdownItem>
|
||||||
|
</DropdownMenu>
|
||||||
|
<DropdownMenu v-else slot="list">
|
||||||
|
<DropdownItem name="exit">{{$L('退出项目')}}</DropdownItem>
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
|
|
||||||
@ -293,6 +297,23 @@
|
|||||||
</div>
|
</div>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|
||||||
|
<!--成员管理-->
|
||||||
|
<Modal
|
||||||
|
v-model="userShow"
|
||||||
|
:title="$L('成员管理')"
|
||||||
|
:mask-closable="false"
|
||||||
|
class-name="simple-modal">
|
||||||
|
<Form ref="addProject" :model="userData" label-width="auto" @submit.native.prevent>
|
||||||
|
<FormItem prop="userids" :label="$L('项目成员')">
|
||||||
|
<UserInput v-if="userShow" v-model="userData.userids" :uncancelable="userData.uncancelable" :multiple-max="100" :placeholder="$L('选择项目成员')"/>
|
||||||
|
</FormItem>
|
||||||
|
</Form>
|
||||||
|
<div slot="footer">
|
||||||
|
<Button type="default" @click="userShow=false">{{$L('取消')}}</Button>
|
||||||
|
<Button type="primary" :loading="userLoad > 0" @click="onUser">{{$L('保存')}}</Button>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
|
||||||
<!--移交项目-->
|
<!--移交项目-->
|
||||||
<Modal
|
<Modal
|
||||||
v-model="transferShow"
|
v-model="transferShow"
|
||||||
@ -833,6 +854,10 @@ export default {
|
|||||||
settingData: {},
|
settingData: {},
|
||||||
settingLoad: 0,
|
settingLoad: 0,
|
||||||
|
|
||||||
|
userShow: false,
|
||||||
|
userData: {},
|
||||||
|
userLoad: 0,
|
||||||
|
|
||||||
transferShow: false,
|
transferShow: false,
|
||||||
transferData: {},
|
transferData: {},
|
||||||
transferLoad: 0,
|
transferLoad: 0,
|
||||||
@ -978,6 +1003,29 @@ export default {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onUser() {
|
||||||
|
this.userLoad++;
|
||||||
|
$A.apiAjax({
|
||||||
|
url: 'project/user',
|
||||||
|
data: {
|
||||||
|
project_id: this.userData.project_id,
|
||||||
|
userid: this.userData.userids,
|
||||||
|
},
|
||||||
|
complete: () => {
|
||||||
|
this.userLoad--;
|
||||||
|
},
|
||||||
|
success: ({ret, data, msg}) => {
|
||||||
|
if (ret === 1) {
|
||||||
|
$A.messageSuccess(msg);
|
||||||
|
this.$store.commit('getProjectDetail', this.userData.project_id);
|
||||||
|
this.userShow = false;
|
||||||
|
} else {
|
||||||
|
$A.modalError(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
onTransfer() {
|
onTransfer() {
|
||||||
this.transferLoad++;
|
this.transferLoad++;
|
||||||
$A.apiAjax({
|
$A.apiAjax({
|
||||||
@ -1004,7 +1052,7 @@ export default {
|
|||||||
onDelete() {
|
onDelete() {
|
||||||
$A.modalConfirm({
|
$A.modalConfirm({
|
||||||
title: '删除项目',
|
title: '删除项目',
|
||||||
content: '你确定要删除此项目吗?',
|
content: '你确定要删除项目【' + this.projectDetail.name + '】吗?',
|
||||||
loading: true,
|
loading: true,
|
||||||
onOk: () => {
|
onOk: () => {
|
||||||
$A.apiAjax({
|
$A.apiAjax({
|
||||||
@ -1031,6 +1079,36 @@ export default {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onExit() {
|
||||||
|
$A.modalConfirm({
|
||||||
|
title: '退出项目',
|
||||||
|
content: '你确定要退出项目【' + this.projectDetail.name + '】吗?',
|
||||||
|
loading: true,
|
||||||
|
onOk: () => {
|
||||||
|
$A.apiAjax({
|
||||||
|
url: 'project/exit',
|
||||||
|
data: {
|
||||||
|
project_id: this.projectDetail.id,
|
||||||
|
},
|
||||||
|
error: () => {
|
||||||
|
this.$Modal.remove();
|
||||||
|
$A.modalAlert('网络繁忙,请稍后再试!');
|
||||||
|
},
|
||||||
|
success: ({ret, data, msg}) => {
|
||||||
|
this.$Modal.remove();
|
||||||
|
if (ret === 1) {
|
||||||
|
$A.messageSuccess(msg);
|
||||||
|
this.$store.commit('getProjectList');
|
||||||
|
this.goForward({path: '/manage/dashboard'}, true);
|
||||||
|
}else{
|
||||||
|
$A.modalError(msg, 301);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
projectDropdown(name) {
|
projectDropdown(name) {
|
||||||
switch (name) {
|
switch (name) {
|
||||||
case "setting":
|
case "setting":
|
||||||
@ -1040,6 +1118,13 @@ export default {
|
|||||||
this.settingShow = true;
|
this.settingShow = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case "user":
|
||||||
|
this.$set(this.userData, 'project_id', this.projectDetail.id);
|
||||||
|
this.$set(this.userData, 'userids', this.projectDetail.project_user.map(({userid}) => userid));
|
||||||
|
this.$set(this.userData, 'uncancelable', [this.projectDetail.owner_userid]);
|
||||||
|
this.userShow = true;
|
||||||
|
break;
|
||||||
|
|
||||||
case "transfer":
|
case "transfer":
|
||||||
this.$set(this.transferData, 'project_id', this.projectDetail.id);
|
this.$set(this.transferData, 'project_id', this.projectDetail.id);
|
||||||
this.$set(this.transferData, 'owner_userid', [this.projectDetail.owner_userid]);
|
this.$set(this.transferData, 'owner_userid', [this.projectDetail.owner_userid]);
|
||||||
@ -1049,6 +1134,10 @@ export default {
|
|||||||
case "delete":
|
case "delete":
|
||||||
this.onDelete();
|
this.onDelete();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case "exit":
|
||||||
|
this.onExit();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -2,85 +2,32 @@
|
|||||||
<div v-if="$store.state.projectChatShow" class="project-message">
|
<div v-if="$store.state.projectChatShow" class="project-message">
|
||||||
<div class="group-member">
|
<div class="group-member">
|
||||||
<div class="member-head">
|
<div class="member-head">
|
||||||
<div class="member-title">Member<span>(25)</span></div>
|
<div class="member-title">{{$L('项目成员')}}<span>({{projectDetail.project_user.length}})</span></div>
|
||||||
<div class="member-view-all">View All</div>
|
<div class="member-view-all" @click="memberShowAll=!memberShowAll">{{$L('查看所有')}}</div>
|
||||||
</div>
|
</div>
|
||||||
<ul class="member-list">
|
<ul :class="['member-list', memberShowAll ? 'member-all' : '']">
|
||||||
<li class="online"><Avatar src="https://i.loli.net/2017/08/21/599a521472424.jpg" /></li>
|
<li v-for="item in projectDetail.project_user">
|
||||||
<li class="online"><Avatar src="https://i.loli.net/2017/08/21/599a521472424.jpg" /></li>
|
<UserAvatar :userid="item.userid" :size="36"/>
|
||||||
<li class="online"><Avatar src="https://i.loli.net/2017/08/21/599a521472424.jpg" /></li>
|
</li>
|
||||||
<li class="online"><Avatar src="https://i.loli.net/2017/08/21/599a521472424.jpg" /></li>
|
|
||||||
<li><Avatar src="https://i.loli.net/2017/08/21/599a521472424.jpg" /></li>
|
|
||||||
<li><Avatar src="https://i.loli.net/2017/08/21/599a521472424.jpg" /></li>
|
|
||||||
<li><Avatar src="https://i.loli.net/2017/08/21/599a521472424.jpg" /></li>
|
|
||||||
<li><Avatar src="https://i.loli.net/2017/08/21/599a521472424.jpg" /></li>
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="group-title">Group Chat</div>
|
<div class="group-title">Group Chat</div>
|
||||||
<ScrollerY ref="groupChat" class="group-chat" @on-scroll="groupChatScroll">
|
<ScrollerY ref="groupChat" class="group-chat message-scroller" @on-scroll="groupChatScroll">
|
||||||
<div ref="manageList" class="message-list">
|
<div ref="manageList" class="message-list">
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li v-if="dialogLoad > 0" class="loading"><Loading/></li>
|
||||||
<div class="message-avatar online"><Avatar src="https://i.loli.net/2017/08/21/599a521472424.jpg" /></div>
|
<li v-else-if="dialogList.length === 0" class="nothing">{{$L('暂无消息')}}</li>
|
||||||
<div class="message-item">
|
<li v-for="(item, key) in dialogList" :key="key" :class="{self:item.userid == userId}">
|
||||||
<div class="message-text">Selamat pagi, Mas!</div>
|
<div class="message-avatar">
|
||||||
<div class="message-time">08:00 AM</div>
|
<UserAvatar :userid="item.userid" :size="30"/>
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li class="self">
|
|
||||||
<div class="message-avatar"><Avatar src="https://i.loli.net/2017/08/21/599a521472424.jpg" /></div>
|
|
||||||
<div class="message-item">
|
|
||||||
<div class="message-text">Selamat pagi, Mas!</div>
|
|
||||||
<div class="message-time">08:00 AM</div>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<div class="message-avatar offline"><Avatar src="https://i.loli.net/2017/08/21/599a521472424.jpg" /></div>
|
|
||||||
<div class="message-item">
|
|
||||||
<div class="message-text">Pagi Mas Piko, Langsung saja Ada apa Gerangan mas?</div>
|
|
||||||
<div class="message-time">08:00 AM</div>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li class="self">
|
|
||||||
<div class="message-avatar"><Avatar src="https://i.loli.net/2017/08/21/599a521472424.jpg" /></div>
|
|
||||||
<div class="message-item">
|
|
||||||
<div class="message-text">Pagi Mas Piko, Langsung saja Ada apa Gerangan mas?</div>
|
|
||||||
<div class="message-time">08:00 AM</div>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<div class="message-avatar online"><Avatar src="https://i.loli.net/2017/08/21/599a521472424.jpg" /></div>
|
|
||||||
<div class="message-item">
|
|
||||||
<div class="message-text">Selamat pagi, Mas!</div>
|
|
||||||
<div class="message-time">08:00 AM</div>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li class="self">
|
|
||||||
<div class="message-avatar"><Avatar src="https://i.loli.net/2017/08/21/599a521472424.jpg" /></div>
|
|
||||||
<div class="message-item">
|
|
||||||
<div class="message-text">Selamat pagi, Mas!</div>
|
|
||||||
<div class="message-time">08:00 AM</div>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<div class="message-avatar offline"><Avatar src="https://i.loli.net/2017/08/21/599a521472424.jpg" /></div>
|
|
||||||
<div class="message-item">
|
|
||||||
<div class="message-text">Pagi Mas Piko, Langsung saja Ada apa Gerangan mas?</div>
|
|
||||||
<div class="message-time">08:00 AM</div>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li class="self">
|
|
||||||
<div class="message-avatar"><Avatar src="https://i.loli.net/2017/08/21/599a521472424.jpg" /></div>
|
|
||||||
<div class="message-item">
|
|
||||||
<div class="message-text">Pagi Mas Piko, Langsung saja Ada apa Gerangan mas?</div>
|
|
||||||
<div class="message-time">08:00 AM</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
<MessageView :msg-data="item"/>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</ScrollerY>
|
</ScrollerY>
|
||||||
<div class="group-footer">
|
<div class="group-footer">
|
||||||
<DragInput class="group-input" v-model="groupText" type="textarea" :rows="1" :autosize="{ minRows: 1, maxRows: 3 }" :maxlength="255" @on-keydown="groupKeydown" @on-input-paste="groupPasteDrag" :placeholder="$L('输入消息...')" />
|
<DragInput class="group-input" v-model="msgText" type="textarea" :rows="1" :autosize="{ minRows: 1, maxRows: 3 }" :maxlength="255" @on-keydown="groupKeydown" @on-input-paste="groupPasteDrag" :placeholder="$L('输入消息...')" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -130,6 +77,11 @@
|
|||||||
}
|
}
|
||||||
.member-view-all {
|
.member-view-all {
|
||||||
color: #999;
|
color: #999;
|
||||||
|
font-size: 13px;
|
||||||
|
cursor: pointer;
|
||||||
|
&:hover {
|
||||||
|
color: #777;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.member-list {
|
.member-list {
|
||||||
@ -141,33 +93,19 @@
|
|||||||
position: relative;
|
position: relative;
|
||||||
list-style: none;
|
list-style: none;
|
||||||
margin-right: 14px;
|
margin-right: 14px;
|
||||||
.ivu-avatar {
|
margin-bottom: 8px;
|
||||||
width: 36px;
|
}
|
||||||
height: 36px;
|
&.member-all {
|
||||||
}
|
display: block;
|
||||||
&:before {
|
> li {
|
||||||
content: "";
|
display: inline-block;
|
||||||
position: absolute;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
width: 9px;
|
|
||||||
height: 9px;
|
|
||||||
border-radius: 50%;
|
|
||||||
background-color: #ff0000;
|
|
||||||
border: 1px solid #ffffff;
|
|
||||||
z-index: 1;
|
|
||||||
}
|
|
||||||
&.online {
|
|
||||||
&:before {
|
|
||||||
background-color: #87d068;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.group-title {
|
.group-title {
|
||||||
padding: 0 32px;
|
padding: 0 32px;
|
||||||
margin-top: 28px;
|
margin-top: 20px;
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
@ -175,78 +113,6 @@
|
|||||||
flex: 1;
|
flex: 1;
|
||||||
padding: 0 32px;
|
padding: 0 32px;
|
||||||
margin-top: 18px;
|
margin-top: 18px;
|
||||||
overflow: auto;
|
|
||||||
.message-list {
|
|
||||||
> ul {
|
|
||||||
> li {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
align-items: flex-end;
|
|
||||||
list-style: none;
|
|
||||||
margin-bottom: 16px;
|
|
||||||
.message-avatar {
|
|
||||||
position: relative;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
.ivu-avatar {
|
|
||||||
width: 28px;
|
|
||||||
height: 28px;
|
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
|
||||||
&.online,
|
|
||||||
&.offline {
|
|
||||||
&:before {
|
|
||||||
content: "";
|
|
||||||
position: absolute;
|
|
||||||
transform: scale(0.8);
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
width: 9px;
|
|
||||||
height: 9px;
|
|
||||||
border-radius: 50%;
|
|
||||||
background-color: #ff0000;
|
|
||||||
border: 1px solid #ffffff;
|
|
||||||
z-index: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&.online {
|
|
||||||
&:before {
|
|
||||||
background-color: #87d068;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.message-item {
|
|
||||||
max-width: 70%;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: flex-start;
|
|
||||||
margin: 0 0 0 8px;
|
|
||||||
.message-text {
|
|
||||||
color: #333333;
|
|
||||||
background-color: #F4F5F7;
|
|
||||||
padding: 8px;
|
|
||||||
border-radius: 6px 6px 6px 0;
|
|
||||||
}
|
|
||||||
.message-time {
|
|
||||||
color: #bbbbbb;
|
|
||||||
font-size: 12px;
|
|
||||||
padding-top: 3px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&.self {
|
|
||||||
flex-direction: row-reverse;
|
|
||||||
.message-item {
|
|
||||||
align-items: flex-end;
|
|
||||||
margin: 0 8px 0 0;
|
|
||||||
.message-text {
|
|
||||||
color: #ffffff;
|
|
||||||
background-color: #2d8cf0;
|
|
||||||
border-radius: 6px 6px 0 6px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.group-footer {
|
.group-footer {
|
||||||
padding: 0 28px;
|
padding: 0 28px;
|
||||||
@ -259,27 +125,98 @@
|
|||||||
<script>
|
<script>
|
||||||
import DragInput from "../../../components/DragInput";
|
import DragInput from "../../../components/DragInput";
|
||||||
import ScrollerY from "../../../components/ScrollerY";
|
import ScrollerY from "../../../components/ScrollerY";
|
||||||
|
import {mapState} from "vuex";
|
||||||
|
import MessageView from "./message-view";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "ProjectMessage",
|
name: "ProjectMessage",
|
||||||
components: {ScrollerY, DragInput},
|
components: {MessageView, ScrollerY, DragInput},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
groupText: '',
|
autoBottom: true,
|
||||||
autoBottom: true
|
memberShowAll: false,
|
||||||
|
|
||||||
|
dialogId: 0,
|
||||||
|
|
||||||
|
msgText: '',
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
this.groupChatGoAuto();
|
this.groupChatGoAuto();
|
||||||
this.groupChatGoBottom();
|
this.groupChatGoBottom();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
...mapState(['userId', 'projectDetail', 'projectMsgUnread', 'dialogLoad', 'dialogList']),
|
||||||
|
},
|
||||||
|
|
||||||
|
watch: {
|
||||||
|
projectDetail(detail) {
|
||||||
|
this.dialogId = detail.dialog_id;
|
||||||
|
},
|
||||||
|
|
||||||
|
dialogId(id) {
|
||||||
|
this.$store.commit('getDialogMsg', id);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
groupKeydown() {
|
sendMsg() {
|
||||||
|
let mid = $A.randomString(16);
|
||||||
|
this.dialogList.push({
|
||||||
|
id: mid,
|
||||||
|
userid: this.userId,
|
||||||
|
type: 'text',
|
||||||
|
msg: {
|
||||||
|
text: this.msgText,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
this.groupChatGoBottom(true);
|
||||||
|
//
|
||||||
|
$A.apiAjax({
|
||||||
|
url: 'dialog/msg/sendtext',
|
||||||
|
data: {
|
||||||
|
dialog_id: this.projectDetail.dialog_id,
|
||||||
|
text: this.msgText,
|
||||||
|
},
|
||||||
|
error:() => {
|
||||||
|
this.dialogList = this.dialogList.filter(({id}) => id != mid);
|
||||||
|
},
|
||||||
|
success: ({ret, data, msg}) => {
|
||||||
|
if (ret === 1) {
|
||||||
|
let index = this.dialogList.findIndex(({id}) => id == mid);
|
||||||
|
if (index > -1) this.dialogList.splice(index, 1, data);
|
||||||
|
} else {
|
||||||
|
this.dialogList = this.dialogList.filter(({id}) => id != mid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
//
|
||||||
|
this.msgText = '';
|
||||||
},
|
},
|
||||||
groupPasteDrag() {
|
|
||||||
|
|
||||||
|
groupKeydown(e) {
|
||||||
|
if (e.keyCode === 13) {
|
||||||
|
if (e.shiftKey) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
e.preventDefault();
|
||||||
|
this.sendMsg();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
groupPasteDrag(e, type) {
|
||||||
|
const files = type === 'drag' ? e.dataTransfer.files : e.clipboardData.files;
|
||||||
|
const postFiles = Array.prototype.slice.call(files);
|
||||||
|
if (postFiles.length > 0) {
|
||||||
|
e.preventDefault();
|
||||||
|
postFiles.forEach((file) => {
|
||||||
|
// 上传文件
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
groupChatScroll(res) {
|
groupChatScroll(res) {
|
||||||
if (res.directionreal === 'up') {
|
if (res.directionreal === 'up') {
|
||||||
if (res.scrollE < 10) {
|
if (res.scrollE < 10) {
|
||||||
@ -289,23 +226,40 @@ export default {
|
|||||||
this.autoBottom = false;
|
this.autoBottom = false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
groupChatGoAuto() {
|
groupChatGoAuto() {
|
||||||
clearTimeout(this.groupChatGoTimeout);
|
clearTimeout(this.groupChatGoTimeout);
|
||||||
this.groupChatGoTimeout = setTimeout(() => {
|
this.groupChatGoTimeout = setTimeout(() => {
|
||||||
if (this.autoBottom) {
|
if (this.autoBottom) {
|
||||||
this.groupChatGoBottom();
|
this.groupChatGoBottom(true);
|
||||||
}
|
}
|
||||||
this.groupChatGoAuto();
|
this.groupChatGoAuto();
|
||||||
}, 1000);
|
}, 1000);
|
||||||
},
|
},
|
||||||
|
|
||||||
groupChatGoBottom(animation = false) {
|
groupChatGoBottom(animation = false) {
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
if (typeof this.$refs.groupChat !== "undefined") {
|
if (typeof this.$refs.groupChat !== "undefined") {
|
||||||
this.$refs.groupChat.scrollTo(this.$refs.manageList.clientHeight, animation);
|
if (this.$refs.groupChat.getScrollInfo().scrollE > 0) {
|
||||||
|
this.$refs.groupChat.scrollTo(this.$refs.manageList.clientHeight, animation);
|
||||||
|
}
|
||||||
this.autoBottom = true;
|
this.autoBottom = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
formatTime(date) {
|
||||||
|
let time = Math.round(new Date(date).getTime() / 1000),
|
||||||
|
string = '';
|
||||||
|
if ($A.formatDate('Ymd') === $A.formatDate('Ymd', time)) {
|
||||||
|
string = $A.formatDate('H:i', time)
|
||||||
|
} else if ($A.formatDate('Y') === $A.formatDate('Y', time)) {
|
||||||
|
string = $A.formatDate('m-d', time)
|
||||||
|
} else {
|
||||||
|
string = $A.formatDate('Y-m-d', time)
|
||||||
|
}
|
||||||
|
return string || '';
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
66
resources/assets/js/store/mutations.js
vendored
66
resources/assets/js/store/mutations.js
vendored
@ -260,7 +260,22 @@ export default {
|
|||||||
console.log("[WS] Callerr", err);
|
console.log("[WS] Callerr", err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
if (type === "dialog") {
|
||||||
|
const msgData = msgDetail.data;
|
||||||
|
const dialog_id = msgData.dialog_id;
|
||||||
|
if (dialog_id == state.dialogId) {
|
||||||
|
let index = state.dialogList.findIndex(({id}) => id === msgData.id);
|
||||||
|
if (index === -1) {
|
||||||
|
if (state.dialogList.length >= 200) {
|
||||||
|
state.dialogList.splice(0, 1);
|
||||||
|
}
|
||||||
|
state.dialogList.push(msgData);
|
||||||
|
} else {
|
||||||
|
state.dialogList.splice(index, 1, msgData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -315,5 +330,54 @@ export default {
|
|||||||
*/
|
*/
|
||||||
wsClose(state) {
|
wsClose(state) {
|
||||||
state.ws && state.ws.close();
|
state.ws && state.ws.close();
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取对话消息
|
||||||
|
* @param state
|
||||||
|
* @param dialog_id
|
||||||
|
*/
|
||||||
|
getDialogMsg(state, dialog_id) {
|
||||||
|
if (state.method.runNum(dialog_id) === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (state.method.isArray(state.cacheDialog[dialog_id])) {
|
||||||
|
state.dialogList = state.cacheDialog[dialog_id]
|
||||||
|
} else {
|
||||||
|
state.dialogList = [];
|
||||||
|
}
|
||||||
|
state.dialogId = dialog_id;
|
||||||
|
//
|
||||||
|
if (state.cacheDialog[dialog_id + "::load"]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
state.cacheDialog[dialog_id + "::load"] = true;
|
||||||
|
//
|
||||||
|
state.dialogLoad++;
|
||||||
|
$A.apiAjax({
|
||||||
|
url: 'dialog/msg/lists',
|
||||||
|
data: {
|
||||||
|
dialog_id: dialog_id,
|
||||||
|
},
|
||||||
|
complete: () => {
|
||||||
|
state.dialogLoad--;
|
||||||
|
state.cacheDialog[dialog_id + "::load"] = false;
|
||||||
|
},
|
||||||
|
success: ({ret, data, msg}) => {
|
||||||
|
if (ret === 1) {
|
||||||
|
state.cacheDialog[dialog_id] = data.data.reverse();
|
||||||
|
if (state.dialogId === dialog_id) {
|
||||||
|
state.cacheDialog[dialog_id].forEach((item) => {
|
||||||
|
let index = state.dialogList.findIndex(({id}) => id === item.id);
|
||||||
|
if (index === -1) {
|
||||||
|
state.dialogList.push(item);
|
||||||
|
} else {
|
||||||
|
state.dialogList.splice(index, 1, item);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
35
resources/assets/js/store/state.js
vendored
35
resources/assets/js/store/state.js
vendored
@ -172,18 +172,27 @@ state.wsCall = {};
|
|||||||
state.wsTimeout = null;
|
state.wsTimeout = null;
|
||||||
state.wsListener = {};
|
state.wsListener = {};
|
||||||
|
|
||||||
export default Object.assign(state, {
|
// 项目信息
|
||||||
cacheProject: {},
|
state.projectLoad = 0;
|
||||||
cacheUserBasic: {},
|
state.projectList = [];
|
||||||
|
state.projectDetail = {
|
||||||
|
id: 0,
|
||||||
|
project_column: [],
|
||||||
|
project_user: []
|
||||||
|
};
|
||||||
|
state.projectMsgUnread = 0;
|
||||||
|
|
||||||
projectLoad: 0,
|
// 会话消息
|
||||||
projectList: [],
|
state.dialogId = 0;
|
||||||
projectDetail: {
|
state.dialogLoad = 0;
|
||||||
id: 0,
|
state.dialogList = [];
|
||||||
project_column: [],
|
|
||||||
project_user: []
|
|
||||||
},
|
|
||||||
projectMsgUnread: 0,
|
|
||||||
|
|
||||||
taskPriority: [],
|
// 任务优先级
|
||||||
})
|
state.taskPriority = [];
|
||||||
|
|
||||||
|
// 其他
|
||||||
|
state.cacheProject = {};
|
||||||
|
state.cacheUserBasic = {};
|
||||||
|
state.cacheDialog = {};
|
||||||
|
|
||||||
|
export default state
|
||||||
|
76
resources/assets/sass/main.scss
vendored
76
resources/assets/sass/main.scss
vendored
@ -666,3 +666,79 @@ body {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.message-scroller {
|
||||||
|
position: relative;
|
||||||
|
overflow: auto;
|
||||||
|
.message-list {
|
||||||
|
> ul {
|
||||||
|
> li {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: flex-end;
|
||||||
|
list-style: none;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
.message-avatar {
|
||||||
|
position: relative;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
.message-view {
|
||||||
|
max-width: 70%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
margin: 0 0 0 8px;
|
||||||
|
.message-content {
|
||||||
|
color: #333333;
|
||||||
|
background-color: #F4F5F7;
|
||||||
|
padding: 8px;
|
||||||
|
border-radius: 6px 6px 6px 0;
|
||||||
|
}
|
||||||
|
.message-unknown {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
.message-time {
|
||||||
|
color: #bbbbbb;
|
||||||
|
font-size: 12px;
|
||||||
|
padding-top: 3px;
|
||||||
|
height: 21px;
|
||||||
|
line-height: 21px;
|
||||||
|
.common-loading {
|
||||||
|
margin: 0 2px;
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.loading {
|
||||||
|
padding: 12px 0;
|
||||||
|
justify-content: center;
|
||||||
|
.common-loading {
|
||||||
|
margin: 0;
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.nothing {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
color: #999999;
|
||||||
|
}
|
||||||
|
&.self {
|
||||||
|
flex-direction: row-reverse;
|
||||||
|
.message-view {
|
||||||
|
align-items: flex-end;
|
||||||
|
margin: 0 8px 0 0;
|
||||||
|
.message-content {
|
||||||
|
color: #ffffff;
|
||||||
|
background-color: #2d8cf0;
|
||||||
|
border-radius: 6px 6px 0 6px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
use App\Http\Controllers\Api\DialogController;
|
||||||
use App\Http\Controllers\Api\ProjectController;
|
use App\Http\Controllers\Api\ProjectController;
|
||||||
use App\Http\Controllers\Api\SystemController;
|
use App\Http\Controllers\Api\SystemController;
|
||||||
use App\Http\Controllers\Api\UsersController;
|
use App\Http\Controllers\Api\UsersController;
|
||||||
@ -31,6 +32,9 @@ Route::prefix('api')->middleware(['webapi'])->group(function () {
|
|||||||
// 系统
|
// 系统
|
||||||
Route::any('system/{method}', SystemController::class);
|
Route::any('system/{method}', SystemController::class);
|
||||||
Route::any('system/{method}/{action}', SystemController::class);
|
Route::any('system/{method}/{action}', SystemController::class);
|
||||||
|
// 对话
|
||||||
|
Route::any('dialog/{method}', DialogController::class);
|
||||||
|
Route::any('dialog/{method}/{action}', DialogController::class);
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
x
Reference in New Issue
Block a user