Procházet zdrojové kódy

统计报表模块开发

BSWYZ před 4 dny
rodič
revize
44f6705ca5

+ 12 - 1
imcs-ui/src/api/statisticalAnalysis/productlineAvailability.js

@@ -66,6 +66,10 @@ const apiList = {
     method: 'POST',
     url: `/authority/productLinePerformance/exportTaskResourceSum`
   },
+   exportDeviceResourceStatistics1:{
+      method: 'POST',
+      url: `/authority/productLinePerformance/exportDeviceResourceStatistics1`
+    },
   unFinishedBiz:{
     method: 'POST',
     url: `/authority/productLinePerformance/unFinishedBiz`
@@ -178,7 +182,7 @@ export default {
       url: `/authority/productLinePerformance/overTimeTaskSum/${page}/${limit}`,
       method: 'post',
       data:searchObj
-    }) 
+    })
   },
   taskStatusSum(data){
     return axiosApi({
@@ -254,6 +258,13 @@ export default {
       data
     })
   },
+  exportDeviceResourceStatistics1(data){
+    return axiosApi({
+      ...apiList.exportDeviceResourceStatistics1,
+      responseType: 'blob',
+      data
+    })
+  },
   unFinishedBiz(data){
     return axiosApi({
       ...apiList.unFinishedBiz,

+ 39 - 0
imcs-ui/src/api/statisticalAnalysis/statisticalForm.js

@@ -0,0 +1,39 @@
+/*********************** 【质量中心-查看质检结果】API ********************/
+import axiosApi from '../AxiosApi.js'
+
+// 1. 调整接口地址:匹配后端的 /DeviceResourceStatistics1/{page}/{limit}
+// 注意:路径中的 {page} 和 {limit} 是占位符,后续会动态替换为实际数值
+const apiList = {
+  // 列表查询(如果需要分页,复用带 page/limit 的接口;若不需要分页,可单独定义无参数接口)
+  getList: {
+    method: 'POST',
+    url: `/authority/productLinePerformance/DeviceResourceStatistics1/{page}/{limit}` // 后端接口地址,带路径参数占位符
+  },
+  // 分页查询(明确对应后端的 page/limit 接口)
+  page: {
+    method: 'POST',
+    url: `/authority/productLinePerformance/DeviceResourceStatistics1/{page}/{limit}` // 与后端接口完全匹配
+  }
+}
+
+export default {
+  // 2. 列表查询方法(需传递 page/limit 路径参数 + 业务参数 data)
+  getList (page, limit, data) {
+    return axiosApi({
+      ...apiList.getList,
+      // 替换 URL 中的占位符为实际页码和每页条数(路径参数)
+      url: apiList.getList.url.replace('{page}', page).replace('{limit}', limit),
+      data // 业务查询参数(如筛选条件,会作为 POST 请求体传递)
+    })
+  },
+
+  // 3. 分页查询方法(与 getList 逻辑一致,明确语义为“分页”)
+  page (page, limit, data) {
+    return axiosApi({
+      ...apiList.page,
+      // 动态替换路径参数
+      url: apiList.page.url.replace('{page}', page).replace('{limit}', limit),
+      data // 分页查询的筛选条件(如时间范围、设备ID等)
+    })
+  },
+}

+ 1 - 1
imcs-ui/src/views/zuihou/statisticalAnalysis/deviceResource/Index.vue

@@ -87,7 +87,7 @@
         >
         <el-button type="default" @click="resetData()">清空</el-button>
 
-        <el-button type="primary" icon="el-icon-download" @click="exportData()" v-show="false" >导出</el-button>
+        <el-button type="primary" icon="el-icon-download" @click="exportData()" v-show="true" >导出</el-button>
       </el-form>
     </el-card>
     <!-- 列表数据 -->

+ 283 - 0
imcs-ui/src/views/zuihou/statisticalAnalysis/statisticalForm/Index.vue

@@ -0,0 +1,283 @@
+<template>
+  <div class="app-container">
+    <!-- 搜索条件区域 -->
+    <el-card class="operate-container" shadow="never" :body-style="{ padding: '16px 24px' }">
+      <el-form :inline="true" class="demo-form-inline" :model="searchObj">
+        <!-- 起止时间选择 -->
+        <el-form-item label="生产时间">
+          <el-date-picker v-model="searchObj.startDate" placeholder="开始时间" value-format="yyyy-MM-dd"
+            @change="handleTimeChange('dateRange')" />
+        </el-form-item>
+        <el-form-item label="-">
+          <el-date-picker v-model="searchObj.endDate" placeholder="结束时间" value-format="yyyy-MM-dd"
+            @change="handleTimeChange('dateRange')" />
+        </el-form-item>
+
+        <!-- 生产月份选择(默认选中当月) -->
+        <el-form-item label="生产月份">
+          <el-date-picker v-model="searchObj.month" type="month" placeholder="选择月" value-format="yyyy-MM"
+            @change="handleTimeChange('month')" />
+        </el-form-item>
+
+        <!-- 生产年份选择 -->
+        <el-form-item label="生产年份">
+          <el-date-picker v-model="searchObj.years" type="year" placeholder="选择年" value-format="yyyy"
+            @change="handleTimeChange('year')" />
+        </el-form-item>
+
+        <!-- 操作按钮 -->
+        <el-form-item>
+          <el-button type="primary" icon="el-icon-search" @click="fetchData()">查询</el-button>
+          <el-button type="default" @click="resetData()">清空</el-button>
+          <el-button type="primary" icon="el-icon-download" @click="exportData()">导出</el-button>
+        </el-form-item>
+      </el-form>
+    </el-card>
+
+    <!-- 数据表格区域 -->
+    <el-card shadow="never" style="margin-top: 16px;">
+      <el-table :data="tableData" border stripe :header-cell-style="{ background: '#f5f7fa' }" v-loading="loading">
+        <!-- <el-table-column label="设备ID" prop="resourceId" align="center" width="120" /> -->
+        <el-table-column label="日期" prop="dayDate" align="center" width="180" />
+        <el-table-column label="设备名称" prop="resourceName" align="center" min-width="100" />
+        <el-table-column label="零件名称" prop="bomNames" align="center" min-width="100" />
+        <el-table-column label="加工数量" prop="counts" align="center" width="120" />
+         <el-table-column label="主轴利用率" prop="resourceZZLYL" align="center" width="120" />
+      </el-table>
+
+      <!-- 分页组件 -->
+      <el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="page"
+        :page-sizes="[10, 20, 50, 100]" :page-size="limit" :total="total"
+        layout="total, sizes, prev, pager, next, jumper" style="margin-top: 16px; text-align: right;" />
+    </el-card>
+  </div>
+</template>
+
+<script>
+  import statisticalForm from "@/api/statisticalAnalysis/statisticalForm";
+  import productlineAvailabilityApi from "@/api/statisticalAnalysis/productlineAvailability";
+  import {
+    Message
+  } from "element-ui";
+
+  export default {
+    name: "statisticalForm",
+    data() {
+      return {
+        tableData: [],
+        loading: false,
+         allloading: false, // 新增:导出加载状态(区分表格加载)
+        total: 0,
+        page: 1,
+        limit: 10,
+        searchObj: {
+          startDate: "",
+          endDate: "",
+          month: "", // 用于存储默认当月
+          years: "",
+          taskType: "",
+          funcType: ""
+        }
+      };
+    },
+    created() {
+      // 1. 页面初始化时,设置默认查询条件为“当月”
+      this.setDefaultMonth();
+      // 2. 加载当月数据
+      this.fetchData();
+    },
+    methods: {
+      /**
+       * 核心:设置默认查询条件为“当前月份”
+       */
+      setDefaultMonth() {
+        const now = new Date(); // 当前时间
+        const year = now.getFullYear(); // 年(4位)
+        const month = now.getMonth() + 1; // 月(注意:getMonth()返回0-11,需+1)
+        // 格式化为“yyyy-MM”(如2025-05),匹配date-picker的value-format
+        this.searchObj.month = `${year}-${month.toString().padStart(2, "0")}`;
+      },
+
+      /**
+       * 时间选择互斥逻辑(适配默认当月)
+       */
+      handleTimeChange(type) {
+        switch (type) {
+          case "dateRange":
+            this.searchObj.month = "";
+            this.searchObj.years = "";
+            if (this.searchObj.startDate && !this.searchObj.endDate) {
+              Message.warning("请选择结束时间");
+            } else if (!this.searchObj.startDate && this.searchObj.endDate) {
+              Message.warning("请选择开始时间");
+            }
+            break;
+          case "month":
+            this.searchObj.startDate = "";
+            this.searchObj.endDate = "";
+            this.searchObj.years = "";
+            break;
+          case "year":
+            this.searchObj.startDate = "";
+            this.searchObj.endDate = "";
+            this.searchObj.month = "";
+            break;
+        }
+      },
+
+      /**
+       * 加载数据(默认加载当月数据)
+       */
+      async fetchData() {
+        // 验证查询条件(默认当月已满足,无需额外提示)
+        const hasDateRange = this.searchObj.startDate && this.searchObj.endDate;
+        const hasMonth = !!this.searchObj.month;
+        const hasYear = !!this.searchObj.years;
+
+        if (!hasDateRange && !hasMonth && !hasYear) {
+          Message.warning("请选择生产时间范围、月份或年份中的一项");
+          return;
+        }
+
+        this.loading = true;
+        try {
+          // 2. 调用接口:传递分页参数 + 查询条件
+          const response = await statisticalForm.page(
+            this.page,
+            this.limit,
+            this.searchObj
+          );
+
+          // 3. 安全校验:先确保 response 和 response.data 存在(避免 undefined 报错)
+          if (!response || !response.data) {
+            throw new Error("接口返回格式异常,未找到 data 字段");
+          }
+
+          console.log("接口返回完整数据:", response.data); // 便于调试
+
+          // 4. 优先判断后端业务码(关键!区分业务成功/失败)
+          // 假设后端业务码规则:code=200 成功,其他为失败
+          if (response.data.code === 0) {
+            // 5. 安全处理 records 数组:确保是数组,避免非数组导致表格报错
+            const rawRecords = response.data.data.records;
+            console.log("rawRecords:" + rawRecords)
+            this.tableData = Array.isArray(rawRecords) ? rawRecords : [];
+            console.log("表格数据源(处理后):", this.tableData);
+
+            // 6. 安全处理 total:确保是数字,避免分页组件异常
+            this.total = Number(response.data.data.total) || 0; // 空值/非数字时默认 0
+          } else {
+            // 7. 业务失败:显示后端返回的错误信息
+            const errorMsg = response.data.msg || "业务处理失败,请重试";
+            Message.error("数据加载失败:" + errorMsg);
+            // 兜底:清空表格数据,避免残留旧数据
+            this.tableData = [];
+            this.total = 0;
+          }
+
+        } catch (error) {
+          // 8. 捕获所有异常:网络错误、接口格式异常、自定义抛出的错误
+          console.error("数据请求异常详情:", error); // 打印完整错误栈,便于定位问题
+          // 区分错误类型,显示更精准的提示
+          const errorMsg = error.message.includes("Network Error") ?
+            "网络错误,请检查网络连接后重试" :
+            "数据请求失败,请刷新页面重试";
+          Message.error(errorMsg);
+          // 兜底:清空表格数据 + 重置总条数
+          this.tableData = [];
+          this.total = 0;
+
+        } finally {
+          // 9. 无论成功/失败,都关闭加载状态(避免卡死)
+          this.loading = false;
+
+          // (可选)表格数据更新后,调整 Element UI 表格布局(避免高度异常)
+          this.$nextTick(() => {
+            if (this.$refs.statTable) { // 确保表格 ref 存在
+              this.$refs.statTable.doLayout();
+            }
+          });
+        }
+      },
+
+      /**
+       * 清空查询条件(重置后仍默认当月)
+       */
+      resetData() {
+        this.searchObj = {
+          startDate: "",
+          endDate: "",
+          month: "", // 先清空,再重新设置当月
+          years: "",
+          taskType: "",
+          funcType: ""
+        };
+        // 重置后重新设置默认当月
+        this.setDefaultMonth();
+        // 重置分页
+        this.page = 1;
+        this.limit = 10;
+        // 重新加载当月数据
+        this.fetchData();
+      },
+
+      // 分页:每页条数改变
+      handleSizeChange(newSize) {
+        this.limit = newSize;
+        this.page = 1;
+        this.fetchData();
+      },
+
+      // 分页:页码改变
+      handleCurrentChange(newPage) {
+        this.page = newPage;
+        this.fetchData();
+      },
+
+    //导出
+    exportData() {
+      const exportParams = {
+        ...this.searchObj, // 原有查询条件
+        // 场景1:导出全部数据(推荐,忽略当前分页,传递全量标识)
+        page: 1, // 后端若按分页逻辑,传 1 表示第一页
+        limit: this.limit, // 传总条数,表示获取全部数据(需后端支持)
+        // 场景2:导出当前页数据(如需此逻辑,替换为下方代码)
+        // page: this.page,
+        // limit: this.limit,
+        exportType: "excel" // 可选:传递导出类型,便于后端识别(如支持 excel/pdf)
+      };
+      productlineAvailabilityApi.exportDeviceResourceStatistics1(exportParams).then((res) => {
+        if (!res) return;
+        const blob = new Blob([res.data], {
+          type: "application/vnd.ms-excel;",
+        });
+        const a = document.createElement("a");
+        // 生成文件路径
+        let href = window.URL.createObjectURL(blob);
+        a.href = href;
+        // 文件名中有中文 则对文件名进行转码
+        a.download = decodeURIComponent("统计报表导出");
+        // 利用a标签做下载
+        document.body.appendChild(a);
+        a.click();
+        document.body.removeChild(a);
+        window.URL.revokeObjectURL(href);
+        this.allloading = false;
+      });
+    },
+    }
+  };
+</script>
+
+<style scoped>
+  .demo-form-inline .el-form-item {
+    margin-right: 24px;
+    margin-bottom: 16px;
+  }
+
+  @media (max-width: 1200px) {
+    .demo-form-inline .el-form-item {
+      margin-right: 16px;
+    }
+  }
+</style>