diff --git a/app/Http/Controllers/Api/ProjectController.php b/app/Http/Controllers/Api/ProjectController.php
index 27f7f9ee..cb9ebc4a 100755
--- a/app/Http/Controllers/Api/ProjectController.php
+++ b/app/Http/Controllers/Api/ProjectController.php
@@ -23,11 +23,6 @@ use Request;
*/
class ProjectController extends AbstractController
{
- private $projectSelect = [
- 'projects.*',
- 'project_users.owner',
- ];
-
/**
* 项目列表
*
@@ -38,7 +33,7 @@ class ProjectController extends AbstractController
{
$user = User::auth();
//
- $list = Project::select($this->projectSelect)
+ $list = Project::select(Project::projectSelect)
->join('project_users', 'projects.id', '=', 'project_users.project_id')
->where('project_users.userid', $user->userid)
->orderByDesc('projects.id')
@@ -79,7 +74,7 @@ class ProjectController extends AbstractController
$taskQuery->with(['taskUser', 'taskTag'])->where('parent_id', 0);
}]);
}, 'projectUser'])
- ->select($this->projectSelect)
+ ->select(project::projectSelect)
->join('project_users', 'projects.id', '=', 'project_users.project_id')
->where('projects.id', $project_id)
->where('project_users.userid', $user->userid)
@@ -419,7 +414,7 @@ class ProjectController extends AbstractController
return Base::retError('列表不存在');
}
// 项目
- $project = Project::select($this->projectSelect)
+ $project = Project::select(project::projectSelect)
->join('project_users', 'projects.id', '=', 'project_users.project_id')
->where('projects.id', $column->project_id)
->where('project_users.userid', $user->userid)
@@ -456,7 +451,7 @@ class ProjectController extends AbstractController
return Base::retError('列表不存在');
}
// 项目
- $project = Project::select($this->projectSelect)
+ $project = Project::select(project::projectSelect)
->join('project_users', 'projects.id', '=', 'project_users.project_id')
->where('projects.id', $column->project_id)
->where('project_users.userid', $user->userid)
@@ -471,6 +466,46 @@ class ProjectController extends AbstractController
return Base::retError('删除失败');
}
+ /**
+ * 任务列表
+ *
+ * @apiParam {String} name 任务名称(包含)
+ * @apiParam {Array} time 时间范围,格式:数组,如:[2020-12-12,2020-20-12]
+ */
+ public function task__lists()
+ {
+ $user = user::auth();
+ //
+ $builder = ProjectTask::select(ProjectTask::taskSelect);
+ //
+ $name = Request::input('name');
+ $time = Request::input('time');
+ if ($name) {
+ $builder->where(function($query) use ($name) {
+ $query->where('project_tasks.name', 'like', '%,' . $name . ',%');
+ });
+ }
+ if (is_array($time)) {
+ if (Base::isDateOrTime($time[0]) && Base::isDateOrTime($time[1])) {
+ $between = [
+ Carbon::parse($time[0])->startOfDay(),
+ Carbon::parse($time[1])->endOfDay()
+ ];
+ $builder->where(function($query) use ($between) {
+ $query->whereBetween('project_tasks.start_at', $between)->orWhereBetween('project_tasks.end_at', $between);
+ });
+ }
+ }
+ //
+ $list = $builder
+ ->join('project_task_users', 'project_tasks.id', '=', 'project_task_users.task_id')
+ ->where('project_task_users.userid', $user->userid)
+ ->orderByDesc('project_tasks.id')
+ ->paginate(Base::getPaginate(200, 100));
+ //
+ return Base::retSuccess('success', $list);
+ }
+
/**
* 获取任务
*
diff --git a/app/Models/Project.php b/app/Models/Project.php
index 0565d9a2..80a6cd5f 100644
--- a/app/Models/Project.php
+++ b/app/Models/Project.php
@@ -50,6 +50,11 @@ class Project extends AbstractModel
{
use SoftDeletes;
+ const projectSelect = [
+ 'projects.*',
+ 'project_users.owner',
+ ];
+
protected $appends = [
'task_num',
'task_complete',
@@ -295,7 +300,7 @@ class Project extends AbstractModel
*/
public static function userProject($project_id)
{
- $project = Project::select([ 'projects.*', 'project_users.owner' ])
+ $project = Project::select(self::projectSelect)
->join('project_users', 'projects.id', '=', 'project_users.project_id')
->where('projects.id', intval($project_id))
->where('project_users.userid', User::token2userid())
diff --git a/app/Models/ProjectTask.php b/app/Models/ProjectTask.php
index e98f5559..f5697db2 100644
--- a/app/Models/ProjectTask.php
+++ b/app/Models/ProjectTask.php
@@ -79,6 +79,11 @@ class ProjectTask extends AbstractModel
{
use SoftDeletes;
+ const taskSelect = [
+ 'project_tasks.*',
+ 'project_task_users.owner',
+ ];
+
protected $appends = [
'file_num',
'msg_num',
@@ -305,15 +310,16 @@ class ProjectTask extends AbstractModel
$task->save();
if ($owner) {
ProjectTaskUser::createInstance([
- 'project_id' => $task->parent_id,
+ 'project_id' => $task->project_id,
'task_id' => $task->id,
+ 'task_pid' => $task->parent_id ?: $task->id,
'userid' => $owner,
'owner' => 1,
])->save();
}
if ($content) {
ProjectTaskContent::createInstance([
- 'project_id' => $task->parent_id,
+ 'project_id' => $task->project_id,
'task_id' => $task->id,
'content' => $content,
])->save();
@@ -367,7 +373,7 @@ class ProjectTask extends AbstractModel
$row->owner = 0;
$row->save();
ProjectTaskUser::updateInsert([
- 'project_id' => $this->parent_id,
+ 'project_id' => $this->project_id,
'task_id' => $this->id,
'userid' => $owner,
], [
@@ -402,8 +408,9 @@ class ProjectTask extends AbstractModel
//
if (empty($this->useridInTheTask($uid))) {
ProjectTaskUser::createInstance([
- 'project_id' => $this->parent_id,
+ 'project_id' => $this->project_id,
'task_id' => $this->id,
+ 'task_pid' => $this->parent_id ?: $this->id,
'userid' => $uid,
'owner' => 0,
])->save();
@@ -422,7 +429,7 @@ class ProjectTask extends AbstractModel
// 内容
if (Arr::exists($data, 'content')) {
ProjectTaskContent::updateInsert([
- 'project_id' => $this->parent_id,
+ 'project_id' => $this->project_id,
'task_id' => $this->id,
], [
'content' => $data['content'],
@@ -625,7 +632,7 @@ class ProjectTask extends AbstractModel
throw new ApiException('任务不存在');
}
//
- $project = Project::select([ 'projects.*', 'project_users.owner' ])
+ $project = Project::select(Project::projectSelect)
->join('project_users', 'projects.id', '=', 'project_users.project_id')
->where('projects.id', $task->project_id)
->where('project_users.userid', User::token2userid())
diff --git a/app/Models/ProjectTaskUser.php b/app/Models/ProjectTaskUser.php
index 36b366c8..70aea076 100644
--- a/app/Models/ProjectTaskUser.php
+++ b/app/Models/ProjectTaskUser.php
@@ -9,6 +9,7 @@ namespace App\Models;
* @property int $id
* @property int|null $project_id 项目ID
* @property int|null $task_id 任务ID
+ * @property int|null $task_pid 任务ID(如果是子任务则是父级任务ID)
* @property int|null $userid 成员ID
* @property int|null $owner 是否任务负责人
* @property \Illuminate\Support\Carbon|null $created_at
@@ -21,6 +22,7 @@ namespace App\Models;
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskUser whereOwner($value)
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskUser whereProjectId($value)
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskUser whereTaskId($value)
+ * @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskUser whereTaskPid($value)
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskUser whereUpdatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskUser whereUserid($value)
* @mixin \Eloquent
diff --git a/app/Module/Base.php b/app/Module/Base.php
index 50b3a055..68ee4c43 100755
--- a/app/Module/Base.php
+++ b/app/Module/Base.php
@@ -914,6 +914,16 @@ class Base
return true;
}
+ /**
+ * 检测 日期格式 或 时间格式
+ * @param string $str 需要检测的字符串
+ * @return bool
+ */
+ public static function isDateOrTime($str)
+ {
+ return self::isDate($str) || self::isTime($str);
+ }
+
/**
* 检测手机号码格式
* @param string $str 需要检测的字符串
diff --git a/package.json b/package.json
index d8fa3fe5..aca77aa6 100644
--- a/package.json
+++ b/package.json
@@ -18,6 +18,7 @@
"jquery": "^3.5.1",
"laravel-mix": "^6.0.6",
"lodash": "^4.17.19",
+ "moment": "^2.29.1",
"node-sass": "^4.11.0",
"postcss": "^8.1.14",
"resolve-url-loader": "^4.0.0",
@@ -37,6 +38,7 @@
"echarts": "^5.1.1",
"element-ui": "^2.15.2",
"tinymce": "^5.8.1",
+ "tui-calendar-hi": "^1.13.0-3",
"view-design-hi": "^4.6.1-1",
"vue-clipboard2": "^0.3.1",
"vue-emoji-picker": "^1.0.1",
diff --git a/resources/assets/js/pages/manage/calendar.vue b/resources/assets/js/pages/manage/calendar.vue
index 8b5a07af..a8fac00f 100644
--- a/resources/assets/js/pages/manage/calendar.vue
+++ b/resources/assets/js/pages/manage/calendar.vue
@@ -4,166 +4,212 @@
-
{{viewDay}}
+ {{rangeText}}
+
+
+
+
+
-
- - SUN
- - MON
- - TUE
- - WED
- - THU
- - FRI
- - SAT
-
-
+
diff --git a/resources/assets/js/pages/manage/components/ProjectList.vue b/resources/assets/js/pages/manage/components/ProjectList.vue
index d0611d94..3d1fd509 100644
--- a/resources/assets/js/pages/manage/components/ProjectList.vue
+++ b/resources/assets/js/pages/manage/components/ProjectList.vue
@@ -46,7 +46,7 @@
-
+
{{$L('隐藏已完成')}}
@@ -480,10 +480,15 @@ export default {
},
myList() {
- const {searchText, userId, projectDetail} = this;
+ const {searchText, projectCompleteHide, userId, projectDetail} = this;
const array = [];
projectDetail.project_column.forEach(({project_task, name}) => {
project_task.some((task) => {
+ if (projectCompleteHide) {
+ if (task.complete_at) {
+ return false;
+ }
+ }
if (searchText) {
if (!$A.strExists(task.name, searchText) && !$A.strExists(task.desc, searchText)) {
return false;
@@ -507,10 +512,15 @@ export default {
},
undoneList() {
- const {searchText, projectDetail} = this;
+ const {searchText, projectCompleteHide, projectDetail} = this;
const array = [];
projectDetail.project_column.forEach(({project_task, name}) => {
project_task.some((task) => {
+ if (projectCompleteHide) {
+ if (task.complete_at) {
+ return false;
+ }
+ }
if (searchText) {
if (!$A.strExists(task.name, searchText) && !$A.strExists(task.desc, searchText)) {
return false;
@@ -533,11 +543,25 @@ export default {
});
},
+ completedCount() {
+ const {projectDetail} = this;
+ let count = 0;
+ projectDetail.project_column.forEach(({project_task, name}) => {
+ count += project_task.filter(({complete_at}) => !!complete_at).length;
+ });
+ return count;
+ },
+
completedList() {
- const {searchText, projectDetail} = this;
+ const {searchText, projectCompleteHide, projectDetail} = this;
const array = [];
projectDetail.project_column.forEach(({project_task, name}) => {
project_task.some((task) => {
+ if (projectCompleteHide) {
+ if (task.complete_at) {
+ return false;
+ }
+ }
if (searchText) {
if (!$A.strExists(task.name, searchText) && !$A.strExists(task.desc, searchText)) {
return false;
diff --git a/resources/assets/js/pages/manage/messenger.vue b/resources/assets/js/pages/manage/messenger.vue
index 21fe372b..d1661c79 100644
--- a/resources/assets/js/pages/manage/messenger.vue
+++ b/resources/assets/js/pages/manage/messenger.vue
@@ -26,7 +26,7 @@
-
+
diff --git a/resources/assets/js/store/actions.js b/resources/assets/js/store/actions.js
index d789e940..23716eee 100644
--- a/resources/assets/js/store/actions.js
+++ b/resources/assets/js/store/actions.js
@@ -398,6 +398,30 @@ export default {
}
},
+ /**
+ * 获取任务列表
+ * @param state
+ * @param dispatch
+ * @param whereData
+ * @returns {Promise}
+ */
+ getTaskList({state, dispatch}, whereData) {
+ return new Promise(function (resolve, reject) {
+ if (state.userId === 0) {
+ reject()
+ return;
+ }
+ dispatch("call", {
+ url: 'project/task/lists',
+ data: whereData,
+ }).then(result => {
+ resolve(result)
+ }).catch(result => {
+ reject(result)
+ });
+ });
+ },
+
/**
* 获取任务信息
* @param state
diff --git a/resources/assets/sass/element.scss b/resources/assets/sass/element.scss
index f877c6f2..c9a2b74d 100644
--- a/resources/assets/sass/element.scss
+++ b/resources/assets/sass/element.scss
@@ -12,6 +12,21 @@ $--tooltip-font-size: 14px;
.el-dropdown-menu__item {
min-width: 100px;
line-height: 34px;
+ .item {
+ &.red {
+ color: #f00;
+ > i {
+ color: #f00;
+ }
+ }
+ &:hover {
+ &.red {
+ > i {
+ color: #f00;
+ }
+ }
+ }
+ }
}
.el-dropdown-menu__item--divided:before {
diff --git a/resources/assets/sass/pages/components/dialog-wrapper.scss b/resources/assets/sass/pages/components/dialog-wrapper.scss
index bcfd39be..a7b9065d 100644
--- a/resources/assets/sass/pages/components/dialog-wrapper.scss
+++ b/resources/assets/sass/pages/components/dialog-wrapper.scss
@@ -22,7 +22,7 @@
bottom: 0;
width: 100%;
height: 1px;
- background-color: #f2f2f2;
+ background-color: #f4f5f5;
}
.main-title {
display: flex;
diff --git a/resources/assets/sass/pages/components/project-list.scss b/resources/assets/sass/pages/components/project-list.scss
index 808c8972..c68aaccb 100644
--- a/resources/assets/sass/pages/components/project-list.scss
+++ b/resources/assets/sass/pages/components/project-list.scss
@@ -739,23 +739,12 @@
font-size: 16px;
}
}
- &.red {
- color: #f00;
- > i {
- color: #f00;
- }
- }
&:hover {
> i {
&.ivu-icon {
color: #66b1ff;
}
}
- &.red {
- > i {
- color: #f00;
- }
- }
}
}
}
diff --git a/resources/assets/sass/pages/page-calendar.scss b/resources/assets/sass/pages/page-calendar.scss
index 472308ca..66e03aaf 100644
--- a/resources/assets/sass/pages/page-calendar.scss
+++ b/resources/assets/sass/pages/page-calendar.scss
@@ -1,6 +1,4 @@
.page-calendar {
- display: flex;
- flex-direction: column;
.calendar-head {
display: flex;
align-items: flex-start;
@@ -30,100 +28,79 @@
}
}
}
- }
- }
- .calendar-box {
- flex: 1;
- height: 0;
- display: flex;
- flex-direction: column;
- padding: 0 48px;
- .head {
- display: flex;
- align-items: center;
- border-bottom: 1px solid #f4f5f5;
- > li {
+ .calendar-view {
+ margin-left: 36px;
flex: 1;
- list-style: none;
display: flex;
- align-items: center;
- justify-content: center;
- padding: 12px;
- position: relative;
- &:after {
- content: "";
- position: absolute;
- top: 0;
- right: 0;
- width: 1px;
- height: 100%;
- background-color: #f4f5f5;
- }
- &:last-child {
- &:after {
- display: none;
+ justify-content: flex-end;
+ > button {
+ &:focus {
+ box-shadow: none;
}
}
}
}
- .days {
+ }
+ .calendar-box {
+ padding: 0 48px;
+ .calendar-wrapper {
flex: 1;
- flex-shrink: 0;
- display: flex;
- flex-direction: column;
- > li {
- flex: 1;
- flex-shrink: 0;
- list-style: none;
- display: flex;
- flex-direction: column;
- border-bottom: 1px solid #f4f5f5;
- > ul {
- flex: 1;
- flex-shrink: 0;
+ position: relative;
+ &:before {
+ content: "";
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ height: 2px;
+ background-color: #ffffff;
+ z-index: 1;
+ }
+ .tui-full-calendar-popup-creation {
+ .tui-full-calendar-popup-section {
display: flex;
- > li {
- flex: 1;
- flex-shrink: 0;
- list-style: none;
- position: relative;
- display: flex;
- flex-direction: column;
- .time {
- padding: 10px 10px 0;
- > em {
- font-style: normal;
- display: inline-block;
- border-radius: 50%;
- min-height: 24px;
- min-width: 24px;
- line-height: 24px;
- text-align: center;
- &.cur-day {
- background-color: #2d8cf0;
- color: #ffffff;
- }
- }
- }
- &:after {
- content: "";
- position: absolute;
- top: 0;
- right: 0;
- width: 1px;
- height: 100%;
- background-color: #f4f5f5;
- }
- &:last-child {
- &:after {
- display: none;
- }
- }
- &.pre,
- &.after {
- color: #aaaaaa;
- }
+ justify-content: space-between;
+ margin-bottom: 6px;
+ }
+ .tui-full-calendar-section-title {
+ width: 100%;
+ }
+ .tui-full-calendar-section-start-date,
+ .tui-full-calendar-section-end-date {
+ width: 210px;
+ }
+ .tui-full-calendar-popup-location,
+ .tui-full-calendar-section-private,
+ .tui-full-calendar-section-allday,
+ .tui-full-calendar-section-state {
+ display: none;
+ }
+ }
+ .tui-full-calendar-popup-task {
+ .priority {
+ color: #ffffff;
+ padding: 2px 3px;
+ border-radius: 4px;
+ }
+ .tui-full-calendar-calendar-dot,
+ .tui-full-calendar-ic-priority {
+ opacity: 0;
+ }
+ }
+ .tui-datepicker {
+ .tui-calendar {
+ th,
+ td {
+ height: 35px;
}
+ .tui-calendar-prev-month.tui-calendar-date,
+ .tui-calendar-next-month.tui-calendar-date {
+ visibility: visible;
+ }
+ }
+ .tui-datepicker-body .tui-timepicker,
+ .tui-datepicker-footer .tui-timepicker {
+ padding: 16px 46px 16px 47px;
}
}
}
diff --git a/resources/assets/sass/pages/page-messenger.scss b/resources/assets/sass/pages/page-messenger.scss
index 3903e484..24047107 100644
--- a/resources/assets/sass/pages/page-messenger.scss
+++ b/resources/assets/sass/pages/page-messenger.scss
@@ -20,7 +20,7 @@
right: 0;
height: 100%;
width: 1px;
- background-color: #f2f2f2;
+ background-color: #f4f5f5;
}
.messenger-search {
display: flex;
@@ -83,8 +83,9 @@
list-style: none;
.user-avatar,
.icon-avatar {
- width: 46px;
- height: 46px;
+ width: 42px;
+ height: 42px;
+ margin: 2px;
flex-grow: 0;
flex-shrink: 0;
}
@@ -229,12 +230,12 @@
display: flex;
align-items: center;
justify-content: center;
- height: 54px;
+ height: 52px;
flex-shrink: 0;
- border-top: 1px solid #f2f2f2;
+ border-top: 1px solid #f4f5f5;
> i {
cursor: pointer;
- font-size: 28px;
+ font-size: 24px;
margin: 0 24px;
color: #aaaaaa;
opacity: 0.9;