更多功能看演示系统
gitee源代码地址
后端代码: https://gitee.com/nbacheng/nbcio-boot
前端代码:https://gitee.com/nbacheng/nbcio-vue.git
在线演示(包括H5) : http://122.227.135.243:9888
基于项目的任务显示,最直观的就是甘特图显示,所以今天就说甘特图的显示
经过选择,最终选择dhtmlx-gantt组件,使用最新的8.0.3版本,当然这个组件就是一些高级功能需要付费。
1、后端代码
获取项目任务相关信息如下:
@Overridepublic Result<?> taskGantt(Map<String, Object> mmap) {String projectId = MapUtils.getString(mmap, "projectId");List<Map> listStagesGantt = taskStagesMapper.selectTaskStagesGanttByProjectId(projectId);List<Map> listTasksGantt = baseMapper.selectTaskGanttByProjectId(projectId);if (!CollectionUtils.isEmpty(listStagesGantt)) {if (!CollectionUtils.isEmpty(listTasksGantt)) {for (Map stagesmap : listStagesGantt) {for (Map tasksmap : listTasksGantt) {if (ObjectUtils.isEmpty(tasksmap.get("parent"))) {tasksmap.replace("parent", stagesmap.get("id"));}}}Map<String, Object> tasksmap = new HashMap<String, Object>();listStagesGantt.addAll(listTasksGantt);tasksmap.put("data", listStagesGantt);return Result.OK(tasksmap);} else {Map<String, Object> tasksmap = new HashMap<String, Object>();tasksmap.put("data", listStagesGantt);return Result.OK(tasksmap);}} else {return Result.error("获取不到数据");}}
其中用到的两个sql如下,注意下面对日期做了格式转换:
@Select("select id,name as text,null assign_to,null as start_date,null as end_date,sort,null parent from tw_task_stages where project_id = #{projectId} order by sort" )List<Map> selectTaskStagesGanttByProjectId(@Param("projectId") String projectId);@Select("select id,name as text,assign_to,DATE_FORMAT(begin_time,'%d-%m-%Y') as start_date,DATE_FORMAT(end_time,'%d-%m-%Y') as end_date, id_num as sort, pid as parent from tw_task where project_id = #{projectId} order by sort")List<Map> selectTaskGanttByProjectId(@Param("projectId") String projectId);
2、前端代码
<template><div class="project-space-gantt"><div class="project-navigation"><div class="project-nav-header"><a-breadcrumb><a-breadcrumb-item><a><a-icon type="home" />首页</a></a-breadcrumb-item></a-breadcrumb></div><section class="nav-body"><ul class="nav-wrapper nav nav-underscore pull-left"><li><a class="app" data-app="tasks" @click="$router.push('/estar/teamwork/space/task/' + id)">任务</a></li><li class="app"><a class="app" data-app="works" @click="$router.push('/estar/teamwork/space/files/' + id)">文件</a><li><a class="app" data-app="build" @click="$router.push('/estar/teamwork/space/overview/' + id)">概览</a></li><li class=""><a class="app" data-app="build" @click="$router.push('/estar/teamwork/space/features/' + id)">版本</a></li><li class="actives"><a class="app" data-app="build"@click="$router.push('/estar/teamwork/space/gantt/' + id)">甘特图</a></li></ul></section></div><wrapper-content :showHeader="false"><div class="content-wrapper"><div class="ganntClass" :style="{ height: ganttHeight }" v-loading="ganttLoading"><div ref="gantt" class="gantt-container" /></div></div></wrapper-content></div>
</template><script>import {mapState} from 'vuex'import {getTasksGanttByProjectId} from "@/api/teamwork/task";import WrapperContent from '../components/WrapperContent'import '@/assets/tw/css/theme.less';import gantt from 'dhtmlx-gantt';import 'dhtmlx-gantt/codebase/dhtmlxgantt.css';export default {name: "project-space-gantt",components: {WrapperContent},data() {return {id: this.$route.params.id,loading: true,showLoading: false,loadingMore: false,//gantt高度ganttHeight: innerHeight - 50 + 'px',ganttLoading: false,projectId: '',tasksGantt: {},}},created() {//清空gantt数据gantt.clearAll();this.projectId = this.$route.params.id;this.getTasksGantt();},mounted() {var that = this;//本地化gantt.i18n.setLocale("cn");//自适应甘特图的尺寸大小, 使得在不出现滚动条的情况下, 显示全部任务gantt.config.autosize = false;//只读模式:打开后不可以操作甘特图gantt.config.readonly = false;//是否显示左侧树表格gantt.config.show_grid = true;//表格列设置:我们在后台获取数据后,会解析到这个表格列中,这里面会含有很多隐藏列,作用是甘特图中不需要看隐藏列,但当我们获取甘特图的任务时,这些隐藏列会跟随任务方便使用gantt.config.columns = [{//最左侧新增符号列,甘特图内置可选使用列name: 'add',label: '',width: '40'},{name: 'text',label: '任务名称',tree: true,width: '150'},{name: 'assign_to',label: '执行人',width: '100'},{name: 'start_date',label: '开始时间',align: 'center',width: '90'},{name: 'end_date',label: '结束时间',align: 'center',width: '90'}];//自适应//gantt.config.fit_tasks = true;//开启提示:鼠标悬浮在gantt行上显示gantt.plugins({tooltip: true});gantt.attachEvent('onGanttReady', function() {var tooltips = gantt.ext.tooltips;gantt.templates.tooltip_text = function(start, end, task) {return '任务编号:' + task.id + '<br/>任务:' + task.text + '<br/>执行人:' +task.assign_to + '<br/>计划开始时间:' + gantt.templates.tooltip_date_format(start) + '<br/>结束时间:' + gantt.templates.tooltip_date_format(end);};});//禁用双击事件gantt.config.details_on_dblclick = false;//关闭所有错误提示信息:gantt有自己的异常消息,如果不关闭可能页面会弹出异常消息gantt.config.show_errors = false;//灯箱事件gantt.attachEvent('onBeforeLightbox', function(task_id) {//刷新灯箱数据//gantt.resetLightbox();//true:打开灯箱//return true;//这里调用了自己的页面,没有打开默认灯箱that.addTask(task_id);});//禁止拖动设置任务长度gantt.attachEvent('onBeforeTaskDrag', function(id, mode, e) {return false;});//禁止拖动任务gantt.config.drag_move = false;//禁止拖动任务进度gantt.config.drag_progress = false;//禁止拖放添加Linkgantt.config.drag_links = false;//开启标记gantt.plugins({marker: true});//标记当前日期var dateToStr = gantt.date.date_to_str(gantt.config.task_date);var markerId = gantt.addMarker({start_date: new Date(),css: 'today', //标记样式,style中对应text: 'Today',title: dateToStr(new Date())});gantt.getMarker(markerId);//设置 scale_unit 属性为 month,以显示月刻度gantt.config.scale_unit = "month";//设置 step 属性为 1,以每个月显示一个刻度gantt.config.step = 1;//设置 date_scale 属性为 %Y-%m-%d,以显示年月日格式的刻度gantt.config.date_scale = "%Y-%m-%d";//设置 scale_date 属性为 gantt.date.monthStart,以从每个月的第一天开始显示刻度。gantt.config.scale_date = gantt.date.monthStart;//表头高度gantt.config.scale_height = 60;gantt.config.scales = [{unit: "month", format: "%F, %Y"},{unit: "day", step: 1, format: "%j, %D"}];//设置 subscale 属性为一个包含两个刻度的对象,分别为 day 和 week。gantt.config.subscales = [ // 配置时间{unit: "day",step: 1,date: "%j %D"},];// 初始化gantt.init(this.$refs.gantt);//gantt.clearAll(); // 防止数据缓存问题//gantt.parse(tasks);},methods: {//获取甘特图数据getTasksGantt() {let that = this;getTasksGanttByProjectId({projectId: that.id}).then((res) => {console.log("getTasksGanttByProjectId res=", res);this.tasksGantt = res.result;// 数据解析:将数据解析到gantt列数据中gantt.parse(this.tasksGantt);// 刷新数据gantt.refreshData();this.ganttLoading = false;});},//自定义新增任务addTask(taskId) {var that = this;this.$nextTick(() => {that.$refs.taskAdd.init(task, action, parentTask, $this.milestoneOriginalData);});//删除任务:每次调用gantt内置新增事件时,gantt会直接新增任务到甘特图中,而我们需要的是自定义新增任务gantt.deleteTask(taskId);//灯箱事件必须返回布尔值,这里使用了自定义灯箱返回false,即不打开灯箱return false;}},}
</script><style lang="less">.project-space-gantt {.project-navigation {top: 0px;z-index: 4;}.layout-content {padding: 0px;width: 100%;margin: 0px 0px 0px;background: initial;.content-item {background: #fff;padding: 0px 0px 0px 0px;border-radius: 4px;}}.wrapper-main {padding: 24px 0 12px 0px;background: initial;}}.gantt-container {height: 100%;width: 100%;}.ganntClass {background-color: #fff;padding: 10px;border-radius: 4px;}//今日标记样式.today {}
</style>
2、效果如下: