123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853 |
- <template>
- <div class="app-container">
-
- <div class="u-gantt-container u-flex">
- <div>
- <el-table
- :data="tableData"
- stripe
- :cell-class-name="tableCellClassName"
- :header-cell-class-name="tableCellClassName"
- row-key="id"
- default-expand-all
- :tree-props="{children: 'children', hasChildren: 'hasChildren'}"
- @expand-change="expandChange"
- :row-style="{ height: uStyle.ganttHeight + 'px' }"
- :header-row-style="{ height: uStyle.ganttHeight + 'px' }"
- @cell-click="cellClick"
- @row-dblclick="rowDblclick"
- >
- <template v-for="(item, index) in configColumns">
- <el-table-column
- v-if="item.name !== 'add'"
- :prop="item.name"
- :label="item.label"
- :width="item.width"
- :align="item.align"
- :key="index"
- show-overflow-tooltip
- >
- </el-table-column>
- <el-table-column
- v-if="item.name === 'add'"
- :prop="item.name"
- :label="item.label"
- :align="item.align"
- :width="item.width"
- :key="index"
- >
- <template slot-scope="scope">
- <!-- <i class="el-icon-plus" v-if="!scope.row.pid" @click="addRow(scope.row, scope.$index)"></i> -->
- <span v-if="!scope.row.pid" @click="addRow(scope.row, scope.$index)" class="add-btn">+</span>
- </template>
- </el-table-column>
- <!-- :fixed="item.fixed" -->
- </template>
- </el-table>
- </div>
- <!-- <div class="u-gantt-area" ref="uGantt"> -->
-
- <div class="u-gantt" ref="uGantt">
- <div class="u-gantt-title u-flex" >
- <div v-for="(item, index) in uGanttColumns" :key="index" class="item-title" :style="{'height': uStyle.ganttHeight + 'px', 'lineHeight': uStyle.ganttHeight + 'px'}">{{ item.label}}</div>
- </div>
- <div class="u-gantt-content">
- <div class="u-gantt-bg">
- <div v-for="(item, tr) in ganttLists" :key="tr" class="item-tr u-flex" :style="{'height': uStyle.ganttHeight + 'px'}">
- <!-- :style="{'display': item.show}" -->
- <div class="item-td" v-for="(item, td) in uGanttColumns" :key="td"></div>
- </div>
- </div>
- <div class="u-gantt-task">
- <div class="u-gantt-task-content" v-for="(item, index) in ganttLists" :key="index">
- <!-- <span class="resize" ref="`resize${index}}`" @mousedown="dragControllerDiv(index)"></span> -->
- <!-- 计划 -->
- <div class="u-gantt-plan" ref="uGanttTaskItem" :style="setPlanStyle(item)">
- <div class="u-gantt-task-drag" ref="uGanttDrag"></div>
- <div class="u-gantt-task-resize resize-left" ref="uGanttResizeL"></div>
- <div class="u-gantt-task-text">{{ item.task_text }}</div>
- <div class="u-gantt-task-resize resize-right" ref="uGanttResizeR"></div>
- </div>
- <!-- 实际 -->
- <div v-if="hasReality" class="u-gantt-reality" :style="setRealityStyle(item)"></div>
- </div>
- </div>
- </div>
- </div>
- <!-- </div> -->
- </div>
- <!-- 自定义内容:弹窗 -->
- <slot/>
- </div>
- </template>
- <script>
- export default {
- props: {
- configColumns: {
- type: Array,
- default: []
- },
- taskLists: {
- type: Array,
- default: []
- },
- uStyle: {
- type: Object,
- default: () => ({
- ganttHeight: 40, // 一行的高度(整体一行的)
- planHeight: 26, // 计划甘特条的高度
- planBg: '#44c2e5', // 计划甘特条的颜色
- realityHeight: 10, // 实际甘特条的高度
- realityBgIncomplete: '#ffaf58', // 实际甘特条进行中的颜色
- realityBgCompleted: '#9BDF90', // 实际甘特条已完成的颜色
- // #e5de44
- top: 4, // 甘特条离上线条距离
- })
- },
- hasReality: {
- type: Boolean,
- default: false
- }
- },
- data(){
- return {
- // 甘特图部分时间表头
- uGanttColumns: [],
- // 表格使用数据
- tableData: [],
- // 甘特图显示的
- ganttLists: [],
-
- }
- },
- watch: {
- taskLists: {
- handler(newValue, oldValue){
- console.log(newValue, oldValue)
- if(newValue.length > 0){
-
- newValue.forEach(res=>{
- if(!res.end_date){
- res.end_date = res.start_date
- }
- })
- console.log(newValue)
- this.changeTableTree()
- this.getStartEndTime()
- this.$nextTick(() => {
- this.uGanttDrag()
- this.uGanttResizeL()
- this.uGanttResizeR()
- })
- // this.$forceUpdate()
- } else {
- console.log(this.setDefaultDate())
- this.uGanttColumns = this.setDefaultDate()
- }
- },
- immediate: true,
- // deep: true
- }
- },
- created (){
- // this.changeTableTree()
- // this.getStartEndTime()
- },
- mounted () {
- // this.uGanttDrag()
- // this.uGanttResizeL()
- // this.uGanttResizeR()
- },
- methods: {
- // 没有数据时设置默认当月日期
- setDefaultDate() {
- // 获取标准时间
- var nowdays = new Date()
- // 获取当年
- var currentYear = new Date().getFullYear()
- // 获取当月
- var currentMonth = new Date().getMonth() + 1
- // 获取当天
- var nowDay = new Date().getDate()
- // 获取当前月有多少天
- var currentMonthNum = new Date(currentYear, currentMonth, 0).getDate()
- // console.log(nowDay, currentMonth, currentMonthNum)
- //
- // let now = new Date(nowDay)
- // console.log(nowdays, now)
- // 当前月份所有日期集合
- let currentMonthArr = []
- for (let i = 1; i <= currentMonthNum; i++) {
- // let day = nowdays.setDate(i);
- // console.log(day)
- // 年月日(yyyy-MM-dd)
- let dateLabel = (currentMonth < 10 ? '0' + currentMonth : currentMonth) + "月" + (i < 10 ? '0' + i : i) + "日";
- let dateName = currentYear + "-" + (currentMonth < 10 ? '0' + currentMonth : currentMonth) + "-" + (i < 10 ? '0' + i : i);
- // let day =
- currentMonthArr.push({label: dateLabel, name: dateName});
- }
- console.log(currentMonthArr)
- return currentMonthArr
- },
- // 获取最开始和最末尾时间
- getStartEndTime(){
- // 开始日期(实际和计划都)排序选择最开始的一天
- // var hasSjStartArr = this.taskLists.filter(res=> res.reality_startDate) // 因为计划开始日期一定有,所以就不判断了
- var allStartDataArr = []
- this.taskLists.forEach(res=>{
- // console.log(res.reality_startDate)
- if(res.reality_startDate){allStartDataArr.push(res.reality_startDate)}
- allStartDataArr.push(res.start_date)
- })
- // 从小到大排序
- allStartDataArr.sort(function(a, b) {
- return new Date(a) - new Date(b)
- })
- // console.log(allStartDataArr)
- // 结束日期(实际和计划都)排序选择最后的一天
- var allEndDataArr = []
- this.taskLists.forEach(res=>{
- allEndDataArr.push(res.reality_endDate)
- allEndDataArr.push(res.end_date)
- })
- // 从大到小排序
- allEndDataArr.sort(function(a, b) {
- return new Date(b) - new Date(a)
- })
- // console.log(allEndDataArr)
- // 获取最开始和最结束时间
- const start_date = allStartDataArr[0]
- const end_date = allEndDataArr[0]
- // const end_date = setTimeData[setTimeData.length - 1].end_date
- // 判断两个日期之间多少天--bug:少一天
- var betweenDays = (new Date(end_date).getTime() - new Date(start_date).getTime()) / (1000 * 60 * 60 * 24)
- // console.log(betweenDays)
- var final_date = betweenDays > 30 ? 2 : (30 - betweenDays)
- // 最前面往前一天,最后面往后两天
- var addStart = this.addDate(start_date, -1)
- var addEnd = this.addDate(end_date, final_date)
- this.uGanttColumns = this.getBetweenDate(addStart, addEnd)
- },
- /**
- * 计算某个日期几天后的日期
- * @param {*} date 相加前的时间
- * @param {*} days 需要相加的天数
- */
- addDate(date, days) {
- var date = new Date(date);
- date.setDate(date.getDate() + days);
- var year = date.getFullYear();
- var month = date.getMonth() + 1;
- var day = date.getDate();
- var mm = "'" + month + "'";
- var dd = "'" + day + "'";
- if(mm.length == 3) {
- month = "0" + month;
- }
- if(dd.length == 3) {
- day = "0" + day;
- }
- var time = year + "-" + month + "-" + day
- return time;
- },
- /** 获取两个日期之间的间隔日期
- * @param { Date | number | string } startTime 开始时间 标准时间格式 时间戳格式 字符串格式(2008-08-08,2008-8-8,2008-08-8,2008-8-08)
- * @param { Date | number | string } endTime 结束时间 标准时间格式 时间戳格式 字符串格式(2008-08-08,2008-8-8,2008-08-8,2008-8-08)
- * */
- getBetweenDate(startTime, endTime){
- // 校验时间格式
- if (typeof startTime === 'string') {
- const reg = /^\d{4}-(0?[1-9]|1[0-2])-((0?[1-9])|((1|2)[0-9])|30|31)$/g
- if (!reg.test(startTime)) throw `开始时间:${startTime}时间格式错误`
- }
- if (typeof endTime === 'string') {
- const reg = /^\d{4}-(0?[1-9]|1[0-2])-((0?[1-9])|((1|2)[0-9])|30|31)$/g
- if (!reg.test(endTime)) throw `结束时间:${endTime}时间格式错误`
- }
- let start = new Date(startTime)
- let end = new Date(endTime)
- const resultTime = []
- // 当 开始时间小于结束时间的时候进入循环
- while (start <= end) {
- let getDay = start.getDate()
- // 月份需要加 1
- let getMonth = start.getMonth() + 1
- let getYear = start.getFullYear()
- /**
- * 拼接时间格式
- * (getMonth >= 10 ? `${getMonth}` : `0${getMonth}`) 自动给 小于10的时间前面补0
- */
- let setTime =
- `${getYear}-` +
- (getMonth >= 10 ? `${getMonth}` : `0${getMonth}`) +
- '-' +
- (getDay >= 10 ? `${getDay}` : `0${getDay}`)
- let dateLabel = (getMonth < 10 ? '0' + getMonth : getMonth) + "月" + (getDay < 10 ? '0' + getDay : getDay) + "日";
- resultTime.push({label: dateLabel, name: setTime})
- /**
- * 重新设置开始时间
- * 使用 setFullYear() 方法会自动将时间累加,返回的是时间戳格式
- * 使用 new Date() 将时间重新设置为标准时间
- * getMonth - 1 将月份时间重新还原
- */
- start = new Date(start.setFullYear(getYear, getMonth - 1, getDay + 1))
- }
- return resultTime
- },
- // 将一维数组改成多维数组
- changeTableTree(){
- // console.log(this.taskLists)
- this.tableData = this.changeDataTree(this.taskLists, 'id', 'pid')
- // this.tableData = this.handleTree(this.taskLists, 'id', "pid")
- // console.log(this.tableData)
- this.ganttLists = []
- this.changeTaskSort(this.tableData)
- },
- // 将一维数组转成table使用的二维数组(时间问题没改成多维)
- changeDataTree(Array, id, pid){
- let data = JSON.parse(JSON.stringify(Array));
- data.forEach(item => {
- console.log(item[pid])
- if(item[pid]){
- // 有父级的情况
- var index = data.findIndex(res => res[id] === item[pid])
- data[index].children = data[index].children || []
- data[index].children.push(item)
- } else {
- item.children = item.children || undefined;
- }
- })
- console.log(data)
- return data.filter(res => !res[pid])
- },
- // 将组好的多维数组转成一维数组--是为了左右对应
- changeTaskSort(arr){
- for(var i = 0; i < arr.length; i++){
- // arr[i].show = 'flex'
- if(Array.isArray(arr[i].children)){
- this.ganttLists.push(arr[i]);
- this.changeTaskSort(arr[i].children);
- }else{
- this.ganttLists.push(arr[i]);
- }
- }
- },
- // 绘制计划甘特条
- setPlanStyle(item){
- var startIndex = this.uGanttColumns.findIndex(res => res.name === item.start_date)
- var endIndex = this.uGanttColumns.findIndex(res => res.name === item.end_date)
- if(endIndex !== -1){
- var trIndex = this.ganttLists.findIndex(res => res.id === item.id)
- // console.log(trIndex, this.ganttLists)
- var style = {
- left: 70 * startIndex + 'px',
- width: 70 * (endIndex - startIndex + 1) + 'px',
- top: (this.uStyle.ganttHeight * trIndex + this.uStyle.top) + 'px',
- height: this.uStyle.planHeight + 'px',
- lineHeight: this.uStyle.planHeight + 'px',
- background: this.uStyle.planBg
- }
- return style
- }
- },
- // 绘制实际的甘特条
- setRealityStyle(item){
- // 如果没有实际开始 直接返回
- if(!item.reality_startDate){
- return
- }
- console.log(item.reality_startDate, item.reality_endDate)
- var startIndex = this.uGanttColumns.findIndex(res => res.name === item.reality_startDate)
- var endIndex
-
- // 如果没有结束时间,则显示到的当天,如果有则显示赋值的
- if(item.reality_endDate){
- endIndex = this.uGanttColumns.findIndex(res => res.name === item.reality_endDate)
- } else {
- var year = new Date().getFullYear();
- var month = new Date().getMonth() + 1;
- var day = new Date().getDate();
- var mm = "'" + month + "'";
- var dd = "'" + day + "'";
- if(mm.length == 3) {
- month = "0" + month;
- }
- if(dd.length == 3) {
- day = "0" + day;
- }
- var time = year + "-" + month + "-" + day
- endIndex = this.uGanttColumns.findIndex(res => res.name === time)
- }
- var trIndex = this.ganttLists.findIndex(res => res.id === item.id)
- // console.log(trIndex, this.ganttLists)
- var style = {
- left: 70 * startIndex + 'px',
- width: 70 * (endIndex - startIndex + 1) + 'px',
- top: (this.uStyle.ganttHeight * (trIndex+1) - 10) + 'px',
- height: this.uStyle.realityHeight,
- // jhpqStatus:0未完成 1已完成
- background: item.jhpqStatus === '0' ? this.uStyle.realityBgIncomplete : this.uStyle.realityBgCompleted
- }
- return style
- },
- // 拖拽位移事件
- uGanttDrag(){
- var _this = this
- // 当前甘特条可移动部分
- var uGanttDrag = this.$refs.uGanttDrag;
- // 当前甘特条
- var uGanttTaskItem = this.$refs.uGanttTaskItem;
- // 整个甘特图
- var uGantt = this.$refs.uGantt
- // console.log(this.$refs)
- //当前甘特区域宽度
- for (let i = 0; i < uGanttDrag.length; i++) {
- // 鼠标按下
- uGanttDrag[i].onmousedown = function (e) {
- // 整个甘特图区域滚动宽度(非展示宽度,加上看不见的滚动区域)
- var scrollWidth = uGantt.scrollWidth
- const uGanttWidth = uGantt.offsetWidth // 放在down外值不对,不知道为啥
- /**如果这些参数放在move设置就是会变的,放在down中就是固定值 */
- // 当前甘特条距离左侧距离
- const offsetLeft = uGanttTaskItem[i].offsetLeft
- // 当前甘特条宽度
- const offsetWidth = uGanttTaskItem[i].offsetWidth
- // 设置上次移动结束滚动条位置,用来判断
- const oldScrollLeft = uGantt.scrollLeft
- // 甘特图距离窗口左侧的距离
- var ganttWindowLeft = uGantt.getBoundingClientRect().left
- // 鼠标按下位置-用于计算
- var startX = e.clientX;
- var endX, moveLen
- // 向上取证获取当前是第几行
- var ganttIndex = Math.trunc(uGanttTaskItem[i].offsetTop / _this.uStyle.ganttHeight)
- // console.log(uGantt.scrollLeft)
- // console.log(startX)
- // 移动事件
- document.onmousemove = function (e) {
- endX = e.clientX;
- // 设置当前甘特条距离左侧的距离(使得左侧移动,而宽度不变,右侧对应向右移,产生移动效果)
- // console.log(oldScrollLeft, uGantt.scrollLeft)
- var distance
- if(uGantt.scrollLeft === oldScrollLeft){
- // 如果滚动条没有滚动
- distance = offsetLeft + ( endX - startX )
- } else {
- // 如果滚动条滚动了
- distance = offsetLeft + ( endX - startX ) + (uGantt.scrollLeft - oldScrollLeft)
- }
- // 判断超出左右距离时设置临界值
- if(distance > (scrollWidth - offsetWidth)){
- // 超出右边距离
- moveLen = scrollWidth - offsetWidth
- } else if(distance < 0) {
- // 超出左边距离
- moveLen = 0
- } else {
- moveLen = distance
- }
- uGanttTaskItem[i].style.left = moveLen + 'px'
- // 移动过程鼠标变成拖拽形状
- uGanttDrag[i].style.cursor = 'move'
-
- // 监听位置进行滚动条滚动
- // 鼠标当前位置
- var pointRight = ganttWindowLeft + uGanttWidth - endX
- // console.log(document.documentElement.clientWidth)
-
- if(pointRight < 50){
- uGantt.scrollLeft += 70
- }
- // 鼠标当前位置位于左侧边缘
- if(endX - ganttWindowLeft < 50){
- uGantt.scrollLeft -= 70
- }
- // uGantt.scrollHeight // 滚动条的高度
- }
- document.onmouseup = function (evt) {
- // 同样:不能停在一段的中间位置,所以计算使其整段整段的形式显示
- // console.log(uGanttTaskItem[i].offsetLeft)
- // 移动到最后一列的时候:时间往前+1天
- var StartLeft = Math.round(moveLen/70) * 70
- // var startNum
- if(StartLeft <= 0){
- var currentStartData = _this.addDate(_this.uGanttColumns[0].name, -1)
- _this.uGanttColumns = _this.getBetweenDate(currentStartData, _this.uGanttColumns[_this.uGanttColumns.length - 1].name)
- uGanttTaskItem[i].style.left = (Math.round(moveLen/70) + 1) * 70 + 'px';
- // startNum = (uGanttTaskItem[i].offsetLeft)/70
- } else {
- uGanttTaskItem[i].style.left = Math.round(moveLen/70) * 70 + 'px';
- }
- // 获取最终左侧停在第几列
- var startNum = (uGanttTaskItem[i].offsetLeft)/70
- // console.log(startNum)
- // var StartNum0 = startNum === 0 ? startNum + 1 : startNum
- // console.log(isStartNum)
- // 获取最终右侧停在第几列
- var endNum = (offsetWidth / 70) + startNum
- // 找到对应的时间强制赋值刷新
- _this.$set(_this.ganttLists[ganttIndex], 'start_date', _this.uGanttColumns[startNum].name)
- _this.$set(_this.ganttLists[ganttIndex], 'end_date', _this.uGanttColumns[endNum - 1].name)
- // 移动到最后一列的时候:时间+2天
- if(endNum >= _this.uGanttColumns.length){
- var currentEndData = _this.addDate(_this.uGanttColumns[endNum - 1].name, 2)
- _this.uGanttColumns = _this.getBetweenDate(_this.uGanttColumns[0].name, currentEndData)
- }
-
-
- // 鼠标变回手型
- uGanttDrag[i].style.cursor = 'pointer'
- // 释放
- document.onmousemove = null;
- document.onmouseup = null;
- document.releaseCapture && document.releaseCapture();
- }
- document.setCapture && document.setCapture();
- return false;
- }
- }
- },
- // 改变大小
- uGanttResizeL(){
- var _this = this
- var resize = this.$refs.uGanttResizeL;
- var uGanttTaskItem = this.$refs.uGanttTaskItem;
- for (let i = 0; i < resize.length; i++) {
- resize[i].onmousedown = function (e) {
- var startX = e.clientX;
- var ganttIndex = Math.trunc(uGanttTaskItem[i].offsetTop / _this.uStyle.ganttHeight)
- const offsetLeft = uGanttTaskItem[i].offsetLeft;
- const offsetWidth = uGanttTaskItem[i].offsetWidth
- var moveLen
- var ganttWidth
- document.onmousemove = function (e) {
- var endX = e.clientX;
- moveLen = offsetLeft - (startX - endX);
- ganttWidth = (startX - endX) + offsetWidth
- if (ganttWidth < 70){
- ganttWidth = 70
- moveLen = offsetLeft + offsetWidth - 70
- }
-
- uGanttTaskItem[i].style.left = moveLen + 'px';
- uGanttTaskItem[i].style.width = ganttWidth + 'px';
- }
- document.onmouseup = function (evt) {
- // 移动到最后一列的时候:时间往前+1天
- var StartLeft = Math.round(moveLen/70) * 70
- if(StartLeft <= 0){
- var currentStartData = _this.addDate(_this.uGanttColumns[0].name, -1)
- _this.uGanttColumns = _this.getBetweenDate(currentStartData, _this.uGanttColumns[_this.uGanttColumns.length - 1].name)
- uGanttTaskItem[i].style.left = (Math.round(moveLen/70) + 1) * 70 + 'px';
- // startNum = (uGanttTaskItem[i].offsetLeft)/70
- } else {
- uGanttTaskItem[i].style.left = Math.round(moveLen/70) * 70 + 'px';
- }
- uGanttTaskItem[i].style.width = Math.round(ganttWidth/70) * 70 + 'px';
- var num = (uGanttTaskItem[i].offsetLeft)/70
- // console.log(num)
- // 普通赋值
- // _this.ganttLists[0].end_date = _this.uGanttColumns[num - 1].name
- // 强制赋值刷新
- // console.log(ganttIndex)
- _this.$set(_this.ganttLists[ganttIndex], 'start_date', _this.uGanttColumns[num].name)
- // 强制刷新
- // _this.$forceUpdate()
- document.onmousemove = null;
- document.onmouseup = null;
- document.releaseCapture && document.releaseCapture();
- }
- document.setCapture && document.setCapture();
- return false;
- }
- }
- },
- // 改变大小
- uGanttResizeR(){
- // 方法域(onmousedown等方法中有自己的this,所以在外面重新赋值this,让内部方法调用)
- var _this = this
- // 1.获取ref
- var resize = this.$refs.uGanttResizeR;
- var uGanttTaskItem = this.$refs.uGanttTaskItem;
- // 整个甘特图
- var uGantt = this.$refs.uGantt
- // 2.循环监听获取当前点击的事件
- // 上面设置onmousedown方法会出现第一次点击无法调用的问题,所以在mounted中写(不知道为什么有类似监听的效果)
- // 因为ref有好几个,获取的数组,所以这里要循环
- for (let i = 0; i < resize.length; i++) {
- // 不可以设置var resize = resize[i] 下面统一使用resize的方式 =>这样会有问题
- // 1.鼠标按下事件:
- // 用[resize[i].],而不是全局document监听,这样才能监听到是哪儿一个甘特条触发了事件
- resize[i].onmousedown = function (e) {
- // 1.整个甘特图区域滚动宽度(非展示宽度,加上看不见的滚动区域)
- var scrollWidth = uGantt.scrollWidth
- const uGanttWidth = uGantt.offsetWidth
- // 2.获取当前点击的甘特条是第几行的,也就是对应左侧项目组中的index
- var ganttIndex = Math.trunc(uGanttTaskItem[i].offsetTop / _this.uStyle.ganttHeight)
- // 3.获取按下位置距离
- var startX = e.clientX;
- // 4.获取当前右侧拖拽区域距离父元素左侧距离(也就是右侧拖拽区域距离甘特图左边的距离:注意父子关系)
- var offsetLeft = resize[i].offsetLeft;
- // 转言之:上面那个就是当前甘特条的宽度--也就可以写作下面的方式
- // var offsetLeft = uGanttTaskItem[i].offsetWidth;
- // 5.甘特图距离窗口左侧的距离
- var ganttWindowLeft = uGantt.getBoundingClientRect().left
- // 6.定义拖拽参数--主要是为了onmouseup能调用
- var moveLen
- // 7.鼠标移动事件--注意:这里是document全局,这样就可以实现超出位置依旧可以控制拖拽
- document.onmousemove = function (e) {
- // 1.获取移动过程中实时位置
- var endX = e.clientX;
- // 2.设置当前甘特条的宽度:一开始甘特条的宽度 +(拖拽区域(鼠标点)末位置-初始位置)
- moveLen = offsetLeft + (endX - startX);
- // 3.判断如果小于1格,就不再减少
- if (moveLen < 70) moveLen = 70;
- // 这一步好像是没啥用啊?
- // resize[i].style.left = moveLen;
- // 设置甘特条随move变化:即实时宽度也为moveLen即可
- uGanttTaskItem[i].style.width = moveLen + 'px';
- // 4.监听位置进行滚动条滚动
- // 鼠标当前位置
- var pointRight = ganttWindowLeft + uGanttWidth - endX
- // 如果位置靠右小于50,滚动条滚动
- // if(pointRight < 50){
- // uGantt.scrollLeft += 70
- // }
- }
- // 鼠标抬起事件
- document.onmouseup = function (evt) {
- // 1.因为时间一段一段的,设置少于35(70的一半)最终结果向左靠,反之向右靠
- uGanttTaskItem[i].style.width = Math.round(moveLen/70) * 70 + 'px';
- // 2.获取当前甘特条最后位置在第几列--用于赋值
- var num = (uGanttTaskItem[i].offsetLeft + uGanttTaskItem[i].offsetWidth)/70
- // 移动到最后一列的时候:时间+2天
- if(num >= _this.uGanttColumns.length){
- var currentEndData = _this.addDate(_this.uGanttColumns[num - 1].name, 2)
- _this.uGanttColumns = _this.getBetweenDate(_this.uGanttColumns[0].name, currentEndData)
- }
- // 普通赋值
- // _this.ganttLists[0].end_date = _this.uGanttColumns[num - 1].name
- // 3.强制赋值刷新--获取列对应的时间,赋值给左侧的第ganttIndex个项目的end_date
- _this.$set(_this.ganttLists[ganttIndex], 'end_date', _this.uGanttColumns[num - 1].name)
- // 强制刷新
- // _this.$forceUpdate()
- // 4.释放鼠标事件
- document.onmousemove = null;
- document.onmouseup = null;
- // 5.从当前线程中的窗口释放鼠标捕获,并恢复通常的鼠标输入处理
- document.releaseCapture && document.releaseCapture();
- }
- // 当前线程的给定窗口设置鼠标捕获
- document.setCapture && document.setCapture();
- return false;
- }
- }
- },
- tableCellClassName({ row, column, rowIndex, columnIndex }){
- //把每一行的索引放进row--可以用于获取index
- // row.index = rowIndex;
- // 设置新增列
- if(columnIndex === this.configColumns.length - 1 && column.property === 'add'){
- return 'add-btn-cell u-table-cell'
- }
- return 'u-table-cell'
- },
- // 展开隐藏事件
- expandChange(row, isExpend){
- console.log(row, isExpend)
- if(isExpend){
- // 展开
- var index = this.ganttLists.findIndex(res=>res.id === row.id)
- this.ganttLists.splice(index+1, 0, ...row.children)
- this.$forceUpdate()
- } else {
- // 隐藏
- this.ganttLists = this.ganttLists.filter(res=>res.pid !== row.id)
- this.$forceUpdate()
- }
- },
- // 双击事件
- rowDblclick(row, column, event){
- // console.log(row, column, event)
- // 深拷贝:直接赋值会有还没点确定,甘特图部分就已经改变的bug
- // this.currentDbEdit = JSON.parse(JSON.stringify(row))
- // this.$emit('dbclick', JSON.parse(JSON.stringify(row)))
- const dbClickRow = JSON.parse(JSON.stringify(row))
- const dbClickColumn = JSON.parse(JSON.stringify(column))
- this.$emit('dbclick', dbClickRow, dbClickColumn)
- },
- // 单元格点击事件
- cellClick(row,column,event,cell){
- // console.log(row,column,event,cell)
- const clickRow = JSON.parse(JSON.stringify(row))
- const clickColumn = JSON.parse(JSON.stringify(column))
- this.$emit('cellClick', clickRow, clickColumn)
- },
- // 添加事件
- addRow(row, index){
- // console.log(row, index)
- this.$emit('addRow', row, index)
- // var current = this.ganttLists[index].children
- // console.log(current)
- // var copy = current[current.length - 1]
- // this.ganttLists[index].children.push(copy)
- // this.$forceUpdate()
- },
- // 将数据返回
- getSaveData(){
- return this.ganttLists
- }
- }
- }
- </script>
- <style lang="scss">
- .u-flex{
- display: flex;
- }
- .u-gantt-container{
- background-color: #fff;
- // width: calc(100vw - 240px);
- .el-table{
- user-select: none;
- // border-top: 1px solid #ebebeb;
- // border-left: 1px solid #ebebeb;
- // width: auto;
- .u-table-cell{
- padding: 0 !important;
- height: 40px !important;
- line-height: 40px !important;
- box-sizing: border-box !important;
- }
- .el-table--enable-row-transition .el-table__body td.el-table__cell{
- padding: 0 !important;
- }
- //
- .add-btn-cell .cell{
- padding-left: 0;
- padding-right: 0;
- }
- .add-btn{
- font-size: 28px;
- font-weight: bolder;
- color: #44c2e5;
- }
- }
- .u-gantt-area{
- flex: 1;
- overflow: hidden;
- }
- .u-gantt{
- flex: 1;
- border-top: 1px solid #ebebeb;
- border-left: 1px solid #ebebeb;
- // width: calc(100% - 371px);
- overflow: auto;
- }
- .u-gantt-title{
- .item-title{
- width: 70px;
- // height: 40px;
- // line-height: 40px;
- text-align: center;
- border-right: 1px solid #ebebeb;
- border-bottom: 1px solid #ebebeb;
- font-size: 12px;
- color: #787878;
- flex-shrink: 0; // 设置宽度不够时,元素不压缩而是超出滚动
- }
- }
- .u-gantt-content{
- position: relative;
- // 底层表格线框
- .u-gantt-bg{
- // position: absolute;
- .item-tr{
- // height: 40px;
- }
- .item-td{
- width: 70px;
- // height: 40px;
- border-right: 1px solid #ebebeb;
- border-bottom: 1px solid #ebebeb;
- flex-shrink: 0; // 设置宽度不够时,元素不压缩而是超出滚动
- }
- }
- // 项目甘特条
- .u-gantt-task{
- // position: absolute;
- // top: 0;
- // left: 0;
- // right: 0;
- // bottom: 0;
- // background-color: #b72222;
- .u-gantt-task-content{
- .u-gantt-plan{
- position: absolute;
- top: 0;
- left: 0;
- width: 0;
- height: 0;
- line-height: 0;
- background-color: #44c2e5;
- border-radius: 0;
- .u-gantt-task-drag{
- position: absolute;
- top: 0;
- left: 1px;
- right: 1px;
- bottom: 0;
- cursor: pointer;
- }
- .u-gantt-task-resize{
- position: absolute;
- width: 8px;
- height: 26px;
- top: 0;
- cursor: w-resize;
- }
- .resize-left{
- left: -7px;
- }
- .u-gantt-task-text{
- color: #fff;
- text-align: center;
-
- }
- .resize-right{
- right: -7px;
- }
- }
- .u-gantt-reality{
- position: absolute;
- top: 0;
- left: 0;
- width: 0;
- height: 6px;
- // line-height: 6px;
- background-color: #e5de44;
- border-radius: 0;
- }
- }
- }
- }
- }
- </style>
|