소스 검색

merge develop

Renxy 2 년 전
부모
커밋
27239b95ee

+ 8 - 0
config/router.config.js

@@ -7,6 +7,10 @@ export default [
         path: '/login',
         component: './PurchaseAdmin/PurchaseList/Login/Login',
       },
+      {
+        path: '/mobile/craft',
+        component: './Mobile/DataMeter/Craft',
+      },
       {
         path: '/home',
         component: './PurchaseAdmin/PurchaseList/Index',
@@ -70,6 +74,10 @@ export default [
           },
         ],
       },
+      {
+        path: '/mobiletest/chart',
+        component: './Mobile/DataMeter/Chart',
+      },
       {
         component: '404',
       },

+ 4 - 4
public/luckysheet.html

@@ -7,20 +7,20 @@
     <title>Document</title>
 
    <!-- 线上发布使用路径 -->
-   <!-- <link rel="stylesheet" href="/bom/Luckysheet/plugins/css/pluginsCss.css" />
+   <link rel="stylesheet" href="/bom/Luckysheet/plugins/css/pluginsCss.css" />
    <link rel="stylesheet" href="/bom/Luckysheet/plugins/plugins.css" />
    <link rel="stylesheet" href="/bom/Luckysheet/css/luckysheet.css" />
    <link rel="stylesheet" href="/bom/Luckysheet/assets/iconfont/iconfont.css" />
    <script src="/bom/Luckysheet/plugins/js/plugin.js"></script>
-   <script src="/bom/Luckysheet/luckysheet.umd.js"></script> -->
+   <script src="/bom/Luckysheet/luckysheet.umd.js"></script>
 
    <!-- 本地开发使用路径 -->
-   <link rel='stylesheet' href='http://localhost:3000/plugins/css/pluginsCss.css' />
+   <!-- <link rel='stylesheet' href='http://localhost:3000/plugins/css/pluginsCss.css' />
    <link rel='stylesheet' href='http://localhost:3000/plugins/plugins.css' />
    <link rel='stylesheet' href='http://localhost:3000/css/luckysheet.css' />
    <link rel='stylesheet' href='http://localhost:3000/assets/iconfont/iconfont.css' />
    <script src="http://localhost:3000/plugins/js/plugin.js"></script>
-   <script src="http://localhost:3000/luckysheet.umd.js"></script>
+   <script src="http://localhost:3000/luckysheet.umd.js"></script> -->
   </head>
   <body>
     <div

+ 345 - 0
src/components/ChartUtils/utils.js

@@ -0,0 +1,345 @@
+import moment from 'moment';
+
+import {
+  getDeviceRealData,
+  getDeviceRealDataByTime,
+  queryFormCurrentData,
+  queryFormHistoryData,
+} from '@/services/ProjectAdmin';
+
+const computePrefixExpression = (function() {
+  var s1 = [],
+    result;
+  return function(prefixExpression) {
+    s1.length = 0;
+    //计算
+    while (prefixExpression.length > 0) {
+      var o = prefixExpression.shift();
+      if (operator_map.indexOf(o) == -1) {
+        s1.push(Number(o));
+      } else {
+        switch (o) {
+          case '+': {
+            result = s1.pop() + s1.pop();
+            break;
+          }
+          case '-': {
+            result = s1.pop() - s1.pop();
+            break;
+          }
+          case '*': {
+            result = s1.pop() * s1.pop();
+            break;
+          }
+          case '/': {
+            result = s1.pop() / s1.pop();
+            break;
+          }
+        }
+        s1.push(result);
+      }
+    }
+    return s1[0];
+  };
+})();
+
+const getFunctionValue = child => {
+  let data = {};
+  data.data = [];
+  let expression = child.tempExpression;
+  let first = child.data[0];
+  let indexArr = child.indexArr;
+  first.data.forEach(item => {
+    // firstDevice.device
+    let resObj = {
+      [first.device.deviceName]: item,
+    };
+    let htime = item.htime;
+    for (let i = 1; i < child.data.length; i++) {
+      let element = child.data[i];
+      // deviceName = element.name
+      let result = element.data.find(item => item.htime === htime);
+      if (!result) return;
+      resObj[element.device.deviceName] = result;
+    }
+    Object.keys(resObj).forEach(key => {
+      var result = indexArr.find(item => key === item.deviceName);
+      if (result) expression[result.index] = resObj[key].val;
+    });
+    // console.log(expression);
+    data.data.push({
+      htime: moment(htime).format('YYYY-MM-DD HH:mm:ss'),
+      val: computePrefixExpression([...expression]),
+    });
+    // console.log(indexArr, resObj, expression);
+    //  indexArr   resObj     expression
+  });
+  data.name = child.name;
+  return data;
+};
+
+/**
+ * 获取图表的options
+ * @param {object} values 表单数据
+ * @param {array} datas 数据项
+ * @param {array} formula 数据公式
+ * @returns
+ */
+export async function getPlcOptions(values, datas, formula) {
+  let arrtData = values.data || [];
+  let params = getSingleData(datas);
+  let multiParams = getFormula(formula);
+  if (!values.timeType) {
+    let res = await getData(params, values);
+    for (let i = 0; i < multiParams.length; i++) {
+      let device = multiParams[i].paramsDevice;
+      let indexArr = multiParams[i].indexArr;
+      let tempExpression = [...multiParams[i].expression];
+      let formulaRes = await getData(device, values);
+      formulaRes.data.map(res => {
+        let temp = device.find(child => child.deviceName === res.alias);
+        console.log(temp);
+        if (temp) {
+          var indexObj = indexArr.find(item => item.deviceName === temp.deviceName);
+          if (indexObj) {
+            tempExpression[indexObj.index] = res.val;
+          }
+        }
+      });
+      let tempValue = computePrefixExpression([...tempExpression]);
+      multiParams[i].formatExpression = tempExpression;
+      multiParams[i].value = tempValue;
+    }
+    let resData = res.data.map((item, index) => {
+      let attrDataItem = arrtData[index + formula.length] || {};
+      return {
+        ...attrDataItem,
+        name: item.alias,
+        value: item.val * 1,
+      };
+    });
+    let formulaData = multiParams.map((item, index) => {
+      let attrDataItem = arrtData[index] || {};
+      return {
+        ...attrDataItem,
+        name: item.FormulaName,
+        value: item.value * 1,
+      };
+    });
+
+    return {
+      ...values,
+      data: [...resData, ...formulaData],
+    };
+  } else {
+    let singleData = [];
+    for (let i = 0; i < params.length; i++) {
+      const item = params[i];
+      let res = await getData(item, values);
+      let attrDataItem = arrtData[i + multiParams.length] || {};
+      singleData.push({
+        ...attrDataItem,
+        name: item.deviceName,
+        data: (res.data || []).map(item => {
+          return {
+            val: item.val,
+            htime: moment(item.htime_at).format('YYYY-MM-DD HH:mm:ss'),
+          };
+        }),
+      });
+    }
+
+    let firstHTimeArr = [];
+    let formulaData = [];
+    for (let i = 0; i < multiParams.length; i++) {
+      const element = multiParams[i];
+      let indexArr = element.indexArr;
+      let tempExpression = [...element.expression];
+      let device = element.paramsDevice;
+      let child = {};
+      child.tempExpression = tempExpression;
+      child.name = element.FormulaName;
+      child.data = [];
+      child.indexArr = indexArr;
+      for (let j = 0; j < device.length; j++) {
+        const tempDevice = device[j];
+        let res = await getData(tempDevice, values);
+        child.data.push({
+          data: res.data,
+          device: tempDevice,
+        });
+      }
+      formulaData.push(child);
+    }
+
+    let data = [];
+
+    formulaData.map((item, index) => {
+      let attrDataItem = arrtData[index] || {};
+      data.push({ ...attrDataItem, ...getFunctionValue(item) });
+    });
+
+    values.data = [...singleData, ...data];
+    return values;
+  }
+}
+// 根据数据项获取请求参数
+function getSingleData(datas) {
+  let params = [];
+  datas.forEach(({ device_id, device_items, seq }) => {
+    if (device_id && device_items) {
+      params.push({
+        deviceName: seq,
+        deviceId: device_id,
+        deviceItems: device_items,
+      });
+    }
+  });
+  return params;
+}
+// 根据公式获得请求参数
+function getFormula(formula) {
+  let params = [];
+  formula.forEach(item => {
+    let tempItem = item;
+    let tempDeviceArr = [];
+    let indexArr = [];
+    item.Device.map(device => {
+      if (device.Id && device.ItemAlias && device.ItemName) {
+        tempDeviceArr.push({
+          deviceName: device.ItemAlias,
+          deviceId: String(device.PlcDeviceId),
+          deviceItems: device.ItemName,
+        });
+
+        indexArr.push({ index: device.index, deviceName: device.ItemAlias });
+      }
+    });
+    tempItem.paramsDevice = tempDeviceArr;
+    tempItem.indexArr = indexArr;
+    params.push(tempItem);
+  });
+  return params;
+}
+
+var DATA_CACHE = {};
+// 请求plc数据
+async function getData(params, values) {
+  const { timeType, date, size, interval, aggregator } = values;
+  let key, etime, stime;
+  if (!timeType) {
+    key = `${params.map(item => item.deviceItems).join(',')}-${timeType}`;
+  } else if (timeType != -1) {
+    key = `${params.deviceItems}-${timeType}-${size}-${interval}-${aggregator}`;
+  } else {
+    let clear = { hour: 0, minute: 0, second: 0, millisecond: 0 };
+    etime = moment(date[1]).set(clear) * 1;
+    stime = moment(date[0]).set(clear) * 1;
+    key = `${params.deviceItems}-${stime}-${etime}-${size}-${interval}-${aggregator}`;
+  }
+  if (!DATA_CACHE[key]) {
+    if (!timeType) {
+      DATA_CACHE[key] = await getDeviceRealData({
+        ...params,
+      });
+    } else {
+      if (timeType != -1) {
+        let currentDate = moment();
+        etime = currentDate * 1;
+        stime = currentDate.add(-1 * timeType, 'hour') * 1;
+      }
+      DATA_CACHE[key] = await getDeviceRealDataByTime({
+        deviceid: params.deviceId * 1,
+        dataitemid: params.deviceItems,
+        stime,
+        etime,
+        size,
+        interval,
+        aggregator,
+      });
+    }
+  }
+  return DATA_CACHE[key];
+}
+
+// 获取表单的options
+export async function getFormOptions(values, datas, projectId) {
+  let arrtData = values.data || [];
+  const params = getFormParams(datas, projectId);
+  if (!values.timeType) {
+    // 请求最新数据
+    let data = await getFormCurrentData(params, values);
+    let resData = data.map((item, index) => {
+      let attrDataItem = arrtData[index] || {};
+      return {
+        ...attrDataItem,
+        name: item.title,
+        value: item.value * 1,
+      };
+    });
+    return {
+      ...values,
+      data: resData,
+    };
+  } else {
+    // 请求历史数据
+    let data = await getFormHistoryData(params, values);
+    values.data = data.map((item, i) => {
+      let attrDataItem = arrtData[i] || {};
+      return {
+        ...attrDataItem,
+        ...item,
+      };
+    });
+
+    return values;
+  }
+}
+
+// 根据表单的数据项获取请求参数
+function getFormParams(datas, projectId) {
+  let params = {};
+  datas.forEach(item => {
+    if (!params[item.data_name]) params[item.data_name] = [];
+    params[item.data_name].push(item.data_title);
+  });
+  return Object.keys(params).map(data_name => ({
+    formName: data_name,
+    titles: params[data_name],
+    projectId,
+  }));
+}
+
+// 请求表单最新数据
+async function getFormCurrentData(params, values) {
+  const { timeType, date } = values;
+  let data = [];
+  for (let i = 0; i < params.length; i++) {
+    const resData = await queryFormCurrentData(params[i]);
+    data = [...data, ...resData];
+  }
+  return data;
+}
+
+// 请求表单历史数据
+async function getFormHistoryData(params, values) {
+  const { timeType, date } = values;
+  let sTime, eTime;
+  let data = [];
+  // -1为自选日期  从date内获取时间
+  if (timeType == -1) {
+    let clear = { hour: 0, minute: 0, second: 0, millisecond: 0 };
+    eTime = moment(date[1]).set(clear) * 1;
+    sTime = moment(date[0]).set(clear) * 1;
+  } else {
+    let currentDate = moment();
+    eTime = currentDate * 1;
+    sTime = currentDate.add(-1 * timeType, 'hour') * 1;
+  }
+
+  for (let i = 0; i < params.length; i++) {
+    const resData = await queryFormHistoryData({ ...params[i], eTime, sTime });
+    data = [...data, ...resData];
+  }
+  return data;
+}

+ 944 - 0
src/components/DataMeter/config.js

@@ -0,0 +1,944 @@
+export const CHILD_MAP = {
+  ProjectInfo: [
+    {
+      title: '项目编号',
+      key: 'Code',
+      show: true,
+    },
+    {
+      title: '项目工期',
+      key: 'Duration',
+      show: true,
+    },
+    {
+      title: '建设单位',
+      key: 'ConstructionUnit',
+      show: true,
+    },
+    {
+      title: '承建单位',
+      key: 'UndertakenUnit',
+      show: true,
+    },
+    {
+      title: '所在地',
+      key: 'Position',
+      show: true,
+    },
+
+    {
+      title: '项目规模',
+      key: 'Scale',
+      show: true,
+    },
+    {
+      title: '主体工艺',
+      key: 'MainProcess',
+      show: true,
+    },
+    {
+      title: '服务范围',
+      key: 'ServiceScope',
+      show: true,
+    },
+    {
+      title: '签约时间',
+      key: 'ContractTime',
+      show: true,
+    },
+    {
+      title: '运营服务时间',
+      key: 'ServiceTime',
+      show: true,
+    },
+    {
+      title: '合作模式',
+      key: 'CooperateMode',
+      show: true,
+    },
+    {
+      title: '出水执行标准',
+      key: 'WaterStandard',
+      show: true,
+    },
+    {
+      title: '核心管理人员',
+      key: 'Admin',
+      show: true,
+    },
+    {
+      title: '项目成员',
+      key: 'User',
+      show: true,
+    },
+  ],
+  AlarmCenter: [
+    { title: '全部', key: 4, show: true },
+    {
+      title: '待办事项',
+      key: 3,
+      show: true,
+    },
+    {
+      title: '异常报警',
+      key: 1,
+      show: true,
+    },
+    {
+      title: '逾期预警',
+      key: 2,
+      show: true,
+    },
+  ],
+  MessageCenter: [
+    {
+      title: '消息推送',
+      key: 1,
+      show: true,
+    },
+    {
+      title: '新闻动态',
+      key: 2,
+      show: true,
+    },
+    {
+      title: '大事记',
+      key: 3,
+      show: true,
+    },
+    {
+      title: '所获奖项',
+      key: 4,
+      show: true,
+    },
+  ],
+  PlanManagement: [
+    // {
+    //   title: '设计',
+    //   key: 1,
+    //   show: true,
+    // },
+    // {
+    //   title: '采购',
+    //   key: 2,
+    //   show: true,
+    // },
+    {
+      title: '到货',
+      key: 1,
+      show: true,
+    },
+    {
+      title: '施工',
+      key: 2,
+      show: true,
+    },
+    {
+      title: '单机调试',
+      key: 3,
+      show: true,
+    },
+    {
+      title: '系统调试',
+      key: 4,
+      show: true,
+    },
+    {
+      title: '试运行',
+      key: 5,
+      show: true,
+    },
+    // {
+    //   title: '维修',
+    //   key: 6,
+    //   show: true,
+    // },
+    {
+      title: '项目动态',
+      key: 7,
+      show: true,
+    },
+    // {
+    //   title: '巡检',
+    //   key: 7,
+    //   show: true,
+    // },
+    // {
+    //   title: '其它',
+    //   key: 8,
+    //   show: true,
+    // },
+  ],
+  Other: [
+    {
+      title: '安全操作规范',
+      key: 1,
+      show: true,
+    },
+    {
+      title: '项目日志',
+      key: 2,
+      show: true,
+    },
+  ],
+  Monitor: [],
+  DebugData: [],
+  DataCenter: [
+    {
+      title: '水质管理',
+      key: 1,
+      show: true,
+    },
+    {
+      title: '水质指标',
+      key: 2,
+      show: true,
+    },
+    {
+      title: '客户满意度',
+      key: 3,
+      show: true,
+    },
+    {
+      title: '设备完好率',
+      key: 4,
+      show: true,
+    },
+    {
+      title: 'KPI',
+      key: 5,
+      show: true,
+      children: [
+        {
+          title: '累计EBITDA',
+          key: 11,
+          show: true,
+        },
+        {
+          title: '累计经营性净现金流',
+          key: 12,
+          show: true,
+        },
+      ],
+    },
+    {
+      title: '水量计费',
+      key: 6,
+      show: true,
+    },
+    {
+      title: '预算成本',
+      key: 7,
+      show: true,
+      children: [
+        {
+          title: '累计成本支出',
+          key: 13,
+          show: true,
+        },
+        {
+          title: '累计月度吨水成本',
+          key: 14,
+          show: true,
+        },
+      ],
+    },
+    {
+      title: '季度绩效',
+      key: 8,
+      show: true,
+    },
+    {
+      title: '化学实验室数据',
+      key: 9,
+      show: true,
+    },
+    {
+      title: '安全生产天',
+      key: 10,
+      show: true,
+    },
+    // {
+    //   title: '调试数据',
+    //   key: 11,
+    //   show: true,
+    // },
+  ],
+};
+
+export const DEFAULT_LAYOUT = [
+  {
+    i: '41',
+    key: 'AlarmCenter',
+    w: 8,
+    h: 5,
+    x: 28,
+    y: 14,
+    child: [
+      { title: '全部', key: 4, show: true },
+      { title: '待办事项', key: 3, show: true },
+      { title: '异常报警', key: 1, show: true },
+      { title: '逾期预警', key: 2, show: true },
+    ],
+    moved: false,
+    static: false,
+    active: 2,
+  },
+  {
+    i: '40',
+    key: 'DataCenter',
+    active: 11,
+    w: 6,
+    h: 5,
+    x: 42,
+    y: 14,
+    child: [
+      { title: '水质管理', key: 1, show: true },
+      { title: '水质指标', key: 2, show: true },
+      { title: '客户满意度', key: 3, show: true },
+      { title: '设备完好率', key: 4, show: true },
+      { title: '累计EBITDA', key: 11, show: true },
+      { title: '累计经营性净现金流', key: 12, show: true },
+      { title: '水量计费', key: 6, show: true },
+      { title: '累计成本支出', key: 13, show: true },
+      { title: '累计月度吨水成本', key: 14, show: true },
+      { title: '季度绩效', key: 8, show: true },
+      { title: '化学实验室数据', key: 9, show: true },
+      { title: '安全生产天', key: 10, show: true },
+    ],
+    moved: false,
+    static: false,
+  },
+  {
+    i: '39',
+    key: 'DataCenter',
+    active: '4',
+    w: 6,
+    h: 5,
+    x: 42,
+    y: 9,
+    child: [
+      { title: '水质管理', key: 1, show: true },
+      { title: '水质指标', key: 2, show: true },
+      { title: '客户满意度', key: 3, show: true },
+      { title: '设备完好率', key: 4, show: true },
+      { title: '累计EBITDA', key: 11, show: true },
+      { title: '累计经营性净现金流', key: 12, show: true },
+      { title: '水量计费', key: 6, show: true },
+      { title: '累计成本支出', key: 13, show: true },
+      { title: '累计月度吨水成本', key: 14, show: true },
+      { title: '季度绩效', key: 8, show: true },
+      { title: '化学实验室数据', key: 9, show: true },
+      { title: '安全生产天', key: 10, show: true },
+    ],
+    moved: false,
+    static: false,
+  },
+  {
+    i: '38',
+    key: 'DataCenter',
+    active: '2',
+    w: 6,
+    h: 5,
+    x: 42,
+    y: 4,
+    child: [
+      { title: '水质管理', key: 1, show: true },
+      { title: '水质指标', key: 2, show: true },
+      { title: '客户满意度', key: 3, show: true },
+      { title: '设备完好率', key: 4, show: true },
+      { title: '累计EBITDA', key: 11, show: true },
+      { title: '累计经营性净现金流', key: 12, show: true },
+      { title: '水量计费', key: 6, show: true },
+      { title: '累计成本支出', key: 13, show: true },
+      { title: '累计月度吨水成本', key: 14, show: true },
+      { title: '季度绩效', key: 8, show: true },
+      { title: '化学实验室数据', key: 9, show: true },
+      { title: '安全生产天', key: 10, show: true },
+    ],
+    moved: false,
+    static: false,
+  },
+  {
+    i: '37',
+    key: 'DataCenter',
+    active: 10,
+    w: 6,
+    h: 4,
+    x: 42,
+    y: 0,
+    child: [
+      { title: '水质管理', key: 1, show: true },
+      { title: '水质指标', key: 2, show: true },
+      { title: '客户满意度', key: 3, show: true },
+      { title: '设备完好率', key: 4, show: true },
+      { title: '累计EBITDA', key: 11, show: true },
+      { title: '累计经营性净现金流', key: 12, show: true },
+      { title: '水量计费', key: 6, show: true },
+      { title: '累计成本支出', key: 13, show: true },
+      { title: '累计月度吨水成本', key: 14, show: true },
+      { title: '季度绩效', key: 8, show: true },
+      { title: '化学实验室数据', key: 9, show: true },
+      { title: '安全生产天', key: 10, show: true },
+    ],
+    moved: false,
+    static: false,
+  },
+  {
+    i: '36',
+    key: 'DataCenter',
+    active: '1',
+    w: 6,
+    h: 5,
+    x: 36,
+    y: 4,
+    child: [
+      { title: '水质管理', key: 1, show: true },
+      { title: '水质指标', key: 2, show: true },
+      { title: '客户满意度', key: 3, show: true },
+      { title: '设备完好率', key: 4, show: true },
+      { title: '累计EBITDA', key: 11, show: true },
+      { title: '累计经营性净现金流', key: 12, show: true },
+      { title: '水量计费', key: 6, show: true },
+      { title: '累计成本支出', key: 13, show: true },
+      { title: '累计月度吨水成本', key: 14, show: true },
+      { title: '季度绩效', key: 8, show: true },
+      { title: '化学实验室数据', key: 9, show: true },
+      { title: '安全生产天', key: 10, show: true },
+    ],
+    moved: false,
+    static: false,
+  },
+  {
+    i: '35',
+    key: 'DataCenter',
+    active: 13,
+    w: 7,
+    h: 5,
+    x: 7,
+    y: 14,
+    child: [
+      { title: '水质管理', key: 1, show: true },
+      { title: '水质指标', key: 2, show: true },
+      { title: '客户满意度', key: 3, show: true },
+      { title: '设备完好率', key: 4, show: true },
+      { title: '累计EBITDA', key: 11, show: true },
+      { title: '累计经营性净现金流', key: 12, show: true },
+      { title: '水量计费', key: 6, show: true },
+      { title: '累计成本支出', key: 13, show: true },
+      { title: '累计月度吨水成本', key: 14, show: true },
+      { title: '季度绩效', key: 8, show: true },
+      { title: '化学实验室数据', key: 9, show: true },
+      { title: '安全生产天', key: 10, show: true },
+    ],
+    moved: false,
+    static: false,
+  },
+  {
+    i: '34',
+    key: 'DataCenter',
+    active: '8',
+    w: 7,
+    h: 5,
+    x: 0,
+    y: 14,
+    child: [
+      { title: '水质管理', key: 1, show: true },
+      { title: '水质指标', key: 2, show: true },
+      { title: '客户满意度', key: 3, show: true },
+      { title: '设备完好率', key: 4, show: true },
+      { title: '累计EBITDA', key: 11, show: true },
+      { title: '累计经营性净现金流', key: 12, show: true },
+      { title: '水量计费', key: 6, show: true },
+      { title: '累计成本支出', key: 13, show: true },
+      { title: '累计月度吨水成本', key: 14, show: true },
+      { title: '季度绩效', key: 8, show: true },
+      { title: '化学实验室数据', key: 9, show: true },
+      { title: '安全生产天', key: 10, show: true },
+    ],
+    moved: false,
+    static: false,
+  },
+  {
+    i: '33',
+    key: 'DataCenter',
+    active: 11,
+    w: 7,
+    h: 4,
+    x: 7,
+    y: 10,
+    child: [
+      { title: '水质管理', key: 1, show: true },
+      { title: '水质指标', key: 2, show: true },
+      { title: '客户满意度', key: 3, show: true },
+      { title: '设备完好率', key: 4, show: true },
+      { title: '累计EBITDA', key: 11, show: true },
+      { title: '累计经营性净现金流', key: 12, show: true },
+      { title: '水量计费', key: 6, show: true },
+      { title: '累计成本支出', key: 13, show: true },
+      { title: '累计月度吨水成本', key: 14, show: true },
+      { title: '季度绩效', key: 8, show: true },
+      { title: '化学实验室数据', key: 9, show: true },
+      { title: '安全生产天', key: 10, show: true },
+    ],
+    moved: false,
+    static: false,
+  },
+  {
+    i: '32',
+    key: 'DataCenter',
+    active: '2',
+    w: 7,
+    h: 5,
+    x: 7,
+    y: 5,
+    child: [
+      { title: '水质管理', key: 1, show: true },
+      { title: '水质指标', key: 2, show: true },
+      { title: '客户满意度', key: 3, show: true },
+      { title: '设备完好率', key: 4, show: true },
+      { title: '累计EBITDA', key: 11, show: true },
+      { title: '累计经营性净现金流', key: 12, show: true },
+      { title: '水量计费', key: 6, show: true },
+      { title: '累计成本支出', key: 13, show: true },
+      { title: '累计月度吨水成本', key: 14, show: true },
+      { title: '季度绩效', key: 8, show: true },
+      { title: '化学实验室数据', key: 9, show: true },
+      { title: '安全生产天', key: 10, show: true },
+    ],
+    moved: false,
+    static: false,
+  },
+  {
+    i: '31',
+    key: 'DataCenter',
+    active: '1',
+    w: 7,
+    h: 5,
+    x: 0,
+    y: 0,
+    child: [
+      { title: '水质管理', key: 1, show: true },
+      { title: '水质指标', key: 2, show: true },
+      { title: '客户满意度', key: 3, show: true },
+      { title: '设备完好率', key: 4, show: true },
+      { title: '累计EBITDA', key: 11, show: true },
+      { title: '累计经营性净现金流', key: 12, show: true },
+      { title: '水量计费', key: 6, show: true },
+      { title: '累计成本支出', key: 13, show: true },
+      { title: '累计月度吨水成本', key: 14, show: true },
+      { title: '季度绩效', key: 8, show: true },
+      { title: '化学实验室数据', key: 9, show: true },
+      { title: '安全生产天', key: 10, show: true },
+    ],
+    moved: false,
+    static: false,
+  },
+  {
+    i: '30',
+    key: 'DataCenter',
+    w: 7,
+    h: 5,
+    x: 7,
+    y: 0,
+    child: [
+      { title: '水质管理', key: 1, show: true },
+      { title: '水质指标', key: 2, show: true },
+      { title: '客户满意度', key: 3, show: true },
+      { title: '设备完好率', key: 4, show: true },
+      { title: '累计EBITDA', key: 11, show: true },
+      { title: '累计经营性净现金流', key: 12, show: true },
+      { title: '水量计费', key: 6, show: true },
+      { title: '累计成本支出', key: 13, show: true },
+      { title: '累计月度吨水成本', key: 14, show: true },
+      { title: '季度绩效', key: 8, show: true },
+      { title: '化学实验室数据', key: 9, show: true },
+      { title: '安全生产天', key: 10, show: true },
+    ],
+    moved: false,
+    static: false,
+    active: 12,
+  },
+  {
+    i: '29',
+    key: 'DataCenter',
+    w: 6,
+    h: 5,
+    x: 36,
+    y: 14,
+    child: [
+      { title: '水质管理', key: 1, show: true },
+      { title: '水质指标', key: 2, show: true },
+      { title: '客户满意度', key: 3, show: true },
+      { title: '设备完好率', key: 4, show: true },
+      { title: 'KPI', key: 5, show: true },
+      { title: '水量计费', key: 6, show: true },
+      { title: '预算成本', key: 7, show: true },
+      { title: '季度绩效', key: 8, show: true },
+      { title: '化学实验室数据', key: 9, show: true },
+      { title: '安全生产天', key: 10, show: true },
+    ],
+    moved: false,
+    static: false,
+  },
+  {
+    i: '20',
+    key: 'DataCenter',
+    w: 6,
+    h: 5,
+    x: 36,
+    y: 9,
+    child: [
+      { title: '水质管理', key: 1, show: true },
+      { title: '水质指标', key: 2, show: true },
+      { title: '客户满意度', key: 3, show: true },
+      { title: '设备完好率', key: 4, show: true },
+      { title: 'KPI', key: 5, show: true },
+      { title: '水量计费', key: 6, show: true },
+      { title: '预算成本', key: 7, show: true },
+      { title: '季度绩效', key: 8, show: true },
+      { title: '化学实验室数据', key: 9, show: true },
+      { title: '安全生产天', key: 10, show: true },
+    ],
+    moved: false,
+    static: false,
+    active: 3,
+  },
+  {
+    i: '14',
+    key: 'DataCenter',
+    w: 7,
+    h: 5,
+    x: 0,
+    y: 5,
+    child: [
+      { title: '水质管理', key: 1, show: true },
+      { title: '水质指标', key: 2, show: true },
+      { title: '客户满意度', key: 3, show: true },
+      { title: '设备完好率', key: 4, show: true },
+      { title: 'KPI', key: 5, show: true },
+      { title: '水量计费', key: 6, show: true },
+      { title: '预算成本', key: 7, show: true },
+      { title: '季度绩效', key: 8, show: true },
+      { title: '化学实验室数据', key: 9, show: true },
+      { title: '安全生产天', key: 10, show: true },
+    ],
+    moved: false,
+    static: false,
+    active: 3,
+  },
+  {
+    i: '12',
+    key: 'PlanManagement',
+    w: 6,
+    h: 4,
+    x: 36,
+    y: 0,
+    child: [
+      { title: '设计', key: 1, show: true },
+      { title: '采购', key: 2, show: true },
+      { title: '施工', key: 3, show: true },
+      { title: '调试', key: 4, show: true },
+      { title: '保养', key: 5, show: true },
+      { title: '维修', key: 6, show: true },
+      { title: '项目动态', key: 7, show: true },
+    ],
+    moved: false,
+    static: false,
+    active: 1,
+  },
+  {
+    i: '10',
+    key: 'PlanManagement',
+    w: 7,
+    h: 4,
+    x: 0,
+    y: 10,
+    child: [
+      { title: '设计', key: 1, show: true },
+      { title: '采购', key: 2, show: true },
+      { title: '施工', key: 3, show: true },
+      { title: '调试', key: 4, show: true },
+      { title: '保养', key: 5, show: true },
+      { title: '维修', key: 6, show: true },
+      { title: '项目动态', key: 7, show: true },
+    ],
+    moved: false,
+    static: false,
+    active: 2,
+  },
+  {
+    i: '8',
+    key: 'ProjectInfo',
+    w: 14,
+    h: 5,
+    x: 14,
+    y: 14,
+    active: 1,
+    child: [
+      { title: '项目编号', key: 'Code', show: true },
+      { title: '项目工期', key: 'Duration', show: true },
+      { title: '建设单位', key: 'ConstructionUnit', show: true },
+      { title: '承建单位', key: 'UndertakenUnit', show: true },
+      { title: '所在地', key: 'Position', show: true },
+      { title: '项目规模', key: 'Scale', show: true },
+      { title: '主体工艺', key: 'MainProcess', show: true },
+      { title: '服务范围', key: 'ServiceScope', show: true },
+      { title: '签约时间', key: 'ContractTime', show: true },
+      { title: '运营服务时间', key: 'ServiceTime', show: true },
+      { title: '合作模式', key: 'CooperateMode', show: true },
+      { title: '出水执行标准', key: 'WaterStandard', show: true },
+      { title: '核心管理人员', key: 'Admin', show: true },
+      { title: '项目成员', key: 'User', show: true },
+    ],
+    moved: false,
+    static: false,
+  },
+  { i: '7', key: 'Map', w: 22, h: 14, x: 14, y: 0, moved: false, static: false },
+];
+export const DEFAULT_MAP_LAYOUT = [
+  {
+    i: '20',
+    key: 'DataCenter',
+    w: 14,
+    h: 7,
+    x: 0,
+    y: 0,
+    child: [
+      { title: '水质管理', key: 1, show: true },
+      { title: '水质指标', key: 2, show: true },
+      { title: '客户满意度', key: 3, show: true },
+      { title: '设备完好率', key: 4, show: true },
+      { title: 'KPI', key: 5, show: true },
+      { title: '水量计费', key: 6, show: true },
+      { title: '预算成本', key: 7, show: true },
+      { title: '季度绩效', key: 8, show: true },
+      { title: '化学实验室数据', key: 9, show: true },
+      { title: '安全生产天', key: 10, show: true },
+    ],
+    moved: false,
+    static: false,
+  },
+  {
+    i: '19',
+    key: 'DataCenter',
+    w: 7,
+    h: 7,
+    x: 7,
+    y: 13,
+    child: [
+      { title: '水质管理', key: 1, show: true },
+      { title: '水质指标', key: 2, show: true },
+      { title: '客户满意度', key: 3, show: true },
+      { title: '设备完好率', key: 4, show: true },
+      { title: 'KPI', key: 5, show: true },
+      { title: '水量计费', key: 6, show: true },
+      { title: '预算成本', key: 7, show: true },
+      { title: '季度绩效', key: 8, show: true },
+      { title: '化学实验室数据', key: 9, show: true },
+      { title: '安全生产天', key: 10, show: true },
+    ],
+    moved: false,
+    static: false,
+    active: 9,
+  },
+  {
+    i: '18',
+    key: 'DataCenter',
+    w: 7,
+    h: 6,
+    x: 0,
+    y: 13,
+    child: [
+      { title: '水质管理', key: 1, show: true },
+      { title: '水质指标', key: 2, show: true },
+      { title: '客户满意度', key: 3, show: true },
+      { title: '设备完好率', key: 4, show: true },
+      { title: 'KPI', key: 5, show: true },
+      { title: '水量计费', key: 6, show: true },
+      { title: '预算成本', key: 7, show: true },
+      { title: '季度绩效', key: 8, show: true },
+      { title: '化学实验室数据', key: 9, show: true },
+      { title: '安全生产天', key: 10, show: true },
+    ],
+    moved: false,
+    static: false,
+    active: 3,
+  },
+  {
+    i: '17',
+    key: 'DataCenter',
+    w: 7,
+    h: 6,
+    x: 7,
+    y: 7,
+    child: [
+      { title: '水质管理', key: 1, show: true },
+      { title: '水质指标', key: 2, show: true },
+      { title: '客户满意度', key: 3, show: true },
+      { title: '设备完好率', key: 4, show: true },
+      { title: 'KPI', key: 5, show: true },
+      { title: '水量计费', key: 6, show: true },
+      { title: '预算成本', key: 7, show: true },
+      { title: '季度绩效', key: 8, show: true },
+      { title: '化学实验室数据', key: 9, show: true },
+      { title: '安全生产天', key: 10, show: true },
+    ],
+    moved: false,
+    static: false,
+    active: 7,
+  },
+  {
+    i: '15',
+    key: 'DataCenter',
+    w: 13,
+    h: 6,
+    x: 35,
+    y: 6,
+    child: [
+      { title: '水质管理', key: 1, show: true },
+      { title: '水质指标', key: 2, show: true },
+      { title: '客户满意度', key: 3, show: true },
+      { title: '设备完好率', key: 4, show: true },
+      { title: 'KPI', key: 5, show: true },
+      { title: '水量计费', key: 6, show: true },
+      { title: '预算成本', key: 7, show: true },
+      { title: '季度绩效', key: 8, show: true },
+      { title: '化学实验室数据', key: 9, show: true },
+      { title: '安全生产天', key: 10, show: true },
+    ],
+    moved: false,
+    static: false,
+    active: 6,
+  },
+  {
+    i: '12',
+    key: 'DataCenter',
+    w: 7,
+    h: 6,
+    x: 0,
+    y: 7,
+    child: [
+      { title: '水质管理', key: 1, show: true },
+      { title: '水质指标', key: 2, show: true },
+      { title: '客户满意度', key: 3, show: true },
+      { title: '设备完好率', key: 4, show: true },
+      { title: 'KPI', key: 5, show: true },
+      { title: '水量计费', key: 6, show: true },
+      { title: '预算成本', key: 7, show: true },
+      { title: '季度绩效', key: 8, show: true },
+      { title: '化学实验室数据', key: 9, show: true },
+      { title: '安全生产天', key: 10, show: true },
+    ],
+    moved: false,
+    static: false,
+    active: 5,
+  },
+  {
+    i: '11',
+    key: 'DataCenter',
+    w: 13,
+    h: 7,
+    x: 35,
+    y: 12,
+    child: [
+      { title: '水质管理', key: 1, show: true },
+      { title: '水质指标', key: 2, show: true },
+      { title: '客户满意度', key: 3, show: true },
+      { title: '设备完好率', key: 4, show: true },
+      { title: 'KPI', key: 5, show: true },
+      { title: '水量计费', key: 6, show: true },
+      { title: '预算成本', key: 7, show: true },
+      { title: '季度绩效', key: 8, show: true },
+      { title: '化学实验室数据', key: 9, show: true },
+      { title: '安全生产天', key: 10, show: true },
+    ],
+    moved: false,
+    static: false,
+    active: 4,
+  },
+  { i: '7', key: 'Map', w: 21, h: 12, x: 14, y: 0, moved: false, static: false },
+  {
+    i: '5',
+    key: 'AlarmCenter',
+    w: 10,
+    h: 6,
+    x: 25,
+    y: 12,
+    active: 3,
+    child: [
+      { title: '待办事项', key: 3, show: true },
+      { title: '异常报警', key: 1, show: true },
+      { title: '项目预警', key: 2, show: true },
+    ],
+    moved: false,
+    static: false,
+  },
+  {
+    i: '3',
+    key: 'DataCenter',
+    w: 13,
+    h: 6,
+    x: 35,
+    y: 0,
+    active: 10,
+    child: [
+      { title: '水质管理', key: 1, show: true },
+      { title: '水质指标', key: 2, show: true },
+      { title: '客户满意度', key: 3, show: true },
+      { title: '设备完好率', key: 4, show: true },
+      { title: 'KPI', key: 5, show: true },
+      { title: '水量计费', key: 6, show: true },
+      { title: '预算成本', key: 7, show: true },
+      { title: '季度绩效', key: 8, show: true },
+      { title: '化学实验室数据', key: 9, show: true },
+      { title: '安全生产天', key: 10, show: true },
+    ],
+    moved: false,
+    static: false,
+  },
+  {
+    i: '2',
+    key: 'MessageCenter',
+    w: 11,
+    h: 6,
+    x: 14,
+    y: 12,
+    active: 1,
+    child: [
+      { title: '消息推送', key: 1, show: true },
+      { title: '新闻动态', key: 2, show: true },
+      { title: '大事记', key: 3, show: true },
+      { title: '所获奖项', key: 4, show: true },
+    ],
+    moved: false,
+    static: false,
+  },
+];
+
+export const U3D_PATH_STATE = {
+  ProjectInfo: 1,
+  AlarmCenter: {
+    3: 53,
+    1: 39,
+    2: 54,
+  },
+  MessageCenter: {
+    1: 54,
+  },
+  FileManagement: [27, 44],
+  Monitor: 100,
+  PlanManagement: {
+    1: 48,
+    2: 49,
+    3: 50,
+    4: 50,
+    5: 51,
+  },
+  Other: {
+    2: 35
+  },
+};
+
+export const COL_COLS = 48;
+export const ROW_COLS = 24;

+ 624 - 0
src/models/dataMeterNew.js

@@ -0,0 +1,624 @@
+import {
+  getProject,
+  getFaultAnalysis,
+  getIssueList,
+  getProjectActive,
+  getNotificationList,
+  getMediaList,
+  getMonitorList,
+  getUserGuide,
+  getDailyList,
+  getProjectProgress,
+  deleteFile,
+  getProjectTotalProgress,
+  getLayoutOptions,
+  saveLayoutOptions,
+  getProjectAlarm,
+  getBreakdownRecord,
+  getProjectList,
+  getAutoPatrol,
+  getBreakdownList,
+  getPatrolRecord,
+} from '@/services/DataMeter';
+import { queryProjectFileList } from '@/services/FileAdmin';
+import { getprojectPlanProgress, getProjectRealProgress } from '@/services/projectPlanProgress';
+import { getRepairRecord } from '@/services/EquipmentMaintenance';
+import { queryConfigList, queryTemplateList } from '@/services/CharUtils';
+import { queryPatrolRecord } from '@/services/patrol';
+import { message } from 'antd';
+import { DEFAULT_LAYOUT, DEFAULT_MAP_LAYOUT } from '@/components/DataMeter/config';
+import { getDefaultConfList } from '@/services/ProjectAdmin';
+const PLAN_TYPE = {
+  15: 1,
+  3: 3,
+  12: 4,
+};
+
+export default {
+  namespace: 'dataMeterNew',
+  state: {
+    projectDetail: {},
+    faultAnalysis: [],
+    issueList: [],
+    projectActive: [],
+    news: [],
+    memorabilia: [],
+    awards: [],
+    notificationList: [],
+    projectAlarmList: [],
+    repairList: [],
+    breakdownList: [],
+    mediaImgList: [],
+    mediaVideo: null,
+    monitorList: [],
+    userGuideList: [],
+    dailyList: [],
+    projectProgress: null,
+    projectTotalProgress: {
+      AllProgress: 0,
+    },
+    layout: {
+      0: {
+        config_json: [],
+      },
+      1: {
+        config_json: [],
+      },
+      2: {
+        config_json: [],
+      },
+    },
+    chartConfigList: false,
+    realProgress: {},
+    progress: {},
+    // currentChart: {}
+    projectList: [],
+    autoReport: {},
+    patrolRecordDetail: {},
+    patrolList: [],
+    fileList: [],
+    defaultConf: {},
+    layoutAdmin: {
+      0: {
+        config_json: [],
+      },
+      1: {
+        config_json: [],
+      },
+      2: {
+        config_json: [],
+      },
+    },
+  },
+
+  effects: {
+    *getAutoPatrol({ payload, callback }, { call, put }) {
+      const response = yield call(getAutoPatrol, payload);
+      if (response) {
+        // 查询数据报表详情
+        const { data } = yield call(queryPatrolRecord, { recordId: response.data[0].Id });
+        if (data) {
+          const creatorName = data.CreatorUser && data.CreatorUser.CName;
+          var status = {};
+          let Items = [];
+          const getItems = (item, patrolType) => {
+            let key;
+            if (patrolType == 1) {
+              key = item.PatrolName;
+            } else {
+              key = item.DeviceCode + '-' + item.DeviceName;
+            }
+            item.patrolType = patrolType;
+            item.ThresholdEnum = item.TemplateItem.ThresholdEnum;
+            item.Type = item.TemplateItem.Type;
+            if (!status[key]) status[key] = { normal: 0, error: 0 };
+            if (item.Status == 1) {
+              status[key].error++;
+            } else {
+              status[key].normal++;
+            }
+            return item;
+          };
+          data.ItemsExtend.forEach(item => {
+            console.log(Items);
+            if (item.PatrolCardRecordItemAssocThreshold) {
+              var arr = item.PatrolCardRecordItemAssocThreshold.map(i => getItems(i, 1));
+              Items = Items.concat(arr);
+            } else {
+              Items.push(getItems(item, 0));
+            }
+          });
+          data.Items = Items;
+
+          data.Points.forEach(item => {
+            let key;
+            if (item.PatrolType == 1) {
+              key = item.DeviceName;
+            } else {
+              key = item.DeviceCode + '-' + item.DeviceName;
+            }
+            item.creatorName = creatorName;
+            item.level = `${item.ExceptionLevel || '-'}/${item.DeviceLevel || '-'}`;
+            item.status = status[key] || { normal: 0, error: 0 };
+          });
+          console.log(data);
+          callback && callback(data);
+          yield put({
+            type: 'save',
+            payload: { autoReport: data },
+          });
+        }
+      }
+    },
+    *getProject({ payload }, { call, put }) {
+      const response = yield call(getProject, payload);
+      if (response) {
+        yield put({
+          type: 'save',
+          payload: { projectDetail: response.data },
+        });
+      }
+    },
+    *getFaultAnalysis({ payload }, { call, put }) {
+      const response = yield call(getFaultAnalysis, payload);
+      if (response) {
+        var list = [];
+        response.data.forEach(item => {
+          item.Details.forEach(err => {
+            list.push({
+              ...item,
+              ...err,
+            });
+          });
+        });
+        yield put({
+          type: 'save',
+          payload: { faultAnalysis: list },
+        });
+      }
+    },
+    *getIssueList({ payload }, { call, put }) {
+      const response = yield call(getIssueList, payload);
+      if (response) {
+        yield put({
+          type: 'save',
+          payload: { issueList: response.data.list },
+        });
+      }
+    },
+    *getRepairRecord({ payload }, { call, put }) {
+      const response = yield call(getRepairRecord, payload);
+      if (response) {
+        yield put({
+          type: 'save',
+          payload: { repairList: response.data.list },
+        });
+      }
+    },
+    *getBreakdownRecord({ payload }, { call, put }) {
+      const response = yield call(getBreakdownList, payload);
+      if (response) {
+        yield put({
+          type: 'save',
+          payload: { breakdownList: response.data.list },
+        });
+      }
+    },
+    *getPatrolRecord({ payload }, { call, put }) {
+      const response = yield call(getPatrolRecord, payload);
+      if (response) {
+        yield put({
+          type: 'save',
+          payload: { patrolList: response.data.list },
+        });
+      }
+    },
+    *getProjectAlarm({ payload }, { call, put }) {
+      const response = yield call(getProjectAlarm, payload);
+      if (response) {
+        yield put({
+          type: 'save',
+          payload: { projectAlarmList: response.data.list },
+        });
+      }
+    },
+    *getProjectActive({ payload }, { call, put }) {
+      const response = yield call(getProjectActive, payload);
+      if (response) {
+        let stateName;
+
+        // 0-项目动态 1-新闻动态 2-大事记 3-所获奖项
+        switch (payload.type) {
+          case 0:
+            stateName = 'projectActive';
+            break;
+          case 1:
+            stateName = 'news';
+            break;
+          case 2:
+            stateName = 'memorabilia';
+            break;
+          case 3:
+            stateName = 'awards';
+            break;
+        }
+        if (!stateName) return;
+        yield put({
+          type: 'save',
+          payload: { [stateName]: response.data.list },
+        });
+      }
+    },
+    *getNotificationList({ payload }, { call, put }) {
+      const response = yield call(getNotificationList, payload);
+      if (response) {
+        yield put({
+          type: 'save',
+          payload: { notificationList: response.data.list },
+        });
+      }
+    },
+    *getMediaList({ payload }, { call, put }) {
+      const response = yield call(getMediaList, payload);
+      if (response) {
+        var mediaVideo = null,
+          mediaImgList = [];
+        response.data.forEach(item => {
+          if (/\.mp4$/.test(item.Name)) {
+            if (!mediaVideo) {
+              mediaVideo = item;
+            }
+          } else {
+            mediaImgList.push(item);
+          }
+        });
+        yield put({
+          type: 'save',
+          payload: {
+            mediaVideo,
+            mediaImgList,
+          },
+        });
+      }
+    },
+    *getMonitorList({ payload }, { call, put }) {
+      const response = yield call(getMonitorList, payload);
+      if (response) {
+        var obj = JSON.parse(response.data.config_json) || {};
+        yield put({
+          type: 'save',
+          // payload: { monitorList: response.data.list },
+          payload: { monitorList: Object.keys(obj).map(key => obj[key]) || [] },
+        });
+      }
+    },
+    *getUserGuide({ payload }, { call, put }) {
+      const response = yield call(getUserGuide, payload);
+      if (response) {
+        var list = [];
+        response.data.list.forEach(item => {
+          item.UserGuideFiles.forEach(file => {
+            list.push({
+              ...item,
+              ...file,
+            });
+          });
+        });
+        yield put({
+          type: 'save',
+          payload: { userGuideList: list },
+        });
+      }
+    },
+    *getDailyList({ payload }, { call, put }) {
+      const response = yield call(getDailyList, payload);
+      if (response) {
+        yield put({
+          type: 'save',
+          payload: { dailyList: response.data.list },
+        });
+      }
+    },
+
+    *getProjectPlanProgress({ payload, callback }, { call, put }) {
+      const response = yield call(getprojectPlanProgress, payload);
+      if (response) {
+        var progress = response.data;
+        Object.keys(progress).forEach(k => {
+          if (
+            progress[k] == '0001-01-01T00:00:00Z' ||
+            progress[k] == '0001-01-01 00:00:00' ||
+            progress[k] == '0001-01-01 00:00:00 +0000 UTC'
+          ) {
+            progress[k] = '';
+          }
+        });
+        yield put({
+          type: 'save',
+          payload: { progress },
+        });
+      }
+    },
+    *getProjectRealProgress({ payload }, { call, put, select }) {
+      const calcProgress = data => {
+        let count = 0,
+          total = 0;
+        data.forEach(item => {
+          total += item.TotalCount;
+          count += item.RealCount;
+        });
+        return ((count / total) * 100).toFixed(2);
+      };
+      let { realProgress } = yield select(s => s.dataMeterNew);
+      console.log(realProgress);
+      var keys = Object.keys(PLAN_TYPE);
+      for (let i = 0; i < keys.length; i++) {
+        let k = keys[i];
+        var response = yield call(getProjectRealProgress, {
+          ...payload,
+          type: PLAN_TYPE[k],
+        });
+        if (response) {
+          let tempRealProgress = response.data.Task.map(item => ({
+            ...item,
+            RealCount: item.FinishList.length || 0,
+            TotalCount: item.DeviceCodes ? item.DeviceCodes.length : 0,
+            children: null,
+          }));
+          console.log(tempRealProgress);
+          realProgress[k] = calcProgress(tempRealProgress);
+        }
+      }
+      yield put({
+        type: 'save',
+        payload: { realProgress: { ...realProgress } },
+      });
+    },
+    *getProjectProgress({ payload }, { call, put }) {
+      const response = yield call(getProjectProgress, payload);
+      if (response) {
+        yield put({
+          type: 'save',
+          payload: { projectProgress: response.data },
+        });
+      }
+    },
+    *deleteFile({ payload }, { call, put }) {
+      const response = yield call(deleteFile, payload);
+      if (response) {
+        yield put({
+          type: 'getMediaList',
+          payload: payload,
+        });
+      }
+    },
+    *getProjectTotalProgress({ payload }, { call, put }) {
+      const response = yield call(getProjectTotalProgress, payload);
+      if (response) {
+        yield put({
+          type: 'save',
+          payload: { projectTotalProgress: response.data },
+        });
+      }
+    },
+    *getLayoutOptions({ payload }, { call, put, select }) {
+      // if (payload.is_default == 1) {
+      //   // 默认配置的projectId为0
+      //   payload.projectId = 0;
+      // }
+      const response = yield call(getLayoutOptions, payload);
+      if (response) {
+        var layout = yield select(state => state.dataMeterNew.layout);
+        if (payload.is_default == 1) {
+          layout = yield select(state => state.dataMeterNew.layoutAdmin);
+        }
+        var defaultLayout = payload.sub_module === 0 ? DEFAULT_MAP_LAYOUT : DEFAULT_LAYOUT;
+        var data = response.data;
+        try {
+          data.config_json = JSON.parse(data.config_json);
+          // response.data.config_json = defaultLayout;
+        } catch (error) {
+          // 解析失败则使用默认布局
+          data.config_json = defaultLayout;
+          console.log(error);
+        }
+        layout[payload.sub_module] = data;
+        if (payload.is_default == 0)
+          yield put({
+            type: 'save',
+            payload: { layout: { ...layout } },
+          });
+        else
+          yield put({
+            type: 'save',
+            payload: { layoutAdmin: { ...layout } },
+          });
+      }
+    },
+    *saveLayoutOptions({ payload }, { call, put, select }) {
+      // if (payload.is_default == 1) {
+      //   // 默认配置的projectId为0
+      //   payload.projectId = 0;
+      // }
+      if (payload.config_json == '[]') {
+        message.error('保存的配置不能为空');
+        return;
+      }
+      var response = yield call(saveLayoutOptions, payload);
+      if (response) {
+        var layout = yield select(state => state.dataMeterNew.layout);
+        if (payload.is_default == 1) {
+          layout = yield select(state => state.dataMeterNew.layoutAdmin);
+        }
+        console.log(payload.config_json);
+        layout[payload.sub_module].config_json = JSON.parse(payload.config_json);
+        if (payload.is_default == 0)
+          yield put({
+            type: 'save',
+            payload: { layout: { ...layout } },
+          });
+        else
+          yield put({
+            type: 'save',
+            payload: { layoutAdmin: { ...layout } },
+          });
+      }
+    },
+    *resizeLayout({ payload }, { call, select, put }) {
+      // 默认配置的projectId为0
+      const response = yield call(getLayoutOptions, {
+        ...payload,
+        // projectId: 0,
+      });
+      if (response) {
+        var layout = yield select(state => state.dataMeterNew.layout);
+        var defaultLayout = payload.sub_module === 0 ? DEFAULT_MAP_LAYOUT : DEFAULT_LAYOUT;
+        var config_json = response.data.config_json
+          ? JSON.parse(response.data.config_json)
+          : defaultLayout;
+        // response.data.config_json = defaultLayout;
+
+        // 将默认配置保存到本地
+        layout[payload.sub_module].config_json = config_json;
+        yield put({
+          type: 'save',
+          payload: { layout: { ...layout } },
+        });
+        yield call(saveLayoutOptions, {
+          ...payload,
+          config_json: JSON.stringify(config_json),
+          is_default: 0,
+        });
+      }
+    },
+    *resizeDefaultLayout({ payload }, { call, select, put }) {
+      var layout = yield select(state => state.dataMeterNew.layout);
+      var config_json = payload.sub_module === 0 ? DEFAULT_MAP_LAYOUT : DEFAULT_LAYOUT;
+
+      // 将默认配置保存到本地
+      layout[payload.sub_module].config_json = config_json;
+      yield put({
+        type: 'save',
+        payload: { layout: { ...layout } },
+      });
+      yield call(saveLayoutOptions, {
+        ...payload,
+        config_json: JSON.stringify(config_json),
+        is_default: 0,
+      });
+    },
+    *queryConfigList({ payload, callback }, { call, put }) {
+      const {
+        data: { list: tplList },
+      } = yield call(queryTemplateList, { pageSize: 999 });
+      const {
+        data: { list: configList },
+      } = yield call(queryConfigList, {
+        ...payload,
+        isNew: 1,
+        pageSize: 9999,
+      });
+      let list = [];
+      configList.map(item => {
+        let template = tplList.find(tpl => tpl.ID == item.type);
+        item.options = JSON.parse(item.options);
+        item.template = template;
+        list.push(item);
+      });
+      callback && callback(list);
+      yield put({
+        type: 'save',
+        payload: {
+          chartConfigList: list,
+        },
+      });
+    },
+    *queryConfig({ payload, callback }, { call, put }) {
+      const response = yield call(queryConfigList, payload);
+      if (response) {
+        var currentChart = response.data.list[0];
+        currentChart.options = JSON.parse(currentChart.options);
+        let { options, configs, type } = currentChart;
+
+        // 将接口返回的实时数据更新到图表中
+        if (type != 'pfd') {
+          if (!options.series) {
+            callback && callback(currentChart);
+          }
+          let series = options.series[0];
+          if (type == 'pie') {
+            configs.forEach((item, index) => {
+              series.data[index].value = item.value;
+            });
+          } else if (series.type == 'bar') {
+            configs.forEach((item, index) => {
+              series.data[index] = item.value;
+            });
+          }
+        }
+        callback && callback(currentChart);
+        // yield put({
+        //   type: 'save',
+        //   payload: {
+        //     currentChart,
+        //   },
+        // });
+      }
+    },
+    *getProjectList({ payload, callback }, { call, put }) {
+      const response = yield call(getProjectList, payload);
+      if (response) {
+        let nowDate = new Date();
+        (response.data.list || []).map(item => {
+          let type;
+          if (!item.EndDate) {
+            type = 2;
+          } else {
+            type = nowDate >= new Date(item.EndDate) ? 2 : 1;
+          }
+          item.type = type;
+        });
+        yield put({
+          type: 'save',
+          payload: { projectList: response.data.list },
+        });
+        console.log(response.data.list);
+        callback && callback(response.data.list);
+      }
+    },
+    *queryProjectFileList({ payload }, { call, put, select }) {
+      try {
+        const response = yield call(queryProjectFileList, {
+          ...payload,
+          deviceCode: -1,
+        });
+        if (response) {
+          yield put({
+            type: 'save',
+            payload: { fileList: response.data },
+          });
+        }
+      } catch (e) {
+        console.error(e);
+      }
+    },
+    *getDefaultConfList({ payload }, { call, put }) {
+      const response = yield call(getDefaultConfList, payload);
+      if (response) {
+        yield put({
+          type: 'save',
+          payload: { defaultConf: response.data },
+        });
+      }
+    },
+  },
+
+  reducers: {
+    save(state, action) {
+      return {
+        ...state,
+        ...action.payload,
+      };
+    },
+  },
+};

+ 0 - 0
src/pages/Mobile/DataMeter/Alarm.js


+ 109 - 0
src/pages/Mobile/DataMeter/Chart.js

@@ -0,0 +1,109 @@
+import React, { useState, useEffect, useRef } from 'react';
+import echarts from 'echarts';
+import { connect } from 'dva';
+import moment from 'moment';
+import style from './Chart.less';
+import { getPlcOptions, getFormOptions } from '@/components/ChartUtils/utils';
+const dataCache = {};
+console.log(style);
+function DataCenter(props) {
+  const [chart, setChart] = useState();
+  const [timer, setTimer] = useState();
+  const [chartOptions, setChartOptions] = useState(false);
+  const chartEle = useRef();
+  const iframeRef = useRef();
+  const signalRef = useRef();
+  const [loading, setLoading] = useState(false);
+  const { chartConfigList, dispatch ,location:{query:{projectId}}} = props;
+  // const { projectId } = props.location; //?
+  // const projectId = 92;
+
+  const handleClickTabs = id => {
+    let item = chartConfigList.find(c => c.id == id);
+    getOptionsForConfig(item);
+  };
+
+  useEffect(() => {
+    if (projectId) {
+      // 获取自定义图表列表
+      dispatch({
+        type: 'dataMeterNew/queryConfigList',
+        payload: {
+          projectId,
+        },
+      });
+    }
+  }, [projectId]);
+
+  useEffect(() => {
+    const chartWindow = iframeRef.current?.contentWindow;
+    console.log(chartOptions);
+    if (!chartWindow || !chartOptions) return;
+    renderChart();
+  }, [chartOptions]);
+
+  useEffect(() => {
+    chartConfigList && handleClickTabs(chartConfigList[0].id);
+  }, [chartConfigList]);
+
+  const getOptionsForConfig = item => {
+    console.log(item);
+    setChartOptions(item);
+    clearTimeout(timer);
+    let t = setTimeout(() => {
+      getOptionsForConfig({ ...item });
+    }, 1000 * 60);
+    setTimer(t);
+  };
+
+  const renderChart = async () => {
+    let datas = chartOptions.configs;
+    let values = chartOptions.options;
+    let formula = JSON.parse(chartOptions.formula || '[]');
+    setLoading(true);
+    try {
+      if (chartOptions.source === 0) {
+        // plc渲染数据
+        let options = await getPlcOptions(values, datas, formula);
+        iframeRef.current.contentWindow.render(options);
+      } else {
+        // 图表渲染数据
+        let options = await getFormOptions(values, datas, projectId);
+        iframeRef.current.contentWindow.render(options);
+      }
+    } catch (error) {
+      console.log(error);
+    }
+    setLoading(false);
+  };
+
+  return (
+    <div className={style.body}>
+      <div className={style.title}>数据项</div>
+      <div className={style.listWrapper}>
+        <div className={style.list}>
+          {(chartConfigList || []).map(item => (
+            <div key={item.id} onClick={() => handleClickTabs(item.id)} className={style.listItem}>
+              {item.name}
+            </div>
+          ))}
+        </div>
+      </div>
+      <div className={style.title}>图表</div>
+      <div className={style.chartWrapper} style={{ height: '43vh' }}>
+        <div style={{ paddingTop: '0.3rem', paddingRight: '0.6rem', overflow: 'hidden' }}>
+          <iframe
+            ref={iframeRef}
+            style={{ width: '100%', height: '43vh', border: 'none' }}
+            onLoad={renderChart}
+            srcDoc={chartOptions?.template?.Content}
+          ></iframe>
+        </div>
+      </div>
+    </div>
+  );
+}
+export default connect(({ dataMeterNew, user }) => ({
+  chartConfigList: dataMeterNew.chartConfigList,
+  user: user.currentUser,
+}))(DataCenter);

+ 34 - 0
src/pages/Mobile/DataMeter/Chart.less

@@ -0,0 +1,34 @@
+.body {
+  background-color: #0d1a2b;
+  color: #fff;
+  height: 100%;
+}
+
+.title {
+  font-size: 20px;
+  padding: 10px;
+}
+
+.listWrapper {
+  height: 40vh;
+  overflow-y: auto;
+}
+
+.list {
+  display: flex;
+  justify-content: center;
+  flex-wrap: wrap;
+}
+
+.listItem {
+  width: 80%;
+  text-align: center;
+  border: 1px solid #fff;
+  border-radius: 5px;
+  margin: 5px 0px;
+  padding: 5px 0px;
+}
+
+.chartWrapper{
+	height: 40vh;
+}

+ 39 - 0
src/pages/Mobile/DataMeter/Craft.js

@@ -0,0 +1,39 @@
+import React from 'react';
+import Flow, { FLOW_TYPE } from '@/components/Flow';
+import { connect } from 'dva';
+import { UnityAction } from '@/utils/utils';
+
+const graphData = JSON.parse(localStorage.graphData || null);
+
+// @connect(({ xflow }) => ({ flowDetail: xflow.flowDetail }))
+class Craft extends React.PureComponent {
+  state = {
+    flowDetail: graphData || { nodes: [], edges: [] },
+  };
+  componentDidMount() {
+    const {
+      dispatch,
+      match: {
+        params: { flowId },
+      },
+    } = this.props;
+
+    UnityAction.on('NODE_SAVE', nodeConfig => {
+      console.log(nodeConfig);
+    });
+  }
+  componentWillUnmount() {
+    UnityAction.off('NODE_SAVE');
+  }
+  render() {
+    const { flowDetail } = this.state;
+
+    return (
+      <div>
+        <Flow meta={{ type: 'edit', flowId: 1 }} flowDetail={flowDetail} />
+      </div>
+    );
+  }
+}
+
+export default Craft;

+ 0 - 0
src/pages/Mobile/DataMeter/Report.js


+ 15 - 19
src/pages/PurchaseAdmin/PurchaseList/Approval/DetailModal.js

@@ -37,28 +37,24 @@ function DetailModal(props) {
             {data.TypeInfo?.name}
           </Form.Item>
         )}
-        {data.IndustryInfo && (
-          <Form.Item className={styles.formItem} label="行业名称">
-            {data.IndustryInfo?.name}
-          </Form.Item>
-        )}
         <Form.Item className={styles.formItem} label="流程">
           {flowList.find(item => item.id == data.flow_id)?.name}
         </Form.Item>
-        {data.location && (
-          <Form.Item className={styles.formItem} label="项目地区">
-            {data.location}({data.location_code})
-          </Form.Item>
-        )}
-        {data.name && (
-          <Form.Item className={styles.formItem} label="项目简称">
-            {data.name}
-          </Form.Item>
-        )}
-        {data.version && (
-          <Form.Item className={styles.formItem} label="项目批次">
-            {data.version}期
-          </Form.Item>
+        {data.type_id != 7 && (
+          <>
+            <Form.Item className={styles.formItem} label="行业名称">
+              {data.IndustryInfo?.name}
+            </Form.Item>
+            <Form.Item className={styles.formItem} label="项目地区">
+              {data.location}({data.location_code})
+            </Form.Item>
+            <Form.Item className={styles.formItem} label="项目简称">
+              {data.name}
+            </Form.Item>
+            <Form.Item className={styles.formItem} label="项目批次">
+              {data.version}期
+            </Form.Item>
+          </>
         )}
         {data.AuthorUser && (
           <Form.Item className={styles.formItem} label="售前项目经理">

+ 0 - 3
src/pages/PurchaseAdmin/PurchaseList/Detail/FlowModal.js

@@ -77,11 +77,9 @@ function FlowModal(props) {
     let newData = [];
     let set = new Set()
     data.forEach(item=>set.add(item.template_node_id));
-    console.log("========================节点id ",[...set])
     let dataList = [...set].map(template_node_id=>{
       
       let itemDataList = data.filter(item => item.template_node_id == template_node_id)
-      console.log("========================节点id ",itemDataList)
       let  curid = 3
       let status = 'process';
       itemDataList.forEach(item=>{
@@ -98,7 +96,6 @@ function FlowModal(props) {
         if(idx >= obj.list.length) return;
         obj.list[idx].auditor = itemData.AuthorInfo.CName;
       })
-      console.log("---------------------", obj)
       return obj
     })
     console.log(dataList)

+ 20 - 17
src/pages/document.ejs

@@ -1,27 +1,30 @@
 <!DOCTYPE html>
 <html lang="en">
+  <head>
+    <meta charset="UTF-8" />
+    <meta http-equiv="Pragma" content="no-cache" />
+    <meta http-equiv="Cache-Control" content="no-cache" />
+    <meta http-equiv="Expires" content="Sat, 01 Dec 2001 00:00:00 GMT" />
+    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
+    <meta
+      name="viewport"
+      content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=yes"
+    />
+    <title>金科环境股份有限公司</title>
+    <link rel="icon" href="<%= context.config.publicPath %>favicon.png" type="image/x-icon" />
 
-<head>
-  <meta charset="UTF-8" />
-  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
-  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" />
-  <title>金科环境股份有限公司</title>
-  <link rel="icon" href="<%= context.config.publicPath %>favicon.png" type="image/x-icon" />
-
-  <!-- <script src="https://gw.alipayobjects.com/os/lib/react/16.13.1/umd/react.production.min.js"></script>
+    <!-- <script src="https://gw.alipayobjects.com/os/lib/react/16.13.1/umd/react.production.min.js"></script>
   <script src="https://gw.alipayobjects.com/os/lib/react-dom/16.13.1/umd/react-dom.production.min.js"></script>
   <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>
   <script src="https://cdn.bootcdn.net/ajax/libs/antd/3.26.19/antd.min.js"></script>
   <script src="https://cdnjs.cloudflare.com/ajax/libs/antv-g2/3.5.19/g2.min.js"></script>
   <script src="https://cdn.bootcdn.net/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script> -->
-</head>
-
-<body>
-  <!--    <noscript>Sorry, we need js to run correctly!</noscript>-->
-
-  <div id="root"></div>
+  </head>
 
-</body>
-<script src="<%= context.config.publicPath %>rem.js"></script>
+  <body>
+    <!--    <noscript>Sorry, we need js to run correctly!</noscript>-->
 
-</html>
+    <div id="root"></div>
+  </body>
+  <script src="<%= context.config.publicPath %>rem.js"></script>
+</html>

+ 13 - 0
src/services/DataMeter.js

@@ -204,3 +204,16 @@ export async function getProjectList(params) {
   return request(`/api/v2/project?${stringify(params)}`)
 }
 
+//获取巡检结果
+export async function getAutoPatrol(params) {
+  return request(`/patrol/auto/data/${params.projectId}`)
+}
+
+export async function getBreakdownList(params) {
+  return request(`/breakdown-record/list/${params.projectId}?${stringify(params)}`);
+}
+
+export async function getPatrolRecord(params) {
+  return request(`/patrol/data/${params.projectId}?${stringify(params)}`);
+}
+

+ 103 - 2
src/services/ProjectAdmin.js

@@ -1,4 +1,5 @@
 import request from '@/utils/request';
+import moment from 'moment';
 import { stringify } from 'qs';
 
 export async function queryProjectV1(params) {
@@ -256,7 +257,7 @@ export async function getDeviceRealData(params) {
 export async function getDeviceRealDataByTime(params) {
   params.size = 999999;
   return request(`/jinke-cloud/db/device/history-data?${stringify(params)}`, {
-  // return request(`/jinke-cloud/device/history-data?${stringify(params)}`, {
+    // return request(`/jinke-cloud/device/history-data?${stringify(params)}`, {
     method: 'GET',
     // body: params,
   });
@@ -272,5 +273,105 @@ export async function queryScreenShort(data) {
 }
 
 export async function deleteScreenShort(data) {
-  return request(`/api/v1/project-file/${data.id}`,{method: 'DELETE'});
+  return request(`/api/v1/project-file/${data.id}`, { method: 'DELETE' });
+}
+
+const CACHE = {};
+// 查询图表对应的表单数据-最新数据
+export async function queryFormCurrentData({ projectId, formName, titles }) {
+  if (!CACHE[formName]) {
+    const resCell = await queryFormCell({ projectId, formName });
+    CACHE[formName] = resCell.data || [];
+  }
+  let cells = titles.map(t => {
+    let cell = CACHE[formName].find(item => item.title == t);
+    return cell;
+  });
+  const { data } = await request(`/runtime_form/chart/current/${projectId}/${formName}`);
+
+  return cells.map(item => ({
+    key: item.cell_key,
+    value: data[item.cell_key],
+    title: item.title,
+  }));
+}
+
+export async function queryFormCell({ projectId, formName }) {
+  const res = await request(`/api/v1/runtime_form/cell/to/chart/${projectId}/${formName}`);
+  return res;
+}
+
+// 查询图表对应的表单数据-历史数据
+export async function queryFormHistoryData({ projectId, formName, titles, sTime, eTime }) {
+  // 查询表单配置
+  if (!CACHE[formName]) {
+    const resCell = await queryFormCell({ projectId, formName });
+    CACHE[formName] = resCell.data || [];
+  }
+  // 获取key、time与title的对应关系
+  let titleKey = titles.map(t => {
+    let data = CACHE[formName].filter(item => item.title == t);
+    if (data[0].time) {
+      return {
+        title: t,
+        keys: data.map(item => {
+          return {
+            time: item.time,
+            key: item.cell_key,
+          };
+        }),
+      };
+    } else {
+      return {
+        title: t,
+        keys: data.map(item => item.cell_key),
+      };
+    }
+  });
+  // 查询数据
+  const { data } = await request(
+    `/runtime_form/chart/list/${projectId}/${formName}?sTime=${sTime}&eTime=${eTime}`
+  );
+
+  return titleKey.map(item => {
+    const { title, keys } = item;
+    let chartData = [];
+    // 从数据中获取key和value
+    keys.forEach(keyItem => {
+      // 判断是否含有time
+      if (keyItem instanceof Object) {
+        const { key, time } = keyItem;
+        data.forEach(dItem => {
+          let value = dItem[key];
+          // 含有time则替换时间  c_time结构2022-03-10T16:05:37+08:00
+          let t = dItem.c_time.split('T')[0] + ' ' + dItem[time];
+          chartData.push({
+            htime: new Date(t),
+            val: value || 0,
+          });
+        });
+      } else {
+        data.forEach(dItem => {
+          let value = dItem[keyItem];
+          // 没有time则使用c_time
+          let time = dItem.c_time;
+          chartData.push({
+            htime: new Date(time),
+            val: value || 0,
+          });
+        });
+      }
+    });
+
+    chartData
+      .sort((a, b) => a.htime - b.htime)
+      .forEach(item => {
+        item.htime = moment(item.htime).format('YYYY-MM-DD HH:mm:ss');
+      });
+
+    return {
+      name: title,
+      data: chartData,
+    };
+  });
 }