no message

This commit is contained in:
kuaifan 2021-06-08 22:51:56 +08:00
parent d1b5179838
commit c478dbeeaa
7 changed files with 370 additions and 106 deletions

View File

@ -7,10 +7,13 @@ use App\Models\Project;
use App\Models\ProjectColumn;
use App\Models\ProjectLog;
use App\Models\ProjectTask;
use App\Models\ProjectTaskContent;
use App\Models\ProjectTaskUser;
use App\Models\ProjectUser;
use App\Models\User;
use App\Models\WebSocketDialogMsg;
use App\Module\Base;
use Carbon\Carbon;
use Request;
/**
@ -261,6 +264,9 @@ class ProjectController extends AbstractController
'column_id' => $item['id'],
'sort' => $index
]);
ProjectTask::whereParentId($task_id)->whereProjectId($project->id)->update([
'column_id' => $item['id'],
]);
$index++;
}
}
@ -515,12 +521,10 @@ class ProjectController extends AbstractController
}
/**
* 添加、修改 任务列表
* 添加任务列表
*
* @apiParam {Number} project_id 项目ID
* @apiParam {Number} [column_id] 列表ID留空为添加列表
* @apiParam {String} name 列表名称
* @apiParam {String} color 颜色
*/
public function column__add()
{
@ -532,12 +536,7 @@ class ProjectController extends AbstractController
}
//
$project_id = intval(Request::input('project_id'));
$column_id = intval(Request::input('column_id'));
$name = trim(Request::input('name'));
$color = trim(Request::input('color'));
if (empty($name)) {
return Base::retError('列表名称不能为空');
}
// 项目
$project = Project::select($this->projectSelect)
->join('project_users', 'projects.id', '=', 'project_users.project_id')
@ -548,28 +547,59 @@ class ProjectController extends AbstractController
return Base::retError('项目不存在或不在成员列表内');
}
//
if ($column_id > 0) {
$column = ProjectColumn::whereId($column_id)->whereProjectId($project_id)->first();
if (empty($column)) {
return Base::retError('列表不存在');
}
$column->name = $name;
$column->color = $color;
$column->save();
return Base::retSuccess('修改成功', $column);
} else {
$column = ProjectColumn::createInstance([
'project_id' => $project->id,
'name' => $name,
'color' => $color,
]);
$column->sort = intval(ProjectColumn::whereProjectId($project->id)->orderByDesc('sort')->value('sort')) + 1;
$column->save();
//
$data = $column->toArray();
$data['project_task'] = [];
return Base::retSuccess('添加成功', $data);
if (empty($name)) {
return Base::retError('列表名称不能为空');
}
$column = ProjectColumn::createInstance([
'project_id' => $project->id,
'name' => $name,
]);
$column->sort = intval(ProjectColumn::whereProjectId($project->id)->orderByDesc('sort')->value('sort')) + 1;
$column->save();
//
$data = $column->toArray();
$data['project_task'] = [];
return Base::retSuccess('添加成功', $data);
}
/**
* 修改任务列表
*
* @apiParam {Number} column_id 列表ID
* @apiParam {String} [name] 列表名称
* @apiParam {String} [color] 颜色
*/
public function column__update()
{
$user = User::authE();
if (Base::isError($user)) {
return $user;
} else {
$user = User::IDE($user['data']);
}
//
$column_id = intval(Request::input('column_id'));
$name = trim(Request::input('name'));
$color = trim(Request::input('color'));
// 列表
$column = ProjectColumn::whereId($column_id)->first();
if (empty($column)) {
return Base::retError('列表不存在');
}
// 项目
$project = Project::select($this->projectSelect)
->join('project_users', 'projects.id', '=', 'project_users.project_id')
->where('projects.id', $column->project_id)
->where('project_users.userid', $user->userid)
->first();
if (empty($project)) {
return Base::retError('项目不存在或不在成员列表内');
}
//
if ($name) $column->name = $name;
if ($color) $column->color = $color;
$column->save();
return Base::retSuccess('修改成功', $column);
}
/**
@ -690,4 +720,57 @@ class ProjectController extends AbstractController
}
return $result;
}
/**
* {post} 修改任务、子任务
*
* @apiParam {Number} task_id 任务ID
* @apiParam {String} [name] 任务描述
* @apiParam {String} [color] 任务描述(子任务不支持)
* @apiParam {String} [content] 任务详情(子任务不支持)
* @apiParam {Array} [times] 计划时间(格式:开始时间,结束时间2020-01-01 00:00,2020-01-01 23:59
* @apiParam {Number} [owner] 修改负责人
*/
public function task__update()
{
$user = User::authE();
if (Base::isError($user)) {
return $user;
} else {
$user = User::IDE($user['data']);
}
//
$task_id = Base::getPostInt('task_id');
$name = Base::getPostValue('name');
$color = Base::getPostValue('color');
$content = Base::getPostValue('content');
$times = Base::getPostValue('times');
$owner = Base::getPostValue('owner');
// 任务
$task = ProjectTask::whereId($task_id)->first();
if (empty($task)) {
return Base::retError('任务不存在');
}
// 项目
$project = Project::select($this->projectSelect)
->join('project_users', 'projects.id', '=', 'project_users.project_id')
->where('projects.id', $task->project_id)
->where('project_users.userid', $user->userid)
->first();
if (empty($project)) {
return Base::retError('项目不存在或不在成员列表内');
}
//
$result = $task->updateTask([
'name' => $name,
'color' => $color,
'content' => $content,
'times' => $times,
'owner' => $owner,
]);
if (Base::isSuccess($result)) {
$result['data'] = ProjectTask::with(['taskUser', 'taskTag'])->whereId($task->id)->first();
}
return $result;
}
}

View File

@ -24,6 +24,9 @@ class VerifyCsrfToken extends Middleware
// 添加任务
'api/project/task/add/',
// 修改任务
'api/project/task/update/',
// 聊天发文件
'api/dialog/msg/sendfile/',
];

View File

@ -309,4 +309,66 @@ class ProjectTask extends AbstractModel
]);
});
}
/**
* 修改任务
* @param $params
* @return array|bool
*/
public function updateTask($params)
{
return AbstractModel::transaction(function () use ($params) {
$name = $params['name'];
$color = $params['color'];
$content = $params['content'];
$times = $params['times'];
$owner = $params['owner'];
// 子任务禁止修改项
if ($this->parent_id > 0) {
$color = null;
$content = null;
}
// 名称、背景色
if ($name) $this->name = $name;
if ($color) $this->color = $color;
if ($content) {
ProjectTaskContent::updateInsert([
'project_id' => $this->parent_id,
'task_id' => $this->id,
], [
'content' => $content,
]);
}
// 计划时间
if ($times) {
list($start, $end) = is_string($times) ? explode(",", $times) : (is_array($times) ? $times : []);
if (Base::isDate($start) && Base::isDate($end)) {
if ($start != $end) {
$this->start_at = Carbon::parse($start);
$this->end_at = Carbon::parse($end);
}
}
}
// 负责人
if ($owner) {
if (is_array($owner)) {
$owner = Base::arrayFirst($owner);
}
$ownerUser = ProjectTaskUser::whereTaskId($this->id)->whereOwner(1)->first();
if ($ownerUser->userid != $owner) {
$ownerUser->owner = 0;
$ownerUser->save();
ProjectTaskUser::updateInsert([
'project_id' => $this->parent_id,
'task_id' => $this->id,
'userid' => $owner,
], [
'owner' => 1,
]);
}
}
$this->save();
return Base::retSuccess('修改成功');
});
}
}

View File

@ -31,18 +31,18 @@
<Badge :count="msgUnread"></Badge>
</li>
<li class="project-icon">
<Dropdown @on-click="projectDropdown" trigger="click" transfer>
<EDropdown @command="projectDropdown" trigger="click" transfer>
<Icon type="ios-more" />
<DropdownMenu v-if="projectDetail.owner_userid === userId" slot="list">
<DropdownItem name="setting">{{$L('项目设置')}}</DropdownItem>
<DropdownItem name="user">{{$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>
</Dropdown>
<EDropdownMenu v-if="projectDetail.owner_userid === userId" slot="dropdown">
<EDropdownItem command="setting">{{$L('项目设置')}}</EDropdownItem>
<EDropdownItem command="user">{{$L('成员管理')}}</EDropdownItem>
<EDropdownItem command="transfer" divided>{{$L('移交项目')}}</EDropdownItem>
<EDropdownItem command="delete" style="color:#f40">{{$L('删除项目')}}</EDropdownItem>
</EDropdownMenu>
<EDropdownMenu v-else slot="dropdown">
<EDropdownItem command="exit">{{$L('退出项目')}}</EDropdownItem>
</EDropdownMenu>
</EDropdown>
</li>
</ul>
@ -66,16 +66,20 @@
<li v-for="column in projectDetail.project_column" class="column-item">
<div
:class="['column-head', column.color ? 'custom-color' : '']"
:style="column.color ? {backgroundColor: column.color}:null">
:style="column.color ? {backgroundColor: column.color} : null">
<div class="column-head-title">
<AutoTip>{{column.name}}</AutoTip>
<em>({{column.project_task.length}})</em>
</div>
<div class="column-head-icon">
<EDropdown trigger="click" @command="dropColumn(column, $event)">
<div v-if="column.loading === true" class="loading"><Loading /></div>
<EDropdown
v-else
trigger="click"
@command="dropColumn(column, $event)">
<Icon type="ios-more" />
<EDropdownMenu slot="dropdown" class="project-list-column-more-content">
<EDropdownItem command="modify">
<EDropdownMenu slot="dropdown" class="project-list-more-dropdown-menu column-more">
<EDropdownItem command="title">
<div class="item">
<Icon type="md-create" />{{$L('修改')}}
</div>
@ -86,7 +90,7 @@
</div>
</EDropdownItem>
<EDropdownItem divided disabled>{{$L('颜色')}}</EDropdownItem>
<EDropdownItem v-for="(c, k) in colorList" :key="k" :command="c">
<EDropdownItem v-for="(c, k) in columnList" :key="k" :command="c">
<div class="item">
<i class="iconfont" :style="{color:c.color}" v-html="c.color == column.color ? '&#xe61d;' : '&#xe61c;'"></i>{{$L(c.name)}}
</div>
@ -116,15 +120,35 @@
group="task"
@sort="sortUpdate"
@remove="sortUpdate">
<div v-for="item in panelTask(column.project_task)" class="task-item task-draggable">
<div
v-for="item in panelTask(column.project_task)"
class="task-item task-draggable"
:style="item.color ? {backgroundColor: item.color} : null">
<div :class="['task-head', item.desc ? 'has-desc' : '']">
<i class="task-choose iconfont">&#xe625;</i>
<div class="task-title"><pre>{{item.name}}</pre></div>
<EDropdown trigger="click" @command="dropTask(item, $event)">
<div v-if="item.loading === true" class="loading"><Loading /></div>
<EDropdown
v-else
trigger="click"
@command="dropTask(item, $event)">
<Icon type="ios-more" />
<EDropdownMenu slot="dropdown">
<EDropdownItem command="complete">{{$L('完成')}}</EDropdownItem>
<EDropdownItem command="delete" divided>{{$L('删除')}}</EDropdownItem>
<EDropdownMenu slot="dropdown" class="project-list-more-dropdown-menu">
<EDropdownItem command="complete">
<div class="item">
<Icon type="md-create" />{{$L('完成')}}
</div>
</EDropdownItem>
<EDropdownItem command="delete">
<div class="item">
<Icon type="md-trash" />{{$L('删除')}}
</div>
</EDropdownItem>
<EDropdownItem divided disabled>{{$L('颜色')}}</EDropdownItem>
<EDropdownItem v-for="(c, k) in taskList" :key="k" :command="c">
<div class="item">
<i class="iconfont" :style="{color:c.color||'#f9f9f9'}" v-html="c.color == column.color ? '&#xe61d;' : '&#xe61c;'"></i>{{$L(c.name)}}
</div>
</EDropdownItem>
</EDropdownMenu>
</EDropdown>
</div>
@ -461,7 +485,7 @@ export default {
transferData: {},
transferLoad: 0,
colorList: [
columnList: [
{name: '默认', color: ''},
{name: '灰色', color: '#6C6F71'},
{name: '棕色', color: '#695C56'},
@ -472,6 +496,16 @@ export default {
{name: '紫色', color: '#6B5C8D'},
{name: '粉色', color: '#8E5373'},
{name: '红色', color: '#9D6058'},
],
taskList: [
{name: '默认', color: ''},
{name: '黄色', color: '#FCF4A7'},
{name: '蓝色', color: '#BCF2FD'},
{name: '绿色', color: '#C3FDAA'},
{name: '粉色', color: '#F6C9C8'},
{name: '紫色', color: '#BAC9FB'},
{name: '灰色', color: '#EEEEEE'},
]
}
},
@ -740,43 +774,89 @@ export default {
},
dropColumn(column, command) {
if (command === 'modify') {
this.modifyColumn(column);
if (command === 'title') {
this.titleColumn(column);
}
else if (command === 'delete') {
this.removeColumn(column);
}
else if (command.name) {
this.saveColumn(column, column.name, command.color)
this.updateColumn(column, {
color: command.color
});
}
},
modifyColumn(column) {
titleColumn(column) {
$A.modalInput({
value: column.name,
title: "修改列表",
placeholder: "输入列表名称",
onOk: (value) => {
if (value) {
this.saveColumn(column, value, column.color);
this.updateColumn(column, {
name: value
});
}
return true;
}
});
},
updateColumn(column, updata) {
if (column.loading === true) {
return;
}
this.$set(column, 'loading', true);
//
const backup = $A.cloneJSON(column);
Object.keys(updata).forEach(key => {
this.$set(column, key, updata[key]);
});
//
$A.apiAjax({
url: 'project/column/update',
data: Object.assign(updata, {
column_id: column.id,
}),
complete: () => {
this.$set(column, 'loading', false);
},
error: () => {
Object.keys(updata).forEach(key => {
this.$set(column, key, backup[key]);
});
},
success: ({ret, data, msg}) => {
if (ret !== 1) {
Object.keys(updata).forEach(key => {
this.$set(column, key, backup[key]);
});
}
}
});
},
removeColumn(column) {
$A.modalConfirm({
title: '删除列表',
content: '你确定要删除列表【' + column.name + '】及列表内的任务吗?',
loading: true,
onOk: () => {
if (column.loading === true) {
return;
}
this.$set(column, 'loading', true);
//
$A.apiAjax({
url: 'project/column/delete',
data: {
project_id: this.projectDetail.id,
column_id: column.id,
},
complete: () => {
this.$set(column, 'loading', false);
},
error: () => {
this.$Modal.remove();
$A.modalAlert('网络繁忙,请稍后再试!');
@ -785,6 +865,10 @@ export default {
this.$Modal.remove();
if (ret === 1) {
$A.messageSuccess(msg);
let index = this.projectDetail.project_column.findIndex(({id}) => id === column.id);
if (index > -1) {
this.projectDetail.project_column.splice(index, 1);
}
this.$store.commit('getProjectDetail', this.projectDetail.id);
}else{
$A.modalError(msg, 301);
@ -795,43 +879,54 @@ export default {
});
},
saveColumn(column, name, color) {
let bakName = column.name;
let bakColor = column.color;
this.$set(column, 'name', name);
this.$set(column, 'color', color);
dropTask(task, command) {
if (command === 'complete') {
//
}
else if (command === 'delete') {
//
}
else if (command.name) {
this.updateTask(task, {
color: command.color
})
}
},
updateTask(task, updata) {
if (task.loading === true) {
return;
}
this.$set(task, 'loading', true);
//
const backup = $A.cloneJSON(task);
Object.keys(updata).forEach(key => {
this.$set(task, key, updata[key]);
});
$A.apiAjax({
url: 'project/column/add',
data: {
project_id: this.projectDetail.id,
column_id: column.id,
name: name,
color: color,
url: 'project/task/update',
data: Object.assign(updata, {
task_id: task.id,
}),
method: 'post',
complete: () => {
this.$set(task, 'loading', false);
},
error: () => {
this.$set(column, 'name', bakName);
this.$set(column, 'color', bakColor);
Object.keys(updata).forEach(key => {
this.$set(task, key, backup[key]);
});
},
success: ({ret, data, msg}) => {
if (ret !== 1) {
this.$set(column, 'name', data.name);
this.$set(column, 'color', data.color);
Object.keys(updata).forEach(key => {
this.$set(task, key, backup[key]);
});
}
}
});
},
dropTask(task, command) {
switch (command) {
case 'complete':
break;
case 'delete':
break;
}
},
onSetting() {
this.settingLoad++;
$A.apiAjax({

View File

@ -114,9 +114,7 @@ export default {
return;
}
if (state.method.isJson(state.cacheProject[project_id])) {
setTimeout(() => {
state.projectDetail = state.cacheProject[project_id];
});
state.projectDetail = state.cacheProject[project_id];
}
state.projectDetail.id = project_id;
//
@ -309,14 +307,12 @@ export default {
//
state.dialogMsgList = [];
if (state.method.isJson(state.cacheDialogMsg[dialog_id])) {
setTimeout(() => {
let length = state.cacheDialogMsg[dialog_id].data.length;
if (length > 50) {
state.cacheDialogMsg[dialog_id].data.splice(0, length - 50);
}
state.dialogDetail = state.cacheDialogMsg[dialog_id].dialog
state.dialogMsgList = state.cacheDialogMsg[dialog_id].data
});
let length = state.cacheDialogMsg[dialog_id].data.length;
if (length > 50) {
state.cacheDialogMsg[dialog_id].data.splice(0, length - 50);
}
state.dialogDetail = state.cacheDialogMsg[dialog_id].dialog
state.dialogMsgList = state.cacheDialogMsg[dialog_id].data
}
state.dialogId = dialog_id;
//

View File

@ -13,3 +13,6 @@ $--tooltip-font-size: 14px;
min-width: 100px;
line-height: 34px;
}
.el-dropdown-menu__item--divided:before {
height: 5px;
}

View File

@ -229,11 +229,24 @@
display: flex;
align-items: center;
margin-left: 16px;
.loading,
.ivu-icon {
width: 24px;
height: 24px;
display: flex;
align-items: center;
justify-content: center;
padding-right: 8px;
.common-loading {
width: 16px;
height: 16px;
margin: 0;
}
}
.ivu-icon {
cursor: pointer;
font-size: 16px;
color: #aaaaaa;
cursor: pointer;
font-weight: 600;
transition: color 0.3s;
&:hover {
@ -296,14 +309,6 @@
.task-head {
display: flex;
align-items: flex-start;
.task-choose {
margin-right: 5px;
font-size: 22px;
color: #aaaaaa;
height: 22px;
line-height: 22px;
cursor: pointer;
}
.task-title {
flex: 1;
padding-top: 1px;
@ -315,10 +320,23 @@
word-wrap: break-word;
}
}
.loading,
.ivu-icon {
width: 22px;
height: 22px;
display: flex;
align-items: center;
justify-content: center;
margin-left: 8px;
.common-loading {
width: 16px;
height: 16px;
margin: 0;
}
}
.ivu-icon {
font-size: 22px;
color: #666666;
margin-left: 8px;
cursor: pointer;
&:hover {
color: #555555;
@ -361,7 +379,7 @@
margin-left: 0;
}
.common-avatar {
border: 2px solid #ffffff;
padding: 2px;
}
}
}
@ -567,9 +585,8 @@
}
}
}
.project-list-column-more-content {
.project-list-more-dropdown-menu {
> li {
min-width: 130px;
.item {
display: flex;
align-items: center;
@ -584,4 +601,9 @@
}
}
}
&.column-more {
> li {
min-width: 130px;
}
}
}