no message

This commit is contained in:
kuaifan 2021-06-07 20:04:46 +08:00
parent e0ea6e8303
commit fd1ce8b257
6 changed files with 316 additions and 109 deletions

View File

@ -208,11 +208,71 @@ class ProjectController extends AbstractController
return Base::retSuccess('修改成功'); return Base::retSuccess('修改成功');
} }
/**
* 排序任务
*
* @apiParam {Number} project_id 项目ID
* @apiParam {Object} sort 排序数据
* @apiParam {Number} [only_column] 仅更新列表
*/
public function sort()
{
$user = User::authE();
if (Base::isError($user)) {
return $user;
} else {
$user = User::IDE($user['data']);
}
//
$project_id = intval(Request::input('project_id'));
$sort = Base::json2array(Request::input('sort'));
$only_column = intval(Request::input('only_column'));
//
$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 ($only_column) {
// 排序列表
$index = 0;
foreach ($sort as $item) {
if (!is_array($item)) continue;
if (!intval($item['id'])) continue;
if (!is_array($item['task'])) continue;
ProjectColumn::whereId($item['id'])->whereProjectId($project->id)->update([
'sort' => $index
]);
$index++;
}
} else {
// 排序任务
foreach ($sort as $item) {
if (!is_array($item)) continue;
if (!intval($item['id'])) continue;
if (!is_array($item['task'])) continue;
$index = 0;
foreach ($item['task'] as $task_id) {
ProjectTask::whereId($task_id)->whereProjectId($project->id)->update([
'column_id' => $item['id'],
'sort' => $index
]);
$index++;
}
}
}
return Base::retSuccess('调整成功');
}
/** /**
* 修改项目成员 * 修改项目成员
* *
* @apiParam {Number} project_id 项目ID * @apiParam {Number} project_id 项目ID
* @apiParam {Number} userid 成员ID或成员ID组 * @apiParam {Number} userid 成员ID 成员ID组
*/ */
public function user() public function user()
{ {
@ -505,7 +565,10 @@ class ProjectController extends AbstractController
]); ]);
$column->sort = intval(ProjectColumn::whereProjectId($project->id)->orderByDesc('sort')->value('sort')) + 1; $column->sort = intval(ProjectColumn::whereProjectId($project->id)->orderByDesc('sort')->value('sort')) + 1;
$column->save(); $column->save();
return Base::retSuccess('添加成功', $column); //
$data = $column->toArray();
$data['project_task'] = [];
return Base::retSuccess('添加成功', $data);
} }
} }
@ -608,7 +671,7 @@ class ProjectController extends AbstractController
return Base::retError('任务列表不存在或已被删除'); return Base::retError('任务列表不存在或已被删除');
} }
// //
return ProjectTask::addTask([ $result = ProjectTask::addTask([
'parent_id' => 0, 'parent_id' => 0,
'project_id' => $project->id, 'project_id' => $project->id,
'column_id' => $column->id, 'column_id' => $column->id,
@ -622,5 +685,9 @@ class ProjectController extends AbstractController
'p_color' => $p_color, 'p_color' => $p_color,
'top' => $top, 'top' => $top,
]); ]);
if (Base::isSuccess($result)) {
$result['data'] = ProjectTask::with(['taskUser', 'taskTag'])->whereId($result['data']['id'])->first();
}
return $result;
} }
} }

View File

@ -298,13 +298,15 @@ class ProjectTask extends AbstractModel
$subtask['p_level'] = $task->p_level; $subtask['p_level'] = $task->p_level;
$subtask['p_name'] = $task->p_name; $subtask['p_name'] = $task->p_name;
$subtask['p_color'] = $task->p_color; $subtask['p_color'] = $task->p_color;
$res = self::addTask($subtask); $result = self::addTask($subtask);
if (Base::isError($res)) { if (Base::isError($result)) {
return $res; return $result;
} }
} }
} }
return Base::retSuccess('添加成功'); return Base::retSuccess('添加成功', [
'id' => $task->id
]);
}); });
} }
} }

View File

@ -184,6 +184,7 @@
return; return;
} }
if (typeof config === "string") config = {title:config}; if (typeof config === "string") config = {title:config};
let inputId = "modalInput_" + $A.randomString(6);
$A.Modal.confirm({ $A.Modal.confirm({
render: (h) => { render: (h) => {
return h('div', [ return h('div', [
@ -197,7 +198,8 @@
h('Input', { h('Input', {
props: { props: {
value: config.value, value: config.value,
placeholder: $A.L(config.placeholder) placeholder: $A.L(config.placeholder),
elementId: inputId,
}, },
on: { on: {
input: (val) => { input: (val) => {
@ -220,6 +222,9 @@
} }
}, },
}); });
setTimeout(() => {
document.getElementById(inputId) && document.getElementById(inputId).focus();
});
}, },
modalConfirm(config, millisecond = 0) { modalConfirm(config, millisecond = 0) {

View File

@ -13,7 +13,7 @@
<li> <li>
<UserAvatar :userid="projectDetail.owner_userid" :size="36"/> <UserAvatar :userid="projectDetail.owner_userid" :size="36"/>
</li> </li>
<li class="project-icon" @click="addOpen(0)"> <li class="project-icon" @click="addTaskOpen(0)">
<Icon type="md-add" /> <Icon type="md-add" />
</li> </li>
<li class="project-icon"> <li class="project-icon">
@ -53,8 +53,15 @@
</div> </div>
</div> </div>
<div v-if="projectListPanel" class="project-column"> <div v-if="projectListPanel" class="project-column">
<ul> <Draggable
<li v-for="column in projectDetail.project_column"> :list="projectDetail.project_column"
:animation="150"
:disabled="sortDisabled"
class="column-list"
tag="ul"
draggable=".column-item"
@sort="sortUpdate(true)">
<li v-for="column in projectDetail.project_column" class="column-item">
<div <div
:class="['column-head', column.color ? 'custom-color' : '']" :class="['column-head', column.color ? 'custom-color' : '']"
:style="column.color ? {backgroundColor: column.color}:null"> :style="column.color ? {backgroundColor: column.color}:null">
@ -77,20 +84,30 @@
</ul> </ul>
</div> </div>
</Poptip> </Poptip>
<Icon type="md-add" @click="addTop(column)" /> <Icon type="md-add" @click="addTopShow(column)" />
</div> </div>
</div> </div>
<ul class="overlay-y" :ref="'column_' + column.id"> <div :ref="'column_' + column.id" class="column-task overlay-y">
<li v-if="column.addTop===true" class="task-add"> <div v-if="column.addTopShow===true" class="task-item">
<TaskAddSimple <TaskAddSimple
:column-id="column.id" :column-id="column.id"
:project-id="projectDetail.id" :project-id="projectDetail.id"
:add-top="true" :add-top="true"
@on-close="column.addTop=false" @on-close="column.addTopShow=false"
@on-priority="addOpen" @on-priority="addTaskOpen"
@on-success="addTaskSuccess"
auto-active/> auto-active/>
</li> </div>
<li v-for="item in panelTask(column.project_task)"> <Draggable
:list="column.project_task"
:animation="150"
:disabled="sortDisabled"
class="task-list"
draggable=".task-draggable"
group="task"
@sort="sortUpdate"
@remove="sortUpdate">
<div v-for="item in panelTask(column.project_task)" class="task-item task-draggable">
<div :class="['task-head', item.desc ? 'has-desc' : '']"> <div :class="['task-head', item.desc ? 'has-desc' : '']">
<div class="task-title"><pre>{{item.name}}</pre></div> <div class="task-title"><pre>{{item.name}}</pre></div>
<Icon type="ios-more" /> <Icon type="ios-more" />
@ -120,17 +137,33 @@
</Tooltip> </Tooltip>
</div> </div>
<em v-if="item.p_name" class="priority-color" :style="{backgroundColor:item.p_color}"></em> <em v-if="item.p_name" class="priority-color" :style="{backgroundColor:item.p_color}"></em>
</li> </div>
<li class="task-add"> <div class="task-item">
<TaskAddSimple <TaskAddSimple
:column-id="column.id" :column-id="column.id"
:project-id="projectDetail.id" :project-id="projectDetail.id"
@on-priority="addOpen"/> @on-priority="addTaskOpen"
@on-success="addTaskSuccess"/>
</div>
</Draggable>
</div>
</li> </li>
</ul> <li :class="['add-column', addColumnShow ? 'show-input' : '']">
<div class="add-column-text" @click="addColumnOpen">
<Icon type="md-add" />{{$L('添加列表')}}
</div>
<div class="add-column-input">
<Input
ref="addColumnName"
v-model="addColumnName"
@on-blur="addColumnShow=false"
@on-clear="addColumnShow=false"
@on-enter="addColumnSubmit"
:placeholder="$L('列表名称,回车创建')"
clearable/>
</div>
</li> </li>
<li class="add-column" @click="addColumn"><Icon type="md-add" />{{$L('添加列表')}}</li> </Draggable>
</ul>
</div> </div>
<div v-else class="project-table"> <div v-else class="project-table">
<div class="project-table-head"> <div class="project-table-head">
@ -188,7 +221,7 @@
<em v-if="item.p_name" class="priority-color" :style="{backgroundColor:item.p_color}"></em> <em v-if="item.p_name" class="priority-color" :style="{backgroundColor:item.p_color}"></em>
</Row> </Row>
</div> </div>
<div @click="addOpen(0)"> <div @click="addTaskOpen(0)">
<Row class="project-row"> <Row class="project-row">
<Col span="12" class="row-add"> <Col span="12" class="row-add">
<Icon type="ios-add" /> {{$L('添加任务')}} <Icon type="ios-add" /> {{$L('添加任务')}}
@ -370,6 +403,7 @@
</template> </template>
<script> <script>
import Draggable from 'vuedraggable'
import TaskPriority from "./TaskPriority"; import TaskPriority from "./TaskPriority";
import TaskAdd from "./TaskAdd"; import TaskAdd from "./TaskAdd";
import {mapState} from "vuex"; import {mapState} from "vuex";
@ -377,7 +411,7 @@ import UserInput from "../../../components/UserInput";
import TaskAddSimple from "./TaskAddSimple"; import TaskAddSimple from "./TaskAddSimple";
export default { export default {
name: "ProjectList", name: "ProjectList",
components: {TaskAddSimple, UserInput, TaskAdd, TaskPriority}, components: {Draggable, TaskAddSimple, UserInput, TaskAdd, TaskPriority},
data() { data() {
return { return {
nowTime: Math.round(new Date().getTime() / 1000), nowTime: Math.round(new Date().getTime() / 1000),
@ -397,6 +431,12 @@ export default {
}, },
taskLoad: 0, taskLoad: 0,
addColumnShow: false,
addColumnName: '',
sortData: [],
sortDisabled: false,
settingShow: false, settingShow: false,
settingData: {}, settingData: {},
settingLoad: 0, settingLoad: 0,
@ -538,8 +578,94 @@ export default {
}, },
}, },
watch: {
projectDetail() {
this.sortData = this.getSort();
}
},
methods: { methods: {
addOpen(column_id) { getSort() {
const sortData = [];
this.projectDetail.project_column.forEach((column) => {
sortData.push({
id: column.id,
task: column.project_task.map(({id}) => id)
});
});
return sortData;
},
sortUpdate(only_column) {
const oldSort = this.sortData;
const newSort = this.getSort();
if (JSON.stringify(oldSort) === JSON.stringify(newSort)) {
return;
}
this.sortData = newSort;
//
this.sortDisabled = true;
$A.apiAjax({
url: 'project/sort',
data: {
project_id: this.projectDetail.id,
sort: this.sortData,
only_column: only_column === true ? 1 : 0
},
complete: () => {
this.sortDisabled = false;
},
error: () => {
$A.modalAlert('网络繁忙,请稍后再试!');
this.$store.commit('getProjectDetail', this.projectDetail.id);
},
success: ({ret, data, msg}) => {
if (ret === 1) {
$A.messageSuccess(msg);
} else {
$A.modalError(msg);
this.$store.commit('getProjectDetail', this.projectDetail.id);
}
}
});
},
onAddTask() {
this.taskLoad++;
$A.apiAjax({
url: 'project/task/add',
data: this.addData,
method: 'post',
complete: () => {
this.taskLoad--;
},
success: ({ret, data, msg}) => {
if (ret === 1) {
$A.messageSuccess(msg);
this.addTaskSuccess(data)
this.addShow = false;
this.addData = {
owner: 0,
column_id: 0,
times: [],
subtasks: [],
p_level: 0,
p_name: '',
p_color: '',
};
} else {
$A.modalError(msg);
}
}
});
},
addTopShow(column) {
this.$set(column, 'addTopShow', true);
this.$refs['column_' + column.id][0].scrollTop = 0;
},
addTaskOpen(column_id) {
if ($A.isJson(column_id)) { if ($A.isJson(column_id)) {
this.addData = Object.assign(this.addData, column_id); this.addData = Object.assign(this.addData, column_id);
} else { } else {
@ -550,25 +676,35 @@ export default {
this.addShow = true; this.addShow = true;
}, },
addTop(column) { addTaskSuccess(data) {
this.$set(column, 'addTop', true); this.projectDetail.project_column.some((item) => {
this.$refs['column_' + column.id][0].scrollTop = 0; if (item.id === data.column_id) {
if (data.top) {
item.project_task.unshift(data);
} else {
item.project_task.push(data);
}
}
});
}, },
addColumn() { addColumnOpen() {
$A.modalInput({ this.addColumnShow = true;
title: "添加列表", this.$nextTick(() => {
placeholder: "输入列表名称", this.$refs.addColumnName.focus();
onOk: (value, callback) => { })
if (!value) return true; },
addColumnSubmit() {
let name = this.addColumnName.trim();
if (name === '') {
return;
}
$A.apiAjax({ $A.apiAjax({
url: 'project/column/add', url: 'project/column/add',
data: { data: {
project_id: this.projectDetail.id, project_id: this.projectDetail.id,
name: value, name: name,
},
complete: () => {
callback();
}, },
error: () => { error: () => {
$A.modalAlert('网络繁忙,请稍后再试!'); $A.modalAlert('网络繁忙,请稍后再试!');
@ -576,14 +712,12 @@ export default {
success: ({ret, data, msg}) => { success: ({ret, data, msg}) => {
if (ret === 1) { if (ret === 1) {
$A.messageSuccess(msg); $A.messageSuccess(msg);
this.$store.commit('getProjectDetail', this.projectDetail.id); this.projectDetail.project_column.push(data)
} else { } else {
$A.modalError(msg, 301); $A.modalError(msg, 301);
} }
} }
}); });
}
})
}, },
modifyColumn(column) { modifyColumn(column) {
@ -650,38 +784,8 @@ export default {
}, },
success: ({ret, data, msg}) => { success: ({ret, data, msg}) => {
if (ret !== 1) { if (ret !== 1) {
this.$set(column, 'name', bakName); this.$set(column, 'name', data.name);
this.$set(column, 'color', bakColor); this.$set(column, 'color', data.color);
}
}
});
},
onAddTask() {
this.taskLoad++;
$A.apiAjax({
url: 'project/task/add',
data: this.addData,
method: 'post',
complete: () => {
this.taskLoad--;
},
success: ({ret, data, msg}) => {
if (ret === 1) {
$A.messageSuccess(msg);
this.$store.commit('getProjectDetail', this.addData.project_id);
this.addShow = false;
this.addData = {
owner: 0,
column_id: 0,
times: [],
subtasks: [],
p_level: 0,
p_name: '',
p_color: '',
};
} else {
$A.modalError(msg);
} }
} }
}); });

View File

@ -161,7 +161,8 @@ export default {
success: ({ret, data, msg}) => { success: ({ret, data, msg}) => {
if (ret === 1) { if (ret === 1) {
$A.messageSuccess(msg); $A.messageSuccess(msg);
this.$store.commit('getProjectDetail', this.projectId); data.top = this.addTop ? 1 : 0;
this.$emit("on-success", data)
this.active = false; this.active = false;
} else { } else {
$A.modalError(msg); $A.modalError(msg);

View File

@ -4,7 +4,7 @@
.project-head { .project-head {
display: flex; display: flex;
align-items: flex-start; align-items: flex-start;
margin: 32px 32px 18px; margin: 32px 32px 0;
.project-titbox { .project-titbox {
flex: 1; flex: 1;
margin-bottom: 16px; margin-bottom: 16px;
@ -139,7 +139,9 @@
.project-column { .project-column {
display: flex; display: flex;
height: 100%; height: 100%;
padding-top: 18px;
overflow-x: auto; overflow-x: auto;
overflow-y: hidden;
> ul { > ul {
display: inline-flex; display: inline-flex;
justify-content: space-between; justify-content: space-between;
@ -158,22 +160,41 @@
margin-right: 22px; margin-right: 22px;
} }
&.add-column { &.add-column {
display: flex;
flex-direction: row;
align-items: center;
height: 36px; height: 36px;
padding: 0 12px;
color: #888888; color: #888888;
cursor: pointer; cursor: pointer;
background-color: #F2F3F5; background-color: #F2F3F5;
border-radius: 4px; border-radius: 4px;
&:hover { .add-column-text {
color: #777777; display: flex;
} flex-direction: row;
align-items: center;
line-height: 36px;
padding: 0 12px;
> i { > i {
font-size: 16px; font-size: 16px;
padding-right: 8px; padding-right: 8px;
} }
&:hover {
color: #777777;
}
}
.add-column-input {
display: none;
align-items: center;
height: 36px;
.ivu-input {
height: 36px;
}
}
&.show-input {
.add-column-text {
display: none;
}
.add-column-input {
display: flex;
}
}
} }
.column-head { .column-head {
display: flex; display: flex;
@ -278,18 +299,25 @@
} }
} }
} }
> ul { .column-task {
flex: 1; flex: 1;
height: 0; display: flex;
flex-direction: column;
overflow-x: hidden; overflow-x: hidden;
overflow-y: auto; overflow-y: auto;
> li { .task-list {
flex: 1;
height: 0;
display: flex;
flex-direction: column;
}
.task-item {
list-style: none; list-style: none;
margin: 0 10px 16px; margin: 0 10px 16px;
background-color: #ffffff; background-color: #ffffff;
border-radius: 12px; border-radius: 12px;
padding: 12px; padding: 12px;
transition: all 0.3s; transition: box-shadow 0.3s;
position: relative; position: relative;
&:hover { &:hover {
box-shadow: 0 0 10px #e6ecfa; box-shadow: 0 0 10px #e6ecfa;