Преглед изворни кода

Merge branch 'xf_dev' of http://192.168.101.4:3000/jiaxiaoqiang/JG-ADMIN-TEMP into xf_dev

lupeng пре 10 месеци
родитељ
комит
f0496da26d

+ 1 - 1
.env.production

@@ -2,7 +2,7 @@
 NODE_ENV='production'
 
 # 上传文件接口地址
-VITE_APP_UPLOAD_URL = 'http://10.88.19.201:9000'
+VITE_APP_UPLOAD_URL = ''
 # 代理前缀
 VITE_APP_BASE_API = '/mes-server'
 

+ 5 - 1
index.html

@@ -57,7 +57,11 @@
       animation: inherit;
       animation-direction: reverse;
     }
-
+    /* 甘特图样式控制 */
+    .gantt_task_line {
+      border-radius: 15px !important;
+      border: 0px solid black;
+    }
     @keyframes l19 {
       100% {
         transform: rotate(360deg);

+ 3 - 0
package.json

@@ -49,9 +49,11 @@
     "@wangeditor/editor-for-vue": "5.1.10",
     "animate.css": "^4.1.1",
     "axios": "^1.6.7",
+    "dhtmlx-gantt": "8.0.9",
     "echarts": "^5.5.0",
     "element-plus": "^2.6.0",
     "html2canvas": "^1.4.1",
+    "jspdf": "^2.5.1",
     "lodash-es": "^4.17.21",
     "net": "^1.0.2",
     "nprogress": "^0.2.0",
@@ -71,6 +73,7 @@
     "vue-qrcode": "^2.2.2",
     "vue-router": "^4.3.0",
     "vue3-pdfjs": "^0.1.6",
+    "vue3-print-nb": "^0.1.4",
     "xlsx": "^0.18.5"
   },
   "devDependencies": {

+ 6 - 2
src/hooks/userCrud.ts

@@ -29,6 +29,7 @@ interface UseCrudConfig {
 
 export const useCrud = (config?: UseCrudConfig) => {
   const url = ref(config?.src);
+  const pageStr = ref(config?.pageStr ? config?.pageStr : "yes");
   const commonConfig = ref(config);
   /** 表格配置属性 */
   const option = ref({
@@ -104,7 +105,10 @@ export const useCrud = (config?: UseCrudConfig) => {
       handleSearchData();
       try {
         const res = await request({
-          url: commonConfig.value?.dataListUrl ?? `${url.value}/page`,
+          url:
+            pageStr.value == "no"
+              ? (commonConfig.value?.dataListUrl ?? `${url.value}`)
+              : (commonConfig.value?.dataListUrl ?? `${url.value}/page`),
           method: "post",
           data: {
             pageNo: page.value.currentPage,
@@ -133,7 +137,7 @@ export const useCrud = (config?: UseCrudConfig) => {
       handleSearchData();
       try {
         const res = await request({
-          url: `${url.value}/page`,
+          url: pageStr.value == "no" ? `${url.value}` : `${url.value}/page`,
           method: "post",
           data: {
             pageNo: page.value.currentPage,

+ 3 - 2
src/main.ts

@@ -1,6 +1,7 @@
 import { createApp } from "vue";
 import App from "./App.vue";
 import router from "@/router";
+import print from "vue3-print-nb";
 import { setupStore } from "@/store";
 import { setupDirective } from "@/directive";
 import { setupElIcons, setupI18n, setupPermission } from "@/plugins";
@@ -31,6 +32,6 @@ setupPermission();
 
 setupEleAvue(app);
 
-app.component('vue-qrcode', VueQrcode)
+app.component("VueQrcode", VueQrcode);
 
-app.use(router).mount("#app");
+app.use(router).use(print).mount("#app");

+ 0 - 1
src/styles/index.scss

@@ -3,7 +3,6 @@
 .app-container {
   padding: 10px;
 }
-
 .search-container {
   padding: 18px 0 0 10px;
   margin-bottom: 10px;

+ 133 - 0
src/utils/htmlPDF.js

@@ -0,0 +1,133 @@
+// 页面导出为pdf格式 //title表示为下载的标题,html表示document.querySelector('#myPrintHtml')
+import html2Canvas from "html2canvas";
+import JsPDF from "jspdf";
+var noTableHeight = 0; //table外的元素高度
+
+export const htmlPdf = (title, html, fileList, type) => {
+  // type传有效值pdf则为横版
+  if (fileList) {
+    const pageHeight = Math.floor((277 * html.scrollWidth) / 190) + 20; //计算pdf高度
+    for (let i = 0; i < fileList.length; i++) {
+      //循环获取的元素
+      const multiple = Math.ceil(
+        (fileList[i].offsetTop + fileList[i].offsetHeight) / pageHeight
+      ); //元素的高度
+      if (isSplit(fileList, i, multiple * pageHeight)) {
+        //计算是否超出一页
+        var _H = ""; //向pdf插入空白块的内容高度
+        if (fileList[i].localName !== "tr") {
+          //判断是不是表格里的内容
+          _H =
+            multiple * pageHeight -
+            (fileList[i].offsetTop + fileList[i].offsetHeight);
+        } else {
+          _H =
+            multiple * pageHeight -
+            (fileList[i].offsetTop + fileList[i].offsetHeight + noTableHeight) +
+            20;
+        }
+        var newNode = getFooterElement(_H); //向pdf插入空白块的内容
+        const divParent = fileList[i].parentNode; // 获取该div的父节点
+        const next = fileList[i].nextSibling; // 获取div的下一个兄弟节点
+        // 判断兄弟节点是否存在
+        if (next) {
+          // 存在则将新节点插入到div的下一个兄弟节点之前,即div之后
+          divParent.insertBefore(newNode, next);
+        } else {
+          // 否则向节点添加最后一个子节点
+          divParent.appendChild(newNode);
+        }
+      }
+    }
+  }
+  html2Canvas(html, {
+    allowTaint: false,
+    taintTest: false,
+    logging: false,
+    useCORS: true,
+    dpi: window.devicePixelRatio * 1,
+    scale: 1, // 按比例增加分辨率
+  }).then((canvas) => {
+    var pdf = new JsPDF("l", "mm", "a4"); // A4纸,纵向
+    var ctx = canvas.getContext("2d");
+    var a4w = type ? 277 : 190;
+    var a4h = type ? 190 : 277; // A4大小,210mm x 297mm,四边各保留10mm的边距,显示区域190x277
+    var imgHeight = Math.floor((a4h * canvas.width) / a4w); // 按A4显示比例换算一页图像的像素高度
+    var renderedHeight = 0;
+    while (renderedHeight < canvas.height) {
+      var page = document.createElement("canvas");
+      page.width = canvas.width;
+      page.height = Math.min(imgHeight, canvas.height - renderedHeight); // 可能内容不足一页
+
+      // 用getImageData剪裁指定区域,并画到前面创建的canvas对象中
+      page
+        .getContext("2d")
+        .putImageData(
+          ctx.getImageData(
+            0,
+            renderedHeight,
+            canvas.width,
+            Math.min(imgHeight, canvas.height - renderedHeight)
+          ),
+          0,
+          0
+        );
+      pdf.addImage(
+        page.toDataURL("image/jpeg", 1.0),
+        "JPEG",
+        10,
+        10,
+        a4w,
+        Math.min(a4h, (a4w * page.height) / page.width)
+      ); // 添加图像到页面,保留10mm边距
+
+      renderedHeight += imgHeight;
+      if (renderedHeight < canvas.height) {
+        pdf.addPage(); // 如果后面还有内容,添加一个空页
+      }
+      // delete page;
+    }
+    // 保存文件
+    pdf.save(title + ".pdf");
+  });
+};
+// pdf截断需要一个空白位置来补充
+const getFooterElement = (remainingHeight, fillingHeight = 0) => {
+  const newNode = document.createElement("div");
+  newNode.style.background = "#ffffff";
+  newNode.style.width = "calc(100% + 8px)";
+  newNode.style.marginLeft = "-4px";
+  newNode.style.marginBottom = "0px";
+  newNode.classList.add("divRemove");
+  newNode.style.height = remainingHeight + fillingHeight + "px";
+  return newNode;
+};
+const isSplit = (nodes, index, pageHeight) => {
+  // 判断是不是tr 如果不是高度存起来
+  // 表格里的内容要特殊处理
+  // tr.offsetTop 是tr到table表格的高度
+  // 所以计算高速时候要把表格外的高度加起来
+  // 生成的pdf没有表格了这里可以不做处理 直接计算就行
+  if (nodes[index].localName !== "tr") {
+    //判断元素是不是tr
+    noTableHeight += nodes[index].clientHeight;
+  }
+
+  if (nodes[index].localName !== "tr") {
+    return (
+      nodes[index].offsetTop + nodes[index].offsetHeight < pageHeight &&
+      nodes[index + 1] &&
+      nodes[index + 1].offsetTop + nodes[index + 1].offsetHeight > pageHeight
+    );
+  } else {
+    return (
+      nodes[index].offsetTop + nodes[index].offsetHeight + noTableHeight <
+        pageHeight &&
+      nodes[index + 1] &&
+      nodes[index + 1].offsetTop +
+        nodes[index + 1].offsetHeight +
+        noTableHeight >
+        pageHeight
+    );
+  }
+};

+ 4 - 2
src/views/plan/workOrder/index.vue

@@ -479,11 +479,13 @@ const lineInfo = (value) => {
   dialog3.visible = false;
 };
 const workShopInfo = (value) => {
+  if(form.value.workshopCode && value.code && form.value.workshopCode !== value.code){
+    form.value.productLineId = "";
+    form.value.productLineName = "";
+  }
   form.value.workshopName = value.id;
   form.value.workshopCode = value.code;
   form.value.workshopName = value.name;
-  form.value.productLineId = "";
-  form.value.productLineName = "";
   dialog2.visible = false;
 };
 const routeInfo = (value) => {

+ 1 - 4
src/views/quality/faultHandle/components/fault-detail.vue

@@ -213,15 +213,12 @@
       {
         label: "跟踪卡号",
         prop: "seqNo",
-        labelWidth:130,
       },
       {
-        label: "返工工序",
+        label: "返工工序/报废",
         prop: "reworkOperationName",
-        labelWidth:130,
         type:"select",
       },
-
     ],
   };
 

+ 23 - 10
src/views/quality/faultHandle/components/fault-page.vue

@@ -63,6 +63,9 @@
       :data="data2"
       :option="option2"
     >
+      <template #isScrap="{row,index,type}">
+        <el-checkbox v-model="row.isScrap" label="报废" size="small" value=true border @click="checkScrap(row)"/>
+      </template>
       <template #processInfo="{row,index,type}">
         <el-select v-model="value[row.$index]" placeholder="请选择" @click="getFaults(row)" @change="listData(row)">
           <el-option
@@ -191,12 +194,14 @@ const listData=(row)=>{
 const faultHandle=ref({});
  const onHandle=()=>{
    for(let i=0;i<postDetail.value.length;i++){
-     if(undefined===postDetail.value[i].reworkProcessId){
-       ElMessage({
-         message:postDetail.value[i].seqNo+"没选择返工工序",
-         type: "error",
-       });
-       return;
+     if(!postDetail.value[i].isScrap){
+       if(undefined===postDetail.value[i].reworkProcessId){
+         ElMessage({
+           message:postDetail.value[i].seqNo+"没选择返工工序",
+           type: "error",
+         });
+         return;
+       }
      }
    }
    faultHandle.value.reworkList=Array.from(postDetail.value);
@@ -246,7 +251,6 @@ const faultHandle=ref({});
   const optionFault=ref([]);
   const processFault=ref({});
   const getFaults=(row)=>{
-
     processFault.value.seqNo=row.seqNo;
     processFault.value.workOrderCode=props.workOrderCode;
     getProcessInfoList(processFault.value).then(
@@ -255,6 +259,14 @@ const faultHandle=ref({});
       }
     )
   }
+  const checkScrap= (row)=>{
+    if(row.isScrap){
+      row.enabled = false
+    }else{
+      row.enabled = true
+    }
+    row.reworkProcessId = undefined
+  }
   const option2=ref(null);
   const value=ref([]);
 
@@ -272,15 +284,16 @@ const faultHandle=ref({});
       {
         label: "跟踪卡号",
         prop: "seqNo",
-        labelWidth:130,
       },
       {
         label: "返工工序",
         prop: "processInfo",
-        labelWidth:130,
         type:"select",
       },
-
+      {
+        label: "是否报废",
+        prop: "isScrap",
+      },
     ],
   };
   const cancelWindow=()=>{

+ 1 - 0
src/views/report/environment/equipment/index.vue

@@ -41,6 +41,7 @@ const { dicts } = useDictionaryStore();
 const { form, data, option, search, page, toDeleteIds, Methords, Utils } =
   useCrud({
     src: "/api/v1/op/baseOperation",
+    method: "get",
   });
 const { dataList, createRow, updateRow, deleteRow, searchChange, resetChange } =
   Methords; //增删改查

+ 410 - 0
src/views/report/productionScheduling/line/index.vue

@@ -0,0 +1,410 @@
+<template>
+  <div>
+    <avue-crud
+      v-model:search="search"
+      :option="option"
+      @search-change="searchChange"
+      @search-reset="resetChange"
+    />
+    <div class="btns">
+      <el-button type="params" @click="exportToPNG">导出PNG图片</el-button>
+      <el-button type="params" @click="exportToPDF">导出PDF文件</el-button>
+      <!-- <el-button type="params" v-print="printObj" @click="toPrint"
+        >打印</el-button
+      > -->
+    </div>
+    <div class="main-content">
+      <div ref="ganttRef" id="gantt_here" class="gantt-container"></div>
+    </div>
+  </div>
+</template>
+
+<script setup>
+import { gantt } from "dhtmlx-gantt";
+import "dhtmlx-gantt/codebase/dhtmlxgantt.css";
+import html2canvas from "html2canvas";
+import { htmlPdf } from "@/utils/htmlPDF.js";
+import { useCrud } from "@/hooks/userCrud";
+const ganttRef = ref(null);
+const { form, data, option, search, page, toDeleteIds, Methords, Utils } =
+  useCrud({
+    src: "/api/v1/process/census/productLineApsResultGant",
+    pageStr: "no",
+  });
+const exportToPDF = () => {
+  var fileName = "甘特图pdf";
+  const fileList = document.getElementsByClassName("gantt_here");
+  htmlPdf(fileName, document.querySelector("#gantt_here"), fileList, 1111);
+};
+const exportToPNG = async () => {
+  const chartContainer = ganttRef.value;
+  const canvas = await html2canvas(chartContainer);
+  const img = canvas.toDataURL("image/png");
+  const a = document.createElement("a");
+  a.href = img;
+  a.download = "甘特图.png";
+  a.click();
+};
+// const printUrl = ref("");
+// const toPrint = async () => {
+//   const chartContainer = ganttRef.value;
+//   const canvas = await html2canvas(chartContainer);
+//   const img = canvas.toDataURL("image/png");
+//   printUrl.value = img;
+// };
+// const printObj = ref({
+//   id: "gantt_here",
+//   preview: true,
+//   popTitle: "甘特图",
+//   url: printUrl.value,
+// });
+const { dataList, createRow, updateRow, deleteRow, searchChange, resetChange } =
+  Methords;
+option.value = Object.assign(option.value, {
+  selection: false,
+  menu: true,
+  menuWidth: 100,
+  addBtn: false,
+  filterBtn: false,
+  searchShowBtn: true,
+  columnBtn: false,
+  gridBtn: false,
+  editBtn: false,
+  viewBtn: false,
+  delBtn: false,
+  column: [
+    {
+      label: "日期范围",
+      prop: "searchTime",
+      search: true,
+      hide: true,
+      type: "date",
+      format: "YYYY-MM-DD",
+      valueFormat: "YYYY-MM-DD",
+      searchRange: true,
+      startPlaceholder: "开始日期",
+      endPlaceholder: "结束日期",
+    },
+    {
+      label: "订单名称",
+      prop: "name",
+      search: true,
+    },
+    {
+      label: "时间维度",
+      prop: "timeType",
+      search: true,
+      type: "select",
+      searchValue: "1",
+      dicData: [
+        {
+          dictLabel: "小时",
+          dictValue: "0",
+        },
+        {
+          dictLabel: "日",
+          dictValue: "1",
+        },
+        {
+          dictLabel: "月",
+          dictValue: "2",
+        },
+      ],
+      props: {
+        label: "dictLabel",
+        value: "dictValue",
+      },
+    },
+    {
+      label: "订单状态",
+      prop: "type",
+      search: true,
+      type: "select",
+      dicData: [
+        {
+          dictLabel: "订单",
+          dictValue: "0",
+        },
+        {
+          dictLabel: "工单",
+          dictValue: "1",
+        },
+        {
+          dictLabel: "流转卡号",
+          dictValue: "2",
+        },
+        {
+          dictLabel: "工序",
+          dictValue: "3",
+        },
+      ],
+      props: {
+        label: "dictLabel",
+        value: "dictValue",
+      },
+    },
+  ],
+});
+const getCurrentMonthStartAndEndDates = () => {
+  // 获取当前日期
+  let now = new Date();
+
+  // 获取当前月份的第一天
+  let startDate = new Date(now.getFullYear(), now.getMonth(), 1);
+
+  // 获取当前月份的最后一天
+  let endDate = new Date(now.getFullYear(), now.getMonth() + 1, 0);
+
+  // 格式化日期为'YYYY-MM-DD'格式
+  function formatDate(date) {
+    let year = date.getFullYear();
+    let month = String(date.getMonth() + 1).padStart(2, "0");
+    let day = String(date.getDate()).padStart(2, "0");
+    return `${year}-${month}-${day}`;
+  }
+
+  // 返回包含开始和结束日期的数组
+  return [formatDate(startDate), formatDate(endDate)];
+};
+const demoData = {
+  data: [
+    {
+      id: 11,
+      text: "Project #1",
+      start_date: "2024-07-01 08:00:00",
+      endTime: "2024-09-30 09:00:00",
+      startTime: "2024-07-30 08:00:00",
+      duration: "11",
+      progress: 0.8,
+      open: true,
+    },
+  ],
+};
+//初始化甘特图
+const initGantt = (type) => {
+  gantt.plugins({
+    tooltip: true,
+    marker: true,
+    critical_path: true,
+    export_api: true,
+  });
+  gantt.templates.task_text = function (start, end, task) {
+    return (
+      "<span style='padding:0 5px;color: #000; display: inline-block;width: 100%; white-space: nowrap;overflow: hidden; text-overflow: ellipsis; '>" +
+      task.text +
+      "</span>"
+    );
+  };
+  gantt.templates.progress_text = function (start, end, task) {
+    return (
+      "<span style='text-align:left;'>" +
+      Math.round(task.progress * 100) +
+      "% </span>"
+    );
+  };
+  gantt.templates.task_class = function (start, end, task) {
+    return "taskClass";
+  };
+  if (type) {
+    gantt.config.duration_unit = type;
+  }
+  gantt.config.show_today = true;
+  gantt.config.grid_width = 350;
+  gantt.config.add_column = false;
+  gantt.config.duration_step = 1;
+  gantt.config.drag_resize = true;
+  gantt.config.columns = [
+    {
+      tree: true,
+      name: "text",
+      label: "订单名称",
+      width: "240",
+    },
+    {
+      name: "startTime",
+      label: "开始时间",
+      align: "center",
+      width: "160",
+      template(task) {
+        return task.startTime;
+      },
+    },
+    {
+      name: "endTime",
+      label: "结束时间",
+      align: "center",
+      width: "160",
+      template(task) {
+        return task.endTime;
+      },
+    },
+  ];
+  gantt.config.autofit = true;
+  gantt.config.resize_rows = true;
+  gantt.config.row_height = 40;
+  gantt.config.bar_height = 30;
+  gantt.config.min_column_width = 60;
+  gantt.config.xml_date = "%Y-%m-%d %H:%i:%s"; //甘特图时间格式
+  gantt.config.readonly = true; //是否只读
+  gantt.i18n.setLocale("cn"); //设置语言
+  gantt.templates.tooltip_text = function (start, end, task) {
+    const text = `名称: ${task.text}<br/>总数: ${task.num}<br/>完成进度: ${task.progress * 100}%`;
+    return !task.parent
+      ? `${text}<br/>交期时间: ${task.deliverWhen}`
+      : `${text}<br/>计划开始时间: ${task.startTime}<br/>计划结束时间: ${task.endTime}`; // eslint-disable-line
+  };
+  const dateToStr = gantt.date.date_to_str(gantt.config.task_date);
+  const today = new Date(new Date().setHours(0, 0, 0, 0));
+  gantt.addMarker({
+    start_date: today,
+    css: "today",
+    text: "今日",
+    title: `Today: ${dateToStr(today)}`,
+  });
+  gantt.init("gantt_here"); //初始化
+};
+const setTime = () => {
+  search.value = {
+    searchTime: getCurrentMonthStartAndEndDates(),
+    timeType: "1",
+  };
+};
+
+function convertDateString1(str) {
+  // 将输入的日期字符串转换为 Date 对象
+  let date = new Date(str);
+  // 获取年、月、日
+  let year = date.getFullYear();
+  let month = date.toLocaleString("en-us", { month: "short" });
+  let day = date.getDate();
+  // 构造新的日期字符串格式
+  let formattedDate = `${date.toDateString().slice(0, 3)} ${month} ${day} ${year} 00:00:00 GMT+0800 (GMT+08:00)`;
+  return formattedDate;
+}
+function convertDateString2(str) {
+  // 将输入的日期字符串转换为 Date 对象
+  let date = new Date(str);
+
+  // 获取年、月、日
+  let year = date.getFullYear();
+  let month = date.toLocaleString("en-us", { month: "short" });
+  let day = date.getDate();
+
+  // 构造新的日期字符串格式
+  let formattedDate = `${date.toDateString().slice(0, 3)} ${month} ${day} ${year} 24:00:00 GMT+0800 (GMT+08:00)`;
+
+  return formattedDate;
+}
+// watchEffect(() => {
+//   //此api后续弃用
+//   // gantt.parse({ data: data.value });
+//   gantt.parse(demoData);
+// });
+const setGantt = () => {
+  if (search?.value.searchTime) {
+    gantt.config.start_date = convertDateString1(search?.value.searchTime[0]);
+    gantt.config.end_date = convertDateString2(search?.value.searchTime[1]);
+    gantt.config.show_tasks_outside_timescale = true;
+  }
+  switch (search.value.timeType) {
+    case "0":
+      gantt.config.duration_unit = "hour";
+      gantt.config.scale_height = 28 * 4;
+      gantt.config.scales = [
+        { unit: "year", step: 1, format: "%Y年" },
+        { unit: "month", step: 1, format: "%m月" },
+        {
+          unit: "day",
+          step: 1,
+          format: "%d日",
+        },
+        {
+          unit: "hour",
+          step: 1,
+          format: "%H时",
+        },
+      ];
+      gantt.init("gantt_here");
+      gantt.render();
+      gantt.parse({ data: useData.value });
+      break;
+    case "1":
+      gantt.config.scale_height = 28 * 4;
+      gantt.config.scales = [
+        { unit: "year", step: 1, format: "%Y年" },
+        { unit: "month", step: 1, format: "%m月" },
+        {
+          unit: "day",
+          step: 1,
+          format: "%d日",
+        },
+      ];
+      gantt.config.duration_unit = "day";
+
+      gantt.init("gantt_here");
+      gantt.render();
+      gantt.parse({ data: useData.value });
+      break;
+    case "2":
+      // initGantt("month");
+      gantt.config.scale_height = 28 * 4;
+      gantt.config.scales = [
+        { unit: "year", step: 1, format: "%Y年" },
+        { unit: "month", step: 1, format: "%m月" },
+      ];
+      gantt.config.duration_unit = "month";
+      gantt.init("gantt_here");
+      gantt.parse({ data: useData.value });
+      gantt.render();
+      break;
+  }
+};
+const useData = ref([]);
+const setUseData = (data) => {
+  const data1 = [...data];
+  data1.forEach((element) => {
+    element.start_date = element.startTime;
+    if (element.progress != 1) {
+      element.color = "orange";
+    } else {
+      element.color = "green";
+    }
+  });
+  const data2 = JSON.parse(JSON.stringify(data1));
+  useData.value = data2;
+};
+onMounted(() => {
+  setTime();
+  dataList();
+  initGantt();
+});
+watch(
+  () => data.value,
+  () => {
+    if (data.value) {
+      setUseData(data.value);
+      setGantt();
+    }
+  },
+  { immediate: true, deep: true }
+);
+</script>
+<style scoped lang="scss">
+.btns {
+  margin: 7px 0;
+}
+:deep(.avue-crud__body) {
+  display: none;
+}
+.main-content {
+  width: 100%;
+  height: 600px;
+  .gantt-container {
+    width: 100%;
+    height: 100%;
+  }
+}
+.ganttStyle {
+  border-radius: 50%;
+}
+</style>

+ 410 - 0
src/views/report/productionScheduling/order/index.vue

@@ -0,0 +1,410 @@
+<template>
+  <div>
+    <avue-crud
+      v-model:search="search"
+      :option="option"
+      @search-change="searchChange"
+      @search-reset="resetChange"
+    />
+    <div class="btns">
+      <el-button type="params" @click="exportToPNG">导出PNG图片</el-button>
+      <el-button type="params" @click="exportToPDF">导出PDF文件</el-button>
+      <!-- <el-button type="params" v-print="printObj" @click="toPrint"
+        >打印</el-button
+      > -->
+    </div>
+    <div class="main-content">
+      <div ref="ganttRef" id="gantt_here" class="gantt-container"></div>
+    </div>
+  </div>
+</template>
+
+<script setup>
+import { gantt } from "dhtmlx-gantt";
+import "dhtmlx-gantt/codebase/dhtmlxgantt.css";
+import html2canvas from "html2canvas";
+import { htmlPdf } from "@/utils/htmlPDF.js";
+import { useCrud } from "@/hooks/userCrud";
+const ganttRef = ref(null);
+const { form, data, option, search, page, toDeleteIds, Methords, Utils } =
+  useCrud({
+    src: "/api/v1/process/census/queryApsResultGant",
+    pageStr: "no",
+  });
+const exportToPDF = () => {
+  var fileName = "甘特图pdf";
+  const fileList = document.getElementsByClassName("gantt_here");
+  htmlPdf(fileName, document.querySelector("#gantt_here"), fileList, 1111);
+};
+const exportToPNG = async () => {
+  const chartContainer = ganttRef.value;
+  const canvas = await html2canvas(chartContainer);
+  const img = canvas.toDataURL("image/png");
+  const a = document.createElement("a");
+  a.href = img;
+  a.download = "甘特图.png";
+  a.click();
+};
+// const printUrl = ref("");
+// const toPrint = async () => {
+//   const chartContainer = ganttRef.value;
+//   const canvas = await html2canvas(chartContainer);
+//   const img = canvas.toDataURL("image/png");
+//   printUrl.value = img;
+// };
+// const printObj = ref({
+//   id: "gantt_here",
+//   preview: true,
+//   popTitle: "甘特图",
+//   url: printUrl.value,
+// });
+const { dataList, createRow, updateRow, deleteRow, searchChange, resetChange } =
+  Methords;
+option.value = Object.assign(option.value, {
+  selection: false,
+  menu: true,
+  menuWidth: 100,
+  addBtn: false,
+  filterBtn: false,
+  searchShowBtn: true,
+  columnBtn: false,
+  gridBtn: false,
+  editBtn: false,
+  viewBtn: false,
+  delBtn: false,
+  column: [
+    {
+      label: "日期范围",
+      prop: "searchTime",
+      search: true,
+      hide: true,
+      type: "date",
+      format: "YYYY-MM-DD",
+      valueFormat: "YYYY-MM-DD",
+      searchRange: true,
+      startPlaceholder: "开始日期",
+      endPlaceholder: "结束日期",
+    },
+    {
+      label: "订单名称",
+      prop: "name",
+      search: true,
+    },
+    {
+      label: "时间维度",
+      prop: "timeType",
+      search: true,
+      type: "select",
+      searchValue: "1",
+      dicData: [
+        {
+          dictLabel: "小时",
+          dictValue: "0",
+        },
+        {
+          dictLabel: "日",
+          dictValue: "1",
+        },
+        {
+          dictLabel: "月",
+          dictValue: "2",
+        },
+      ],
+      props: {
+        label: "dictLabel",
+        value: "dictValue",
+      },
+    },
+    {
+      label: "订单状态",
+      prop: "type",
+      search: true,
+      type: "select",
+      dicData: [
+        {
+          dictLabel: "订单",
+          dictValue: "0",
+        },
+        {
+          dictLabel: "工单",
+          dictValue: "1",
+        },
+        {
+          dictLabel: "流转卡号",
+          dictValue: "2",
+        },
+        {
+          dictLabel: "工序",
+          dictValue: "3",
+        },
+      ],
+      props: {
+        label: "dictLabel",
+        value: "dictValue",
+      },
+    },
+  ],
+});
+const getCurrentMonthStartAndEndDates = () => {
+  // 获取当前日期
+  let now = new Date();
+
+  // 获取当前月份的第一天
+  let startDate = new Date(now.getFullYear(), now.getMonth(), 1);
+
+  // 获取当前月份的最后一天
+  let endDate = new Date(now.getFullYear(), now.getMonth() + 1, 0);
+
+  // 格式化日期为'YYYY-MM-DD'格式
+  function formatDate(date) {
+    let year = date.getFullYear();
+    let month = String(date.getMonth() + 1).padStart(2, "0");
+    let day = String(date.getDate()).padStart(2, "0");
+    return `${year}-${month}-${day}`;
+  }
+
+  // 返回包含开始和结束日期的数组
+  return [formatDate(startDate), formatDate(endDate)];
+};
+const demoData = {
+  data: [
+    {
+      id: 11,
+      text: "Project #1",
+      start_date: "2024-07-01 08:00:00",
+      endTime: "2024-09-30 09:00:00",
+      startTime: "2024-07-30 08:00:00",
+      duration: "11",
+      progress: 0.8,
+      open: true,
+    },
+  ],
+};
+//初始化甘特图
+const initGantt = (type) => {
+  gantt.plugins({
+    tooltip: true,
+    marker: true,
+    critical_path: true,
+    export_api: true,
+  });
+  gantt.templates.task_text = function (start, end, task) {
+    return (
+      "<span style='padding:0 5px;color: #000; display: inline-block;width: 100%; white-space: nowrap;overflow: hidden; text-overflow: ellipsis; '>" +
+      task.text +
+      "</span>"
+    );
+  };
+  gantt.templates.progress_text = function (start, end, task) {
+    return (
+      "<span style='text-align:left;'>" +
+      Math.round(task.progress * 100) +
+      "% </span>"
+    );
+  };
+  gantt.templates.task_class = function (start, end, task) {
+    return "taskClass";
+  };
+  if (type) {
+    gantt.config.duration_unit = type;
+  }
+  gantt.config.show_today = true;
+  gantt.config.grid_width = 350;
+  gantt.config.add_column = false;
+  gantt.config.duration_step = 1;
+  gantt.config.drag_resize = true;
+  gantt.config.columns = [
+    {
+      tree: true,
+      name: "text",
+      label: "订单名称",
+      width: "240",
+    },
+    {
+      name: "startTime",
+      label: "开始时间",
+      align: "center",
+      width: "160",
+      template(task) {
+        return task.startTime;
+      },
+    },
+    {
+      name: "endTime",
+      label: "结束时间",
+      align: "center",
+      width: "160",
+      template(task) {
+        return task.endTime;
+      },
+    },
+  ];
+  gantt.config.autofit = true;
+  gantt.config.resize_rows = true;
+  gantt.config.row_height = 40;
+  gantt.config.bar_height = 30;
+  gantt.config.min_column_width = 60;
+  gantt.config.xml_date = "%Y-%m-%d %H:%i:%s"; //甘特图时间格式
+  gantt.config.readonly = true; //是否只读
+  gantt.i18n.setLocale("cn"); //设置语言
+  gantt.templates.tooltip_text = function (start, end, task) {
+    const text = `名称: ${task.text}<br/>总数: ${task.num}<br/>完成进度: ${task.progress * 100}%`;
+    return !task.parent
+      ? `${text}<br/>交期时间: ${task.deliverWhen}`
+      : `${text}<br/>计划开始时间: ${task.startTime}<br/>计划结束时间: ${task.endTime}`; // eslint-disable-line
+  };
+  const dateToStr = gantt.date.date_to_str(gantt.config.task_date);
+  const today = new Date(new Date().setHours(0, 0, 0, 0));
+  gantt.addMarker({
+    start_date: today,
+    css: "today",
+    text: "今日",
+    title: `Today: ${dateToStr(today)}`,
+  });
+  gantt.init("gantt_here"); //初始化
+};
+const setTime = () => {
+  search.value = {
+    searchTime: getCurrentMonthStartAndEndDates(),
+    timeType: "1",
+  };
+};
+
+function convertDateString1(str) {
+  // 将输入的日期字符串转换为 Date 对象
+  let date = new Date(str);
+  // 获取年、月、日
+  let year = date.getFullYear();
+  let month = date.toLocaleString("en-us", { month: "short" });
+  let day = date.getDate();
+  // 构造新的日期字符串格式
+  let formattedDate = `${date.toDateString().slice(0, 3)} ${month} ${day} ${year} 00:00:00 GMT+0800 (GMT+08:00)`;
+  return formattedDate;
+}
+function convertDateString2(str) {
+  // 将输入的日期字符串转换为 Date 对象
+  let date = new Date(str);
+
+  // 获取年、月、日
+  let year = date.getFullYear();
+  let month = date.toLocaleString("en-us", { month: "short" });
+  let day = date.getDate();
+
+  // 构造新的日期字符串格式
+  let formattedDate = `${date.toDateString().slice(0, 3)} ${month} ${day} ${year} 24:00:00 GMT+0800 (GMT+08:00)`;
+
+  return formattedDate;
+}
+// watchEffect(() => {
+//   //此api后续弃用
+//   // gantt.parse({ data: data.value });
+//   gantt.parse(demoData);
+// });
+const setGantt = () => {
+  if (search?.value.searchTime) {
+    gantt.config.start_date = convertDateString1(search?.value.searchTime[0]);
+    gantt.config.end_date = convertDateString2(search?.value.searchTime[1]);
+    gantt.config.show_tasks_outside_timescale = true;
+  }
+  switch (search.value.timeType) {
+    case "0":
+      gantt.config.duration_unit = "hour";
+      gantt.config.scale_height = 28 * 4;
+      gantt.config.scales = [
+        { unit: "year", step: 1, format: "%Y年" },
+        { unit: "month", step: 1, format: "%m月" },
+        {
+          unit: "day",
+          step: 1,
+          format: "%d日",
+        },
+        {
+          unit: "hour",
+          step: 1,
+          format: "%H时",
+        },
+      ];
+      gantt.init("gantt_here");
+      gantt.render();
+      gantt.parse({ data: useData.value });
+      break;
+    case "1":
+      gantt.config.scale_height = 28 * 4;
+      gantt.config.scales = [
+        { unit: "year", step: 1, format: "%Y年" },
+        { unit: "month", step: 1, format: "%m月" },
+        {
+          unit: "day",
+          step: 1,
+          format: "%d日",
+        },
+      ];
+      gantt.config.duration_unit = "day";
+
+      gantt.init("gantt_here");
+      gantt.render();
+      gantt.parse({ data: useData.value });
+      break;
+    case "2":
+      // initGantt("month");
+      gantt.config.scale_height = 28 * 4;
+      gantt.config.scales = [
+        { unit: "year", step: 1, format: "%Y年" },
+        { unit: "month", step: 1, format: "%m月" },
+      ];
+      gantt.config.duration_unit = "month";
+      gantt.init("gantt_here");
+      gantt.parse({ data: useData.value });
+      gantt.render();
+      break;
+  }
+};
+const useData = ref([]);
+const setUseData = (data) => {
+  const data1 = [...data];
+  data1.forEach((element) => {
+    element.start_date = element.startTime;
+    if (element.progress != 1) {
+      element.color = "orange";
+    } else {
+      element.color = "green";
+    }
+  });
+  const data2 = JSON.parse(JSON.stringify(data1));
+  useData.value = data2;
+};
+onMounted(() => {
+  setTime();
+  dataList();
+  initGantt();
+});
+watch(
+  () => data.value,
+  () => {
+    if (data.value) {
+      setUseData(data.value);
+      setGantt();
+    }
+  },
+  { immediate: true, deep: true }
+);
+</script>
+<style scoped lang="scss">
+.btns {
+  margin: 7px 0;
+}
+:deep(.avue-crud__body) {
+  display: none;
+}
+.main-content {
+  width: 100%;
+  height: 600px;
+  .gantt-container {
+    width: 100%;
+    height: 100%;
+  }
+}
+.ganttStyle {
+  border-radius: 50%;
+}
+</style>

+ 39 - 14
src/views/report/statistics/dailystorage/index.vue

@@ -1,21 +1,46 @@
 <template>
   <div class="mainContentBox">
-    <avue-crud ref="crudRef1" v-model:search="data1.search" :data="data1.data" :option="data1.option"
-      v-model:page="data1.page" @row-save="createRow" @row-update="updateRow" @row-del="deleteRow"
-      @search-change="searchChange" @search-reset="resetChange" @size-change="dataList" @current-change="dataList"
-      @selection-change="selectionChange" @cell-click="ckickCell">
+    <avue-crud
+      ref="crudRef1"
+      v-model:search="data1.search"
+      :data="data1.data"
+      :option="data1.option"
+      v-model:page="data1.page"
+      @row-save="createRow"
+      @row-update="updateRow"
+      @row-del="deleteRow"
+      @search-change="searchChange"
+      @search-reset="resetChange"
+      @size-change="dataList"
+      @current-change="dataList"
+      @selection-change="selectionChange"
+      @cell-click="ckickCell"
+    >
       <template #header="{ size }">
         <div id="dailystoragecharts"></div>
       </template>
     </avue-crud>
-    <el-dialog v-model="editDialog.visible" :title="editDialog.title" width="1200px"
-      @close="editDialog.visible = false">
+    <el-dialog
+      v-model="editDialog.visible"
+      :title="editDialog.title"
+      width="1200px"
+      @close="editDialog.visible = false"
+    >
       <div class="mainContentBox">
-        <avue-crud ref="crudRef2" v-model:search="data2.search" :data="data2.data" :option="data2.option"
-          v-model:page="data2.page" @row-update="data2.Methords.updateRow" @row-del="data2.Methords.deleteRow"
-          @search-change="data2.Methords.dataList" @search-reset="data2.Methords.resetChange"
-          @size-change="data2.Methords.dataList" @current-change="data2.Methords.dataList"
-          @selection-change="data2.Methords.selectionChange" />
+        <avue-crud
+          ref="crudRef2"
+          v-model:search="data2.search"
+          :data="data2.data"
+          :option="data2.option"
+          v-model:page="data2.page"
+          @row-update="data2.Methords.updateRow"
+          @row-del="data2.Methords.deleteRow"
+          @search-change="data2.Methords.dataList"
+          @search-reset="data2.Methords.resetChange"
+          @size-change="data2.Methords.dataList"
+          @current-change="data2.Methords.dataList"
+          @selection-change="data2.Methords.selectionChange"
+        />
       </div>
     </el-dialog>
   </div>
@@ -102,7 +127,7 @@ data1.value.option = Object.assign(data1.value.option, {
     },
     {
       label: "产品规格",
-      prop: "userName",
+      prop: "materialModel",
       overHidden: true,
       search: true,
       editDisabled: true,
@@ -218,8 +243,8 @@ data2.value.option = Object.assign(data2.value.option, {
       label: "流转卡号",
       prop: "seqNo",
       search: false,
-      width:150,
-      overHidden:true,
+      width: 150,
+      overHidden: true,
     },
     {
       label: "交付日期",