no message
This commit is contained in:
parent
e6794bce8c
commit
dd3df81c63
@ -16,6 +16,7 @@ use App\Module\Base;
|
|||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use Illuminate\Support\Arr;
|
use Illuminate\Support\Arr;
|
||||||
use Request;
|
use Request;
|
||||||
|
use function Swoole\Coroutine\Http\get;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @apiDefine project
|
* @apiDefine project
|
||||||
@ -440,87 +441,6 @@ class ProjectController extends AbstractController
|
|||||||
return Base::retError('删除失败');
|
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 添加任务列表
|
* 添加任务列表
|
||||||
*
|
*
|
||||||
@ -638,6 +558,73 @@ class ProjectController extends AbstractController
|
|||||||
return Base::retError('删除失败');
|
return Base::retError('删除失败');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取任务
|
||||||
|
*
|
||||||
|
* @apiParam {Number} task_id 任务ID
|
||||||
|
*/
|
||||||
|
public function task__one()
|
||||||
|
{
|
||||||
|
$user = User::authE();
|
||||||
|
if (Base::isError($user)) {
|
||||||
|
return $user;
|
||||||
|
} else {
|
||||||
|
$user = User::IDE($user['data']);
|
||||||
|
}
|
||||||
|
//
|
||||||
|
$task_id = intval(Request::input('task_id'));
|
||||||
|
// 任务
|
||||||
|
$task = ProjectTask::with(['taskUser', 'taskTag'])->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('项目不存在或不在成员列表内');
|
||||||
|
}
|
||||||
|
//
|
||||||
|
return Base::retSuccess('success', $task);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取子任务
|
||||||
|
*
|
||||||
|
* @apiParam {Number} task_id 任务ID
|
||||||
|
*/
|
||||||
|
public function task__sublist()
|
||||||
|
{
|
||||||
|
$user = User::authE();
|
||||||
|
if (Base::isError($user)) {
|
||||||
|
return $user;
|
||||||
|
} else {
|
||||||
|
$user = User::IDE($user['data']);
|
||||||
|
}
|
||||||
|
//
|
||||||
|
$task_id = intval(Request::input('task_id'));
|
||||||
|
// 任务
|
||||||
|
$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('项目不存在或不在成员列表内');
|
||||||
|
}
|
||||||
|
//
|
||||||
|
$data = ProjectTask::with(['taskUser', 'taskTag'])->where('parent_id', $task->id)->get();
|
||||||
|
return Base::retSuccess('success', $data);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {post} 添加任务
|
* {post} 添加任务
|
||||||
*
|
*
|
||||||
|
@ -35,6 +35,7 @@ use Illuminate\Database\Eloquent\SoftDeletes;
|
|||||||
* @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_complete
|
||||||
* @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 \App\Models\Project|null $project
|
||||||
@ -77,10 +78,11 @@ class ProjectTask extends AbstractModel
|
|||||||
'file_num',
|
'file_num',
|
||||||
'msg_num',
|
'msg_num',
|
||||||
'sub_num',
|
'sub_num',
|
||||||
'dialog_id',
|
'sub_complete',
|
||||||
'percent',
|
'percent',
|
||||||
'today',
|
'today',
|
||||||
'overdue',
|
'overdue',
|
||||||
|
'dialog_id',
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -107,31 +109,50 @@ class ProjectTask extends AbstractModel
|
|||||||
return $this->attributes['msg_num'];
|
return $this->attributes['msg_num'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成子任务数据
|
||||||
|
*/
|
||||||
|
private function generateSubTaskData()
|
||||||
|
{
|
||||||
|
if ($this->parent_id > 0) {
|
||||||
|
$this->attributes['sub_num'] = 0;
|
||||||
|
$this->attributes['sub_complete'] = 0;
|
||||||
|
$this->attributes['percent'] = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!isset($this->attributes['sub_num'])) {
|
||||||
|
$builder = self::whereParentId($this->id);
|
||||||
|
$this->attributes['sub_num'] = $builder->count();
|
||||||
|
$this->attributes['sub_complete'] = $builder->whereNotNull('complete_at')->count();
|
||||||
|
//
|
||||||
|
if ($this->complete_at) {
|
||||||
|
$this->attributes['percent'] = 100;
|
||||||
|
} elseif ($this->attributes['sub_complete'] == 0) {
|
||||||
|
$this->attributes['percent'] = 0;
|
||||||
|
} else {
|
||||||
|
$this->attributes['percent'] = intval($this->attributes['sub_complete'] / $this->attributes['sub_num'] * 100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 子任务数量
|
* 子任务数量
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
public function getSubNumAttribute()
|
public function getSubNumAttribute()
|
||||||
{
|
{
|
||||||
if ($this->parent_id > 0) {
|
$this->generateSubTaskData();
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (!isset($this->attributes['sub_num'])) {
|
|
||||||
$this->attributes['sub_num'] = self::whereParentId($this->id)->count();
|
|
||||||
}
|
|
||||||
return $this->attributes['sub_num'];
|
return $this->attributes['sub_num'];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 对话ID
|
* 子任务已完成数量
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
public function getDialogIdAttribute()
|
public function getSubCompleteAttribute()
|
||||||
{
|
{
|
||||||
if (!isset($this->attributes['dialog_id'])) {
|
$this->generateSubTaskData();
|
||||||
$this->attributes['dialog_id'] = intval(Project::whereId($this->project_id)->value('dialog_id'));
|
return $this->attributes['sub_complete'];
|
||||||
}
|
|
||||||
return $this->attributes['dialog_id'];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -140,22 +161,8 @@ class ProjectTask extends AbstractModel
|
|||||||
*/
|
*/
|
||||||
public function getPercentAttribute()
|
public function getPercentAttribute()
|
||||||
{
|
{
|
||||||
if ($this->parent_id > 0) {
|
$this->generateSubTaskData();
|
||||||
return 0;
|
return $this->attributes['percent'];
|
||||||
}
|
|
||||||
$builder = self::whereParentId($this->id);
|
|
||||||
if (!isset($this->attributes['sub_num'])) {
|
|
||||||
$this->attributes['sub_num'] = $builder->count();
|
|
||||||
}
|
|
||||||
$subTaskTotal = $this->attributes['sub_num'];
|
|
||||||
if ($subTaskTotal == 0) {
|
|
||||||
return $this->complete_at ? 100 : 0;
|
|
||||||
}
|
|
||||||
$subTaskComplete = $builder->whereNotNull('complete_at')->count();
|
|
||||||
if ($subTaskComplete == 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return intval($subTaskComplete / $subTaskTotal * 100);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -187,6 +194,18 @@ class ProjectTask extends AbstractModel
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对话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'];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\HasOne
|
* @return \Illuminate\Database\Eloquent\Relations\HasOne
|
||||||
*/
|
*/
|
||||||
|
@ -43,7 +43,6 @@
|
|||||||
<EDropdownItem command="exit">{{$L('退出项目')}}</EDropdownItem>
|
<EDropdownItem command="exit">{{$L('退出项目')}}</EDropdownItem>
|
||||||
</EDropdownMenu>
|
</EDropdownMenu>
|
||||||
</EDropdown>
|
</EDropdown>
|
||||||
|
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<div class="project-switch">
|
<div class="project-switch">
|
||||||
@ -66,7 +65,7 @@
|
|||||||
<li v-for="column in projectDetail.project_column" class="column-item">
|
<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} : {}">
|
||||||
<div class="column-head-title">
|
<div class="column-head-title">
|
||||||
<AutoTip>{{column.name}}</AutoTip>
|
<AutoTip>{{column.name}}</AutoTip>
|
||||||
<em>({{column.project_task.length}})</em>
|
<em>({{column.project_task.length}})</em>
|
||||||
@ -90,7 +89,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</EDropdownItem>
|
</EDropdownItem>
|
||||||
<EDropdownItem divided disabled>{{$L('颜色')}}</EDropdownItem>
|
<EDropdownItem divided disabled>{{$L('颜色')}}</EDropdownItem>
|
||||||
<EDropdownItem v-for="(c, k) in columnList" :key="k" :command="c">
|
<EDropdownItem v-for="(c, k) in columnColorList" :key="k" :command="c">
|
||||||
<div class="item">
|
<div class="item">
|
||||||
<i class="iconfont" :style="{color:c.color}" v-html="c.color == column.color ? '' : ''"></i>{{$L(c.name)}}
|
<i class="iconfont" :style="{color:c.color}" v-html="c.color == column.color ? '' : ''"></i>{{$L(c.name)}}
|
||||||
</div>
|
</div>
|
||||||
@ -123,13 +122,14 @@
|
|||||||
<div
|
<div
|
||||||
v-for="item in panelTask(column.project_task)"
|
v-for="item in panelTask(column.project_task)"
|
||||||
:class="['task-item task-draggable', item.complete_at ? 'complete' : '']"
|
:class="['task-item task-draggable', item.complete_at ? 'complete' : '']"
|
||||||
:style="item.color ? {backgroundColor: item.color} : null">
|
:style="item.color ? {backgroundColor: item.color} : {}">
|
||||||
<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>
|
||||||
<div v-if="item.loading === true" class="loading"><Loading /></div>
|
<div v-if="item.loading === true" class="loading"><Loading /></div>
|
||||||
<EDropdown
|
<EDropdown
|
||||||
v-else
|
v-else
|
||||||
trigger="click"
|
trigger="click"
|
||||||
|
size="small"
|
||||||
@command="dropTask(item, $event)">
|
@command="dropTask(item, $event)">
|
||||||
<Icon type="ios-more" />
|
<Icon type="ios-more" />
|
||||||
<EDropdownMenu slot="dropdown" class="project-list-more-dropdown-menu">
|
<EDropdownMenu slot="dropdown" class="project-list-more-dropdown-menu">
|
||||||
@ -154,9 +154,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</EDropdownItem>
|
</EDropdownItem>
|
||||||
<EDropdownItem divided disabled>{{$L('背景色')}}</EDropdownItem>
|
<EDropdownItem divided disabled>{{$L('背景色')}}</EDropdownItem>
|
||||||
<EDropdownItem v-for="(c, k) in taskList" :key="k" :command="c">
|
<EDropdownItem v-for="(c, k) in taskColorList" :key="k" :command="c">
|
||||||
<div class="item">
|
<div class="item">
|
||||||
<i class="iconfont" :style="{color:c.color||'#f9f9f9'}" v-html="c.color == column.color ? '' : ''"></i>{{$L(c.name)}}
|
<i class="iconfont" :style="{color:c.color||'#f9f9f9'}" v-html="c.color == item.color ? '' : ''"></i>{{$L(c.name)}}
|
||||||
</div>
|
</div>
|
||||||
</EDropdownItem>
|
</EDropdownItem>
|
||||||
</EDropdownMenu>
|
</EDropdownMenu>
|
||||||
@ -176,6 +176,7 @@
|
|||||||
<div v-if="item.msg_num > 0" class="task-icon">{{item.msg_num}}<Icon type="ios-chatbubbles-outline" /></div>
|
<div v-if="item.msg_num > 0" class="task-icon">{{item.msg_num}}<Icon type="ios-chatbubbles-outline" /></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="task-progress">
|
<div class="task-progress">
|
||||||
|
<div v-if="item.sub_num > 0" class="task-sub-num">{{item.sub_complete}}/{{item.sub_num}}</div>
|
||||||
<Progress :percent="item.percent" :stroke-width="6" />
|
<Progress :percent="item.percent" :stroke-width="6" />
|
||||||
<ETooltip
|
<ETooltip
|
||||||
v-if="item.end_at"
|
v-if="item.end_at"
|
||||||
@ -216,7 +217,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div v-else class="project-table">
|
<div v-else class="project-table">
|
||||||
<div class="project-table-head">
|
<div class="project-table-head">
|
||||||
<Row class="project-row">
|
<Row class="task-row">
|
||||||
<Col span="12"># {{$L('任务名称')}}</Col>
|
<Col span="12"># {{$L('任务名称')}}</Col>
|
||||||
<Col span="3">{{$L('列表')}}</Col>
|
<Col span="3">{{$L('列表')}}</Col>
|
||||||
<Col span="3">{{$L('优先级')}}</Col>
|
<Col span="3">{{$L('优先级')}}</Col>
|
||||||
@ -226,10 +227,9 @@
|
|||||||
</div>
|
</div>
|
||||||
<!--我的任务-->
|
<!--我的任务-->
|
||||||
<div :class="['project-table-body', !taskMyShow ? 'project-table-hide' : '']">
|
<div :class="['project-table-body', !taskMyShow ? 'project-table-hide' : '']">
|
||||||
<div @click="toggleBoolean('taskMyShow')">
|
<Row class="task-row">
|
||||||
<Row class="project-row">
|
|
||||||
<Col span="12" class="row-title">
|
<Col span="12" class="row-title">
|
||||||
<i class="iconfont"></i>
|
<i class="iconfont" @click="toggleBoolean('taskMyShow')"></i>
|
||||||
<div class="row-h1">{{$L('我的任务')}}</div>
|
<div class="row-h1">{{$L('我的任务')}}</div>
|
||||||
<div class="row-num">({{myList.length}})</div>
|
<div class="row-num">({{myList.length}})</div>
|
||||||
</Col>
|
</Col>
|
||||||
@ -238,39 +238,9 @@
|
|||||||
<Col span="3"></Col>
|
<Col span="3"></Col>
|
||||||
<Col span="3"></Col>
|
<Col span="3"></Col>
|
||||||
</Row>
|
</Row>
|
||||||
</div>
|
<TaskRow :list="myList" :color-list="taskColorList" @command="dropTask"/>
|
||||||
<div class="project-rows">
|
|
||||||
<Row v-for="(item, key) in myList" :key="key" class="project-row">
|
|
||||||
<Col span="12" class="row-item">
|
|
||||||
<Icon v-if="item.complete_at" class="completed" type="md-checkmark-circle" />
|
|
||||||
<Icon v-else type="md-radio-button-off" />
|
|
||||||
<div class="item-title">{{item.name}}</div>
|
|
||||||
<div v-if="item.file_num > 0" class="item-icon">{{item.file_num}}<Icon type="ios-link-outline" /></div>
|
|
||||||
<div v-if="item.msg_num > 0" class="item-icon">{{item.msg_num}}<Icon type="ios-chatbubbles-outline" /></div>
|
|
||||||
</Col>
|
|
||||||
<Col span="3">{{item.column_name}}</Col>
|
|
||||||
<Col span="3"><TaskPriority v-if="item.p_name" :backgroundColor="item.p_color">{{item.p_name}}</TaskPriority></Col>
|
|
||||||
<Col span="3" class="row-member">
|
|
||||||
<ul>
|
|
||||||
<li v-for="(user, keyu) in item.task_user" :key="keyu">
|
|
||||||
<UserAvatar :userid="user.userid" size="28"/>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</Col>
|
|
||||||
<Col span="3">
|
|
||||||
<ETooltip
|
|
||||||
v-if="item.end_at"
|
|
||||||
:class="['task-time', item.today ? 'today' : '', item.overdue ? 'overdue' : '']"
|
|
||||||
:open-delay="600"
|
|
||||||
:content="item.end_at">
|
|
||||||
<div>{{item.end_at ? expiresFormat(item.end_at) : ''}}</div>
|
|
||||||
</ETooltip>
|
|
||||||
</Col>
|
|
||||||
<em v-if="item.p_name" class="priority-color" :style="{backgroundColor:item.p_color}"></em>
|
|
||||||
</Row>
|
|
||||||
</div>
|
|
||||||
<div @click="addTaskOpen(0)">
|
<div @click="addTaskOpen(0)">
|
||||||
<Row class="project-row">
|
<Row class="task-row">
|
||||||
<Col span="12" class="row-add">
|
<Col span="12" class="row-add">
|
||||||
<Icon type="ios-add" /> {{$L('添加任务')}}
|
<Icon type="ios-add" /> {{$L('添加任务')}}
|
||||||
</Col>
|
</Col>
|
||||||
@ -283,10 +253,9 @@
|
|||||||
</div>
|
</div>
|
||||||
<!--未完成任务-->
|
<!--未完成任务-->
|
||||||
<div :class="['project-table-body', !taskUndoneShow ? 'project-table-hide' : '']">
|
<div :class="['project-table-body', !taskUndoneShow ? 'project-table-hide' : '']">
|
||||||
<div @click="toggleBoolean('taskUndoneShow')">
|
<Row class="task-row">
|
||||||
<Row class="project-row">
|
|
||||||
<Col span="12" class="row-title">
|
<Col span="12" class="row-title">
|
||||||
<i class="iconfont"></i>
|
<i class="iconfont" @click="toggleBoolean('taskUndoneShow')"></i>
|
||||||
<div class="row-h1">{{$L('未完成任务')}}</div>
|
<div class="row-h1">{{$L('未完成任务')}}</div>
|
||||||
<div class="row-num">({{undoneList.length}})</div>
|
<div class="row-num">({{undoneList.length}})</div>
|
||||||
</Col>
|
</Col>
|
||||||
@ -295,44 +264,13 @@
|
|||||||
<Col span="3"></Col>
|
<Col span="3"></Col>
|
||||||
<Col span="3"></Col>
|
<Col span="3"></Col>
|
||||||
</Row>
|
</Row>
|
||||||
</div>
|
<TaskRow :list="undoneList" :color-list="taskColorList" @command="dropTask"/>
|
||||||
<div class="project-rows">
|
|
||||||
<Row v-for="(item, key) in undoneList" :key="key" class="project-row">
|
|
||||||
<Col span="12" class="row-item">
|
|
||||||
<Icon v-if="item.complete_at" class="completed" type="md-checkmark-circle" />
|
|
||||||
<Icon v-else type="md-radio-button-off" />
|
|
||||||
<div class="item-title">{{item.name}}</div>
|
|
||||||
<div v-if="item.file_num > 0" class="item-icon">{{item.file_num}}<Icon type="ios-link-outline" /></div>
|
|
||||||
<div v-if="item.msg_num > 0" class="item-icon">{{item.msg_num}}<Icon type="ios-chatbubbles-outline" /></div>
|
|
||||||
</Col>
|
|
||||||
<Col span="3">{{item.column_name}}</Col>
|
|
||||||
<Col span="3"><TaskPriority v-if="item.p_name" :backgroundColor="item.p_color">{{item.p_name}}</TaskPriority></Col>
|
|
||||||
<Col span="3" class="row-member">
|
|
||||||
<ul>
|
|
||||||
<li v-for="(user, keyu) in item.task_user" :key="keyu">
|
|
||||||
<UserAvatar :userid="user.userid" size="28"/>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</Col>
|
|
||||||
<Col span="3">
|
|
||||||
<ETooltip
|
|
||||||
v-if="item.end_at"
|
|
||||||
:class="['task-time', item.today ? 'today' : '', item.overdue ? 'overdue' : '']"
|
|
||||||
:open-delay="600"
|
|
||||||
:content="item.end_at">
|
|
||||||
<div>{{item.end_at ? expiresFormat(item.end_at) : ''}}</div>
|
|
||||||
</ETooltip>
|
|
||||||
</Col>
|
|
||||||
<em v-if="item.p_name" class="priority-color" :style="{backgroundColor:item.p_color}"></em>
|
|
||||||
</Row>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<!--已完成任务-->
|
<!--已完成任务-->
|
||||||
<div :class="['project-table-body', !taskCompletedShow ? 'project-table-hide' : '']">
|
<div :class="['project-table-body', !taskCompletedShow ? 'project-table-hide' : '']">
|
||||||
<div @click="toggleBoolean('taskCompletedShow')">
|
<Row class="task-row">
|
||||||
<Row class="project-row">
|
|
||||||
<Col span="12" class="row-title">
|
<Col span="12" class="row-title">
|
||||||
<i class="iconfont"></i>
|
<i class="iconfont" @click="toggleBoolean('taskCompletedShow')"></i>
|
||||||
<div class="row-h1">{{$L('已完成任务')}}</div>
|
<div class="row-h1">{{$L('已完成任务')}}</div>
|
||||||
<div class="row-num">({{completedList.length}})</div>
|
<div class="row-num">({{completedList.length}})</div>
|
||||||
</Col>
|
</Col>
|
||||||
@ -341,37 +279,7 @@
|
|||||||
<Col span="3"></Col>
|
<Col span="3"></Col>
|
||||||
<Col span="3"></Col>
|
<Col span="3"></Col>
|
||||||
</Row>
|
</Row>
|
||||||
</div>
|
<TaskRow :list="completedList" :color-list="taskColorList" @command="dropTask"/>
|
||||||
<div class="project-rows">
|
|
||||||
<Row v-for="(item, key) in completedList" :key="key" class="project-row">
|
|
||||||
<Col span="12" class="row-item">
|
|
||||||
<Icon v-if="item.complete_at" class="completed" type="md-checkmark-circle" />
|
|
||||||
<Icon v-else type="md-radio-button-off" />
|
|
||||||
<div class="item-title">{{item.name}}</div>
|
|
||||||
<div v-if="item.file_num > 0" class="item-icon">{{item.file_num}}<Icon type="ios-link-outline" /></div>
|
|
||||||
<div v-if="item.msg_num > 0" class="item-icon">{{item.msg_num}}<Icon type="ios-chatbubbles-outline" /></div>
|
|
||||||
</Col>
|
|
||||||
<Col span="3">{{item.column_name}}</Col>
|
|
||||||
<Col span="3"><TaskPriority v-if="item.p_name" :backgroundColor="item.p_color">{{item.p_name}}</TaskPriority></Col>
|
|
||||||
<Col span="3" class="row-member">
|
|
||||||
<ul>
|
|
||||||
<li v-for="(user, keyu) in item.task_user" :key="keyu">
|
|
||||||
<UserAvatar :userid="user.userid" size="28"/>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</Col>
|
|
||||||
<Col span="3">
|
|
||||||
<ETooltip
|
|
||||||
v-if="item.end_at"
|
|
||||||
:class="['task-time', item.today ? 'today' : '', item.overdue ? 'overdue' : '']"
|
|
||||||
:open-delay="600"
|
|
||||||
:content="item.end_at">
|
|
||||||
<div>{{item.end_at ? expiresFormat(item.end_at) : ''}}</div>
|
|
||||||
</ETooltip>
|
|
||||||
</Col>
|
|
||||||
<em v-if="item.p_name" class="priority-color" :style="{backgroundColor:item.p_color}"></em>
|
|
||||||
</Row>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -455,9 +363,10 @@ import TaskAdd from "./TaskAdd";
|
|||||||
import {mapState} from "vuex";
|
import {mapState} from "vuex";
|
||||||
import UserInput from "../../../components/UserInput";
|
import UserInput from "../../../components/UserInput";
|
||||||
import TaskAddSimple from "./TaskAddSimple";
|
import TaskAddSimple from "./TaskAddSimple";
|
||||||
|
import TaskRow from "./TaskRow";
|
||||||
export default {
|
export default {
|
||||||
name: "ProjectList",
|
name: "ProjectList",
|
||||||
components: {Draggable, TaskAddSimple, UserInput, TaskAdd, TaskPriority},
|
components: {TaskRow, Draggable, TaskAddSimple, UserInput, TaskAdd, TaskPriority},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
nowTime: Math.round(new Date().getTime() / 1000),
|
nowTime: Math.round(new Date().getTime() / 1000),
|
||||||
@ -495,7 +404,7 @@ export default {
|
|||||||
transferData: {},
|
transferData: {},
|
||||||
transferLoad: 0,
|
transferLoad: 0,
|
||||||
|
|
||||||
columnList: [
|
columnColorList: [
|
||||||
{name: '默认', color: ''},
|
{name: '默认', color: ''},
|
||||||
{name: '灰色', color: '#6C6F71'},
|
{name: '灰色', color: '#6C6F71'},
|
||||||
{name: '棕色', color: '#695C56'},
|
{name: '棕色', color: '#695C56'},
|
||||||
@ -508,7 +417,7 @@ export default {
|
|||||||
{name: '红色', color: '#9D6058'},
|
{name: '红色', color: '#9D6058'},
|
||||||
],
|
],
|
||||||
|
|
||||||
taskList: [
|
taskColorList: [
|
||||||
{name: '默认', color: ''},
|
{name: '默认', color: ''},
|
||||||
{name: '黄色', color: '#FCF4A7'},
|
{name: '黄色', color: '#FCF4A7'},
|
||||||
{name: '蓝色', color: '#BCF2FD'},
|
{name: '蓝色', color: '#BCF2FD'},
|
||||||
@ -698,7 +607,9 @@ export default {
|
|||||||
success: ({ret, data, msg}) => {
|
success: ({ret, data, msg}) => {
|
||||||
if (ret === 1) {
|
if (ret === 1) {
|
||||||
$A.messageSuccess(msg);
|
$A.messageSuccess(msg);
|
||||||
this.addTaskSuccess(data)
|
this.addTaskSuccess(Object.assign(data, {
|
||||||
|
top: !!this.addData.top
|
||||||
|
}))
|
||||||
this.addShow = false;
|
this.addShow = false;
|
||||||
this.addData = {
|
this.addData = {
|
||||||
owner: 0,
|
owner: 0,
|
||||||
@ -723,7 +634,7 @@ export default {
|
|||||||
|
|
||||||
addTaskOpen(column_id) {
|
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 {
|
||||||
this.$set(this.addData, 'owner', this.userId);
|
this.$set(this.addData, 'owner', this.userId);
|
||||||
this.$set(this.addData, 'column_id', column_id);
|
this.$set(this.addData, 'column_id', column_id);
|
||||||
@ -962,6 +873,7 @@ export default {
|
|||||||
Object.keys(data).forEach(key => {
|
Object.keys(data).forEach(key => {
|
||||||
this.$set(task, key, data[key]);
|
this.$set(task, key, data[key]);
|
||||||
});
|
});
|
||||||
|
if (data.parent_id) this.getTaskOne(data.parent_id);
|
||||||
} else {
|
} else {
|
||||||
Object.keys(updata).forEach(key => {
|
Object.keys(updata).forEach(key => {
|
||||||
this.$set(task, key, backup[key]);
|
this.$set(task, key, backup[key]);
|
||||||
@ -972,6 +884,29 @@ export default {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getTaskOne(task_id) {
|
||||||
|
let task = null;
|
||||||
|
this.projectDetail.project_column.some(({project_task}) => {
|
||||||
|
task = project_task.find(({id}) => id === task_id);
|
||||||
|
if (task) return true;
|
||||||
|
});
|
||||||
|
if (!task) return;
|
||||||
|
//
|
||||||
|
$A.apiAjax({
|
||||||
|
url: 'project/task/one',
|
||||||
|
data: {
|
||||||
|
task_id: task.id
|
||||||
|
},
|
||||||
|
success: ({ret, data, msg}) => {
|
||||||
|
if (ret === 1) {
|
||||||
|
Object.keys(data).forEach(key => {
|
||||||
|
this.$set(task, key, data[key]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
archivedOrRemoveTask(task, type) {
|
archivedOrRemoveTask(task, type) {
|
||||||
if (task.loading === true) {
|
if (task.loading === true) {
|
||||||
return;
|
return;
|
||||||
|
220
resources/assets/js/pages/manage/components/TaskRow.vue
Normal file
220
resources/assets/js/pages/manage/components/TaskRow.vue
Normal file
@ -0,0 +1,220 @@
|
|||||||
|
<template>
|
||||||
|
<div class="task-rows">
|
||||||
|
<div v-for="(item, key) in list" :key="key">
|
||||||
|
<Row class="task-row" :style="item.color ? {backgroundColor: item.color, borderBottomColor: item.color} : {}">
|
||||||
|
<em v-if="item.p_name && item.parent_id === 0" class="priority-color" :style="{backgroundColor:item.p_color}"></em>
|
||||||
|
<Col span="12" :class="['row-item', item.complete_at ? 'complete' : '']">
|
||||||
|
<Icon
|
||||||
|
v-if="item.sub_num > 0"
|
||||||
|
:class="['sub-icon', item.sub_open ? 'active' : '']"
|
||||||
|
type="ios-arrow-forward"
|
||||||
|
@click="getSublist(item)"/>
|
||||||
|
<div v-if="item.loading === true" class="loading"><Loading /></div>
|
||||||
|
<EDropdown
|
||||||
|
v-else
|
||||||
|
trigger="click"
|
||||||
|
size="small"
|
||||||
|
@command="dropTask(item, $event)">
|
||||||
|
<div>
|
||||||
|
<Icon v-if="item.complete_at" class="completed" type="md-checkmark-circle" />
|
||||||
|
<Icon v-else type="md-radio-button-off" />
|
||||||
|
</div>
|
||||||
|
<EDropdownMenu slot="dropdown" class="project-list-more-dropdown-menu">
|
||||||
|
<EDropdownItem v-if="item.complete_at" command="uncomplete">
|
||||||
|
<div class="item red">
|
||||||
|
<Icon type="md-checkmark-circle-outline" />{{$L('标记未完成')}}
|
||||||
|
</div>
|
||||||
|
</EDropdownItem>
|
||||||
|
<EDropdownItem v-else command="complete">
|
||||||
|
<div class="item">
|
||||||
|
<Icon type="md-radio-button-off" />{{$L('完成')}}
|
||||||
|
</div>
|
||||||
|
</EDropdownItem>
|
||||||
|
<EDropdownItem command="archived">
|
||||||
|
<div class="item">
|
||||||
|
<Icon type="ios-filing" />{{$L('归档')}}
|
||||||
|
</div>
|
||||||
|
</EDropdownItem>
|
||||||
|
<EDropdownItem command="delete">
|
||||||
|
<div class="item">
|
||||||
|
<Icon type="md-trash" />{{$L('删除')}}
|
||||||
|
</div>
|
||||||
|
</EDropdownItem>
|
||||||
|
<template v-if="item.parent_id === 0">
|
||||||
|
<EDropdownItem v-if="item.parent_id === 0" divided disabled>{{$L('背景色')}}</EDropdownItem>
|
||||||
|
<EDropdownItem v-for="(c, k) in colorList" :key="k" :command="c">
|
||||||
|
<div class="item">
|
||||||
|
<i class="iconfont" :style="{color:c.color||'#f9f9f9'}" v-html="c.color == item.color ? '' : ''"></i>{{$L(c.name)}}
|
||||||
|
</div>
|
||||||
|
</EDropdownItem>
|
||||||
|
</template>
|
||||||
|
</EDropdownMenu>
|
||||||
|
</EDropdown>
|
||||||
|
<div class="item-title">{{item.name}}</div>
|
||||||
|
<div v-if="item.sub_num > 0" class="item-sub-num" @click="getSublist(item)">
|
||||||
|
<Icon type="md-git-merge" />
|
||||||
|
{{item.sub_complete}}/{{item.sub_num}}
|
||||||
|
</div>
|
||||||
|
<div class="item-icons">
|
||||||
|
<div v-if="item.file_num > 0" class="item-icon">{{item.file_num}}<Icon type="ios-link-outline" /></div>
|
||||||
|
<div v-if="item.msg_num > 0" class="item-icon">{{item.msg_num}}<Icon type="ios-chatbubbles-outline" /></div>
|
||||||
|
</div>
|
||||||
|
</Col>
|
||||||
|
<Col span="3">
|
||||||
|
<div v-if="item.parent_id === 0">{{item.column_name}}</div>
|
||||||
|
</Col>
|
||||||
|
<Col span="3">
|
||||||
|
<TaskPriority v-if="item.p_name && item.parent_id === 0" :backgroundColor="item.p_color">{{item.p_name}}</TaskPriority>
|
||||||
|
</Col>
|
||||||
|
<Col span="3" class="row-member">
|
||||||
|
<ul>
|
||||||
|
<li v-for="(user, keyu) in item.task_user" :key="keyu" v-if="keyu < 3">
|
||||||
|
<UserAvatar :userid="user.userid" size="28"/>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</Col>
|
||||||
|
<Col span="3">
|
||||||
|
<ETooltip
|
||||||
|
v-if="!item.complete_at && item.end_at"
|
||||||
|
:class="['task-time', item.today ? 'today' : '', item.overdue ? 'overdue' : '']"
|
||||||
|
:open-delay="600"
|
||||||
|
:content="item.end_at">
|
||||||
|
<div>{{expiresFormat(item.end_at)}}</div>
|
||||||
|
</ETooltip>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<TaskRow
|
||||||
|
v-if="item.sub_open===true"
|
||||||
|
:list="item.sub_list"
|
||||||
|
:color-list="colorList"
|
||||||
|
@command="dropTask"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import TaskPriority from "./TaskPriority";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "TaskRow",
|
||||||
|
components: {TaskPriority},
|
||||||
|
props: {
|
||||||
|
list: {
|
||||||
|
type: Array,
|
||||||
|
default: () => {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
colorList: {
|
||||||
|
type: Array,
|
||||||
|
default: () => {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
nowTime: Math.round(new Date().getTime() / 1000),
|
||||||
|
nowInterval: null,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.nowInterval = setInterval(() => {
|
||||||
|
this.nowTime = Math.round(new Date().getTime() / 1000);
|
||||||
|
}, 1000)
|
||||||
|
},
|
||||||
|
|
||||||
|
destroyed() {
|
||||||
|
clearInterval(this.nowInterval)
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
expiresFormat() {
|
||||||
|
const {nowTime} = this;
|
||||||
|
return function (date) {
|
||||||
|
let time = Math.round(new Date(date).getTime() / 1000) - nowTime;
|
||||||
|
if (time < 86400 * 4 && time > 0 ) {
|
||||||
|
return this.formatSeconds(time);
|
||||||
|
} else if (time <= 0) {
|
||||||
|
return '-' + this.formatSeconds(time * -1);
|
||||||
|
}
|
||||||
|
return this.formatTime(date)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
dropTask(task, command) {
|
||||||
|
this.$emit("command", task, command)
|
||||||
|
},
|
||||||
|
|
||||||
|
getSublist(task) {
|
||||||
|
if (task.sub_open === true) {
|
||||||
|
this.$set(task, 'sub_open', false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (task.loading === true) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.$set(task, 'loading', true);
|
||||||
|
$A.apiAjax({
|
||||||
|
url: 'project/task/sublist',
|
||||||
|
data: {
|
||||||
|
task_id: task.id,
|
||||||
|
},
|
||||||
|
complete: () => {
|
||||||
|
this.$set(task, 'loading', false);
|
||||||
|
},
|
||||||
|
error: () => {
|
||||||
|
$A.modalAlert('网络繁忙,请稍后再试!');
|
||||||
|
},
|
||||||
|
success: ({ret, data, msg}) => {
|
||||||
|
if (ret === 1) {
|
||||||
|
this.$set(task, 'sub_list', data);
|
||||||
|
this.$set(task, 'sub_open', true);
|
||||||
|
} else {
|
||||||
|
$A.modalError(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
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 || '';
|
||||||
|
},
|
||||||
|
|
||||||
|
formatBit(val) {
|
||||||
|
val = +val
|
||||||
|
return val > 9 ? val : '0' + val
|
||||||
|
},
|
||||||
|
|
||||||
|
formatSeconds(second) {
|
||||||
|
let duration
|
||||||
|
let days = Math.floor(second / 86400);
|
||||||
|
let hours = Math.floor((second % 86400) / 3600);
|
||||||
|
let minutes = Math.floor(((second % 86400) % 3600) / 60);
|
||||||
|
let seconds = Math.floor(((second % 86400) % 3600) % 60);
|
||||||
|
if (days > 0) {
|
||||||
|
if (hours > 0) duration = days + "d," + this.formatBit(hours) + "h";
|
||||||
|
else if (minutes > 0) duration = days + "d," + this.formatBit(minutes) + "min";
|
||||||
|
else if (seconds > 0) duration = days + "d," + this.formatBit(seconds) + "s";
|
||||||
|
else duration = days + "d";
|
||||||
|
}
|
||||||
|
else if (hours > 0) duration = this.formatBit(hours) + ":" + this.formatBit(minutes) + ":" + this.formatBit(seconds);
|
||||||
|
else if (minutes > 0) duration = this.formatBit(minutes) + ":" + this.formatBit(seconds);
|
||||||
|
else if (seconds > 0) duration = this.formatBit(seconds) + "s";
|
||||||
|
return duration;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
118
resources/assets/sass/project-list.scss
vendored
118
resources/assets/sass/project-list.scss
vendored
@ -389,6 +389,11 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
|
.task-sub-num {
|
||||||
|
font-size: 12px;
|
||||||
|
margin-right: 8px;
|
||||||
|
color: #777777;
|
||||||
|
}
|
||||||
.task-time {
|
.task-time {
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
color: #777777;
|
color: #777777;
|
||||||
@ -448,10 +453,10 @@
|
|||||||
}
|
}
|
||||||
.project-table {
|
.project-table {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
padding-top: 18px;
|
margin-top: 18px;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
.project-row {
|
.task-row {
|
||||||
background-color: #ffffff;
|
background-color: #ffffff;
|
||||||
border-bottom: 1px solid #F4F4F5;
|
border-bottom: 1px solid #F4F4F5;
|
||||||
position: relative;
|
position: relative;
|
||||||
@ -466,6 +471,12 @@
|
|||||||
&:last-child {
|
&:last-child {
|
||||||
border-right: 0;
|
border-right: 0;
|
||||||
}
|
}
|
||||||
|
&.complete {
|
||||||
|
.item-title {
|
||||||
|
color: #aaaaaa;
|
||||||
|
text-decoration: line-through;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.priority-color {
|
.priority-color {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@ -483,7 +494,7 @@
|
|||||||
border-bottom: 0;
|
border-bottom: 0;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
&.project-table-hide {
|
&.project-table-hide {
|
||||||
.project-rows {
|
.task-rows {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
.row-title {
|
.row-title {
|
||||||
@ -494,7 +505,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.project-table-head {
|
.project-table-head {
|
||||||
.project-row {
|
.task-row {
|
||||||
> div {
|
> div {
|
||||||
color: #888888;
|
color: #888888;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
@ -507,7 +518,33 @@
|
|||||||
&:hover {
|
&:hover {
|
||||||
box-shadow: 0 0 10px #e6ecfa;
|
box-shadow: 0 0 10px #e6ecfa;
|
||||||
}
|
}
|
||||||
.project-row {
|
.task-rows {
|
||||||
|
.task-rows {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
&:before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
box-shadow: rgb(0 0 0 / 8%) 0 0 8px 1px;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
.task-row {
|
||||||
|
background-color: #fcfcfd;
|
||||||
|
> div {
|
||||||
|
&.row-item {
|
||||||
|
padding-left: 56px;
|
||||||
|
.item-title {
|
||||||
|
color: #6C7D8C;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.task-row {
|
||||||
> div {
|
> div {
|
||||||
padding: 10px 12px;
|
padding: 10px 12px;
|
||||||
.task-time {
|
.task-time {
|
||||||
@ -546,24 +583,76 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
&.row-item {
|
&.row-item {
|
||||||
padding-left: 24px;
|
padding-left: 34px;
|
||||||
|
.loading {
|
||||||
|
width: 24px;
|
||||||
|
height: 14px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-start;
|
||||||
|
.common-loading {
|
||||||
|
margin: 0;
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
.ivu-icon {
|
.ivu-icon {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
color: #dddddd;
|
color: #cccccc;
|
||||||
|
margin-right: 8px;
|
||||||
&.completed {
|
&.completed {
|
||||||
color: #87d068;
|
color: #87d068;
|
||||||
}
|
}
|
||||||
|
&.sub-icon {
|
||||||
|
font-size: 16px;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
margin-left: -20px;
|
||||||
|
margin-right: 4px;
|
||||||
|
color: #cfcfcf;
|
||||||
|
transition: transform 0.2s;
|
||||||
|
&.active {
|
||||||
|
transform: rotate(90deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.item-title {
|
.item-title {
|
||||||
padding: 0 22px 0 10px;
|
flex: 1;
|
||||||
|
padding: 0 22px 0 0;
|
||||||
}
|
}
|
||||||
|
.item-sub-num {
|
||||||
|
flex-shrink: 0;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-left: 8px;
|
||||||
|
border: 1px solid #e8e8e8;
|
||||||
|
background-color: #ffffff;
|
||||||
|
padding: 0 6px 0 5px;
|
||||||
|
border-radius: 4px;
|
||||||
|
height: 20px;
|
||||||
|
line-height: 18px;
|
||||||
|
font-size: 12px;
|
||||||
|
.ivu-icon {
|
||||||
|
transform: scale(0.9);
|
||||||
|
font-size: 12px;
|
||||||
|
color: #333333;
|
||||||
|
margin-right: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.item-icons {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-left: 4px;
|
||||||
|
flex-shrink: 0;
|
||||||
.item-icon {
|
.item-icon {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
margin-right: 8px;
|
margin-left: 8px;
|
||||||
color: #777777;
|
color: #777777;
|
||||||
.ivu-icon,
|
.ivu-icon,
|
||||||
.iconfont {
|
.iconfont {
|
||||||
margin-left: 1px;
|
margin-left: 2px;
|
||||||
|
margin-right: 0;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: #666666;
|
color: #666666;
|
||||||
}
|
}
|
||||||
@ -572,15 +661,21 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
&.row-member {
|
&.row-member {
|
||||||
> ul {
|
> ul {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
overflow: auto;
|
|
||||||
margin-left: -4px;
|
margin-left: -4px;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow:ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
> li {
|
> li {
|
||||||
list-style: none;
|
list-style: none;
|
||||||
margin-left: -6px;
|
margin-left: -6px;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow:ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
&:first-child {
|
&:first-child {
|
||||||
margin-left: 0;
|
margin-left: 0;
|
||||||
}
|
}
|
||||||
@ -600,6 +695,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user