From 94f219cf5172d9bb0c9a7db34bd2c64ac360ae1e Mon Sep 17 00:00:00 2001 From: kuaifan Date: Thu, 3 Jun 2021 22:03:48 +0800 Subject: [PATCH] no message --- .../Controllers/Api/ProjectController.php | 141 ++- app/Http/Controllers/Api/SystemController.php | 53 ++ app/Http/Middleware/VerifyCsrfToken.php | 7 +- app/Models/ProjectTask.php | 27 +- app/Models/User.php | 2 +- resources/assets/js/components/UserAvatar.vue | 7 +- resources/assets/js/components/UserInput.vue | 6 +- .../pages/manage/components/project-list.vue | 805 ++++++++++-------- .../manage/components/project-message.vue | 4 +- .../js/pages/manage/components/task-add.vue | 27 +- .../assets/js/pages/manage/project-detail.vue | 5 +- .../assets/js/pages/manage/setting/index.vue | 14 +- .../js/pages/manage/setting/priority.vue | 122 ++- .../assets/js/pages/manage/setting/system.vue | 8 +- resources/assets/js/store/mutations.js | 49 +- resources/assets/js/store/state.js | 14 +- resources/assets/sass/iconfont.scss | 6 +- resources/assets/sass/main.scss | 68 +- webpack.mix.js | 7 +- 19 files changed, 979 insertions(+), 393 deletions(-) diff --git a/app/Http/Controllers/Api/ProjectController.php b/app/Http/Controllers/Api/ProjectController.php index 125f1c90..84e1a678 100755 --- a/app/Http/Controllers/Api/ProjectController.php +++ b/app/Http/Controllers/Api/ProjectController.php @@ -109,6 +109,9 @@ class ProjectController extends AbstractController } elseif (mb_strlen($name) > 32) { return Base::retError('项目名称最多只能设置32个字!'); } + if (mb_strlen($desc) > 255) { + return Base::retError('项目描述最多只能设置255个字!'); + } //流程 $columns = Request::input('columns'); if (!is_array($columns)) $columns = []; @@ -158,6 +161,136 @@ class ProjectController extends AbstractController }); } + /** + * 修改项目 + * + * @apiParam {Number} project_id 项目ID + * @apiParam {String} name 项目名称 + * @apiParam {String} [desc] 项目描述 + */ + public function edit() + { + $user = User::authE(); + if (Base::isError($user)) { + return $user; + } else { + $user = User::IDE($user['data']); + } + // + $project_id = intval(Request::input('project_id')); + $name = trim(Request::input('name', '')); + $desc = trim(Request::input('desc', '')); + if (mb_strlen($name) < 2) { + return Base::retError('项目名称不可以少于2个字!'); + } elseif (mb_strlen($name) > 32) { + return Base::retError('项目名称最多只能设置32个字!'); + } + if (mb_strlen($desc) > 255) { + return Base::retError('项目描述最多只能设置255个字!'); + } + // + $project = Project::select($this->projectSelect) + ->join('project_users', 'projects.id', '=', 'project_users.project_id') + ->where('projects.id', $project_id) + ->where('project_users.userid', $user->userid) + ->first(); + if (empty($project)) { + return Base::retError('项目不存在或不在成员列表内!'); + } + if (!$project->owner) { + return Base::retError('你不是项目负责人!'); + } + // + $project->name = $name; + $project->desc = $desc; + $project->save(); + // + return Base::retSuccess('修改成功'); + } + + /** + * 移交项目 + * + * @apiParam {Number} project_id 项目ID + * @apiParam {Number} owner_userid 新的项目负责人ID + */ + public function transfer() + { + $user = User::authE(); + if (Base::isError($user)) { + return $user; + } else { + $user = User::IDE($user['data']); + } + // + $project_id = intval(Request::input('project_id')); + $owner_userid = intval(Request::input('owner_userid')); + // + $project = Project::select($this->projectSelect) + ->join('project_users', 'projects.id', '=', 'project_users.project_id') + ->where('projects.id', $project_id) + ->where('project_users.userid', $user->userid) + ->first(); + if (empty($project)) { + return Base::retError('项目不存在或不在成员列表内!'); + } + if (!$project->owner) { + return Base::retError('你不是项目负责人!'); + } + // + if (!User::whereUserid($owner_userid)->exists()) { + return Base::retError('会员不存在!'); + } + // + return AbstractModel::transaction(function() use ($owner_userid, $project) { + ProjectUser::whereProjectId($project->id)->update(['owner' => 0]); + ProjectUser::updateInsert([ + 'project_id' => $project->id, + 'userid' => $owner_userid, + ], [ + 'owner' => 1, + ]); + // + return Base::retSuccess('移交成功'); + }); + } + + /** + * 删除项目 + * + * @apiParam {Number} project_id 项目ID + */ + public function delete() + { + $user = User::authE(); + if (Base::isError($user)) { + return $user; + } else { + $user = User::IDE($user['data']); + } + // + $project_id = intval(Request::input('project_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('项目不存在或不在成员列表内!'); + } + if (!$project->owner) { + return Base::retError('你不是项目负责人!'); + } + // + return AbstractModel::transaction(function() use ($project) { + ProjectTask::whereProjectId($project->id)->delete(); + $project->delete(); + // + return Base::retSuccess('删除成功'); + }); + } + /** * {post}【任务】添加任务 * @@ -184,6 +317,9 @@ class ProjectController extends AbstractController $times = Base::getPostValue('times'); $owner = Base::getPostValue('owner'); $subtasks = Base::getPostValue('subtasks'); + $p_level = Base::getPostValue('p_level'); + $p_name = Base::getPostValue('p_name'); + $p_color = Base::getPostValue('p_color'); // 项目 $project = Project::select($this->projectSelect) ->join('project_users', 'projects.id', '=', 'project_users.project_id') @@ -191,7 +327,7 @@ class ProjectController extends AbstractController ->where('project_users.userid', $user->userid) ->first(); if (empty($project)) { - return Base::retError('项目不存在或已被删除!'); + return Base::retError('项目不存在或不在成员列表内!'); } // 列表 if (is_array($column_id)) { @@ -224,6 +360,9 @@ class ProjectController extends AbstractController 'times' => $times, 'owner' => $owner, 'subtasks' => $subtasks, + 'p_level' => $p_level, + 'p_name' => $p_name, + 'p_color' => $p_color, ]); } } diff --git a/app/Http/Controllers/Api/SystemController.php b/app/Http/Controllers/Api/SystemController.php index 88206ec0..881d1235 100755 --- a/app/Http/Controllers/Api/SystemController.php +++ b/app/Http/Controllers/Api/SystemController.php @@ -62,6 +62,59 @@ class SystemController extends AbstractController return Base::retSuccess('success', $setting ?: json_decode('{}')); } + /** + * @api {post} api/system/priority 01. 获取优先级、保存优先级 + * + * @apiVersion 1.0.0 + * @apiGroup system + * @apiName priority + * + * @apiParam {Array} list 优先级数据,格式:[{name,color,days,priority}] + * + * @apiSuccess {Number} ret 返回状态码(1正确、0错误) + * @apiSuccess {String} msg 返回信息(错误描述) + * @apiSuccess {Object} data 返回数据 + */ + public function priority() + { + $type = trim(Request::input('type')); + if ($type == 'save') { + $user = User::authE(); + if (Base::isError($user)) { + return $user; + } else { + $user = User::IDE($user['data']); + } + if (!$user->isAdmin()) { + return Base::retError('权限不足!'); + } + $list = Base::getPostValue('list'); + $array = []; + if (empty($list) || !is_array($list)) { + return Base::retError('参数错误!'); + } + foreach ($list AS $item) { + if (empty($item['name']) || empty($item['color']) || empty($item['days']) || empty($item['priority'])) { + continue; + } + $array[] = [ + 'name' => $item['name'], + 'color' => $item['color'], + 'days' => intval($item['days']), + 'priority' => intval($item['priority']), + ]; + } + if (empty($array)) { + return Base::retError('参数为空!'); + } + $setting = Base::setting('priority', $array); + } else { + $setting = Base::setting('priority'); + } + // + return Base::retSuccess('success', $setting); + } + /** * @api {get} api/system/get/info 02. 获取终端详细信息 * diff --git a/app/Http/Middleware/VerifyCsrfToken.php b/app/Http/Middleware/VerifyCsrfToken.php index 52064db3..cd3a95c8 100644 --- a/app/Http/Middleware/VerifyCsrfToken.php +++ b/app/Http/Middleware/VerifyCsrfToken.php @@ -12,12 +12,15 @@ class VerifyCsrfToken extends Middleware * @var array */ protected $except = [ - //上传图片 + // 上传图片 'api/system/imgupload/', - //上传文件 + // 上传文件 'api/system/fileupload/', + // 保存任务优先级 + 'api/system/priority/', + // 添加任务 'api/project/task/add/', ]; diff --git a/app/Models/ProjectTask.php b/app/Models/ProjectTask.php index 1c7a750b..1572000a 100644 --- a/app/Models/ProjectTask.php +++ b/app/Models/ProjectTask.php @@ -4,6 +4,7 @@ namespace App\Models; use App\Module\Base; use Carbon\Carbon; +use Illuminate\Database\Eloquent\SoftDeletes; /** * Class ProjectTask @@ -20,15 +21,20 @@ use Carbon\Carbon; * @property string|null $archived_at 归档时间 * @property string|null $complete_at 完成时间 * @property int|null $userid 创建人 + * @property int|null $p_level 优先级 + * @property string|null $p_name 优先级名称 + * @property string|null $p_color 优先级颜色 * @property \Illuminate\Support\Carbon|null $created_at * @property \Illuminate\Support\Carbon|null $updated_at * @property \Illuminate\Support\Carbon|null $deleted_at * @property-read int $file_num * @property-read int $msg_num - * @property-read int $sub_num * @property-read bool $overdue * @property-read int $percent + * @property-read int $sub_num * @property-read bool $today + * @property-read \Illuminate\Database\Eloquent\Collection|\App\Models\ProjectTaskTag[] $taskTag + * @property-read int|null $task_tag_count * @property-read \Illuminate\Database\Eloquent\Collection|\App\Models\ProjectTaskUser[] $taskUser * @property-read int|null $task_user_count * @method static \Illuminate\Database\Eloquent\Builder|ProjectTask newModelQuery() @@ -43,17 +49,19 @@ use Carbon\Carbon; * @method static \Illuminate\Database\Eloquent\Builder|ProjectTask whereEndAt($value) * @method static \Illuminate\Database\Eloquent\Builder|ProjectTask whereId($value) * @method static \Illuminate\Database\Eloquent\Builder|ProjectTask whereName($value) + * @method static \Illuminate\Database\Eloquent\Builder|ProjectTask wherePColor($value) + * @method static \Illuminate\Database\Eloquent\Builder|ProjectTask wherePLevel($value) + * @method static \Illuminate\Database\Eloquent\Builder|ProjectTask wherePName($value) * @method static \Illuminate\Database\Eloquent\Builder|ProjectTask whereParentId($value) * @method static \Illuminate\Database\Eloquent\Builder|ProjectTask whereProjectId($value) * @method static \Illuminate\Database\Eloquent\Builder|ProjectTask whereStartAt($value) * @method static \Illuminate\Database\Eloquent\Builder|ProjectTask whereUpdatedAt($value) * @method static \Illuminate\Database\Eloquent\Builder|ProjectTask whereUserid($value) * @mixin \Eloquent - * @property-read \Illuminate\Database\Eloquent\Collection|\App\Models\ProjectTaskTag[] $taskTag - * @property-read int|null $task_tag_count */ class ProjectTask extends AbstractModel { + use SoftDeletes; protected $appends = [ 'file_num', @@ -187,20 +195,26 @@ class ProjectTask extends AbstractModel $times = $params['times']; $owner = $params['owner']; $subtasks = $params['subtasks']; + $p_level = intval($params['p_level']); + $p_name = $params['p_name']; + $p_color = $params['p_color']; // $retPre = $parent_id ? '子任务' : '任务'; $task = self::createInstance(); $task->parent_id = $parent_id; $task->project_id = $project_id; $task->column_id = $column_id; + $task->p_level = $p_level; + $task->p_name = $p_name; + $task->p_color = $p_color; if ($content) { $task->desc = Base::getHtml($content); } // 标题 if (empty($name)) { - return Base::retError($retPre . '名称不能为空!'); + return Base::retError($retPre . '描述不能为空!'); } elseif (mb_strlen($name) > 255) { - return Base::retError($retPre . '名称最多只能设置255个字!'); + return Base::retError($retPre . '描述最多只能设置255个字!'); } $task->name = $name; // 时间 @@ -246,6 +260,9 @@ class ProjectTask extends AbstractModel $subtask['parent_id'] = $task->id; $subtask['project_id'] = $task->project_id; $subtask['column_id'] = $task->column_id; + $subtask['p_level'] = $task->p_level; + $subtask['p_name'] = $task->p_name; + $subtask['p_color'] = $task->p_color; $res = self::addTask($subtask); if (Base::isError($res)) { return $res; diff --git a/app/Models/User.php b/app/Models/User.php index 245577ef..757fdcef 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -69,7 +69,7 @@ class User extends AbstractModel parent::updateInstance($param); // if (isset($param['line_at']) && $this->userid) { - Cache::put("User::online:" . $this->userid, time(), Carbon::now()->addSeconds(30)); + Cache::put("User::online:" . $this->userid, time(), Carbon::now()->addSeconds(60)); } } diff --git a/resources/assets/js/components/UserAvatar.vue b/resources/assets/js/components/UserAvatar.vue index 452a5ad9..07fb1d6b 100755 --- a/resources/assets/js/components/UserAvatar.vue +++ b/resources/assets/js/components/UserAvatar.vue @@ -2,8 +2,11 @@ + :transfer="transfer"> +
+

{{$L('昵称')}}: {{user.nickname}}

+

{{$L('职位/职称')}}: {{user.profession || '-'}}

+
{{nickname}}
diff --git a/resources/assets/js/components/UserInput.vue b/resources/assets/js/components/UserInput.vue index a0326461..8695d469 100755 --- a/resources/assets/js/components/UserInput.vue +++ b/resources/assets/js/components/UserInput.vue @@ -60,10 +60,10 @@ } }, mounted() { - if (!$A.isArray(this.value)) { - this.$emit('input', [this.value]); - } else { + if ($A.isArray(this.value)) { this.values = $A.cloneJSON(this.value); + } else { + this.$emit('input', this.value ? [this.value] : []); } this.$nextTick(() => { this.ready = true; diff --git a/resources/assets/js/pages/manage/components/project-list.vue b/resources/assets/js/pages/manage/components/project-list.vue index f5191050..4e3e2120 100644 --- a/resources/assets/js/pages/manage/components/project-list.vue +++ b/resources/assets/js/pages/manage/components/project-list.vue @@ -29,7 +29,15 @@
  • - + + + + {{$L('项目设置')}} + {{$L('移交项目')}} + {{$L('删除项目')}} + + +
  • @@ -48,7 +56,7 @@
    {{column.project_task.length}}
    @@ -93,333 +102,157 @@ Expiration -
    - - - -
    My task
    -
    (5)
    - - - - - -
    - - - -
    Maxxis Tyres
    -
    5
    -
    5
    - - Next Up - Important - -
      -
    • - -
    • -
    • - -
    • -
    • - -
    • -
    - - 6 June, 2021 -
    - - - -
    Maxxis Tyres
    -
    5
    -
    5
    - - Next Up - Unimportance - -
      -
    • - -
    • -
    • - -
    • -
    • - -
    • -
    - - 6 June, 2021 -
    - - - -
    Maxxis Tyres
    -
    5
    -
    5
    - - Next Up - Important - -
      -
    • - -
    • -
    • - -
    • -
    • - -
    • -
    - - 6 June, 2021 -
    - - - -
    Maxxis Tyres
    -
    5
    -
    5
    -
    6
    - - Next Up - Important - -
      -
    • - -
    • -
    • - -
    • -
    • - -
    • -
    - - 6 June, 2021 -
    + +
    +
    + + + +
    My task
    +
    ({{myList.length}})
    + + + + + +
    +
    +
    + + + + +
    {{item.name}}
    +
    {{item.file_num}}
    +
    {{item.msg_num}}
    + + {{item.column_name}} + {{item.p_name}} + +
      +
    • + +
    • +
    + + + + {{item.end_at ? expiresFormat(item.end_at) : ''}} + + + +
    +
    +
    + + + {{$L('添加任务')}} + + + + + + +
    -
    - - - -
    Undone
    -
    (5)
    - - - - - -
    - - - -
    Maxxis Tyres
    -
    5
    -
    5
    - - Next Up - Unimportance - -
      -
    • - -
    • -
    • - -
    • -
    • - -
    • -
    - - 6 June, 2021 -
    - - - -
    Maxxis Tyres
    -
    5
    -
    5
    - - Next Up - Unimportance - -
      -
    • - -
    • -
    • - -
    • -
    • - -
    • -
    - - 6 June, 2021 -
    - - - -
    Maxxis Tyres
    -
    5
    -
    5
    - - Next Up - Important - -
      -
    • - -
    • -
    • - -
    • -
    • - -
    • -
    - - 6 June, 2021 -
    - - - -
    Maxxis Tyres
    -
    5
    -
    5
    - - Next Up - Important - -
      -
    • - -
    • -
    • - -
    • -
    • - -
    • -
    - - 6 June, 2021 -
    + +
    +
    + + + +
    Undone
    +
    ({{undoneList.length}})
    + + + + + +
    +
    +
    + + + + +
    {{item.name}}
    +
    {{item.file_num}}
    +
    {{item.msg_num}}
    + + {{item.column_name}} + {{item.p_name}} + +
      +
    • + +
    • +
    + + + + {{item.end_at ? expiresFormat(item.end_at) : ''}} + + + +
    +
    -
    - - - -
    Completed
    -
    (5)
    - - - - - -
    - - - -
    Maxxis Tyres
    -
    5
    -
    5
    - - Hi Progress - Important - -
      -
    • - -
    • -
    • - -
    • -
    • - -
    • -
    - - 6 June, 2021 -
    - - - -
    Maxxis Tyres
    -
    5
    -
    5
    - - Hi Progress - Unimportance - -
      -
    • - -
    • -
    • - -
    • -
    • - -
    • -
    - - 6 June, 2021 -
    - - - -
    Maxxis Tyres
    -
    5
    -
    5
    - - Hi Progress - Important - -
      -
    • - -
    • -
    • - -
    • -
    • - -
    • -
    - - 6 June, 2021 -
    - - - -
    Maxxis Tyres
    -
    5
    -
    5
    - - Next Up - Unimportance - -
      -
    • - -
    • -
    • - -
    • -
    • - -
    • -
    - - 6 June, 2021 -
    + +
    +
    + + + +
    Completed
    +
    ({{completedList.length}})
    + + + + + +
    +
    +
    + + + + +
    {{item.name}}
    +
    {{item.file_num}}
    +
    {{item.msg_num}}
    + + {{item.column_name}} + {{item.p_name}} + +
      +
    • + +
    • +
    + + + + {{item.end_at ? expiresFormat(item.end_at) : ''}} + + + +
    +
    @@ -439,6 +272,43 @@
    + + + +
    + + + + + + +
    +
    + + +
    +
    + + + +
    + + + +
    +
    + + +
    +
    @@ -637,12 +507,21 @@ border-radius: 12px; padding: 12px; transition: box-shadow 0.3s; + position: relative; &:hover { box-shadow: 0 0 10px #e6ecfa; } &:first-child { margin-top: 16px; } + .priority-color { + position: absolute; + top: 12px; + left: 0; + width: 3px; + height: 42px; + border-radius: 2px; + } .task-head { display: flex; align-items: flex-start; @@ -770,6 +649,7 @@ .project-row { background-color: #ffffff; border-bottom: 1px solid #F4F4F5; + position: relative; > div { display: flex; align-items: center; @@ -782,6 +662,13 @@ border-right: 0; } } + .priority-color { + position: absolute; + top: 0; + left: 0; + bottom: -1px; + width: 3px; + } } .project-table-head, .project-table-body { @@ -790,6 +677,16 @@ border: 1px solid #F4F4F5; border-bottom: 0; overflow: hidden; + &.project-table-hide { + .project-rows { + display: none; + } + .row-title { + .iconfont { + transform: rotate(-90deg); + } + } + } } .project-table-head { .project-row { @@ -801,18 +698,38 @@ } } .project-table-body { + transition: box-shadow 0.3s; &:hover { box-shadow: 0 0 10px #e6ecfa; } .project-row { > div { padding: 10px 12px; + .task-time { + &.overdue, + &.today { + color: #ffffff; + padding: 1px 5px; + font-size: 13px; + border-radius: 3px; + } + &.overdue { + font-weight: 600; + background-color: #ed4014; + } + &.today { + font-weight: 500; + background-color: #ff9900; + } + } &.row-title { font-size: 14px; font-weight: 500; color: #333333; padding-left: 14px; .iconfont { + cursor: pointer; + transition: transform 0.3s; font-size: 12px; } .row-h1 { @@ -824,7 +741,7 @@ } } &.row-item { - padding-left: 20px; + padding-left: 24px; .ivu-icon { font-size: 16px; color: #dddddd; @@ -862,14 +779,21 @@ &:first-child { margin-left: 0; } - .ivu-avatar { - width: 28px; - height: 28px; - border: 2px solid #ffffff; - } } } } + &.row-add { + display: flex; + align-items: center; + height: 48px; + cursor: pointer; + > i { + font-size: 24px; + color: #777777; + margin-left: 32px; + margin-right: 4px; + } + } } } } @@ -882,11 +806,13 @@ import TaskPriority from "./task-priority"; import TaskAdd from "./task-add"; import {mapState} from "vuex"; +import UserInput from "../../../components/UserInput"; export default { name: "ProjectList", - components: {TaskAdd, TaskPriority}, + components: {UserInput, TaskAdd, TaskPriority}, data() { return { + nowTime: Math.round(new Date().getTime() / 1000), searchText: '', addShow: false, @@ -895,15 +821,108 @@ export default { column_id: 0, times: [], subtasks: [], + p_level: 0, + p_name: '', + p_color: '', }, taskLoad: 0, + + settingShow: false, + settingData: {}, + settingLoad: 0, + + transferShow: false, + transferData: {}, + transferLoad: 0, } }, mounted() { - + setInterval(() => { + this.nowTime = Math.round(new Date().getTime() / 1000); + }, 1000) }, computed: { ...mapState(['userId', 'projectDetail', 'projectLoad', 'projectMsgUnread']), + + panelTask() { + const {searchText} = this; + return function (project_task) { + if (searchText) { + return project_task.filter((task) => { + return $A.strExists(task.name, searchText) || $A.strExists(task.desc, searchText); + }); + } + return project_task; + } + }, + + myList() { + const {searchText, userId, projectDetail} = this; + const array = []; + projectDetail.project_column.forEach(({project_task, name}) => { + project_task.some((task) => { + if (searchText) { + if (!$A.strExists(task.name, searchText) && !$A.strExists(task.desc, searchText)) { + return false; + } + } + if (task.task_user.find(({userid}) => userid == userId)) { + task.column_name = name; + array.push(task); + } + }); + }); + return array; + }, + + undoneList() { + const {searchText, projectDetail} = this; + const array = []; + projectDetail.project_column.forEach(({project_task, name}) => { + project_task.some((task) => { + if (searchText) { + if (!$A.strExists(task.name, searchText) && !$A.strExists(task.desc, searchText)) { + return false; + } + } + if (!task.complete_at) { + task.column_name = name; + array.push(task); + } + }); + }); + return array; + }, + + completedList() { + const {searchText, projectDetail} = this; + const array = []; + projectDetail.project_column.forEach(({project_task, name}) => { + project_task.some((task) => { + if (searchText) { + if (!$A.strExists(task.name, searchText) && !$A.strExists(task.desc, searchText)) { + return false; + } + } + if (task.complete_at) { + task.column_name = name; + array.push(task); + } + }); + }); + return array; + }, + + expiresFormat() { + const {nowTime} = this; + return function (date) { + let time = Math.round(new Date(date).getTime() / 1000) - nowTime; + if (time > 0 && time < 86400 * 4) { + return this.formatSeconds(time); + } + return this.formatTime(date) + } + }, }, methods: { addOpen(column_id) { @@ -934,6 +953,100 @@ export default { }); }, + onSetting() { + this.settingLoad++; + $A.apiAjax({ + url: 'project/edit', + data: this.settingData, + complete: () => { + this.settingLoad--; + }, + success: ({ret, data, msg}) => { + if (ret === 1) { + $A.messageSuccess(msg); + this.$set(this.projectDetail, 'name', this.settingData.name); + this.$set(this.projectDetail, 'desc', this.settingData.desc); + this.settingShow = false; + } else { + $A.modalError(msg); + } + } + }); + }, + + onTransfer() { + this.transferLoad++; + $A.apiAjax({ + url: 'project/transfer', + data: { + project_id: this.transferData.project_id, + owner_userid: this.transferData.owner_userid[0], + }, + complete: () => { + this.transferLoad--; + }, + success: ({ret, data, msg}) => { + if (ret === 1) { + $A.messageSuccess(msg); + this.$store.commit('getProjectDetail', this.transferData.project_id); + this.transferShow = false; + } else { + $A.modalError(msg); + } + } + }); + }, + + onDelete() { + $A.modalConfirm({ + title: '删除项目', + content: '你确定要删除此项目吗?', + loading: true, + onOk: () => { + $A.apiAjax({ + url: 'project/delete', + data: { + project_id: this.projectDetail.id, + }, + error: () => { + this.$Modal.remove(); + $A.modalAlert('网络繁忙,请稍后再试!'); + }, + success: ({ret, data, msg}) => { + this.$Modal.remove(); + if (ret === 1) { + $A.messageSuccess(msg); + this.goForward({path: '/manage/dashboard'}, true); + }else{ + $A.modalError(msg, 301); + } + } + }); + } + }); + }, + + projectDropdown(name) { + switch (name) { + case "setting": + this.$set(this.settingData, 'project_id', this.projectDetail.id); + this.$set(this.settingData, 'name', this.projectDetail.name); + this.$set(this.settingData, 'desc', this.projectDetail.desc); + this.settingShow = true; + break; + + case "transfer": + this.$set(this.transferData, 'project_id', this.projectDetail.id); + this.$set(this.transferData, 'owner_userid', [this.projectDetail.owner_userid]); + this.transferShow = true; + break; + + case "delete": + this.onDelete(); + break; + } + }, + formatTime(date) { let time = Math.round(new Date(date).getTime() / 1000), string = ''; @@ -946,6 +1059,26 @@ export default { } return string || ''; }, + + formatBit: function formatBit(val) { + val = +val + return val > 9 ? val : '0' + val + }, + + formatSeconds: function 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) { + return days + "d," + this.formatBit(hours) + "h"; + } + 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; + }, } } diff --git a/resources/assets/js/pages/manage/components/project-message.vue b/resources/assets/js/pages/manage/components/project-message.vue index c9c3f766..c54dc3dc 100644 --- a/resources/assets/js/pages/manage/components/project-message.vue +++ b/resources/assets/js/pages/manage/components/project-message.vue @@ -159,7 +159,7 @@ } &.online { &:before { - background-color: #509E76; + background-color: #87d068; } } } @@ -210,7 +210,7 @@ } &.online { &:before { - background-color: #509E76; + background-color: #87d068; } } } diff --git a/resources/assets/js/pages/manage/components/task-add.vue b/resources/assets/js/pages/manage/components/task-add.vue index cdab1ff2..090cb6bd 100644 --- a/resources/assets/js/pages/manage/components/task-add.vue +++ b/resources/assets/js/pages/manage/components/task-add.vue @@ -18,7 +18,20 @@ :option-full="taskOptionFull" :placeholder="$L('选填...')"> - +
    + + +
    @@ -142,10 +155,10 @@ export default { } }, mounted() { - + this.$store.commit('getTaskPriority') }, computed: { - ...mapState(['userId', 'projectDetail']), + ...mapState(['userId', 'projectDetail', 'taskPriority']), }, watch: { projectDetail(detail) { @@ -229,6 +242,14 @@ export default { }); this.subName = ''; } + }, + choosePriority(item) { + let start = new Date(); + let end = new Date(new Date().setDate(start.getDate() + $A.runNum(item.days))); + this.$set(this.value, 'times', [start, end]) + this.$set(this.value, 'p_level', item.priority) + this.$set(this.value, 'p_name', item.name) + this.$set(this.value, 'p_color', item.color) } } } diff --git a/resources/assets/js/pages/manage/project-detail.vue b/resources/assets/js/pages/manage/project-detail.vue index 02953f79..f303c203 100644 --- a/resources/assets/js/pages/manage/project-detail.vue +++ b/resources/assets/js/pages/manage/project-detail.vue @@ -20,8 +20,9 @@ .project-message { position: relative; height: 100%; - width: 40%; - max-width: 410px; + width: 30%; + min-width: 320px; + max-width: 520px; flex-shrink: 0; &:before { content: ""; diff --git a/resources/assets/js/pages/manage/setting/index.vue b/resources/assets/js/pages/manage/setting/index.vue index b2b887e1..3d2e37a5 100644 --- a/resources/assets/js/pages/manage/setting/index.vue +++ b/resources/assets/js/pages/manage/setting/index.vue @@ -15,7 +15,7 @@
    -
    {{$L('密码设置')}}
    +
    {{$L(titleNameRoute)}}
    @@ -129,6 +129,18 @@ export default { }, computed: { ...mapState(['userInfo']), + + titleNameRoute() { + const {curPath, menu} = this; + let name = ''; + menu.some((item) => { + if ($A.leftExists(curPath, '/manage/setting/' + item.path)) { + name = item.name; + return true; + } + }) + return name; + } }, watch: { '$route' (route) { diff --git a/resources/assets/js/pages/manage/setting/priority.vue b/resources/assets/js/pages/manage/setting/priority.vue index 5506f1ac..06a96e18 100644 --- a/resources/assets/js/pages/manage/setting/priority.vue +++ b/resources/assets/js/pages/manage/setting/priority.vue @@ -1,29 +1,123 @@ - - diff --git a/resources/assets/js/pages/manage/setting/system.vue b/resources/assets/js/pages/manage/setting/system.vue index 31acc1ce..c92f64d9 100644 --- a/resources/assets/js/pages/manage/setting/system.vue +++ b/resources/assets/js/pages/manage/setting/system.vue @@ -57,16 +57,16 @@ export default { complete: () => { this.loadIng--; }, - success: (res) => { - if (res.ret === 1) { - this.formDatum = res.data; + success: ({ret, data, msg}) => { + if (ret === 1) { + this.formDatum = data; this.formDatum_bak = $A.cloneJSON(this.formDatum); if (save) { $A.messageSuccess('修改成功'); } } else { if (save) { - $A.modalError(res.msg); + $A.modalError(msg); } } } diff --git a/resources/assets/js/store/mutations.js b/resources/assets/js/store/mutations.js index 6d22c1f9..ed708623 100644 --- a/resources/assets/js/store/mutations.js +++ b/resources/assets/js/store/mutations.js @@ -17,6 +17,51 @@ export default { state.setStorage('projectListPanel', state.projectListPanel); }, + /** + * 切换项目面板显示显示我的任务 + * @param state + */ + toggleTaskMyShow(state) { + state.taskMyShow = !state.taskMyShow + state.setStorage('taskMyShow', state.taskMyShow); + }, + + /** + * 切换项目面板显示显示未完成任务 + * @param state + */ + toggleTaskUndoneShow(state) { + state.taskUndoneShow = !state.taskUndoneShow + state.setStorage('taskUndoneShow', state.taskUndoneShow); + }, + + /** + * 切换项目面板显示显示已完成任务 + * @param state + */ + toggleTaskCompletedShow(state) { + state.taskCompletedShow = !state.taskCompletedShow + state.setStorage('taskCompletedShow', state.taskCompletedShow); + }, + + /** + * 获取任务优先级预设数据 + * @param state + * @param callback + */ + getTaskPriority(state, callback) { + $A.apiAjax({ + url: 'system/priority', + success: ({ret, data, msg}) => { + if (ret === 1) { + state.taskPriority = data; + typeof callback === "function" && callback(data); + } + }, + }); + return state.userInfo; + }, + /** * 获取/更新会员信息 * @param state @@ -59,7 +104,7 @@ export default { * @param project_id */ getProjectDetail(state, project_id) { - if (state._runNum(project_id) == 0) { + if (state._runNum(project_id) === 0) { return; } if (state._isJson(state.cacheProject[project_id])) { @@ -85,7 +130,7 @@ export default { success: ({ret, data, msg}) => { if (ret === 1) { state.cacheProject[project_id] = data; - if (state.projectDetail.id == project_id) { + if (state.projectDetail.id === project_id) { state.projectDetail = data; } } else { diff --git a/resources/assets/js/store/state.js b/resources/assets/js/store/state.js index 89b8eccd..3ef9b62e 100644 --- a/resources/assets/js/store/state.js +++ b/resources/assets/js/store/state.js @@ -161,6 +161,10 @@ const stateCommon = { const projectChatShow = stateCommon.getStorageBoolean('projectChatShow', true); const projectListPanel = stateCommon.getStorageBoolean('projectListPanel', true); +const taskMyShow = stateCommon.getStorageBoolean('taskMyShow', true); +const taskUndoneShow = stateCommon.getStorageBoolean('taskUndoneShow', true); +const taskCompletedShow = stateCommon.getStorageBoolean('taskCompletedShow', true); + const userInfo = stateCommon.getStorageJson('userInfo'); const userId = userInfo.userid = stateCommon._runNum(userInfo.userid); const userToken = userInfo.token; @@ -169,10 +173,17 @@ export default Object.assign(stateCommon, { projectChatShow, projectListPanel, + taskMyShow, + taskUndoneShow, + taskCompletedShow, + userId, userInfo, userToken, + cacheProject: {}, + cacheUserBasic: {}, + projectLoad: 0, projectDetail: { id: 0, @@ -181,6 +192,5 @@ export default Object.assign(stateCommon, { }, projectMsgUnread: 0, - cacheProject: {}, - cacheUserBasic: {}, + taskPriority: [], }) diff --git a/resources/assets/sass/iconfont.scss b/resources/assets/sass/iconfont.scss index 476bbb7d..cd9ca14e 100644 --- a/resources/assets/sass/iconfont.scss +++ b/resources/assets/sass/iconfont.scss @@ -1,8 +1,8 @@ @font-face { font-family: 'iconfont'; /* Project id 2583385 */ - src: url('//at.alicdn.com/t/font_2583385_jz78bezyc7o.woff2?t=1622640071039') format('woff2'), - url('//at.alicdn.com/t/font_2583385_jz78bezyc7o.woff?t=1622640071039') format('woff'), - url('//at.alicdn.com/t/font_2583385_jz78bezyc7o.ttf?t=1622640071039') format('truetype'); + src: url('//at.alicdn.com/t/font_2583385_9mlcjsehf5c.woff2?t=1622711688395') format('woff2'), + url('//at.alicdn.com/t/font_2583385_9mlcjsehf5c.woff?t=1622711688395') format('woff'), + url('//at.alicdn.com/t/font_2583385_9mlcjsehf5c.ttf?t=1622711688395') format('truetype'); } .iconfont { diff --git a/resources/assets/sass/main.scss b/resources/assets/sass/main.scss index 9a6fb0bd..6cb3642d 100755 --- a/resources/assets/sass/main.scss +++ b/resources/assets/sass/main.scss @@ -53,7 +53,7 @@ body { .ivu-btn { height: 34px; line-height: 32px; - padding: 0 32px; + min-width: 94px; } } .ivu-modal-content { @@ -354,18 +354,43 @@ body { } .advanced-option { margin-top: -6px; - transition: margin 0.2s; z-index: 1; - &.advanced { - margin-left: 22px; + display: flex; + align-items: center; + > button { + transition: margin 0.2s; + &.advanced { + margin-left: 22px; + } + &:focus { + box-shadow: none; + } } - &:focus { - box-shadow: none; + .advanced-priority { + display: flex; + align-items: center; + margin-left: 24px; + > li { + list-style: none; + margin-left: 3px; + .ivu-tooltip { + display: flex; + align-items: center; + .ivu-tooltip-rel { + height: 34px; + line-height: 1; + .iconfont { + font-size: 34px; + cursor: pointer; + } + } + } + } } } } .task-add-advanced { - margin: 0; + margin: 1px 0 0; padding: 34px 32px 6px; border-radius: 8px; border: 1px solid #e8e8e8; @@ -438,6 +463,7 @@ body { } .common-avatar { + position: relative; .common-avatar-text { background-color: #87d068; } @@ -455,7 +481,7 @@ body { } &.online { &:before { - background-color: #509E76; + background-color: #87d068; } } } @@ -591,11 +617,35 @@ body { .form-tip { color: #999999; } + .setting-color { + max-width: 600px; + margin-bottom: 12px; + > div { + text-align: center; + padding-right: 12px; + &:first-child { + text-align: left; + } + &:last-child { + padding-right: 0; + width: 60px; + flex: auto; + flex-shrink: 0; + max-width: 60px; + } + .ivu-color-picker { + width: 100%; + } + } + .information { + color: #999999; + } + } .setting-footer { > button { height: 34px; line-height: 32px; - padding: 0 32px; + min-width: 94px; } } &.submit { diff --git a/webpack.mix.js b/webpack.mix.js index 134010e6..c49a334c 100644 --- a/webpack.mix.js +++ b/webpack.mix.js @@ -1,4 +1,5 @@ const mix = require('laravel-mix'); +const ipv4 = require('internal-ip').v4.sync(); const mixBuildName = function (str) { if (/resources_assets_js_pages_(.*?)_vue/.test(str)) { @@ -30,7 +31,11 @@ mix }, }) .options({ - processCssUrls: false + processCssUrls: false, + hmrOptions: { + host: ipv4 || 'localhost', + port: '22222' + }, }) .vue({ version: 2,