2023-07-24 18:33:58 +08:00
|
|
|
|
<template>
|
|
|
|
|
|
<div class="gantt-box">
|
|
|
|
|
|
<div class="header">
|
|
|
|
|
|
<div class="left-content">
|
|
|
|
|
|
<div class="item" v-for="(item, index) in headerList" :key="index">
|
|
|
|
|
|
<div class="color-block" :style="{ background: item.color }"></div>
|
|
|
|
|
|
<div class="label">{{ item.label }}</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="right-content">备注:更新(进度填报)内容后该甘特图将自动更新</div>
|
|
|
|
|
|
</div>
|
2023-08-07 17:05:36 +08:00
|
|
|
|
<div class="gantt-chart" v-if="projects.length > 0">
|
2023-07-24 18:33:58 +08:00
|
|
|
|
<div class="table" @scroll="handleScroll">
|
|
|
|
|
|
<div class="thead">
|
|
|
|
|
|
<div class="row">
|
|
|
|
|
|
<div class="td fixed_1">分部分项工程名称</div>
|
|
|
|
|
|
<div class="td fixed_2">开始日期</div>
|
|
|
|
|
|
<div class="td fixed_3" style="border-right: 1px solid #cbd1df">完成日期</div>
|
|
|
|
|
|
<div class="td" v-for="date in dateList" :key="date">
|
|
|
|
|
|
<div class="date">
|
|
|
|
|
|
<div class="month">
|
|
|
|
|
|
{{ date }}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="days">
|
|
|
|
|
|
<div class="day" v-for="day in getDays(date)" :key="day.num">
|
|
|
|
|
|
{{ day.num }}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="tbody">
|
|
|
|
|
|
<div class="row-groups" :class="{ open: openedIndex === i }" v-for="(p, i) in projects" :key="p.name">
|
|
|
|
|
|
<div class="row">
|
|
|
|
|
|
<div class="td fixed_1" @click="handleOpen(i)" style="color: #333333; padding-left: 25px">
|
2023-08-10 17:43:51 +08:00
|
|
|
|
<el-icon size="16" :style="{ visibility: openedIndex === i && p.children.length > 0 ? 'visible' : 'hidden' }"
|
|
|
|
|
|
><caret-bottom
|
|
|
|
|
|
/></el-icon>
|
|
|
|
|
|
<el-icon size="16" :style="{ visibility: openedIndex != i && p.children.length > 0 ? 'visible' : 'hidden' }"
|
|
|
|
|
|
><caret-right
|
|
|
|
|
|
/></el-icon>
|
2023-07-24 18:33:58 +08:00
|
|
|
|
<span>{{ p.name }}</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="td fixed_2">{{ p.planStartTime }}</div>
|
|
|
|
|
|
<div class="td fixed_3">{{ p.planEndTime }}</div>
|
|
|
|
|
|
<div class="td" v-for="date in dateList" :key="date + 'grid-date'">
|
|
|
|
|
|
<div class="grids">
|
|
|
|
|
|
<div
|
|
|
|
|
|
class="grid"
|
|
|
|
|
|
v-for="day in getDays(date)"
|
|
|
|
|
|
:key="'grid' + day.num"
|
|
|
|
|
|
:ref="(el: any) => setItemRef(el, p.name + '@|@' + day.date)"
|
|
|
|
|
|
></div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div
|
|
|
|
|
|
class="progress"
|
|
|
|
|
|
:style="gantt"
|
|
|
|
|
|
v-for="(gantt, index) in p.gantts"
|
|
|
|
|
|
:key="index"
|
2023-08-07 17:05:36 +08:00
|
|
|
|
@mouseenter="e => handleHover(e, p)"
|
2023-07-24 18:33:58 +08:00
|
|
|
|
@mouseleave="handleLeave"
|
|
|
|
|
|
></div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="children" v-show="openedIndex === i">
|
|
|
|
|
|
<div class="row" v-for="child in p.children" :key="'child-' + child.name">
|
|
|
|
|
|
<div class="td fixed_1">{{ child.name }}</div>
|
|
|
|
|
|
<div class="td fixed_2">{{ child.planStartTime }}</div>
|
|
|
|
|
|
<div class="td fixed_3">{{ child.planEndTime }}</div>
|
|
|
|
|
|
<div class="td" v-for="date in dateList" :key="date + 'grid-date'">
|
|
|
|
|
|
<div class="grids">
|
|
|
|
|
|
<div
|
|
|
|
|
|
class="grid"
|
|
|
|
|
|
v-for="day in getDays(date)"
|
|
|
|
|
|
:key="'grid' + day.num"
|
|
|
|
|
|
:ref="(el: any) => setItemRef(el, child.name + '@|@' + day.date)"
|
|
|
|
|
|
></div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div
|
|
|
|
|
|
class="progress"
|
|
|
|
|
|
:style="gantt"
|
|
|
|
|
|
v-for="(gantt, index) in child.gantts"
|
|
|
|
|
|
:key="index"
|
2023-08-07 17:05:36 +08:00
|
|
|
|
@mouseenter="e => handleHover(e, child)"
|
2023-07-24 18:33:58 +08:00
|
|
|
|
@mouseleave="handleLeave"
|
|
|
|
|
|
></div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="tooltips" :style="tooltipsStyle">
|
2023-08-07 17:05:36 +08:00
|
|
|
|
<div class="status">已逾期{{ tooltipContent.day }}天</div>
|
|
|
|
|
|
<div class="charger">负责人:{{ tooltipContent.name }}</div>
|
2023-07-24 18:33:58 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
2023-08-07 17:05:36 +08:00
|
|
|
|
<div class="no-data" v-else>
|
|
|
|
|
|
<img src="@/assets/images/notData.png" alt="notData" />
|
|
|
|
|
|
<div>暂无数据</div>
|
|
|
|
|
|
</div>
|
2023-08-12 11:59:29 +08:00
|
|
|
|
<engineeringEngDrawer v-model="engVisable" ref="engDrawer" :engList="engList">
|
2023-08-09 16:56:27 +08:00
|
|
|
|
<template #default="{ data }">
|
|
|
|
|
|
<span style="margin-left: 10px" @click="onUpdate(data)">{{ data.engineeringName }}</span>
|
|
|
|
|
|
</template>
|
2023-08-12 11:59:29 +08:00
|
|
|
|
</engineeringEngDrawer>
|
2023-08-09 16:56:27 +08:00
|
|
|
|
<allEngineering @click="engVisable = true" />
|
2023-07-24 18:33:58 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script setup lang="tsx" name="ProjectSupervisionRecord">
|
|
|
|
|
|
import { computed, reactive, ref, onMounted, onBeforeMount } from "vue";
|
|
|
|
|
|
import { bigItemAll } from "@/api/modules/project";
|
2023-08-12 11:59:29 +08:00
|
|
|
|
import engineeringEngDrawer from "@/components/engineeringEngDrawer/index.vue";
|
2023-08-09 16:56:27 +08:00
|
|
|
|
import allEngineering from "@/components/allEngineering/index.vue";
|
|
|
|
|
|
import { ElMessage } from "element-plus";
|
|
|
|
|
|
import { getRelevanceList } from "@/api/modules/common";
|
2023-08-12 11:59:29 +08:00
|
|
|
|
const engList = ref([]);
|
2023-08-09 16:56:27 +08:00
|
|
|
|
const engVisable = ref(false);
|
|
|
|
|
|
const searchSn = ref("");
|
2023-07-24 18:33:58 +08:00
|
|
|
|
const headerList = reactive([
|
|
|
|
|
|
{ label: "未开始", color: "#35e5fd" },
|
|
|
|
|
|
{ label: "进行中", color: "#f1d520" },
|
|
|
|
|
|
{ label: "已完成", color: "#4fd389" },
|
|
|
|
|
|
{ label: "逾期未开始", color: "#F80840" },
|
|
|
|
|
|
{ label: "逾期进行中", color: "#fc6f8e" },
|
|
|
|
|
|
{ label: "逾期已完成", color: "#C13F5B" }
|
|
|
|
|
|
]);
|
|
|
|
|
|
const colors = ref(["#35e5fd", "#f1d520", "#4fd389", "#F80840", "#fc6f8e", "#C13F5B"]);
|
|
|
|
|
|
const projects = ref([]);
|
|
|
|
|
|
// const projects = ref([
|
|
|
|
|
|
// {
|
|
|
|
|
|
// pName: "抹灰工程1",
|
|
|
|
|
|
// startTime: "2023/05/29",
|
|
|
|
|
|
// endTime: "2023/07/29",
|
|
|
|
|
|
// status: 1,
|
|
|
|
|
|
// delay: 0,
|
|
|
|
|
|
// gantts: [],
|
|
|
|
|
|
// children: [
|
|
|
|
|
|
// {
|
|
|
|
|
|
// pName: "抹灰工程1-1",
|
|
|
|
|
|
// startTime: "2023/05/29",
|
|
|
|
|
|
// endTime: "2023/07/29",
|
|
|
|
|
|
// status: 1,
|
|
|
|
|
|
// delay: 0,
|
|
|
|
|
|
// gantts: []
|
|
|
|
|
|
// }
|
|
|
|
|
|
// ]
|
|
|
|
|
|
// },
|
|
|
|
|
|
// {
|
|
|
|
|
|
// pName: "抹灰工程2",
|
|
|
|
|
|
// startTime: "2023/06/29",
|
|
|
|
|
|
// endTime: "2023/08/29",
|
|
|
|
|
|
// status: 1,
|
|
|
|
|
|
// delay: 0,
|
|
|
|
|
|
// gantts: [],
|
|
|
|
|
|
// children: [
|
|
|
|
|
|
// {
|
|
|
|
|
|
// pName: "抹灰工程2-1",
|
|
|
|
|
|
// startTime: "2023/06/29",
|
|
|
|
|
|
// endTime: "2023/07/29",
|
|
|
|
|
|
// status: 1,
|
|
|
|
|
|
// delay: 0,
|
|
|
|
|
|
// gantts: []
|
|
|
|
|
|
// }
|
|
|
|
|
|
// ]
|
|
|
|
|
|
// },
|
|
|
|
|
|
// {
|
|
|
|
|
|
// pName: "抹灰工程3",
|
|
|
|
|
|
// startTime: "2023/07/29",
|
|
|
|
|
|
// endTime: "2023/09/29",
|
|
|
|
|
|
// status: 1,
|
|
|
|
|
|
// delay: 0,
|
|
|
|
|
|
// gantts: [],
|
|
|
|
|
|
// children: [
|
|
|
|
|
|
// {
|
|
|
|
|
|
// pName: "抹灰工程3-1",
|
|
|
|
|
|
// startTime: "2023/07/29",
|
|
|
|
|
|
// endTime: "2023/10/29",
|
|
|
|
|
|
// status: 1,
|
|
|
|
|
|
// delay: 0,
|
|
|
|
|
|
// gantts: []
|
|
|
|
|
|
// }
|
|
|
|
|
|
// ]
|
|
|
|
|
|
// }
|
|
|
|
|
|
// ]);
|
|
|
|
|
|
|
|
|
|
|
|
const itemRefs = [];
|
2023-08-12 11:59:29 +08:00
|
|
|
|
const getengineering = async () => {
|
2023-08-09 16:56:27 +08:00
|
|
|
|
// let newParams = JSON.parse(JSON.stringify(params));
|
2023-08-12 11:59:29 +08:00
|
|
|
|
const res = await getRelevanceList();
|
|
|
|
|
|
engList.value = res.result;
|
|
|
|
|
|
if (res.result && res.result.length > 0) {
|
|
|
|
|
|
searchSn.value = res.result[0].engineeringSn;
|
|
|
|
|
|
}
|
|
|
|
|
|
getDataList();
|
|
|
|
|
|
console.log(res);
|
2023-08-09 16:56:27 +08:00
|
|
|
|
};
|
|
|
|
|
|
// 点击抽屉的工程名称更新页面
|
|
|
|
|
|
const onUpdate = async row => {
|
|
|
|
|
|
searchSn.value = row.engineeringSn;
|
|
|
|
|
|
getDataList();
|
|
|
|
|
|
ElMessage.success("页面已更新");
|
|
|
|
|
|
};
|
2023-07-24 18:33:58 +08:00
|
|
|
|
const setItemRef = (el: any, va: any) => {
|
|
|
|
|
|
if (el) {
|
|
|
|
|
|
const b = va.split("@|@");
|
|
|
|
|
|
|
|
|
|
|
|
const dataItem = {
|
|
|
|
|
|
refData: va,
|
|
|
|
|
|
item: el
|
|
|
|
|
|
};
|
|
|
|
|
|
if (itemRefs.length == 0) {
|
|
|
|
|
|
const itemList = [];
|
|
|
|
|
|
itemList.push(dataItem);
|
|
|
|
|
|
const data = {
|
|
|
|
|
|
name: b[0],
|
|
|
|
|
|
itemS: itemList
|
|
|
|
|
|
};
|
|
|
|
|
|
itemRefs.push(data);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
let isCheck = true;
|
|
|
|
|
|
for (let index = 0; index < itemRefs.length; index++) {
|
|
|
|
|
|
const element = itemRefs[index];
|
|
|
|
|
|
if (element.name === b) {
|
|
|
|
|
|
isCheck = false;
|
|
|
|
|
|
element.itemS.push(dataItem);
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (isCheck) {
|
|
|
|
|
|
const itemList = [];
|
|
|
|
|
|
itemList.push(dataItem);
|
|
|
|
|
|
const data = {
|
|
|
|
|
|
name: b[0],
|
|
|
|
|
|
itemS: itemList
|
|
|
|
|
|
};
|
|
|
|
|
|
itemRefs.push(data);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
const scrollLeft = ref(0);
|
|
|
|
|
|
const scrollTimer = ref(0);
|
|
|
|
|
|
const openedIndex = ref(9999);
|
2023-08-07 17:05:36 +08:00
|
|
|
|
const tooltipsStyle = ref({
|
2023-07-24 18:33:58 +08:00
|
|
|
|
display: "none",
|
|
|
|
|
|
left: 0,
|
|
|
|
|
|
top: 0
|
|
|
|
|
|
});
|
2023-08-07 17:05:36 +08:00
|
|
|
|
const tooltipContent = ref({
|
|
|
|
|
|
day: 0,
|
|
|
|
|
|
name: ""
|
|
|
|
|
|
});
|
2023-07-24 18:33:58 +08:00
|
|
|
|
const getDataList = async () => {
|
2023-08-09 16:56:27 +08:00
|
|
|
|
const res = await bigItemAll({ engineeringSn: searchSn.value });
|
2023-07-24 18:33:58 +08:00
|
|
|
|
console.log(res);
|
|
|
|
|
|
if (res) {
|
|
|
|
|
|
const arr = dealArr(res.result);
|
|
|
|
|
|
projects.value = arr;
|
|
|
|
|
|
}
|
|
|
|
|
|
setTimeout(function () {
|
|
|
|
|
|
setGantts();
|
|
|
|
|
|
}, 300);
|
|
|
|
|
|
};
|
|
|
|
|
|
const dealArr = arr => {
|
|
|
|
|
|
arr.map(item => {
|
|
|
|
|
|
item.gantts = [];
|
|
|
|
|
|
item.delay = 0;
|
|
|
|
|
|
if (item.children && item.children.length > 0) {
|
|
|
|
|
|
dealArr(item.children);
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
return arr;
|
|
|
|
|
|
};
|
|
|
|
|
|
onBeforeMount(() => {});
|
|
|
|
|
|
onMounted(() => {
|
2023-08-12 11:59:29 +08:00
|
|
|
|
getengineering();
|
2023-07-24 18:33:58 +08:00
|
|
|
|
console.log(getDays("2022-09"), "月日期分布");
|
|
|
|
|
|
});
|
|
|
|
|
|
const getGanttStyle = (project: any) => {
|
|
|
|
|
|
console.log("进入 getGanttStyle --- ", project);
|
|
|
|
|
|
|
|
|
|
|
|
let { planStartTime, planEndTime, name } = project;
|
|
|
|
|
|
const startArr = planStartTime.split("-");
|
|
|
|
|
|
const endArr = planEndTime.split("-");
|
|
|
|
|
|
let startRef = null;
|
|
|
|
|
|
let endRef = null;
|
|
|
|
|
|
// 抹灰工程1-1-2022/09/03
|
|
|
|
|
|
|
|
|
|
|
|
const a = !(startArr[2] % 2);
|
|
|
|
|
|
console.log(a, ":!(startArr[2] % 2:");
|
|
|
|
|
|
if (a) {
|
|
|
|
|
|
const day = startArr[2] - 1;
|
|
|
|
|
|
startArr[2] = day < 10 ? "0" + day : day;
|
|
|
|
|
|
planStartTime = startArr.join("-");
|
|
|
|
|
|
}
|
|
|
|
|
|
const b = !(endArr[2] % 2);
|
|
|
|
|
|
console.log(a, ":!(endArr[2] % 2):");
|
|
|
|
|
|
if (!(endArr[2] % 2)) {
|
|
|
|
|
|
const day = endArr[2] - 1;
|
|
|
|
|
|
endArr[2] = day < 10 ? "0" + day : day;
|
|
|
|
|
|
planEndTime = endArr.join("-");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
console.log(dateList, "planEndTime ------------", itemRefs.length);
|
|
|
|
|
|
for (let index = 0; index < itemRefs.length; index++) {
|
|
|
|
|
|
const data = itemRefs[index];
|
|
|
|
|
|
|
|
|
|
|
|
if (data.name === name) {
|
|
|
|
|
|
for (let index = 0; index < data.itemS.length; index++) {
|
|
|
|
|
|
const element = data.itemS[index];
|
|
|
|
|
|
if (element.refData === name + "@|@" + planStartTime) {
|
|
|
|
|
|
startRef = data.itemS[index].item;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (element.refData === name + "@|@" + planEndTime) {
|
|
|
|
|
|
endRef = data.itemS[index].item;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const startLeft = startRef.offsetLeft;
|
|
|
|
|
|
|
|
|
|
|
|
const endWidth = endRef.offsetWidth;
|
|
|
|
|
|
|
|
|
|
|
|
const endLeft = endRef.offsetLeft;
|
|
|
|
|
|
const ganttWidth = endLeft - startLeft + endWidth;
|
|
|
|
|
|
|
|
|
|
|
|
return { left: startLeft + "px", width: ganttWidth + "px" };
|
|
|
|
|
|
};
|
|
|
|
|
|
const setGantts = () => {
|
|
|
|
|
|
const configGantts = (projects: any) => {
|
|
|
|
|
|
console.log("进入渲染 setGantts -- ", projects);
|
|
|
|
|
|
projects.map(project => {
|
|
|
|
|
|
let { planEndTime, name, gantts } = project;
|
|
|
|
|
|
const gantt = getGanttStyle(project);
|
|
|
|
|
|
gantt.background = colors.value[project.state - 1];
|
|
|
|
|
|
|
|
|
|
|
|
if (gantts) {
|
|
|
|
|
|
gantts.push(gantt);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
project.gantts = [gantt];
|
|
|
|
|
|
}
|
|
|
|
|
|
if (project.delay) {
|
|
|
|
|
|
const delayStartTime = increaseDate(planEndTime, 1);
|
|
|
|
|
|
const delayEndTime = increaseDate(planEndTime, project.delay);
|
|
|
|
|
|
const gantt = getGanttStyle({
|
|
|
|
|
|
planStartTime: delayStartTime,
|
|
|
|
|
|
planEndTime: delayEndTime,
|
|
|
|
|
|
name
|
|
|
|
|
|
});
|
|
|
|
|
|
gantt.background = colors.value[3];
|
|
|
|
|
|
gantts.push(gantt);
|
|
|
|
|
|
}
|
|
|
|
|
|
project.children && configGantts(project.children);
|
|
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
configGantts(projects.value);
|
|
|
|
|
|
};
|
|
|
|
|
|
const increaseDate = (date: any, delay: any) => {
|
|
|
|
|
|
const timestamp = new Date(date).getTime() + (delay + 1) * 1000 * 60 * 60 * 24;
|
|
|
|
|
|
return new Date(timestamp).toISOString().replace(/-/g, "-").slice(0, 10);
|
|
|
|
|
|
};
|
|
|
|
|
|
const getDays = (date: any) => {
|
|
|
|
|
|
const year = date.split("-")[0];
|
|
|
|
|
|
const month = +date.split("-")[1];
|
|
|
|
|
|
const large = [1, 3, 5, 7, 8, 10, 12];
|
|
|
|
|
|
const normal = [4, 6, 9, 11];
|
|
|
|
|
|
const small = [2];
|
|
|
|
|
|
let count = 0;
|
|
|
|
|
|
switch (true) {
|
|
|
|
|
|
case large.includes(month):
|
|
|
|
|
|
count = 31;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case normal.includes(month):
|
|
|
|
|
|
count = 30;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case small.includes(month):
|
|
|
|
|
|
count = year % 4 ? 28 : 29;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return (() => {
|
|
|
|
|
|
const days = new Array(count)
|
|
|
|
|
|
.fill(0)
|
|
|
|
|
|
.map((item, index) => {
|
|
|
|
|
|
let num = index + 1;
|
|
|
|
|
|
let fulldate = date + (num < 10 ? "-0" + num : "-" + num);
|
|
|
|
|
|
return { num, date: fulldate };
|
|
|
|
|
|
})
|
|
|
|
|
|
.filter(item => item.num % 2);
|
|
|
|
|
|
if (count === 28) {
|
|
|
|
|
|
days.push({ num: 28, date: date + "-28" });
|
|
|
|
|
|
} else if (count === 30) {
|
|
|
|
|
|
days.push({ num: 30, date: date + "-30" });
|
|
|
|
|
|
}
|
|
|
|
|
|
return days;
|
|
|
|
|
|
})();
|
|
|
|
|
|
};
|
|
|
|
|
|
const handleOpen = (index: any) => {
|
|
|
|
|
|
console.log(666);
|
|
|
|
|
|
console.log(index);
|
|
|
|
|
|
console.log(openedIndex.value);
|
|
|
|
|
|
if (index === openedIndex.value) {
|
|
|
|
|
|
openedIndex.value = 9999;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
openedIndex.value = index;
|
|
|
|
|
|
}
|
|
|
|
|
|
setTimeout(function () {
|
|
|
|
|
|
setGantts();
|
|
|
|
|
|
}, 300);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const handleScroll = (e: any) => {
|
|
|
|
|
|
if (scrollTimer.value) {
|
|
|
|
|
|
clearTimeout(scrollTimer.value);
|
|
|
|
|
|
}
|
|
|
|
|
|
scrollTimer.value = setTimeout(() => {
|
|
|
|
|
|
scrollLeft.value = e.target.scrollLeft;
|
|
|
|
|
|
scrollTimer.value = null;
|
|
|
|
|
|
}, 100);
|
|
|
|
|
|
const fixedElement1 = document.querySelectorAll(".fixed_1");
|
|
|
|
|
|
const fixedElement2 = document.querySelectorAll(".fixed_2");
|
|
|
|
|
|
const fixedElement3 = document.querySelectorAll(".fixed_3");
|
|
|
|
|
|
console.log(fixedElement1);
|
|
|
|
|
|
console.log(fixedElement1[0]);
|
|
|
|
|
|
console.log(fixedElement1.length);
|
|
|
|
|
|
for (let i = 0; i < fixedElement1.length; i++) {
|
|
|
|
|
|
fixedElement1[i].style.left = e.target.scrollLeft + "px";
|
|
|
|
|
|
}
|
|
|
|
|
|
for (let i = 0; i < fixedElement2.length; i++) {
|
|
|
|
|
|
fixedElement2[i].style.left = e.target.scrollLeft + "px";
|
|
|
|
|
|
}
|
|
|
|
|
|
for (let i = 0; i < fixedElement3.length; i++) {
|
|
|
|
|
|
fixedElement3[i].style.left = e.target.scrollLeft + "px";
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
2023-08-07 17:05:36 +08:00
|
|
|
|
const handleHover = (e: any, item: any) => {
|
|
|
|
|
|
console.log(666);
|
|
|
|
|
|
console.log(e);
|
|
|
|
|
|
console.log(item);
|
2023-08-10 17:43:51 +08:00
|
|
|
|
if (item.state == 4 || item.state == 5 || item.state == 6) {
|
2023-08-07 17:05:36 +08:00
|
|
|
|
const { clientX, clientY } = e;
|
2023-08-09 16:56:27 +08:00
|
|
|
|
const decreaseLeft = clientX - 380;
|
2023-08-07 17:05:36 +08:00
|
|
|
|
const decreaseTop = clientY - 200;
|
|
|
|
|
|
tooltipsStyle.value = {
|
|
|
|
|
|
left: decreaseLeft + scrollLeft.value + "px",
|
|
|
|
|
|
top: decreaseTop + "px",
|
|
|
|
|
|
display: "block"
|
|
|
|
|
|
};
|
|
|
|
|
|
tooltipContent.value = {
|
|
|
|
|
|
day: item.delay,
|
|
|
|
|
|
name: item.commander
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
2023-07-24 18:33:58 +08:00
|
|
|
|
};
|
|
|
|
|
|
const handleLeave = () => {
|
2023-08-09 16:56:27 +08:00
|
|
|
|
tooltipsStyle.value.display = "none";
|
2023-07-24 18:33:58 +08:00
|
|
|
|
};
|
|
|
|
|
|
const dateList = computed(() => {
|
|
|
|
|
|
let dates = [];
|
|
|
|
|
|
const mapDates = data => {
|
|
|
|
|
|
data.map(p => {
|
|
|
|
|
|
dates.push(p.planStartTime);
|
|
|
|
|
|
dates.push(p.planEndTime);
|
|
|
|
|
|
p.children && mapDates(p.children);
|
|
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
mapDates(projects.value);
|
|
|
|
|
|
dates = dates.map(date => date.slice(0, 7)).sort();
|
|
|
|
|
|
dates = [...new Set(dates)];
|
|
|
|
|
|
console.log("dateList----", dates);
|
|
|
|
|
|
return dates;
|
|
|
|
|
|
});
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style scoped lang="scss">
|
|
|
|
|
|
.gantt-box {
|
|
|
|
|
|
box-sizing: border-box;
|
|
|
|
|
|
min-width: 1120px;
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
padding: 18px;
|
|
|
|
|
|
background: #ffffff;
|
|
|
|
|
|
border-radius: 8px;
|
|
|
|
|
|
.header {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
height: 60px;
|
|
|
|
|
|
|
|
|
|
|
|
.left-content {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
width: 65%;
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
|
|
|
|
|
|
.item {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
// width: calc(100% / 4);
|
|
|
|
|
|
margin-right: 20px;
|
|
|
|
|
|
|
|
|
|
|
|
.color-block {
|
|
|
|
|
|
margin-right: 10px;
|
|
|
|
|
|
width: 15px;
|
|
|
|
|
|
height: 15px;
|
|
|
|
|
|
border-radius: 2px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.label {
|
|
|
|
|
|
color: #29304d;
|
|
|
|
|
|
font-size: 18px;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.right-content {
|
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
|
line-height: 60px;
|
|
|
|
|
|
color: #cccccc;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
.gantt-chart {
|
|
|
|
|
|
height: calc(100% - 145px);
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
.table {
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
overflow-x: auto;
|
|
|
|
|
|
|
|
|
|
|
|
&::-webkit-scrollbar {
|
|
|
|
|
|
width: 10px;
|
|
|
|
|
|
height: 8px;
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
&::-webkit-scrollbar-thumb {
|
|
|
|
|
|
border-radius: 10px;
|
|
|
|
|
|
background-color: #e6f2ff;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.thead {
|
|
|
|
|
|
width: max-content;
|
|
|
|
|
|
// border-left: 1px solid #0a769a;
|
|
|
|
|
|
|
|
|
|
|
|
.row {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
.fixed_1,
|
|
|
|
|
|
.fixed_2,
|
|
|
|
|
|
.fixed_3 {
|
|
|
|
|
|
width: 200px;
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
background: #e2ebff;
|
|
|
|
|
|
z-index: 10;
|
|
|
|
|
|
}
|
|
|
|
|
|
.fixed_1 {
|
|
|
|
|
|
border-left: 1px solid #cbd1df;
|
|
|
|
|
|
left: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
.fixed_2 {
|
|
|
|
|
|
left: 0px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.fixed_3 {
|
|
|
|
|
|
left: 0px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.td {
|
|
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
|
box-sizing: border-box;
|
|
|
|
|
|
height: 42px;
|
|
|
|
|
|
line-height: 42px;
|
|
|
|
|
|
background-color: #e2ebff;
|
|
|
|
|
|
color: #666666;
|
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
|
border-top: 1px solid #cbd1df;
|
|
|
|
|
|
.date {
|
|
|
|
|
|
line-height: 21px;
|
|
|
|
|
|
border-left: 1px solid #cbd1df;
|
|
|
|
|
|
|
|
|
|
|
|
.month {
|
|
|
|
|
|
border-bottom: 1px solid #cbd1df;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.days {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
|
|
|
|
|
|
.day {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
&:nth-child(1) {
|
|
|
|
|
|
padding-left: 30px;
|
|
|
|
|
|
width: 200px;
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
white-space: nowrap;
|
|
|
|
|
|
text-overflow: ellipsis;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
&:not(:nth-child(1)) {
|
|
|
|
|
|
width: 100px;
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
&:nth-child(n + 4) {
|
|
|
|
|
|
width: 400px;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.tbody {
|
|
|
|
|
|
width: max-content;
|
|
|
|
|
|
// border-left: 1px solid #0a769a;
|
|
|
|
|
|
|
|
|
|
|
|
.row-groups {
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
height: 42px;
|
|
|
|
|
|
// &::before {
|
|
|
|
|
|
// content: "";
|
|
|
|
|
|
// position: absolute;
|
|
|
|
|
|
// left: 26px;
|
|
|
|
|
|
// top: 16px;
|
|
|
|
|
|
// width: 0;
|
|
|
|
|
|
// height: 0;
|
|
|
|
|
|
// border-top: 4px solid transparent;
|
|
|
|
|
|
// border-right: 4px solid transparent;
|
|
|
|
|
|
// border-bottom: 4px solid transparent;
|
|
|
|
|
|
// border-left: 4px solid #5be1f4;
|
|
|
|
|
|
// z-index: 99;
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
&.open {
|
|
|
|
|
|
height: unset;
|
|
|
|
|
|
|
|
|
|
|
|
// &::before {
|
|
|
|
|
|
// border-left-color: transparent;
|
|
|
|
|
|
// border-top-color: #5be1f4;
|
|
|
|
|
|
// }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
> .row .td:first-child {
|
|
|
|
|
|
user-select: none;
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.row {
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
border-top: 1px solid #cbd1df;
|
|
|
|
|
|
.fixed_1,
|
|
|
|
|
|
.fixed_2,
|
|
|
|
|
|
.fixed_3 {
|
|
|
|
|
|
width: 200px;
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
background: #092945;
|
|
|
|
|
|
z-index: 10;
|
|
|
|
|
|
}
|
|
|
|
|
|
.fixed_1 {
|
|
|
|
|
|
left: 0;
|
|
|
|
|
|
border-left: 1px solid #cbd1df;
|
|
|
|
|
|
}
|
|
|
|
|
|
.fixed_2 {
|
|
|
|
|
|
left: 0px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.fixed_3 {
|
|
|
|
|
|
left: 0px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.td {
|
|
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
|
box-sizing: border-box;
|
|
|
|
|
|
height: 42px;
|
|
|
|
|
|
line-height: 42px;
|
|
|
|
|
|
background-color: #fff;
|
|
|
|
|
|
border-right: 1px solid #cbd1df;
|
|
|
|
|
|
border-bottom: 1px solid #cbd1df;
|
|
|
|
|
|
border-top: 1px solid #cbd1df;
|
|
|
|
|
|
color: #333333;
|
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
|
|
|
|
|
|
|
.grids {
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
|
|
|
|
|
|
.grid {
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
|
|
|
|
|
|
&:not(:last-child) {
|
|
|
|
|
|
border-right: 1px solid #cbd1df;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
&:nth-child(1) {
|
|
|
|
|
|
padding-left: 40px;
|
|
|
|
|
|
width: 200px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
&:not(:nth-child(1)) {
|
|
|
|
|
|
width: 100px;
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
&:nth-child(n + 4) {
|
|
|
|
|
|
width: 400px;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.progress {
|
|
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
top: calc(50% - 7px);
|
|
|
|
|
|
width: 20px;
|
|
|
|
|
|
height: 14px;
|
|
|
|
|
|
background: #557dee;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.children {
|
|
|
|
|
|
.td {
|
|
|
|
|
|
height: 38px;
|
|
|
|
|
|
line-height: 38px;
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.tooltips {
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
box-sizing: border-box;
|
|
|
|
|
|
padding: 10px;
|
2023-08-07 17:05:36 +08:00
|
|
|
|
width: 160px;
|
2023-07-24 18:33:58 +08:00
|
|
|
|
height: 65px;
|
|
|
|
|
|
border-radius: 8px;
|
2023-08-07 17:05:36 +08:00
|
|
|
|
// background-color: #50a6b3;
|
|
|
|
|
|
box-shadow: 1px 1px 10px #ccc;
|
|
|
|
|
|
background-color: white;
|
2023-07-24 18:33:58 +08:00
|
|
|
|
.status {
|
2023-08-07 17:05:36 +08:00
|
|
|
|
// display: inline-block;
|
2023-07-24 18:33:58 +08:00
|
|
|
|
margin-bottom: 6px;
|
|
|
|
|
|
height: 20px;
|
2023-08-07 17:05:36 +08:00
|
|
|
|
width: 100px;
|
2023-07-24 18:33:58 +08:00
|
|
|
|
line-height: 20px;
|
2023-08-07 17:05:36 +08:00
|
|
|
|
font-size: 14px;
|
2023-07-24 18:33:58 +08:00
|
|
|
|
border-radius: 10px;
|
2023-08-07 17:05:36 +08:00
|
|
|
|
// background-color: #ff6c7f;
|
|
|
|
|
|
background-color: #e83030;
|
|
|
|
|
|
color: white;
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
margin: 0 auto;
|
|
|
|
|
|
}
|
|
|
|
|
|
.charger {
|
|
|
|
|
|
color: #333;
|
|
|
|
|
|
text-align: center;
|
2023-07-24 18:33:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2023-08-07 17:05:36 +08:00
|
|
|
|
.no-data {
|
|
|
|
|
|
height: calc(100% - 145px);
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
color: #999;
|
|
|
|
|
|
}
|
2023-07-24 18:33:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
</style>
|