|
@@ -0,0 +1,458 @@
|
|
|
+<template>
|
|
|
+ <div class="app-container">
|
|
|
+
|
|
|
+ <div class="u-gantt-container u-flex">
|
|
|
+ <el-table
|
|
|
+ :data="taskLists"
|
|
|
+ stripe border
|
|
|
+ :cell-class-name="tableCellClassName"
|
|
|
+ :header-cell-class-name="tableCellClassName"
|
|
|
+ @row-dblclick="rowDblclick">
|
|
|
+ <template v-for="(item, index) in configColumns">
|
|
|
+ <el-table-column
|
|
|
+ :prop="item.name"
|
|
|
+ :label="item.label"
|
|
|
+ :fixed="item.fixed"
|
|
|
+ :width="item.width"
|
|
|
+ :align="item.align"
|
|
|
+ :key="index"
|
|
|
+ show-overflow-tooltip
|
|
|
+ ></el-table-column>
|
|
|
+ </template>
|
|
|
+ </el-table>
|
|
|
+ <div class="u-gantt">
|
|
|
+ <div class="u-gantt-title u-flex" >
|
|
|
+ <div v-for="(item, index) in uGanttColumns" :key="index" class="item-title">{{ item.label}}</div>
|
|
|
+ </div>
|
|
|
+ <div class="u-gantt-content">
|
|
|
+ <div class="u-gantt-bg">
|
|
|
+ <div v-for="(item, tr) in taskLists" :key="tr" class="item-tr u-flex">
|
|
|
+ <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 uGanttTaskItem" ref="uGanttTaskItem" v-for="(item, index) in taskLists" :key="index" :style="setStyle(item)">
|
|
|
+ <!-- <span class="resize" ref="`resize${index}}`" @mousedown="dragControllerDiv(index)"></span> -->
|
|
|
+ <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.content }}</div>
|
|
|
+ <div class="u-gantt-task-resize resize-right" ref="uGanttResizeR"></div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 双击事件弹窗 -->
|
|
|
+ <el-dialog title="修改" :visible.sync="dialogVisible" width="40%">
|
|
|
+ <div>
|
|
|
+ 开始:<el-date-picker v-model="currentDbEdit.task_start" type="date" value-format="yyyy-MM-dd" placeholder="选择日期"></el-date-picker>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ 结束:<el-date-picker v-model="currentDbEdit.task_end" type="date" value-format="yyyy-MM-dd" placeholder="选择日期"></el-date-picker>
|
|
|
+ </div>
|
|
|
+ <!-- 其他需要自定义的弹窗数据 -->
|
|
|
+ <slot/>
|
|
|
+ <span slot="footer" class="dialog-footer">
|
|
|
+ <el-button @click="cancel">取 消</el-button>
|
|
|
+ <el-button type="primary" @click="submit">确 定</el-button>
|
|
|
+ </span>
|
|
|
+ </el-dialog>
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+ export default {
|
|
|
+ data(){
|
|
|
+ return {
|
|
|
+ configColumns: [
|
|
|
+ { name: "testItems", label: "检测项目", width: 80, fixed: true, resize: true, align: "center",resize: true, tree: true },
|
|
|
+ { name: "sampleName", label: "样品名称", width: 90, fixed: true, resize: true, align: "center" },
|
|
|
+ { name: "task_start", label: "开始时间", width: 100, fixed: true, resize: true, align: "center" },
|
|
|
+ { name: "task_end", label: "结束时间", width: 100, fixed: true, resize: true, align: "center" },
|
|
|
+ ],
|
|
|
+ taskLists: [{
|
|
|
+ id: 0,
|
|
|
+ testItems: 'ceshi',
|
|
|
+ sampleName: 'ceshi',
|
|
|
+ task_start: '2023-07-03',
|
|
|
+ task_end: '2023-07-04',
|
|
|
+ statusC: '0',
|
|
|
+ content: '111'
|
|
|
+ }, {
|
|
|
+ id: 1,
|
|
|
+ testItems: '测试',
|
|
|
+ sampleName: '测试',
|
|
|
+ task_start: '',
|
|
|
+ task_end: '',
|
|
|
+ statusC: '0',
|
|
|
+ }, {
|
|
|
+ id: 2,
|
|
|
+ testItems: 'ceshi',
|
|
|
+ sampleName: 'ceshi',
|
|
|
+ task_start: '2023-07-06',
|
|
|
+ task_end: '2023-07-10',
|
|
|
+ statusC: '1',
|
|
|
+ }, {
|
|
|
+ id: 3,
|
|
|
+ testItems: '测试',
|
|
|
+ sampleName: '测试',
|
|
|
+ task_start: '',
|
|
|
+ task_end: '',
|
|
|
+ statusC: '1',
|
|
|
+ },{
|
|
|
+ id: 4,
|
|
|
+ testItems: '测试',
|
|
|
+ sampleName: '测试',
|
|
|
+ task_start: '',
|
|
|
+ task_end: '',
|
|
|
+ statusC: '1',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ id: 5,
|
|
|
+ testItems: '测试',
|
|
|
+ sampleName: '测试',
|
|
|
+ task_start: '',
|
|
|
+ task_end: '',
|
|
|
+ statusC: '1',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ id: 6,
|
|
|
+ testItems: '测试',
|
|
|
+ sampleName: '测试',
|
|
|
+ task_start: '',
|
|
|
+ task_end: '',
|
|
|
+ statusC: '1',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ id: 7,
|
|
|
+ testItems: '测试',
|
|
|
+ sampleName: '测试',
|
|
|
+ task_start: '',
|
|
|
+ task_end: '',
|
|
|
+ statusC: '1',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ id: 8,
|
|
|
+ testItems: '测试',
|
|
|
+ sampleName: '测试',
|
|
|
+ task_start: '',
|
|
|
+ task_end: '',
|
|
|
+ statusC: '1',
|
|
|
+ },],
|
|
|
+
|
|
|
+ // 当前双击的数据
|
|
|
+ currentDbEdit: {},
|
|
|
+ dialogVisible: false,
|
|
|
+ }
|
|
|
+ },
|
|
|
+ computed: {
|
|
|
+ // 甘特图标题日期分配
|
|
|
+ uGanttColumns() {
|
|
|
+ // 获取标准时间
|
|
|
+ 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
|
|
|
+ },
|
|
|
+
|
|
|
+ },
|
|
|
+ mounted () {
|
|
|
+ this.uGanttDrag()
|
|
|
+ this.uGanttResizeL()
|
|
|
+ this.uGanttResizeR()
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ setStyle(item){
|
|
|
+ var startIndex = this.uGanttColumns.findIndex(res => res.name === item.task_start)
|
|
|
+ var endIndex = this.uGanttColumns.findIndex(res => res.name === item.task_end)
|
|
|
+ var trIndex = this.taskLists.findIndex(res => res.id === item.id)
|
|
|
+ // console.log(trIndex, this.taskLists)
|
|
|
+ var style = {
|
|
|
+ left: 70 * startIndex + 'px',
|
|
|
+ width: 70 * (endIndex - startIndex + 1) + 'px',
|
|
|
+ top: (34 * trIndex + 2) + 'px'
|
|
|
+ }
|
|
|
+ return style
|
|
|
+ },
|
|
|
+ // 位移事件
|
|
|
+ uGanttDrag(){
|
|
|
+ var _this = this
|
|
|
+ var uGanttDrag = this.$refs.uGanttDrag;
|
|
|
+ var uGanttTaskItem = this.$refs.uGanttTaskItem;
|
|
|
+ for (let i = 0; i < uGanttDrag.length; i++) {
|
|
|
+ uGanttDrag[i].onmousedown = function (e) {
|
|
|
+ const offsetLeft = uGanttTaskItem[i].offsetLeft
|
|
|
+ const offsetWidth = uGanttTaskItem[i].offsetWidth
|
|
|
+ var startX = e.clientX;
|
|
|
+ var moveLen
|
|
|
+ var ganttIndex = Math.trunc(uGanttTaskItem[i].offsetTop/34)
|
|
|
+ document.onmousemove = function (e) {
|
|
|
+ var endX = e.clientX;
|
|
|
+ moveLen = offsetLeft + ( endX - startX )
|
|
|
+ uGanttTaskItem[i].style.left = moveLen + 'px'
|
|
|
+ uGanttDrag[i].style.cursor = 'move'
|
|
|
+
|
|
|
+ }
|
|
|
+ document.onmouseup = function (evt) {
|
|
|
+ uGanttTaskItem[i].style.left = Math.round(moveLen/70) * 70 + 'px';
|
|
|
+ var startNum = (uGanttTaskItem[i].offsetLeft)/70
|
|
|
+ var endNum = (offsetWidth / 70) + startNum
|
|
|
+ // // 普通赋值
|
|
|
+ // // _this.taskLists[0].task_end = _this.uGanttColumns[num - 1].name
|
|
|
+ // // 强制赋值刷新
|
|
|
+ console.log(ganttIndex)
|
|
|
+ _this.$set(_this.taskLists[ganttIndex], 'task_start', _this.uGanttColumns[startNum].name)
|
|
|
+ _this.$set(_this.taskLists[ganttIndex], 'task_end', _this.uGanttColumns[endNum - 1].name)
|
|
|
+ uGanttDrag[i].style.cursor = 'pointer'
|
|
|
+ // // 强制刷新
|
|
|
+ // // _this.$forceUpdate()
|
|
|
+ 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/34)
|
|
|
+ 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) {
|
|
|
+ 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.taskLists[0].task_end = _this.uGanttColumns[num - 1].name
|
|
|
+ // 强制赋值刷新
|
|
|
+ console.log(ganttIndex)
|
|
|
+ _this.$set(_this.taskLists[ganttIndex], 'task_start', _this.uGanttColumns[num].name)
|
|
|
+ // 强制刷新
|
|
|
+ // _this.$forceUpdate()
|
|
|
+ document.onmousemove = null;
|
|
|
+ document.onmouseup = null;
|
|
|
+ document.releaseCapture && document.releaseCapture();
|
|
|
+ }
|
|
|
+ document.setCapture && document.setCapture();
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 改变大小
|
|
|
+ uGanttResizeR(){
|
|
|
+ var _this = this
|
|
|
+ var resize = this.$refs.uGanttResizeR;
|
|
|
+ var uGanttTaskItem = this.$refs.uGanttTaskItem;
|
|
|
+ // var ganttIndex = this.taskLists.findIndex(res=>res.id === 0)
|
|
|
+ for (let i = 0; i < resize.length; i++) {
|
|
|
+ resize[i].onmousedown = function (e) {
|
|
|
+ var ganttIndex = Math.trunc(uGanttTaskItem[i].offsetTop/34)
|
|
|
+ var startX = e.clientX;
|
|
|
+ resize[i].left = resize[i].offsetLeft;
|
|
|
+ var moveLen
|
|
|
+ document.onmousemove = function (e) {
|
|
|
+ var endX = e.clientX;
|
|
|
+ moveLen = resize[i].left + (endX - startX);
|
|
|
+ if (moveLen < 70) moveLen = 70;
|
|
|
+
|
|
|
+ resize[i].style.left = moveLen;
|
|
|
+
|
|
|
+ uGanttTaskItem[i].style.width = moveLen + 'px';
|
|
|
+ }
|
|
|
+ document.onmouseup = function (evt) {
|
|
|
+ uGanttTaskItem[i].style.width = Math.round(moveLen/70) * 70 + 'px';
|
|
|
+ var num = (uGanttTaskItem[i].offsetLeft + uGanttTaskItem[i].offsetWidth)/70
|
|
|
+ // 普通赋值
|
|
|
+ // _this.taskLists[0].task_end = _this.uGanttColumns[num - 1].name
|
|
|
+ // 强制赋值刷新
|
|
|
+ _this.$set(_this.taskLists[ganttIndex], 'task_end', _this.uGanttColumns[num - 1].name)
|
|
|
+ // 强制刷新
|
|
|
+ // _this.$forceUpdate()
|
|
|
+ document.onmousemove = null;
|
|
|
+ document.onmouseup = null;
|
|
|
+ document.releaseCapture && document.releaseCapture();
|
|
|
+ }
|
|
|
+ document.setCapture && document.setCapture();
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ tableCellClassName({ row, column, rowIndex, columnIndex }){
|
|
|
+ //把每一行的索引放进row--可以用于获取index
|
|
|
+ // row.index = rowIndex;
|
|
|
+ return 'u-table-cell'
|
|
|
+ },
|
|
|
+ // 双击事件
|
|
|
+ rowDblclick(row, column, event){
|
|
|
+ console.log(row, column, event)
|
|
|
+ // 深拷贝:直接赋值会有还没点确定,甘特图部分就已经改变的bug
|
|
|
+ this.currentDbEdit = JSON.parse(JSON.stringify(row))
|
|
|
+ this.dialogVisible = true
|
|
|
+ },
|
|
|
+ cancel(){
|
|
|
+ this.currentDbEdit = {}
|
|
|
+ this.dialogVisible = false
|
|
|
+ },
|
|
|
+ submit(){
|
|
|
+ var taskIndex = this.taskLists.findIndex(res=>res.id === this.currentDbEdit.id)
|
|
|
+ this.taskLists[taskIndex].task_start = this.currentDbEdit.task_start
|
|
|
+ this.taskLists[taskIndex].task_end = this.currentDbEdit.task_end
|
|
|
+ this.dialogVisible = false
|
|
|
+ this.currentDbEdit = {}
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss">
|
|
|
+.u-flex{
|
|
|
+ display: flex;
|
|
|
+}
|
|
|
+.u-gantt-container{
|
|
|
+ // width: calc(100vw - 240px);
|
|
|
+ .el-table{
|
|
|
+ .u-table-cell{
|
|
|
+ padding: 0 !important;
|
|
|
+ height: 34px !important;
|
|
|
+ line-height: 34px !important;
|
|
|
+ box-sizing: border-box !important;
|
|
|
+ }
|
|
|
+ .el-table--enable-row-transition .el-table__body td.el-table__cell{
|
|
|
+ padding: 0 !important;
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ .u-gantt{
|
|
|
+ width: calc(100% - 371px);
|
|
|
+ border-top: 1px solid #ebebeb;
|
|
|
+ border-left: 1px solid #ebebeb;
|
|
|
+ overflow: auto;
|
|
|
+ }
|
|
|
+ .u-gantt-title{
|
|
|
+ .item-title{
|
|
|
+ width: 70px;
|
|
|
+ height: 34px;
|
|
|
+ line-height: 34px;
|
|
|
+ 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: 34px;
|
|
|
+ }
|
|
|
+ .item-td{
|
|
|
+ width: 70px;
|
|
|
+ height: 34px;
|
|
|
+ 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{
|
|
|
+ position: absolute;
|
|
|
+ top: 36px;
|
|
|
+ left: 140px;
|
|
|
+ width: 140px;
|
|
|
+ height: 30px;
|
|
|
+ line-height: 30px;
|
|
|
+ background-color: #44c2e5;
|
|
|
+ border-radius: 2px;
|
|
|
+ .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: 30px;
|
|
|
+ top: 0;
|
|
|
+ cursor: w-resize;
|
|
|
+ }
|
|
|
+ .resize-left{
|
|
|
+ left: -7px;
|
|
|
+ }
|
|
|
+ .u-gantt-task-text{
|
|
|
+ color: #fff;
|
|
|
+ text-align: center;
|
|
|
+
|
|
|
+ }
|
|
|
+ .resize-right{
|
|
|
+ right: -7px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|