perf: 甘特图兼容移动端

This commit is contained in:
kuaifan 2024-06-01 10:19:35 +08:00
parent 956b68a545
commit eb7d93af87
3 changed files with 63 additions and 42 deletions

View File

@ -21,17 +21,18 @@
<i v-if="maximize" class="taskfont">&#xe7d4;</i> <i v-if="maximize" class="taskfont">&#xe7d4;</i>
<i v-else class="taskfont">&#xe7d3;</i> <i v-else class="taskfont">&#xe7d3;</i>
</div> </div>
<div class="gantt-chart"> <div
ref="ganttChart"
class="gantt-chart"
@touchstart="dateTouchstart"
@touchmove="dateTouchmove"
@touchend="dateTouchend">
<ul class="gantt-month"> <ul class="gantt-month">
<li v-for="(item, key) in monthNum" :key="key" :style="monthStyle(key)"> <li v-for="(item, key) in monthNum" :key="key" :style="monthStyle(key)">
<div class="month-format">{{monthFormat(key)}}</div> <div class="month-format">{{monthFormat(key)}}</div>
</li> </li>
</ul> </ul>
<ul class="gantt-date" <ul class="gantt-date" @mousedown="dateMouseDown">
@touchstart="dateTouchstart"
@touchmove="dateTouchmove"
@touchend="dateTouchend"
@mousedown="dateMouseDown">
<li v-for="(item, key) in dateNum" :key="key" :style="dateStyle(key)"> <li v-for="(item, key) in dateNum" :key="key" :style="dateStyle(key)">
<div class="date-format"> <div class="date-format">
<div class="format-day">{{dateFormat(key, 'day')}}</div> <div class="format-day">{{dateFormat(key, 'day')}}</div>
@ -43,7 +44,7 @@
class="gantt-timeline" class="gantt-timeline"
@scroll="timelineScrollListener" @scroll="timelineScrollListener"
@mouseenter="mouseType='timeline'"> @mouseenter="mouseType='timeline'">
<li v-for="(item, key) in lists" :key="key"> <li v-for="(item, key) in lists" :key="key" :data-id="item.id">
<div <div
class="timeline-item" class="timeline-item"
:style="itemStyle(item)" :style="itemStyle(item)"
@ -299,38 +300,58 @@ export default {
if (this.windowPortrait) { if (this.windowPortrait) {
this.maximize = true this.maximize = true
} }
this.mouseItem = null; let parent = e.target.parentNode
this.dateMove = { let item = null
clientX: e.touches[0].clientX while (parent) {
}; if (!parent || parent === this.$refs.ganttChart) {
}, break
dateTouchmove(e) { }
if (this.mouseItem != null) { if (parent.tagName === 'LI') {
const itemId = parent.getAttribute('data-id')
if (itemId) {
item = this.lists.find(({id}) => itemId == id)
}
}
parent = parent.parentNode
}
if (!item) {
this.onDateMove(e.touches[0].clientX);
return return
} }
if (this.dateMove != null) { this.onItemMove(item, e.target, e.touches[0].clientX);
let moveX = (this.dateMove.clientX - e.touches[0].clientX) * 5; },
this.dateMove.clientX = e.touches[0].clientX; dateTouchmove(e) {
this.mouseWidth+= moveX; this.onMoving(e.touches[0].clientX)
this.mouseScaleWidth+= moveX * (100 / this.dateWidth);
}
}, },
dateTouchend() { dateTouchend() {
if (this.dateMove != null) { this.onMoveOver(null);
this.dateMove = null;
}
}, },
dateMouseDown(e) { dateMouseDown(e) {
e.preventDefault(); e.preventDefault();
this.mouseItem = null; this.onDateMove(e.clientX);
this.dateMove = {
clientX: e.clientX
};
}, },
itemMouseDown(e, item) { itemMouseDown(e, item) {
e.preventDefault(); e.preventDefault();
this.onItemMove(item, e.target, e.clientX);
},
itemMouseMove(e) {
if (this.mouseItem != null || this.dateMove != null) {
e.preventDefault();
this.onMoving(e.clientX);
}
},
itemMouseUp(e) {
this.onMoveOver(e.target);
},
onDateMove(clientX) {
this.mouseItem = null;
this.dateMove = {
clientX
};
},
onItemMove(item, target, clientX) {
let type = 'moveX'; let type = 'moveX';
if (e.target.className == 'timeline-resizer') { if (target.classList.contains('timeline-resizer')) {
type = 'moveW'; type = 'moveW';
} }
if (typeof item[type] !== "number") { if (typeof item[type] !== "number") {
@ -338,16 +359,15 @@ export default {
} }
this.mouseBak = { this.mouseBak = {
type: type, type: type,
clientX: e.clientX, clientX: clientX,
value: item[type], value: item[type],
}; };
this.mouseItem = item; this.mouseItem = item;
this.dateMove = null; this.dateMove = null;
}, },
itemMouseMove(e) { onMoving(clientX) {
if (this.mouseItem != null) { if (this.mouseItem != null) {
e.preventDefault(); const diff = this.mouseBak.value + (clientX - this.mouseBak.clientX);
const diff = this.mouseBak.value + (e.clientX - this.mouseBak.clientX);
if (this.mouseBak.type === 'moveW') { if (this.mouseBak.type === 'moveW') {
const oneWidthTime = 86400000 / this.dateWidth; const oneWidthTime = 86400000 / this.dateWidth;
const {start, end} = this.mouseItem.time; const {start, end} = this.mouseItem.time;
@ -360,14 +380,13 @@ export default {
return; return;
} }
if (this.dateMove != null) { if (this.dateMove != null) {
e.preventDefault(); let moveX = (this.dateMove.clientX - clientX) * 5;
let moveX = (this.dateMove.clientX - e.clientX) * 5; this.dateMove.clientX = clientX;
this.dateMove.clientX = e.clientX;
this.mouseWidth+= moveX; this.mouseWidth+= moveX;
this.mouseScaleWidth+= moveX * (100 / this.dateWidth); this.mouseScaleWidth+= moveX * (100 / this.dateWidth);
} }
}, },
itemMouseUp(e) { onMoveOver(target) {
if (this.mouseItem != null) { if (this.mouseItem != null) {
const {start, end} = this.mouseItem.time; const {start, end} = this.mouseItem.time;
let isM = false; let isM = false;
@ -391,7 +410,7 @@ export default {
// //
if (isM) { if (isM) {
this.$emit("on-change", this.mouseItem) this.$emit("on-change", this.mouseItem)
} else if (e.target.className == 'timeline-title') { } else if (target && target.className == 'timeline-title') {
this.clickItem(this.mouseItem); this.clickItem(this.mouseItem);
} }
this.mouseItem = null; this.mouseItem = null;

View File

@ -27,8 +27,8 @@
<div class="project-gstc-edit-info"> <div class="project-gstc-edit-info">
<Table max-height="600" :columns="editColumns" :data="editData"></Table> <Table max-height="600" :columns="editColumns" :data="editData"></Table>
<div class="project-gstc-edit-btns"> <div class="project-gstc-edit-btns">
<Button :loading="editLoad > 0" size="small" type="text" @click="editSubmit(false)">{{$L('取消')}}</Button> <Button :loading="editLoad > 0" type="text" @click="editSubmit(false)">{{$L('取消')}}</Button>
<Button :loading="editLoad > 0" size="small" type="primary" @click="editSubmit(true)">{{$L('保存')}}</Button> <Button :loading="editLoad > 0" type="primary" @click="editSubmit(true)">{{$L('保存')}}</Button>
<Icon type="md-arrow-dropright" class="zoom" @click="editShowInfo=false"/> <Icon type="md-arrow-dropright" class="zoom" @click="editShowInfo=false"/>
</div> </div>
</div> </div>
@ -67,11 +67,11 @@ export default {
{ {
title: this.$L('任务名称'), title: this.$L('任务名称'),
key: 'label', key: 'label',
minWidth: 150, minWidth: 100,
ellipsis: true, ellipsis: true,
}, { }, {
title: this.$L('原计划时间'), title: this.$L('原计划时间'),
minWidth: 135, width: 140,
align: 'center', align: 'center',
render: (h, {row}) => { render: (h, {row}) => {
if (row.notime === true) { if (row.notime === true) {
@ -86,7 +86,7 @@ export default {
} }
}, { }, {
title: this.$L('新计划时间'), title: this.$L('新计划时间'),
minWidth: 135, width: 140,
align: 'center', align: 'center',
render: (h, {row}) => { render: (h, {row}) => {
return h('div', { return h('div', {

View File

@ -48,6 +48,7 @@
position: absolute; position: absolute;
bottom: 6px; bottom: 6px;
right: 6px; right: 6px;
max-width: calc(100% - 6px);
background: #ffffff; background: #ffffff;
border-radius: 4px; border-radius: 4px;
opacity: 0; opacity: 0;
@ -76,6 +77,7 @@
padding: 6px; padding: 6px;
border-radius: 4px; border-radius: 4px;
width: 500px; width: 500px;
max-width: 100%;
.project-gstc-edit-btns { .project-gstc-edit-btns {
margin: 12px 6px 4px; margin: 12px 6px 4px;