From a3e27f5cab583debe11a9c62d8cc0115783b0791 Mon Sep 17 00:00:00 2001
From: Gary Gu <garygu@Garydebijibendiannao.local>
Date: Wed, 28 May 2025 16:59:43 +0800
Subject: [PATCH] fix: 优化实况UI放大缩小

---
 src/components/Gantt.vue |  660 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 660 insertions(+), 0 deletions(-)

diff --git a/src/components/Gantt.vue b/src/components/Gantt.vue
new file mode 100644
index 0000000..d65cee0
--- /dev/null
+++ b/src/components/Gantt.vue
@@ -0,0 +1,660 @@
+<template>
+  <div class="gantt-box">
+    <div class="gantt-header">
+      <div>
+        <el-button size="small" type="primary" @click="yearClick">年</el-button>
+        <el-button size="small" type="primary" @click="monthClick">月</el-button>
+        <el-button size="small" type="primary" @click="weekClick">周</el-button>
+        <!-- <el-button size="small" type="primary" @click="dayClick">日</el-button> -->
+      </div>
+      <div>
+        <el-button style="margin-right: 20px" size="small" type="primary" v-if="!columnsShow" @click="toggle('1')">展开详情</el-button>
+        <el-button style="margin-right: 20px" size="small" type="primary" v-else @click="toggle('2')">关闭详情</el-button>
+        <span>备注:</span>
+        <span>进行中</span><span class="color" style="background-color: rgb(211, 211, 0)"></span>, <span>待进行</span
+        ><span class="color" style="background-color: rgb(170, 170, 127)"></span>, <span>延期未完工</span
+        ><span class="color" style="background-color: rgb(255, 0, 0)"></span>, <span>延期已完工</span
+        ><span class="color" style="background-color: #8bc34a"></span>, <span>已完工/提前完工</span
+        ><span class="color" style="background-color: rgb(14, 172, 81)"></span>
+      </div>
+    </div>
+    <div ref="gantt" style="height: 400px; font-size: 12px"></div>
+  </div>
+</template>
+
+<script>
+  import axios from "axios";
+  import { gantt } from "dhtmlx-gantt";
+  import "dhtmlx-gantt/codebase/dhtmlxgantt.css";
+
+  export default {
+    name: "Gantt",
+    components: {},
+    data() {
+      return {
+        taskslist: [],
+        // 甘特图配置
+        tasks: {
+          data: [],
+        },
+        columnsShow: false,
+      };
+    },
+    mounted() {
+      this.init(); //初始化
+      this.getProjectqryDataColl(); //获取数据
+    },
+    methods: {
+      // 将毫秒值转换为普通的日期格式 yyyy-MM-dd
+      formatDate(time) {
+        const myTime = new Date(time);
+        const yyyy = myTime.getFullYear();
+        let MM = myTime.getMonth() + 1;
+        if (MM < 10) {
+          MM = "0" + MM;
+        }
+        let dd = myTime.getDate();
+        if (dd < 10) {
+          dd = "0" + dd;
+        }
+        const str = yyyy + "-" + MM + "-" + dd;
+        return str;
+      },
+      // 获取两个时间相减的天数
+      getDays(strDateStart, strDateEnd) {
+        var strSeparator = "-";
+        //日期分隔符   var oDate1;   var oDate2;
+        var iDays;
+        var oDate1 = strDateStart.split(strSeparator);
+        var oDate2 = strDateEnd.split(strSeparator);
+        var strDateS = new Date(oDate1[0], oDate1[1] - 1, oDate1[2]);
+        var strDateE = new Date(oDate2[0], oDate2[1] - 1, oDate2[2]);
+        var iDays = parseInt(Math.abs(strDateS - strDateE) / 1000 / 60 / 60 / 24);
+        //把相差的毫秒数转换为天数
+        return iDays;
+      },
+      getIntervalDays(timestamp) {
+        const date1 = new Date();
+        const date2 = new Date(timestamp);
+        const diff = Math.abs(date2.getTime() - date1.getTime()); // 计算时间差(毫秒)
+        return Math.floor(diff / (1000 * 60 * 60 * 24)); // 将时间差转换为天数
+      },
+      // 计算时间进度
+      getIntervalDays2(timestamp1, timestamp2) {
+        const now = new Date();
+        const date1 = new Date(timestamp1);
+        const date2 = new Date(timestamp2);
+        const diff = Math.abs(date2.getTime() - date1.getTime()); // 计算时间差(毫秒)
+        const total = Math.floor(diff / (1000 * 60 * 60 * 24)); // 将时间差转换为天数
+        const diff2 = Math.abs(now.getTime() - date1.getTime()); // 计算时间差(毫秒)
+        const real = Math.floor(diff2 / (1000 * 60 * 60 * 24)); // 将时间差转换为天数
+        return Math.floor((real / total) * 100);
+      },
+
+      clickdataAll() {
+        let clickdata = [];
+        let colors = "";
+        this.taskslist.map((item) => {
+          var arr = this.formatDate(item.begin1).split("-");
+          var arr1 = this.formatDate(item.over1).split("-");
+          var startTime = arr[2] + "-" + arr[1] + "-" + arr[0];
+          var endTime = arr1[2] + "-" + arr1[1] + "-" + arr1[0];
+
+          var arr2 = [];
+          var arr3 = [];
+          var startTime1 = "";
+          var endTime1 = "";
+          var duration1 = "";
+          if (item.begin2 != null) {
+            startTime1 = this.formatDate(item.begin2);
+          }
+          if (item.over2 != null) {
+            endTime1 = this.formatDate(item.over2);
+          }
+
+          if (startTime1 != "" && endTime1 != "") {
+            duration1 = this.getDays(startTime1, endTime1);
+          }
+          if (item.zt == "0") {
+            colors = "#aaaa7f";
+          }
+          if (item.zt == "1") {
+            colors = "#d3d300";
+          }
+          if (item.zt == "2" || item.zt == "3") {
+            colors = "#0eac51";
+          }
+          if (item.zt == "5") {
+            colors = "#ff0000";
+          }
+          if (item.zt == "4") {
+            colors = "#8bc34a";
+          }
+          clickdata.push({
+            id: item.id,
+            text: item.project,
+            start_date: startTime,
+            end_date: endTime,
+            parent: item.parent,
+            duration: "4",
+            start_date1: startTime1,
+            end_date1: endTime1,
+            duration1: duration1,
+            progress: 0,
+            open: true,
+            color: colors,
+            remark: item.remark,
+          });
+        });
+        gantt.clearAll();
+        this.tasks.data = clickdata;
+        gantt.parse(this.tasks);
+        gantt.refreshData();
+        this.ganttLoading = false;
+      },
+
+      clearDirtyData() {
+        let baseList = [];
+        let baseList2 = [];
+        let baseList3 = [];
+        this.taskslist.map((item) => {
+          item.used = false;
+          item.baseTitle = "";
+        });
+        // 先筛选父级
+        this.taskslist.map((item) => {
+          if (!item.used && !item.parent) {
+            item.used = true;
+            item.baseTitle = "[" + item.project + "]";
+            baseList.push(item);
+          }
+        });
+        baseList.map((item) => {
+          this.taskslist.map((item2) => {
+            if (!item2.used && item2.parent == item.id) {
+              item2.used = true;
+              item2.baseTitle = item.baseTitle + "->[" + item2.project + "]";
+              baseList2.push(item2);
+            }
+          });
+        });
+
+        baseList2.map((item) => {
+          this.taskslist.map((item2) => {
+            if (!item2.used && item2.parent == item.id) {
+              item2.used = true;
+              item2.baseTitle = item.baseTitle + "->[" + item2.project + "]";
+              baseList3.push(item2);
+            }
+          });
+        });
+
+        baseList3.map((item) => {
+          this.taskslist.map((item2) => {
+            if (!item2.used && item2.parent == item.id) {
+              item2.used = true;
+              item2.baseTitle = item.baseTitle + "->[" + item2.project + "]";
+            }
+          });
+        });
+
+        let copyTaskslist = [];
+        this.taskslist.map((item) => {
+          if (item.baseTitle) {
+            copyTaskslist.push(item);
+          }
+        });
+        this.taskslist = copyTaskslist;
+      },
+      // 获取工程进度项目列表
+      getProjectqryDataColl() {
+        axios.get("https://api.zhihuibuild.com/zuul/zuul/jinchan-device/project/qryProjectProgress").then(({ data }) => {
+          // 接口获取data
+          if (data.code == "200") {
+            if (data.body.length != 0) {
+              this.taskslist = data.body;
+              this.clearDirtyData();
+              let cache = [];
+
+              this.taskslist.map((item, index) => {
+                item.zIndex = index + 1;
+                // 重新判断状态
+                let nowTime = new Date().getTime();
+                if (!item.begin2) {
+                  //未开始
+                  item.zt = 0;
+                } else {
+                  if (!item.over2) {
+                    //未结束
+                    if (item.over1 >= nowTime) {
+                      //判断预计工期是否超过当前时间
+                      item.zt = 1; //进行中
+                    } else {
+                      item.zt = 5; //延期未完工
+                    }
+                  } else {
+                    if (item.over1 >= item.over2) {
+                      //判断预计工期是否超过实际工期
+                      item.zt = 3; //提前完工2、3
+                    } else {
+                      item.zt = 4; //延期完工
+                    }
+                  }
+                }
+                if (item.zt == "5") {
+                  cache.push([cache.length + 1, item.project, this.getIntervalDays(item.over1)]);
+                }
+              });
+
+              cache.sort(function (a, b) {
+                return b[2] - a[2];
+              });
+              cache.map((item, index) => {
+                item[0] = index + 1;
+                item[2] = item[2] + "天";
+              });
+
+              setTimeout(() => {
+                this.clickdataAll();
+              }, 1000);
+            }
+          }
+        });
+      },
+      yearClick() {
+        gantt.config.scales = [
+          {
+            unit: "year",
+            step: 1,
+            date: " %Y",
+          },
+        ];
+        gantt.init(this.$refs.gantt);
+      },
+      monthClick() {
+        gantt.config.scales = [
+          {
+            unit: "year",
+            step: 1,
+            date: " %Y",
+          },
+          {
+            unit: "month",
+            step: 1,
+            date: "%F",
+          },
+        ];
+        gantt.init(this.$refs.gantt);
+      },
+      weekClick() {
+        gantt.config.scales = [
+          {
+            unit: "year",
+            step: 1,
+            date: " %Y",
+          },
+          {
+            unit: "month",
+            step: 1,
+            date: "%F",
+          },
+          {
+            unit: "week",
+            step: 1,
+            date: "%W周",
+          },
+        ];
+        gantt.init(this.$refs.gantt);
+      },
+      dayClick() {
+        gantt.config.scales = [
+          {
+            unit: "year",
+            step: 1,
+            date: " %Y",
+          },
+          {
+            unit: "month",
+            step: 1,
+            date: "%F",
+          },
+          {
+            unit: "day",
+            step: 1,
+            date: "%j日",
+          },
+        ];
+        gantt.init(this.$refs.gantt);
+      },
+      riliClick() {
+        gantt.config.scales = [
+          {
+            unit: "month",
+            step: 1,
+            date: " %Y - %F",
+          },
+          {
+            unit: "day",
+            step: 1,
+            date: "%j日   周%D",
+          },
+        ];
+        gantt.init(this.$refs.gantt);
+      },
+      toggle(val) {
+        if (val == 1) {
+          this.columnsShow = true;
+        } else {
+          this.columnsShow = false;
+        }
+        //左侧显示列名
+        if (val == "1") {
+          gantt.config.columns = [
+            {
+              name: "text",
+              label: "任务名称",
+              tree: true,
+              align: "left",
+              resize: true,
+              width: "*",
+              min_width: 220,
+            },
+            {
+              name: "start_date",
+              label: "计划开始",
+              align: "center",
+              resize: true,
+              width: "*",
+              min_width: 100,
+            },
+            {
+              name: "end_date",
+              label: "计划结束",
+              align: "center",
+              resize: true,
+              width: "*",
+              min_width: 100,
+            },
+            {
+              name: "duration",
+              label: "工期",
+              align: "center",
+            },
+            {
+              name: "start_date1",
+              label: "实际开始",
+              align: "center",
+              resize: true,
+              width: "*",
+              min_width: 100,
+            },
+            {
+              name: "end_date1",
+              label: "实际结束",
+              align: "center",
+              resize: true,
+              width: "*",
+              min_width: 100,
+            },
+            {
+              name: "duration1",
+              label: "实际工期",
+              align: "center",
+            },
+            {
+              name: "zt",
+              label: "",
+              align: "center",
+              resize: false,
+            },
+          ];
+        } else {
+          gantt.config.columns = [
+            {
+              name: "text",
+              label: "任务名称",
+              tree: true,
+              align: "left",
+              resize: true,
+              width: 250,
+            },
+          ];
+        }
+
+        // 初始化
+        gantt.init(this.$refs.gantt);
+        // 数据解析
+        gantt.parse(this.tasks);
+      },
+      // 初始化
+      init() {
+        // 自动延长时间刻度
+        gantt.config.fit_tasks = true;
+        gantt.config.show_links = false;
+        gantt.config.drag_progress = false; // 取消进度条
+        gantt.config.row_height = 25; //进度条容器高
+        gantt.config.scale_height = 50;
+        gantt.config.autofit = true; //左侧是否自适应
+        gantt.i18n.setLocale("cn"); // 设置中文
+        gantt.config.readonly = true; // 设置为只读
+        //自适应甘特图的尺寸大小, 使得在不出现滚动条的情况下, 显示全部任务
+        gantt.config.autosize = false;
+        gantt.config.open_split_tasks = true;
+        // 允许拖放
+        gantt.config.drag_project = true;
+        // 设置甘特图时间的起始结束时间,并允许显示超过时间刻度任务
+        // gantt.config.start_date = new Date(`${new Date().getFullYear()-1}`,'01');
+        // gantt.config.end_date = new Date(`${new Date().getFullYear()+1}`,'01');
+        gantt.config.show_tasks_outside_timescale = true;
+        //开启提示:鼠标悬浮在gantt行上显示
+        gantt.plugins({
+          tooltip: true,
+          // quick_info: true,// 快速信息框
+          multiselect: true, // 激活多任务选择
+        });
+
+        gantt.templates.tooltip_text = function (start, end, task) {
+          return (
+            "<b>项目: <span style='color:" +
+            task.color +
+            "'>" +
+            task.text +
+            "</span><br/><span>实际开始:" +
+            task.start_date1 +
+            "</span> " +
+            "</span><br/><span>实际结束:" +
+            task.end_date1 +
+            "</span> " +
+            "</span><br/><br/><span>计划开始:" +
+            gantt.templates.tooltip_date_format(start) +
+            "</span> " +
+            "<br/><span>计划结束:" +
+            gantt.templates.tooltip_date_format(end) +
+            "</span> " +
+            (task.remark ? `<br/><span>备注:${task.remark}</span>` : "")
+          );
+        };
+        // 按月
+        gantt.config.scales = [
+          {
+            unit: "year",
+            step: 1,
+            date: " %Y",
+          },
+          {
+            unit: "month",
+            step: 1,
+            date: "%F",
+          },
+        ];
+
+        //左侧显示列名
+        gantt.config.columns = [
+          {
+            name: "text",
+            label: "任务名称",
+            tree: true,
+            align: "left",
+            resize: true,
+            width: 250,
+          },
+        ];
+        // 初始化
+        gantt.init(this.$refs.gantt);
+
+        // 数据解析
+        gantt.parse(this.tasks);
+      },
+    },
+  };
+</script>
+<style lang="scss" scoped>
+  .gantt-box {
+    background-color: rgba(0, 0, 0, 0.2);
+    margin: 10px;
+    color: #fff;
+
+    .gantt-header {
+      padding-top: 5px;
+      margin: 10px;
+      height: 40px;
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+
+      .color {
+        width: 36px;
+        height: 16px;
+        vertical-align: text-top;
+        display: inline-block;
+        margin-right: 5px;
+        margin-left: 5px;
+      }
+    }
+
+    /* 滚动条样式*/
+    ::-webkit-scrollbar {
+      width: 10px;
+      height: 10px;
+      background-color: transparent;
+    }
+
+    ::-webkit-scrollbar-thumb {
+      background-color: #73abb1;
+      border-radius: 6px;
+    }
+
+    ::-webkit-scrollbar-track {
+      background-color: #373f4a;
+      opacity: 0.9;
+    }
+  }
+</style>
+<style lang="scss">
+  body {
+    background-color: rgb(19, 90, 144);
+  }
+
+  /* 自定义甘特图样式 */
+  .gantt_grid_data .gantt_row.gantt_selected,
+  .gantt_grid_data .gantt_row.odd.gantt_selected,
+  .gantt_task_row.gantt_selected {
+    background-color: #409eff !important;
+  }
+
+  .gantt_grid_data .gantt_row.odd:hover,
+  .gantt_grid_data .gantt_row:hover {
+    background-color: #409eff !important;
+  }
+
+  .gantt_grid_scale .gantt_grid_head_cell {
+    color: #fff !important;
+  }
+
+  .gantt_grid_scale,
+  .gantt_task_scale,
+  .gantt_task_vscroll {
+    background-color: transparent;
+  }
+
+  /* 大背景透明 */
+  .gantt_container {
+    background-color: transparent;
+  }
+
+  /* 左标题文字白色 */
+  .gantt_grid_data .gantt_cell {
+    color: #fff;
+  }
+
+  /* 顶部日期白色 */
+  .gantt_task .gantt_task_scale .gantt_scale_cell {
+    color: #fff;
+  }
+
+  /* 偶数行背景透明 */
+  .gantt_row.odd,
+  .gantt_task_row.odd {
+    background-color: transparent;
+  }
+
+  /* 奇数行背景透明 */
+  .gantt_row,
+  .gantt_task_row {
+    background-color: transparent;
+  }
+
+  /* 表格边框*/
+  .gantt_cell {
+    border-right: 1px solid #0de8ec;
+  }
+  .gantt_task_cell {
+    border-right: 1px solid #0de8ec;
+  }
+
+  .gantt_row,
+  .gantt_task_row {
+    border-bottom: 1px solid #0de8ec;
+  }
+
+  .gantt_grid_scale,
+  .gantt_task_scale {
+    border-bottom: 1px solid #0de8ec;
+  }
+
+  .gantt_scale_line {
+    border-top: 1px solid #0de8ec;
+  }
+
+  .gantt_layout_cell_border_right {
+    border-right: 1px solid #0de8ec;
+  }
+
+  .gantt_layout_cell_border_bottom {
+    border-bottom: 1px solid #0de8ec;
+  }
+
+  .gantt_layout_cell_border_left {
+    border-left: 1px solid #0de8ec;
+  }
+
+  .gantt_layout_cell_border_top {
+    border-top: 1px solid #0de8ec;
+  }
+
+  .gantt_task_content {
+    text-shadow: 0 0 4px #333;
+    overflow: visible;
+    transform: translateY(-12px);
+  }
+
+  /* 进度条高度 */
+  .gantt_task_line {
+    height: 10px !important;
+    transform: translateY(10px);
+  }
+
+  .gantt_tooltip {
+    width: 180px;
+  }
+</style>

--
Gitblit v1.9.3