no message
This commit is contained in:
parent
face5a943d
commit
7c6dcc3daa
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取任务
|
||||
*
|
||||
|
@ -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())
|
||||
|
@ -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())
|
||||
|
@ -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
|
||||
|
@ -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 需要检测的字符串
|
||||
|
@ -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",
|
||||
|
@ -4,166 +4,212 @@
|
||||
<div class="calendar-head">
|
||||
<div class="calendar-titbox">
|
||||
<div class="calendar-title">
|
||||
<h1>{{viewDay}}</h1>
|
||||
<h1>{{rangeText}}</h1>
|
||||
</div>
|
||||
<ButtonGroup class="calendar-arrow" size="small">
|
||||
<Button @click="preMonth"><Icon type="ios-arrow-back"></Icon></Button>
|
||||
<Button @click="curMonth">{{$L('今天')}}</Button>
|
||||
<Button @click="afterMonth"><Icon type="ios-arrow-forward"></Icon></Button>
|
||||
</ButtonGroup>
|
||||
<ButtonGroup class="calendar-view">
|
||||
<Button @click="setView('day')" :type="calendarView == 'day' ? 'primary' : 'default'">{{$L('日')}}</Button>
|
||||
<Button @click="setView('week')" :type="calendarView == 'week' ? 'primary' : 'default'">{{$L('周')}}</Button>
|
||||
<Button @click="setView('month')" :type="calendarView == 'month' ? 'primary' : 'default'">{{$L('月')}}</Button>
|
||||
</ButtonGroup>
|
||||
</div>
|
||||
</div>
|
||||
<div class="calendar-box">
|
||||
<ul class="head">
|
||||
<li>SUN</li>
|
||||
<li>MON</li>
|
||||
<li>TUE</li>
|
||||
<li>WED</li>
|
||||
<li>THU</li>
|
||||
<li>FRI</li>
|
||||
<li>SAT</li>
|
||||
</ul>
|
||||
<ul class="days">
|
||||
<li v-for="row in days">
|
||||
<ul>
|
||||
<li v-for="(item, key) in row" :key="key" :class="item.place">
|
||||
<div class="time"><em :class="{'cur-day': item.ymd == curDay}">{{item.day}}</em></div>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<Calendar
|
||||
ref="cal"
|
||||
:view="calendarView"
|
||||
:calendars="calendarLists"
|
||||
:schedules="scheduleLists"
|
||||
@beforeClickSchedule="onBeforeClickSchedule"
|
||||
@beforeUpdateSchedule="onBeforeUpdateSchedule"/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import 'tui-date-picker/dist/tui-date-picker.css';
|
||||
import 'tui-time-picker/dist/tui-time-picker.css';
|
||||
import 'tui-calendar-hi/dist/tui-calendar-hi.css'
|
||||
|
||||
import {mapState} from "vuex";
|
||||
import Calendar from "./components/Calendar";
|
||||
import moment from "moment";
|
||||
|
||||
const today = new Date();
|
||||
|
||||
const getDate = (type, start, value, operator) => {
|
||||
start = new Date(start);
|
||||
type = type.charAt(0).toUpperCase() + type.slice(1);
|
||||
|
||||
if (operator === '+') {
|
||||
start[`set${type}`](start[`get${type}`]() + value);
|
||||
} else {
|
||||
start[`set${type}`](start[`get${type}`]() - value);
|
||||
}
|
||||
|
||||
return start;
|
||||
};
|
||||
|
||||
export default {
|
||||
components: {Calendar},
|
||||
data() {
|
||||
return {
|
||||
viewDay: $A.formatDate("Y-m"),
|
||||
lists: [],
|
||||
|
||||
curDay: $A.formatDate("Y-m-d"),
|
||||
curInterval: null,
|
||||
rangeText: 'Calendar',
|
||||
rangeTime: [],
|
||||
|
||||
calendarView: 'month',
|
||||
|
||||
scheduleLoad: 0,
|
||||
scheduleList: [],
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.curInterval = setInterval(() => {
|
||||
this.curDay = $A.formatDate("Y-m-d");
|
||||
}, 60000)
|
||||
this.setRenderRange();
|
||||
},
|
||||
|
||||
destroyed() {
|
||||
clearInterval(this.curInterval)
|
||||
},
|
||||
computed: {
|
||||
...mapState(['userInfo']),
|
||||
...mapState(['projectList']),
|
||||
|
||||
days() {
|
||||
const days = this.getDateJson(new Date(this.viewDay));
|
||||
let row = days[days.length - 1].day >= 7 ? 5 : 6
|
||||
let array = [], tmp = [];
|
||||
for (let i = 0; i < days.length; i++) {
|
||||
let obj = days[i];
|
||||
tmp.push(obj);
|
||||
if ((i + 1) % 7 == 0) {
|
||||
array.push(tmp);
|
||||
tmp = [];
|
||||
calendarLists() {
|
||||
const {projectList} = this;
|
||||
return projectList.map((project) => {
|
||||
return {
|
||||
id: project.id,
|
||||
name: project.name,
|
||||
bgColor: '#F2F3F5',
|
||||
borderColor: '#F2F3F5'
|
||||
}
|
||||
if (array.length >= row) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return array;
|
||||
});
|
||||
},
|
||||
|
||||
scheduleLists() {
|
||||
return this.scheduleList.filter(({complete_at}) => !complete_at)
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
|
||||
watch: {
|
||||
rangeTime(time) {
|
||||
this.getTask(time);
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
getTask(time) {
|
||||
if (this.scheduleLoad > 0) {
|
||||
setTimeout(() => {
|
||||
this.getTask(time)
|
||||
}, 100)
|
||||
return;
|
||||
}
|
||||
this.scheduleLoad++;
|
||||
this.$store.dispatch("getTaskList", {
|
||||
time
|
||||
}).then(({data}) => {
|
||||
this.scheduleLoad--;
|
||||
data.data.some((task) => {
|
||||
let schedule = {
|
||||
id: task.id,
|
||||
calendarId: task.project_id,
|
||||
title: task.name,
|
||||
category: 'allday',
|
||||
start: new Date(task.start_at).toISOString(),
|
||||
end: new Date(task.end_at).toISOString(),
|
||||
color: "#515a6e",
|
||||
bgColor: task.color || '#E3EAFD',
|
||||
borderColor: task.p_color,
|
||||
complete_at: task.complete_at,
|
||||
preventClick: true,
|
||||
isChecked: false,
|
||||
};
|
||||
if (task.p_name) {
|
||||
schedule.priority = '<span class="priority" style="background-color:' + task.p_color + '">' + task.p_name + '</span>';
|
||||
}
|
||||
if (task.overdue) {
|
||||
schedule.color = "#f56c6c"
|
||||
schedule.bgColor = "#fef0f0"
|
||||
}
|
||||
let index = this.scheduleList.findIndex(({id}) => id === task.id);
|
||||
if (index > -1) {
|
||||
this.scheduleList.splice(index, 1, schedule)
|
||||
} else {
|
||||
this.scheduleList.push(schedule)
|
||||
}
|
||||
});
|
||||
}).catch(() => {
|
||||
this.scheduleLoad--;
|
||||
})
|
||||
},
|
||||
|
||||
preMonth() {
|
||||
const date = new Date(this.viewDay);
|
||||
date.setMonth(date.getMonth() - 1);
|
||||
this.viewDay = $A.formatDate("Y-m", date)
|
||||
this.$refs.cal.getInstance().prev();
|
||||
this.setRenderRange()
|
||||
},
|
||||
|
||||
curMonth() {
|
||||
this.viewDay = $A.formatDate("Y-m");
|
||||
this.$refs.cal.getInstance().today();
|
||||
this.setRenderRange()
|
||||
},
|
||||
|
||||
afterMonth() {
|
||||
const date = new Date(this.viewDay);
|
||||
date.setMonth(date.getMonth() + 1);
|
||||
this.viewDay = $A.formatDate("Y-m", date)
|
||||
this.$refs.cal.getInstance().next();
|
||||
this.setRenderRange()
|
||||
},
|
||||
|
||||
getDateJson(date){
|
||||
const getMonths = (yy) => {
|
||||
let months = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
|
||||
let months2 = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
|
||||
let mrun = yy % 100 == 0 && yy % 400 == 0 ? true : (yy % 4 == 0);
|
||||
return mrun ? months2 : months;
|
||||
}
|
||||
const zeroFill = (num) => {
|
||||
if (num < 9) return '0' + num;
|
||||
return '' + num;
|
||||
}
|
||||
//获取要绘制月份的年月,
|
||||
let yy = date.getFullYear();
|
||||
let mm = date.getMonth();
|
||||
//获取应该使用的月份数组。
|
||||
let month = getMonths(yy);
|
||||
//定义此月的1号的日期,获取其星期。
|
||||
let begin_date = new Date(yy, mm, 1);
|
||||
//获得上个月应该显示几天
|
||||
let pre_num = begin_date.getDay();
|
||||
//数组的总个数
|
||||
let const_num = 7 * 6;
|
||||
//当月的天数
|
||||
let cur_num = month[mm];
|
||||
//下个月的天数
|
||||
let after_num = const_num - cur_num - pre_num;
|
||||
//
|
||||
let preyy = yy;
|
||||
let premm = mm;
|
||||
//月份-1小于0,则前一月为上一年
|
||||
if (premm == 0) {
|
||||
preyy -= 1;
|
||||
}
|
||||
//上个月的月份以及天数
|
||||
premm = premm - 1 < 0 ? 11 : (premm - 1);
|
||||
let pre_max = month[premm];
|
||||
setView(view) {
|
||||
this.calendarView = view;
|
||||
this.setRenderRange()
|
||||
},
|
||||
|
||||
//下个月的月份
|
||||
let afteryy = yy;
|
||||
let aftermm = mm;
|
||||
if (aftermm == 11) {
|
||||
afteryy += 1;
|
||||
setRenderRange() {
|
||||
this.$nextTick(() => {
|
||||
const cal = this.$refs.cal.getInstance();
|
||||
let options = cal.getOptions();
|
||||
let viewName = cal.getViewName();
|
||||
let html = [];
|
||||
if (viewName === 'day') {
|
||||
html.push(this.currentCalendarDate('YYYY.MM.DD'));
|
||||
} else if (viewName === 'month' &&
|
||||
(!options.month.visibleWeeksCount || options.month.visibleWeeksCount > 4)) {
|
||||
html.push(this.currentCalendarDate('YYYY.MM'));
|
||||
} else {
|
||||
html.push(moment(cal.getDateRangeStart().getTime()).format('YYYY.MM.DD'));
|
||||
html.push(' ~ ');
|
||||
html.push(moment(cal.getDateRangeEnd().getTime()).format(' MM.DD'));
|
||||
}
|
||||
this.rangeText = html.join('');
|
||||
this.rangeTime = [moment(cal.getDateRangeStart().getTime()).format('YYYY-MM-DD'), moment(cal.getDateRangeEnd().getTime()).format('YYYY-MM-DD')];
|
||||
})
|
||||
},
|
||||
|
||||
currentCalendarDate(format) {
|
||||
const cal = this.$refs.cal.getInstance();
|
||||
let currentDate = moment([cal.getDate().getFullYear(), cal.getDate().getMonth(), cal.getDate().getDate()]);
|
||||
return currentDate.format(format);
|
||||
},
|
||||
|
||||
onBeforeClickSchedule({type, schedule}) {
|
||||
switch (type) {
|
||||
case "check":
|
||||
break;
|
||||
case "edit":
|
||||
this.$store.dispatch("openTask", schedule.id)
|
||||
break;
|
||||
case "delete":
|
||||
break;
|
||||
}
|
||||
aftermm = aftermm + 1 > 11 ? 0 : (aftermm + 1);
|
||||
//定义日历数组。
|
||||
let dateJson = [];
|
||||
//循环得到上个月的日期。
|
||||
for (let i = pre_num; i > 0; i--) {
|
||||
let obj = {year: preyy, month: premm + 1, day: (pre_max - i + 1), place: 'pre'};
|
||||
obj.ymd = obj.year + '-' + zeroFill(obj.month) + '-' + zeroFill(obj.day)
|
||||
dateJson.push(obj);
|
||||
}
|
||||
//循环添加当月日期
|
||||
for (let i = 1; i <= cur_num; i++) {
|
||||
let obj = {year: yy, month: mm + 1, day: i, place: 'cur'};
|
||||
obj.ymd = obj.year + '-' + zeroFill(obj.month) + '-' + zeroFill(obj.day)
|
||||
dateJson.push(obj);
|
||||
}
|
||||
//循环添加下个月的日期。
|
||||
for (let i = 1; i <= after_num; i++) {
|
||||
let obj = {year: afteryy, month: aftermm + 1, day: i, place: 'after'};
|
||||
obj.ymd = obj.year + '-' + zeroFill(obj.month) + '-' + zeroFill(obj.day)
|
||||
dateJson.push(obj);
|
||||
}
|
||||
return dateJson;
|
||||
},
|
||||
|
||||
onBeforeUpdateSchedule(res) {
|
||||
console.group('onBeforeUpdateSchedule');
|
||||
console.log('BeforeUpdate : ', res);
|
||||
console.groupEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
223
resources/assets/js/pages/manage/components/Calendar.vue
Normal file
223
resources/assets/js/pages/manage/components/Calendar.vue
Normal file
@ -0,0 +1,223 @@
|
||||
<template>
|
||||
<div ref="tuiCalendar" class="calendar-wrapper"></div>
|
||||
</template>
|
||||
<script>
|
||||
import Calendar from 'tui-calendar-hi';
|
||||
|
||||
const scheduleNeedProp = [
|
||||
'start',
|
||||
'category'
|
||||
];
|
||||
|
||||
export default {
|
||||
name: 'Calendar',
|
||||
props: {
|
||||
calendars: {
|
||||
type: Array,
|
||||
default() {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
schedules: {
|
||||
type: Array,
|
||||
default() {
|
||||
return [];
|
||||
},
|
||||
validator(value) {
|
||||
let notHave = false;
|
||||
|
||||
value.forEach(schedule => {
|
||||
notHave = scheduleNeedProp.some(prop => !schedule.hasOwnProperty(prop));
|
||||
});
|
||||
|
||||
return !notHave;
|
||||
}
|
||||
},
|
||||
view: {
|
||||
type: String,
|
||||
default: 'week'
|
||||
},
|
||||
taskView: {
|
||||
type: [Boolean, Array],
|
||||
default: true
|
||||
},
|
||||
scheduleView: {
|
||||
type: [Boolean, Array],
|
||||
default: true
|
||||
},
|
||||
theme: {
|
||||
type: Object,
|
||||
default() {
|
||||
return {
|
||||
'common.border': '1px solid #f4f5f5',
|
||||
'month.dayname.fontSize': '14px',
|
||||
'month.dayname.borderLeft': '1px solid #f4f5f5',
|
||||
'month.dayname.height': '50px',
|
||||
};
|
||||
}
|
||||
},
|
||||
template: {
|
||||
type: Object,
|
||||
default() {
|
||||
return {
|
||||
titlePlaceholder: function () {
|
||||
return "Task Description"
|
||||
}
|
||||
};
|
||||
}
|
||||
},
|
||||
week: {
|
||||
type: Object,
|
||||
default() {
|
||||
return {};
|
||||
}
|
||||
},
|
||||
month: {
|
||||
type: Object,
|
||||
default() {
|
||||
return {};
|
||||
}
|
||||
},
|
||||
useCreationPopup: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
useDetailPopup: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
timezones: {
|
||||
type: Array,
|
||||
default() {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
disableDblClick: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
disableClick: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
isReadOnly: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
usageStatistics: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
calendarInstance: null
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
calendars(newValue) {
|
||||
this.calendarInstance.setCalendars(newValue);
|
||||
},
|
||||
schedules() {
|
||||
this.calendarInstance.clear();
|
||||
this.reflectSchedules();
|
||||
},
|
||||
view(newValue) {
|
||||
this.calendarInstance.changeView(newValue, true);
|
||||
},
|
||||
taskView(newValue) {
|
||||
this.calendarInstance.setOptions({taskView: newValue});
|
||||
},
|
||||
scheduleView(newValue) {
|
||||
this.calendarInstance.setOptions({scheduleView: newValue});
|
||||
},
|
||||
theme: {
|
||||
handler(newValue) {
|
||||
this.calendarInstance.setTheme(this.cloneData(newValue));
|
||||
},
|
||||
deep: true
|
||||
},
|
||||
week: {
|
||||
handler(newValue) {
|
||||
const silent = this.view !== 'week' && this.view !== 'day';
|
||||
this.calendarInstance.setOptions({week: this.cloneData(newValue)}, silent);
|
||||
},
|
||||
deep: true
|
||||
},
|
||||
month: {
|
||||
handler(newValue) {
|
||||
const silent = this.view !== 'month';
|
||||
this.calendarInstance.setOptions({month: this.cloneData(newValue)}, silent);
|
||||
},
|
||||
deep: true
|
||||
},
|
||||
timezones(newValue) {
|
||||
this.calendarInstance.setOptions({timezones: newValue});
|
||||
},
|
||||
disableDblClick(newValue) {
|
||||
this.calendarInstance.setOptions({disableDblClick: newValue});
|
||||
},
|
||||
disableClick(newValue) {
|
||||
this.calendarInstance.setOptions({disableClick: newValue});
|
||||
},
|
||||
isReadOnly(newValue) {
|
||||
this.calendarInstance.setOptions({isReadOnly: newValue});
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.calendarInstance = new Calendar(this.$refs.tuiCalendar, {
|
||||
defaultView: this.view,
|
||||
taskView: this.taskView,
|
||||
scheduleView: this.scheduleView,
|
||||
theme: this.theme,
|
||||
template: this.template,
|
||||
week: this.week,
|
||||
month: this.month,
|
||||
calendars: this.calendars,
|
||||
useCreationPopup: this.useCreationPopup,
|
||||
useDetailPopup: this.useDetailPopup,
|
||||
timezones: this.timezones,
|
||||
disableDblClick: this.disableDblClick,
|
||||
disableClick: this.disableClick,
|
||||
isReadOnly: this.isReadOnly,
|
||||
usageStatistics: this.usageStatistics
|
||||
});
|
||||
this.addEventListeners();
|
||||
this.reflectSchedules();
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.calendarInstance.off();
|
||||
this.calendarInstance.destroy();
|
||||
},
|
||||
methods: {
|
||||
cloneData(data) {
|
||||
return JSON.parse(JSON.stringify(data));
|
||||
},
|
||||
addEventListeners() {
|
||||
for (const eventName of Object.keys(this.$listeners)) {
|
||||
this.calendarInstance.on(eventName, (...args) => this.$emit(eventName, ...args));
|
||||
}
|
||||
},
|
||||
reflectSchedules() {
|
||||
if (this.schedules.length > 0) {
|
||||
this.invoke('createSchedules', this.schedules);
|
||||
}
|
||||
},
|
||||
getRootElement() {
|
||||
return this.$refs.tuiCalendar;
|
||||
},
|
||||
getInstance() {
|
||||
return this.calendarInstance;
|
||||
},
|
||||
invoke(methodName, ...args) {
|
||||
let result;
|
||||
|
||||
if (this.calendarInstance[methodName]) {
|
||||
result = this.calendarInstance[methodName](...args);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
@ -46,7 +46,7 @@
|
||||
</li>
|
||||
</ul>
|
||||
<div class="project-switch">
|
||||
<div v-if="projectTablePanel && completedList.length > 0" class="project-checkbox">
|
||||
<div v-if="completedCount > 0" class="project-checkbox">
|
||||
<Checkbox :value="projectCompleteHide" @on-change="toggleBoolean('projectCompleteHide', $event)">{{$L('隐藏已完成')}}</Checkbox>
|
||||
</div>
|
||||
<div :class="['project-switch-button', !projectTablePanel ? 'menu' : '']" @click="toggleBoolean('projectTablePanel')">
|
||||
@ -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;
|
||||
|
@ -26,7 +26,7 @@
|
||||
<i v-else-if="dialog.group_type=='task'" class="iconfont icon-avatar task"></i>
|
||||
<Icon v-else class="icon-avatar" type="ios-people" />
|
||||
</template>
|
||||
<div v-else-if="dialog.dialog_user" class="user-avatar"><UserAvatar :userid="dialog.dialog_user.userid" :size="46" hide-icon-menu/></div>
|
||||
<div v-else-if="dialog.dialog_user" class="user-avatar"><UserAvatar :userid="dialog.dialog_user.userid" :size="42" hide-icon-menu/></div>
|
||||
<Icon v-else class="icon-avatar" type="md-person" />
|
||||
<div class="dialog-box">
|
||||
<div class="dialog-title">
|
||||
|
24
resources/assets/js/store/actions.js
vendored
24
resources/assets/js/store/actions.js
vendored
@ -398,6 +398,30 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取任务列表
|
||||
* @param state
|
||||
* @param dispatch
|
||||
* @param whereData
|
||||
* @returns {Promise<unknown>}
|
||||
*/
|
||||
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
|
||||
|
15
resources/assets/sass/element.scss
vendored
15
resources/assets/sass/element.scss
vendored
@ -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 {
|
||||
|
@ -22,7 +22,7 @@
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
background-color: #f2f2f2;
|
||||
background-color: #f4f5f5;
|
||||
}
|
||||
.main-title {
|
||||
display: flex;
|
||||
|
@ -739,23 +739,12 @@
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
&.red {
|
||||
color: #f00;
|
||||
> i {
|
||||
color: #f00;
|
||||
}
|
||||
}
|
||||
&:hover {
|
||||
> i {
|
||||
&.ivu-icon {
|
||||
color: #66b1ff;
|
||||
}
|
||||
}
|
||||
&.red {
|
||||
> i {
|
||||
color: #f00;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
151
resources/assets/sass/pages/page-calendar.scss
vendored
151
resources/assets/sass/pages/page-calendar.scss
vendored
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
13
resources/assets/sass/pages/page-messenger.scss
vendored
13
resources/assets/sass/pages/page-messenger.scss
vendored
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user