Răsfoiți Sursa

工厂看板接口对接

695593266@qq.com 3 luni în urmă
părinte
comite
1aee91f4dc

+ 68 - 0
src/api/vis/factoryProductionDashboard.js

@@ -0,0 +1,68 @@
+import request from '@/utils/request';
+
+//工厂生产综合看板-生产统计、生成情况、五品、四数、质量统计
+export async function getFactoryProductionDashboardData(params) {
+  const res = await request.get(
+    '/factoryProductionDataScreen/getFactoryProductionDataOne',
+    {
+      params
+    }
+  );
+  if (res.data.code == 0) {
+    return res.data.data;
+  }
+  return Promise.reject(new Error(res.data.message));
+}
+
+//工厂生产综合看板-生产计划进度
+export async function getFactoryProductionDataByPlan(params) {
+  const res = await request.get(
+    '/factoryProductionDataScreen/getFactoryProductionPlan',
+    {
+      params
+    }
+  );
+  if (res.data.code == 0) {
+    return res.data.data;
+  }
+  return Promise.reject(new Error(res.data.message));
+}
+
+//工厂生产综合看板-库存台账
+export async function getFactoryProductionDataByStock(params) {
+  const res = await request.get(
+    '/factoryProductionDataScreen/getFactoryProductionDataByStock',
+    {
+      params
+    }
+  );
+  if (res.data.code == 0) {
+    return res.data.data;
+  }
+  return Promise.reject(new Error(res.data.message));
+}
+
+//工厂生产综合看板-各类设备台账
+export async function getFactoryProductionDataByDevice(params) {
+  const res = await request.get(
+    '/factoryProductionDataScreen/getFactoryProductionDataByDevice',
+    {
+      params
+    }
+  );
+  if (res.data.code == 0) {
+    return res.data.data;
+  }
+  return Promise.reject(new Error(res.data.message));
+}
+
+//获取当前登录人所有工厂数据
+export async function getFactoryListByUser(params) {
+  const res = await request.get(`/main/factoryarea/page`, {
+    params
+  });
+  if (res.data.code == 0) {
+    return res.data.data;
+  }
+  return Promise.reject(new Error(res.data.message));
+}

+ 299 - 105
src/views/bpm/vis-page/factoryProductionDashboard.vue

@@ -417,6 +417,13 @@
   import Bar3DChart from './components/charts/Bar3DChart';
   import DeviceStatusChart from './components/charts/DeviceStatusChart';
   import BarLineComboChart from './components/charts/BarLineComboChart';
+  import {
+    getFactoryProductionDashboardData,
+    getFactoryProductionDataByPlan,
+    getFactoryProductionDataByStock,
+    getFactoryProductionDataByDevice,
+    getFactoryListByUser
+  } from '@/api/vis/factoryProductionDashboard';
   const inventoryIcon = require('@/assets/png/icon.png');
 
   export default {
@@ -479,13 +486,19 @@
         immediate: true
       },
       factoryId() {
-        this.loadMockData();
+        this.loadDashboardData();
       },
       dateRange: {
         handler() {
-          this.loadMockData();
+          this.loadDashboardData();
         },
         deep: true
+      },
+      activePlanTab() {
+        this.fetchPlanData();
+      },
+      activeInventoryFilter() {
+        this.fetchInventoryData();
       }
     },
     data() {
@@ -500,74 +513,57 @@
         week: '',
         inventoryIcon,
 
-        factoryId: 'F001',
-        factoryList: [
-          { id: 'F001', name: '工厂A' },
-          { id: 'F002', name: '工厂B' }
-        ],
+        factoryId: '',
+        factoryList: [],
         dateRange: [],
 
         productionStats: {
-          quantity: 58500,
+          quantity: 0,
           transformQuantity: [0, 0, 0, 0, 0, 0],
-          requiredTotal: 1000,
-          achievementRate: 58.8
+          requiredTotal: 0,
+          achievementRate: 0
         },
         productionKpi: {
-          delayedCount: 29,
-          planAchievementRate: 82,
-          unpublishedCount: 53
+          delayedCount: 0,
+          planAchievementRate: 0,
+          unpublishedCount: 0
         },
 
         fiveCategoryData: [
-          { name: '成品', value: 2533 },
-          { name: '半成品', value: 1050 },
-          { name: '在制品', value: 2523 },
-          { name: '废品', value: 58 },
-          { name: '返修品', value: 83 }
+          { name: '成品', value: 0 },
+          { name: '半成品', value: 0 },
+          { name: '在制品', value: 0 },
+          { name: '废品', value: 0 },
+          { name: '返修品', value: 0 }
         ],
         fourNumberBarData: [
-          { name: '产品', value: 300 },
-          { name: '物品', value: 260 },
-          { name: '零部件', value: 280 },
-          { name: '备品备件', value: 320 }
+          { name: '投入数', value: 0 },
+          { name: '产出数', value: 0 },
+          { name: '废品数', value: 0 },
+          { name: '周转数', value: 0 }
         ],
 
-        inventoryLedgerData: [
-          { name: '产品', value: 420 },
-          { name: '物品', value: 300 },
-          { name: '半成品', value: 380 },
-          { name: '零件', value: 260 },
-          { name: '生产设备', value: 110 },
-          { name: '仪表计量', value: 180 },
-          { name: '备品备件', value: 220 }
-        ],
-        inventoryLedgerKeeperData: [
-          { name: '仓管A', value: 360 },
-          { name: '仓管B', value: 300 },
-          { name: '仓管C', value: 280 },
-          { name: '仓管D', value: 330 },
-          { name: '仓管E', value: 250 }
-        ],
+        inventoryLedgerData: [],
+        inventoryLedgerKeeperData: [],
         activeInventoryFilter: 'category',
         deviceLedger: {
-          categories: ['设备', '工夹刀模具', '仪表计量', '备品备件'],
-          barData: [2907, 1865, 2735, 865],
-          topBarData: [3607, 2385, 3987, 1685],
-          lineData: [78, 65, 86, 72]
+          categories: [],
+          barData: [],
+          topBarData: [],
+          lineData: []
         },
 
         quality: {
-          passRate: 98,
-          failRate: 2,
-          lossRate: 5
+          passRate: 0,
+          failRate: 0,
+          lossRate: 0
         },
 
         planTabs: [
           { key: 'all', label: '全部' },
           { key: 'monthly', label: '月度滚动计划' },
           { key: 'temporary', label: '临时生产计划' },
-          { key: 'research', label: '科研计划' }
+          { key: 'research', label: '分厂临时计划' }
         ],
         activePlanTab: 'all',
         planRows: []
@@ -579,9 +575,9 @@
       const now = new Date();
       const start = new Date(now.getTime() - 1000 * 60 * 60 * 24 * 30);
       this.dateRange = [this.formatDate(start), this.formatDate(now)];
+      this.getFactoryListByData();
     },
     mounted() {
-      this.loadMockData();
       this.applyScreenSize();
       window.addEventListener('resize', this.handleWindowResize);
       document.addEventListener(
@@ -628,6 +624,25 @@
           }, 150);
         });
       },
+
+      async getFactoryListByData() {
+        const par = {
+          type: 1,
+          size: 9999
+        };
+        await getFactoryListByUser(par).then((res) => {
+          if (res.list && res.list.length > 0) {
+            this.factoryList = res.list.map((el) => {
+              return {
+                id: el.id,
+                name: el.name
+              };
+            });
+          }
+        });
+        this.factoryId = this.factoryList.length ? this.factoryList[0].id : '';
+      },
+
       triggerChartResize() {
         this.$nextTick(() => {
           window.dispatchEvent(new Event('resize'));
@@ -715,72 +730,250 @@
         const paddedStr = String(num ?? 0).padStart(6, '0');
         return paddedStr.split('').map((c) => Number(c));
       },
-      loadMockData() {
-        // mock:后续你接接口时,将这里替换成 API 请求即可
-        const base = this.factoryId === 'F002' ? 74210 : 58500;
-        this.productionStats.quantity = base;
-        this.productionStats.transformQuantity = this.formatNumber6(base);
-        this.productionStats.requiredTotal =
-          this.factoryId === 'F002' ? 1600 : 1000;
-        this.productionStats.achievementRate =
-          this.factoryId === 'F002' ? 76.2 : 58.8;
-
-        this.productionKpi.delayedCount = this.factoryId === 'F002' ? 12 : 29;
-        this.productionKpi.planAchievementRate =
-          this.factoryId === 'F002' ? 91 : 82;
-        this.productionKpi.unpublishedCount =
-          this.factoryId === 'F002' ? 18 : 53;
-
-        this.planRows = [
+      normalizeNumber(value) {
+        const num = Number(value);
+        return Number.isFinite(num) ? num : 0;
+      },
+      normalizePercent(value) {
+        if (value === null || value === undefined || value === '') return 0;
+        const text = String(value).replace('%', '').trim();
+        const num = Number(text);
+        return Number.isFinite(num) ? Number(num.toFixed(2)) : 0;
+      },
+      normalizeNameValueList(list) {
+        if (!Array.isArray(list)) return [];
+        return list.map((item) => ({
+          name: item?.name || '--',
+          value: this.normalizeNumber(item?.value)
+        }));
+      },
+      getDateType() {
+        const [start, end] = this.dateRange || [];
+        if (!start || !end) return 1;
+        const startDate = new Date(start);
+        const endDate = new Date(end);
+        if (
+          Number.isNaN(startDate.getTime()) ||
+          Number.isNaN(endDate.getTime())
+        ) {
+          return 1;
+        }
+        if (start === end) return 1;
+        if (
+          startDate.getFullYear() === endDate.getFullYear() &&
+          startDate.getMonth() === endDate.getMonth()
+        ) {
+          return 2;
+        }
+        return 3;
+      },
+      getBaseParams(extra = {}) {
+        if (!this.factoryId) return null;
+        return {
+          dateType: this.getDateType(),
+          factoryId: this.factoryId,
+          ...extra
+        };
+      },
+      getInventoryStockType(filterType = this.activeInventoryFilter) {
+        return filterType === 'keeper' ? 2 : 1;
+      },
+      mapPlanTabType(tab = this.activePlanTab) {
+        const tabTypeMap = {
+          all: 0,
+          monthly: 1,
+          temporary: 2,
+          research: 3
+        };
+        return tabTypeMap[tab] ?? 0;
+      },
+      mapPlanStatus(status) {
+        const statusMap = {
+          1: '待排产',
+          2: '待发布',
+          3: '发布失败',
+          4: '待生产',
+          5: '进行中',
+          6: '已完成',
+          7: '延期',
+          8: '待下达'
+        };
+        return statusMap[Number(status)] || '--';
+      },
+      formatPlanDate(value) {
+        if (!value) return '--';
+        const text = String(value).replace('T', ' ');
+        return text.slice(0, 10);
+      },
+      mapPlanRow(row, planTab = this.activePlanTab) {
+        const status = Number(row?.status || 0);
+        return {
+          planNo: row?.code || '--',
+          productName: row?.productName || '--',
+          batchNo: row?.batchNo || '--',
+          planQty: this.normalizeNumber(row?.planQuantity),
+          currentProcess: row?.produceRoutingName || '--',
+          planStart: this.formatPlanDate(row?.plannedStartTime),
+          planEnd: this.formatPlanDate(row?.plannedEndTime),
+          isDelayed: status === 7,
+          statusText: this.mapPlanStatus(status),
+          type: planTab
+        };
+      },
+      buildDeviceLedger(list) {
+        const normalized = Array.isArray(list)
+          ? list.map((item) => {
+              const total = this.normalizeNumber(item?.value);
+              const occupied = this.normalizeNumber(
+                item?.value2 !== undefined ? item?.value2 : item?.value
+              );
+              return {
+                name: item?.name || '--',
+                total,
+                occupied
+              };
+            })
+          : [];
+        return {
+          categories: normalized.map((item) => item.name),
+          barData: normalized.map((item) => item.occupied),
+          topBarData: normalized.map((item) => item.total),
+          lineData: normalized.map((item) =>
+            item.total
+              ? Number(((item.occupied / item.total) * 100).toFixed(2))
+              : 0
+          )
+        };
+      },
+      applyDashboardSummary(data = {}) {
+        const quantity = this.normalizeNumber(data?.quantity);
+        this.productionStats.quantity = quantity;
+        this.productionStats.transformQuantity = this.formatNumber6(quantity);
+        this.productionStats.requiredTotal = this.normalizeNumber(
+          data?.totalQuantity
+        );
+        this.productionStats.achievementRate = this.normalizePercent(
+          data?.quantityAchievementRate
+        );
+
+        this.productionKpi.delayedCount = this.normalizeNumber(data?.delayNumber);
+        this.productionKpi.planAchievementRate = this.normalizePercent(
+          data?.achievementRate
+        );
+        this.productionKpi.unpublishedCount = this.normalizeNumber(
+          data?.numberToBeProduced
+        );
+
+        this.fiveCategoryData = [
+          {
+            name: '成品',
+            value: this.normalizeNumber(data?.finishedProductQuantity)
+          },
           {
-            planNo: 'SCH001',
-            productName: '走查机配件',
-            batchNo: 'NP-26-33',
-            planQty: 88,
-            currentProcess: '走查机',
-            planStart: this.dateRange?.[0] || '2026-02-01',
-            planEnd: this.dateRange?.[1] || '2026-03-01',
-            isDelayed: true,
-            statusText: '延期',
-            type: 'monthly'
+            name: '半成品',
+            value: this.normalizeNumber(data?.semiFinishedProductQuantity)
           },
           {
-            planNo: 'SCH002',
-            productName: '走查机配件',
-            batchNo: 'NP-26-33',
-            planQty: 88,
-            currentProcess: '走查机',
-            planStart: this.dateRange?.[0] || '2026-02-01',
-            planEnd: this.dateRange?.[1] || '2026-03-01',
-            isDelayed: false,
-            statusText: '进行中',
-            type: 'monthly'
+            name: '在制品',
+            value: this.normalizeNumber(data?.workInProgressQuantity)
           },
           {
-            planNo: 'TMP031',
-            productName: '工具组件',
-            batchNo: 'TMP-01',
-            planQty: 36,
-            currentProcess: '装配',
-            planStart: this.dateRange?.[0] || '2026-02-01',
-            planEnd: this.dateRange?.[1] || '2026-03-01',
-            isDelayed: false,
-            statusText: '未开始',
-            type: 'temporary'
+            name: '废品',
+            value: this.normalizeNumber(data?.scrapProductQuantity)
           },
           {
-            planNo: 'RW008',
-            productName: '返修件A',
-            batchNo: 'RW-08',
-            planQty: 12,
-            currentProcess: '返修',
-            planStart: this.dateRange?.[0] || '2026-02-01',
-            planEnd: this.dateRange?.[1] || '2026-03-01',
-            isDelayed: false,
-            statusText: '进行中',
-            type: 'research'
+            name: '返修品',
+            value: this.normalizeNumber(data?.reworkProductQuantity)
           }
         ];
+
+        this.fourNumberBarData = [
+          { name: '投入数', value: this.normalizeNumber(data?.inputQuantity) },
+          { name: '产出数', value: this.normalizeNumber(data?.outputQuantity) },
+          { name: '废品数', value: this.normalizeNumber(data?.scrapQuantity) },
+          { name: '周转数', value: this.normalizeNumber(data?.turnoverQuantity) }
+        ];
+
+        this.quality.passRate = this.normalizePercent(data?.passRate);
+        this.quality.failRate = this.normalizePercent(data?.defectiveRate);
+        this.quality.lossRate = this.normalizePercent(data?.attritionRate);
+      },
+      async loadDashboardData() {
+        const baseParams = this.getBaseParams();
+        if (!baseParams) return;
+        await Promise.all([
+          this.fetchSummaryData(baseParams),
+          this.fetchInventoryData(baseParams),
+          this.fetchDeviceData(baseParams),
+          this.fetchPlanData(baseParams)
+        ]);
+      },
+      async fetchSummaryData(baseParams = this.getBaseParams()) {
+        if (!baseParams) return;
+        try {
+          const data = await getFactoryProductionDashboardData(baseParams);
+          this.applyDashboardSummary(data || {});
+        } catch (error) {
+          console.error('获取工厂生产综合看板汇总数据失败:', error);
+          this.applyDashboardSummary({});
+        }
+      },
+      async fetchInventoryData(
+        baseParams = this.getBaseParams(),
+        filterType = this.activeInventoryFilter
+      ) {
+        if (!baseParams) return;
+        try {
+          const list = await getFactoryProductionDataByStock({
+            ...baseParams,
+            stockType: this.getInventoryStockType(filterType)
+          });
+          if (filterType !== this.activeInventoryFilter) return;
+          const normalized = this.normalizeNameValueList(list);
+          if (filterType === 'keeper') {
+            this.inventoryLedgerKeeperData = normalized;
+          } else {
+            this.inventoryLedgerData = normalized;
+          }
+        } catch (error) {
+          console.error('获取库存台账数据失败:', error);
+          if (filterType === 'keeper') {
+            this.inventoryLedgerKeeperData = [];
+          } else {
+            this.inventoryLedgerData = [];
+          }
+        }
+      },
+      async fetchDeviceData(baseParams = this.getBaseParams()) {
+        if (!baseParams) return;
+        try {
+          const list = await getFactoryProductionDataByDevice(baseParams);
+          this.deviceLedger = this.buildDeviceLedger(list);
+        } catch (error) {
+          console.error('获取各类型设备台账数据失败:', error);
+          this.deviceLedger = this.buildDeviceLedger([]);
+        }
+      },
+      async fetchPlanData(
+        baseParams = this.getBaseParams(),
+        planTab = this.activePlanTab
+      ) {
+        if (!baseParams) return;
+        try {
+          const list = await getFactoryProductionDataByPlan({
+            ...baseParams,
+            type: this.mapPlanTabType(planTab)
+          });
+          if (planTab !== this.activePlanTab) return;
+          this.planRows = Array.isArray(list)
+            ? list.map((item) => this.mapPlanRow(item, planTab))
+            : [];
+        } catch (error) {
+          console.error('获取生产计划进度数据失败:', error);
+          if (planTab === this.activePlanTab) {
+            this.planRows = [];
+          }
+        }
       }
     }
   };
@@ -1402,7 +1595,8 @@
     position: relative;
     transform: perspective(260px) rotateX(8deg);
     transform-origin: center bottom;
-    box-shadow: 0 8px 16px rgba(0, 0, 0, 0.22), 0 0 12px rgba(18, 129, 214, 0.22) inset;
+    box-shadow: 0 8px 16px rgba(0, 0, 0, 0.22),
+      0 0 12px rgba(18, 129, 214, 0.22) inset;
     overflow: hidden;
   }
 

+ 2 - 1
vue.config.js

@@ -36,7 +36,8 @@ module.exports = {
         // target: 'http://192.168.1.139:18086', // 粟
         // target: 'http://192.168.1.132:18086', // 徐1
         // target: 'http://192.168.1.134:18086', //徐2
-        target: 'http://192.168.1.125:18086',
+        // target: 'http://192.168.1.125:18086',
+        target: 'http://192.168.1.251:18086',
         // target: 'http://192.168.1.251:18186', // 测试环境
         changeOrigin: true, // 只有这个值为true的情况下 才表示开启跨域
         pathRewrite: {