diff --git a/web/src/components/MyEMS/Shopfloor/ShopfloorBatch.js b/web/src/components/MyEMS/Shopfloor/ShopfloorBatch.js new file mode 100644 index 00000000..418b9d89 --- /dev/null +++ b/web/src/components/MyEMS/Shopfloor/ShopfloorBatch.js @@ -0,0 +1,330 @@ +import React, { Fragment, useEffect, useState } from 'react'; +import { + Breadcrumb, + BreadcrumbItem, + Row, + Col, + Card, + CardBody, + Button, + ButtonGroup, + Form, + FormGroup, + Input, + Label, + CustomInput, + Spinner, +} from 'reactstrap'; +import Datetime from 'react-datetime'; +import moment from 'moment'; +import loadable from '@loadable/component'; +import Cascader from 'rc-cascader'; +import { getCookieValue, createCookie } from '../../../helpers/utils'; +import withRedirect from '../../../hoc/withRedirect'; +import { withTranslation } from 'react-i18next'; +import { toast } from 'react-toastify'; +import ButtonIcon from '../../common/ButtonIcon'; +import { APIBaseURL } from '../../../config'; + + +const DetailedDataTable = loadable(() => import('../common/DetailedDataTable')); + + +const ShopfloorBatch = ({ setRedirect, setRedirectUrl, t }) => { + let current_moment = moment(); + useEffect(() => { + let is_logged_in = getCookieValue('is_logged_in'); + let user_name = getCookieValue('user_name'); + let user_display_name = getCookieValue('user_display_name'); + let user_uuid = getCookieValue('user_uuid'); + let token = getCookieValue('token'); + if (is_logged_in === null || !is_logged_in) { + setRedirectUrl(`/authentication/basic/login`); + setRedirect(true); + } else { + //update expires time of cookies + createCookie('is_logged_in', true, 1000 * 60 * 60 * 8); + createCookie('user_name', user_name, 1000 * 60 * 60 * 8); + createCookie('user_display_name', user_display_name, 1000 * 60 * 60 * 8); + createCookie('user_uuid', user_uuid, 1000 * 60 * 60 * 8); + createCookie('token', token, 1000 * 60 * 60 * 8); + } + }); + // State + // Query Parameters + const [selectedSpaceName, setSelectedSpaceName] = useState(undefined); + const [selectedSpaceID, setSelectedSpaceID] = useState(undefined); + const [shopfloorList, setShopfloorList] = useState([]); + const [reportingPeriodBeginsDatetime, setReportingPeriodBeginsDatetime] = useState(current_moment.clone().startOf('month')); + const [reportingPeriodEndsDatetime, setReportingPeriodEndsDatetime] = useState(current_moment); + const [cascaderOptions, setCascaderOptions] = useState(undefined); + + // buttons + const [submitButtonDisabled, setSubmitButtonDisabled] = useState(false); + const [spinnerHidden, setSpinnerHidden] = useState(true); + const [exportButtonHidden, setExportButtonHidden] = useState(true); + + //Results + const [detailedDataTableColumns, setDetailedDataTableColumns] = useState( + [{dataField: 'name', text: t('Name'), sort: true}, {dataField: 'space', text: t('Space'), sort: true}]); + const [excelBytesBase64, setExcelBytesBase64] = useState(undefined); + + useEffect(() => { + let isResponseOK = false; + fetch(APIBaseURL + '/spaces/tree', { + method: 'GET', + headers: { + "Content-type": "application/json", + "User-UUID": getCookieValue('user_uuid'), + "Token": getCookieValue('token') + }, + body: null, + + }).then(response => { + console.log(response); + if (response.ok) { + isResponseOK = true; + } + return response.json(); + }).then(json => { + console.log(json); + if (isResponseOK) { + // rename keys + json = JSON.parse(JSON.stringify([json]).split('"id":').join('"value":').split('"name":').join('"label":')); + setCascaderOptions(json); + // set the default selected space + setSelectedSpaceName([json[0]].map(o => o.label)); + setSelectedSpaceID([json[0]].map(o => o.value)); + + setSubmitButtonDisabled(false); + setSpinnerHidden(true); + } else { + toast.error(json.description); + } + }).catch(err => { + console.log(err); + }); + + }, []); + + const labelClasses = 'ls text-uppercase text-600 font-weight-semi-bold mb-0'; + + let onSpaceCascaderChange = (value, selectedOptions) => { + setSelectedSpaceName(selectedOptions.map(o => o.label).join('/')); + setSelectedSpaceID(value[value.length - 1]); + setShopfloorList([]); + setExportButtonHidden(true); + setSubmitButtonDisabled(false); + } + let onReportingPeriodBeginsDatetimeChange = (newDateTime) => { + setReportingPeriodBeginsDatetime(newDateTime); + } + + let onReportingPeriodEndsDatetimeChange = (newDateTime) => { + setReportingPeriodEndsDatetime(newDateTime); + } + + var getValidReportingPeriodBeginsDatetimes = function (currentDate) { + return currentDate.isBefore(moment(reportingPeriodEndsDatetime, 'MM/DD/YYYY, hh:mm:ss a')); + } + + var getValidReportingPeriodEndsDatetimes = function (currentDate) { + return currentDate.isAfter(moment(reportingPeriodBeginsDatetime, 'MM/DD/YYYY, hh:mm:ss a')); + } + + // Handler + const handleSubmit = e => { + e.preventDefault(); + console.log('handleSubmit'); + console.log(selectedSpaceID); + console.log(reportingPeriodBeginsDatetime.format('YYYY-MM-DDTHH:mm:ss')); + console.log(reportingPeriodEndsDatetime.format('YYYY-MM-DDTHH:mm:ss')); + + // disable submit button + setSubmitButtonDisabled(true); + // show spinner + setSpinnerHidden(false); + // hide export buttion + setExportButtonHidden(true) + + // Reinitialize tables + setShopfloorList([]); + + let isResponseOK = false; + fetch(APIBaseURL + '/reports/shopfloorbatch?' + + 'spaceid=' + selectedSpaceID + + '&reportingperiodstartdatetime=' + reportingPeriodBeginsDatetime.format('YYYY-MM-DDTHH:mm:ss') + + '&reportingperiodenddatetime=' + reportingPeriodEndsDatetime.format('YYYY-MM-DDTHH:mm:ss'), { + method: 'GET', + headers: { + "Content-type": "application/json", + "User-UUID": getCookieValue('user_uuid'), + "Token": getCookieValue('token') + }, + body: null, + + }).then(response => { + if (response.ok) { + isResponseOK = true; + }; + return response.json(); + }).then(json => { + if (isResponseOK) { + console.log(json) + let shopfloors = []; + if (json['shopfloors'].length > 0) { + json['shopfloors'].forEach((currentShopfloor, index) => { + let detailed_value = {}; + detailed_value['id'] = currentShopfloor['id']; + detailed_value['name'] = currentShopfloor['shopfloor_name']; + detailed_value['space'] = currentShopfloor['space_name']; + detailed_value['costcenter'] = currentShopfloor['cost_center_name']; + currentShopfloor['values'].forEach((currentValue, energyCategoryIndex) => { + detailed_value['a' + energyCategoryIndex] = currentValue.toFixed(2); + }); + shopfloors.push(detailed_value); + }); + }; + + setShopfloorList(shopfloors); + + let detailed_column_list = []; + detailed_column_list.push({ + dataField: 'name', + text: t('Name'), + sort: true + }); + detailed_column_list.push({ + dataField: 'space', + text: t('Space'), + sort: true + }); + json['energycategories'].forEach((currentValue, index) => { + detailed_column_list.push({ + dataField: 'a' + index, + text: currentValue['name'] + ' (' + currentValue['unit_of_measure'] + ')', + sort: true + }) + }); + setDetailedDataTableColumns(detailed_column_list); + + setExcelBytesBase64(json['excel_bytes_base64']); + + // enable submit button + setSubmitButtonDisabled(false); + // hide spinner + setSpinnerHidden(true); + // show export buttion + setExportButtonHidden(false); + + } else { + toast.error(json.description) + } + }).catch(err => { + console.log(err); + }); + }; + + const handleExport = e => { + e.preventDefault(); + const mimeType='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' + const fileName = 'shopfloorbatch.xlsx' + var fileUrl = "data:" + mimeType + ";base64," + excelBytesBase64; + fetch(fileUrl) + .then(response => response.blob()) + .then(blob => { + var link = window.document.createElement("a"); + link.href = window.URL.createObjectURL(blob, { type: mimeType }); + link.download = fileName; + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + }); + }; + + + + return ( + +
+ + {t('Shopfloor Data')}{t('Batch Analysis')} + +
+ + +
+ + + + +
+ + + +
+ + + + + + + + + + + + + + + + +

+ + + +
+ + + +

+
+ + +

+ + +
+
+
+
+ + + +
+ ); +}; + +export default withTranslation()(withRedirect(ShopfloorBatch)); diff --git a/web/src/layouts/MyEMSRoutes.js b/web/src/layouts/MyEMSRoutes.js index f1429c54..6d927bea 100644 --- a/web/src/layouts/MyEMSRoutes.js +++ b/web/src/layouts/MyEMSRoutes.js @@ -150,7 +150,7 @@ import StoreCost from '../components/MyEMS/Store/StoreCost'; import StoreLoad from '../components/MyEMS/Store/StoreLoad'; import StoreStatistics from '../components/MyEMS/Store/StoreStatistics'; import StoreSaving from '../components/MyEMS/Store/StoreSaving'; -import StoreBatch from "../components/MyEMS/Store/StoreBatch"; +import StoreBatch from '../components/MyEMS/Store/StoreBatch'; // Shopfloor import ShopfloorEnergyCategory from '../components/MyEMS/Shopfloor/ShopfloorEnergyCategory'; import ShopfloorEnergyItem from '../components/MyEMS/Shopfloor/ShopfloorEnergyItem'; @@ -158,6 +158,7 @@ import ShopfloorCost from '../components/MyEMS/Shopfloor/ShopfloorCost'; import ShopfloorLoad from '../components/MyEMS/Shopfloor/ShopfloorLoad'; import ShopfloorStatistics from '../components/MyEMS/Shopfloor/ShopfloorStatistics'; import ShopfloorSaving from '../components/MyEMS/Shopfloor/ShopfloorSaving'; +import ShopfloorBatch from '../components/MyEMS/Shopfloor/ShopfloorBatch'; // CombinedEquipment import CombinedEquipmentEnergyCategory from '../components/MyEMS/CombinedEquipment/CombinedEquipmentEnergyCategory'; import CombinedEquipmentEnergyItem from '../components/MyEMS/CombinedEquipment/CombinedEquipmentEnergyItem'; @@ -395,6 +396,7 @@ const MyEMSRoutes = () => ( + {/*CombinedEquipment*/} diff --git a/web/src/routes.js b/web/src/routes.js index c8953f7b..9af983f9 100644 --- a/web/src/routes.js +++ b/web/src/routes.js @@ -405,6 +405,7 @@ export const shopfloorRoutes = { { to: '/shopfloor/load', name: 'Load' }, { to: '/shopfloor/statistics', name: 'Statistics' }, { to: '/shopfloor/saving', name: 'Saving' }, + { to: '/shopfloor/batch', name: 'Batch Analysis'}, ] };