提交 6fe8fbe6 编写于 作者: nengyuangzhang's avatar nengyuangzhang

updated energy storage power station dashboard

上级 249af155
......@@ -227,7 +227,7 @@ class Reporting:
if energy_storage_power_station_id is not None:
query = (" SELECT id, name, uuid, "
" address, postal_code, latitude, longitude, capacity, "
" address, postal_code, latitude, longitude, rated_capacity, rated_power, "
" contact_id, cost_center_id, svg, description "
" FROM tbl_energy_storage_power_stations "
" WHERE id = %s ")
......@@ -235,7 +235,7 @@ class Reporting:
row = cursor_system.fetchone()
elif energy_storage_power_station_uuid is not None:
query = (" SELECT id, name, uuid, "
" address, postal_code, latitude, longitude, capacity, "
" address, postal_code, latitude, longitude, rated_capacity, rated_power, "
" contact_id, cost_center_id, svg, description "
" FROM tbl_energy_storage_power_stations "
" WHERE uuid = %s ")
......@@ -249,8 +249,6 @@ class Reporting:
description='API.ENERGY_STORAGE_POWER_STATION_NOT_FOUND')
else:
energy_storage_power_station_id = row[0]
contact = contact_dict.get(row[8], None)
cost_center = cost_center_dict.get(row[9], None)
meta_result = {"id": row[0],
"name": row[1],
"uuid": row[2],
......@@ -258,11 +256,12 @@ class Reporting:
"postal_code": row[4],
"latitude": row[5],
"longitude": row[6],
"capacity": row[7],
"contact": contact,
"cost_center": cost_center,
"svg": row[10],
"description": row[11],
"rated_capacity": row[7],
"rated_power": row[8],
"contact": contact_dict.get(row[9], None),
"cost_center": cost_center_dict.get(row[10], None),
"svg": row[11],
"description": row[12],
"qrcode": 'energy_storage_power_station:' + row[2]}
point_list = list()
......
......@@ -4,7 +4,6 @@ import falcon
import mysql.connector
import simplejson as json
import config
from core import utilities
from core.useractivity import access_control, api_key_control
......
import React, { Component } from 'react';
import { Bar } from 'react-chartjs-2';
import { Link } from 'react-router-dom';
import range from 'lodash/range';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Card, CardHeader, CardBody, ListGroup, ListGroupItem, CardFooter } from 'reactstrap';
import { rgbaColor } from '../../../helpers/utils';
import { activeUserHistory } from '../../../data/dashboard/activeUsers';
const dividerBorder = '1px solid rgba(255, 255, 255, 0.15)';
const listItemBorderColor = 'rgba(255, 255, 255, 0.05)';
const chartOptions = {
legend: { display: false },
scales: {
yAxes: [
{
display: false,
stacked: true
}
],
xAxes: [
{
stacked: false,
ticks: { display: false },
barPercentage: 0.9,
categoryPercentage: 1.0,
gridLines: {
color: rgbaColor('#fff', 0.1),
display: false
}
}
]
}
};
class ActiveUsersBarChart extends Component {
_isMounted = false;
refreshInterval;
refreshTimeout;
state = {
activeUserHistory,
currentActiveUser: activeUserHistory[activeUserHistory.length - 1],
chartData: {
labels: range(1, 26),
datasets: [
{
label: 'Users',
backgroundColor: rgbaColor('#fff', 0.3),
data: []
}
]
}
};
simulateActiveUsers = () => {
this.refreshInterval = setInterval(() => {
const currentActiveUser = Math.floor(Math.random() * (120 - 60) + 60);
const activeUserHistory = [...this.state.activeUserHistory];
activeUserHistory.shift();
if (this._isMounted) {
this.setState({ activeUserHistory }, () => {
this.refreshTimeout = setTimeout(() => {
const activeUserHistory = [...this.state.activeUserHistory];
activeUserHistory.push(currentActiveUser);
if (this._isMounted) {
this.setState({ activeUserHistory, currentActiveUser });
}
}, 500);
});
}
}, 2000);
};
componentDidMount() {
this._isMounted = true;
this.simulateActiveUsers();
}
componentWillUnmount() {
this._isMounted = false;
clearInterval(this.refreshInterval);
clearTimeout(this.refreshTimeout);
}
render() {
const chartData = {
...this.state.chartData,
datasets: [
{
...this.state.chartData.datasets[0],
data: this.state.activeUserHistory
}
]
};
return (
<Card className="h-100 bg-gradient">
<CardHeader className="bg-transparent">
<h5 className="text-white">瞬时放电功率</h5>
<div className="real-time-user display-1 font-weight-normal text-white">{this.state.currentActiveUser}</div>
</CardHeader>
<CardBody className="text-white fs--1">
<p className="pb-2" style={{ borderBottom: dividerBorder }}>
Page views per second
</p>
<Bar data={chartData} options={chartOptions} width={10} height={4} />
</CardBody>
<CardFooter className="text-right bg-transparent" style={{ borderTop: dividerBorder }}>
<Link className="text-white" to="#!">
Real-time report
<FontAwesomeIcon icon="chevron-right" transform="down-1" className="ml-1 fs--1" />
</Link>
</CardFooter>
</Card>
);
}
}
export default ActiveUsersBarChart;
import React, { useContext } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import { Media } from 'reactstrap';
import Flex from '../../common/Flex';
import AppContext from '../../../context/Context';
import { Link } from 'react-router-dom';
import FalconProgress from '../../common/FalconProgress';
const getProductItemCalculatedData = (unit, price, totalPrice) => {
const productTotalPrice = unit * price;
const percentage = ((productTotalPrice * 100) / totalPrice).toFixed(0);
return { productTotalPrice, percentage };
};
const BestSellingProduct = ({ product, totalPrice, isLast }) => {
const { currency } = useContext(AppContext);
const { img, title, type, unit, price } = product;
const { productTotalPrice, percentage } = getProductItemCalculatedData(unit, price, totalPrice);
return (
<tr className={classNames({ 'border-bottom border-200': !isLast })}>
<td>
<Media className="align-items-center position-relative">
<img className="rounded border border-200" src={img} width="60" alt={title} />
<Media body className="ml-3">
<h6 className="mb-1 font-weight-semi-bold">
<Link className="text-dark stretched-link" to="#!">
{title}
</Link>
</h6>
<p className="font-weight-semi-bold mb-0 text-500">{type}</p>
</Media>
</Media>
</td>
<td className="align-middle text-right font-weight-semi-bold">
{currency}
{productTotalPrice}
</td>
<td className="align-middle pr-card">
<Flex align="center" justify="between">
<FalconProgress
value={percentage}
color="primary"
className="w-100 rounded-soft bg-200"
barClassName="rounded-capsule"
style={{ height: 5, maxWidth: 54 }}
/>
<div className="font-weight-semi-bold ml-2">{percentage}%</div>
</Flex>
</td>
</tr>
);
};
BestSellingProduct.propTypes = {
product: PropTypes.shape({
id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
img: PropTypes.string.isRequired,
title: PropTypes.string.isRequired,
type: PropTypes.string.isRequired,
unit: PropTypes.number.isRequired,
price: PropTypes.number.isRequired
}).isRequired,
totalPrice: PropTypes.number.isRequired,
isLast: PropTypes.bool
};
BestSellingProduct.defaultProps = { isLast: false };
export default BestSellingProduct;
import React, { useContext } from 'react';
import PropTypes from 'prop-types';
import { Button, Card, CardBody, CardFooter, Col, CustomInput, Row, Table } from 'reactstrap';
import BestSellingProduct from './BestSellingProduct';
import { Link } from 'react-router-dom';
import AppContext from '../../../context/Context';
const getTotalPrice = items =>
items.map(({ unit, price }) => unit * price).reduce((total, currentValue) => total + currentValue, 0);
const BestSellingProducts = ({ products }) => {
const { currency } = useContext(AppContext);
const totalPrice = getTotalPrice(products);
const noOfProducts = products.length;
return (
<Card className="h-lg-100 overflow-hidden">
<CardBody className="p-0">
<Table borderless className="table-dashboard mb-0 fs--1">
<thead className="bg-light">
<tr className="text-900">
<th>电站</th>
<th className="text-right">
数据
</th>
<th className="pr-card text-right" style={{ width: '8rem' }}>
占比 (%)
</th>
</tr>
</thead>
<tbody>
{products.map((product, index) => (
<BestSellingProduct
product={product}
totalPrice={totalPrice}
currency={currency}
isLast={index === noOfProducts - 1}
key={product.id}
/>
))}
</tbody>
</Table>
</CardBody>
<CardFooter className="bg-light py-2">
<Row className="flex-between-center">
<Col xs="auto">
<CustomInput type="select" id="exampleCustomSelect" bsSize="sm">
<option>最近7天</option>
<option>最近1月</option>
<option>最近1年</option>
</CustomInput>
</Col>
<Col xs="auto">
<Button color="falcon-default" size="sm" tag={Link} to="#!">
全部
</Button>
</Col>
</Row>
</CardFooter>
</Card>
);
};
BestSellingProducts.propTypes = { products: PropTypes.arrayOf(BestSellingProduct.propTypes.product).isRequired };
export default BestSellingProducts;
......@@ -119,7 +119,8 @@ const EnergyStoragePowerStationDetails = ({ setRedirect, setRedirectUrl, t }) =>
const [energyStoragePowerStationName, setEnergyStoragePowerStationName] = useState();
const [energyStoragePowerStationAddress, setEnergyStoragePowerStationAddress] = useState();
const [energyStoragePowerStationPostalCode, setEnergyStoragePowerStationPostalCode] = useState();
const [energyStoragePowerStationCapacity, setEnergyStoragePowerStationCapacity] = useState();
const [energyStoragePowerStationRatedCapacity, setEnergyStoragePowerStationRatedCapacity] = useState();
const [energyStoragePowerStationRatedPower, setEnergyStoragePowerStationRatedPower] = useState();
const [energyStoragePowerStationLatitude, setEnergyStoragePowerStationLatitude] = useState();
const [energyStoragePowerStationLongitude, setEnergyStoragePowerStationLongitude] = useState();
const [energyStoragePowerStationSVG, setEnergyStoragePowerStationSVG] = useState();
......@@ -151,7 +152,8 @@ const EnergyStoragePowerStationDetails = ({ setRedirect, setRedirectUrl, t }) =>
setEnergyStoragePowerStationName(json['energy_storage_power_station']['name']);
setEnergyStoragePowerStationAddress(json['energy_storage_power_station']['address']);
setEnergyStoragePowerStationPostalCode(json['energy_storage_power_station']['postal_code']);
setEnergyStoragePowerStationCapacity(json['energy_storage_power_station']['capacity']);
setEnergyStoragePowerStationRatedCapacity(json['energy_storage_power_station']['rated_capacity']);
setEnergyStoragePowerStationRatedPower(json['energy_storage_power_station']['rated_power']);
setEnergyStoragePowerStationLatitude(json['energy_storage_power_station']['latitude']);
setEnergyStoragePowerStationLongitude(json['energy_storage_power_station']['longitude']);
setEnergyStoragePowerStationSVG({ __html: json['energy_storage_power_station']['svg'] });
......@@ -857,7 +859,7 @@ const EnergyStoragePowerStationDetails = ({ setRedirect, setRedirectUrl, t }) =>
toggleTabRight('1');
}}
>
<h6>{t('General Information')}</h6>
<h6>{t('General')}</h6>
</NavLink>
</NavItem>
<NavItem className="cursor-pointer">
......@@ -891,8 +893,12 @@ const EnergyStoragePowerStationDetails = ({ setRedirect, setRedirectUrl, t }) =>
<th className="pr-0 text-right">{energyStoragePowerStationPostalCode}</th>
</tr>
<tr className="border-bottom">
<th className="pl-0 pb-0">{t('Capacity')} </th>
<th className="pr-0 text-right">{energyStoragePowerStationCapacity} kW</th>
<th className="pl-0 pb-0">{t('Rated Capacity')} </th>
<th className="pr-0 text-right">{energyStoragePowerStationRatedCapacity} kW</th>
</tr>
<tr className="border-bottom">
<th className="pl-0 pb-0">{t('Rated Power')} </th>
<th className="pr-0 text-right">{energyStoragePowerStationRatedPower} kW</th>
</tr>
<tr className="border-bottom">
<th className="pl-0 pb-0">{t('Latitude')}</th>
......
......@@ -107,7 +107,6 @@ const EnergyStoragePowerStationList = ({ setRedirect, setRedirectUrl, t }) => {
energyStoragePowerStation['postal_code'] = json[index]['postal_code'];
energyStoragePowerStation['latitude'] = json[index]['latitude'];
energyStoragePowerStation['longitude'] = json[index]['longitude'];
energyStoragePowerStation['serial_number'] = json[index]['serial_number'];
energyStoragePowerStation['files'] = [
{ id: json[index]['uuid'], src: require('./EnergyStoragePowerStation.jpeg') }
];
......
import React, { Fragment, createRef } from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
const columns = [
{
dataField: 'name',
text: 'Name',
classes: 'border-0 align-middle',
headerClasses: 'border-0',
sort: false
},
{
dataField: 'value',
text: 'Value',
classes: 'border-0 align-middle',
headerClasses: 'border-0',
sort: true,
},
{
dataField: 'unit',
text: 'Unit',
classes: 'border-0 align-middle',
headerClasses: 'border-0',
sort: false,
},
];
const EnergyStoragePowerStationRankingTable = ({ energyStoragePowerStationList }) => {
let table = createRef();
return (
<Fragment>
<div className="table-responsive">
<BootstrapTable
ref={table}
bootstrap4
keyField="id"
data={energyStoragePowerStationList}
columns={columns}
bordered={false}
classes="table-dashboard table-sm fs--1 border-bottom border-200 mb-0 table-dashboard-th-nowrap"
rowClasses="btn-reveal-trigger border-top border-200"
headerClasses="bg-200 text-900 border-y border-200"
/>
</div>
</Fragment>
);
};
export default EnergyStoragePowerStationRankingTable;
......@@ -120,7 +120,8 @@ const EnergyStoragePowerStationReporting = ({ setRedirect, setRedirectUrl, t })
const [energyStoragePowerStationSerialNumber, setEnergyStoragePowerStationSerialNumber] = useState();
const [energyStoragePowerStationAddress, setEnergyStoragePowerStationAddress] = useState();
const [energyStoragePowerStationPostalCode, setEnergyStoragePowerStationPostalCode] = useState();
const [energyStoragePowerStationCapacity, setEnergyStoragePowerStationCapacity] = useState();
const [energyStoragePowerStationRatedCapacity, setEnergyStoragePowerStationRatedCapacity] = useState();
const [energyStoragePowerStationRatedPower, setEnergyStoragePowerStationRatedPower] = useState();
const [energyStoragePowerStationLatitude, setEnergyStoragePowerStationLatitude] = useState();
const [energyStoragePowerStationLongitude, setEnergyStoragePowerStationLongitude] = useState();
const [energyStoragePowerStationSVG, setEnergyStoragePowerStationSVG] = useState();
......@@ -297,7 +298,8 @@ const EnergyStoragePowerStationReporting = ({ setRedirect, setRedirectUrl, t })
setEnergyStoragePowerStationSerialNumber(json['energy_storage_power_station']['serial_number']);
setEnergyStoragePowerStationAddress(json['energy_storage_power_station']['address']);
setEnergyStoragePowerStationPostalCode(json['energy_storage_power_station']['postal_code']);
setEnergyStoragePowerStationCapacity(json['energy_storage_power_station']['capacity']);
setEnergyStoragePowerStationRatedCapacity(json['energy_storage_power_station']['rated_capacity']);
setEnergyStoragePowerStationRatedPower(json['energy_storage_power_station']['rated_power']);
setEnergyStoragePowerStationLatitude(json['energy_storage_power_station']['latitude']);
setEnergyStoragePowerStationLongitude(json['energy_storage_power_station']['longitude']);
setEnergyStoragePowerStationSVG({ __html: json['energy_storage_power_station']['svg'] });
......
......@@ -7,8 +7,6 @@ import { Button, Col, Row } from 'reactstrap';
import ButtonIcon from '../../common/ButtonIcon';
import { Link } from 'react-router-dom';
import purchases from './stationlist';
const CustomTotal = ({ sizePerPage, totalSize, page, lastIndex }) => (
<span>
{(page - 1) * sizePerPage + 1} to {lastIndex > totalSize ? totalSize : lastIndex} of {totalSize} {' '}
......@@ -16,7 +14,7 @@ const CustomTotal = ({ sizePerPage, totalSize, page, lastIndex }) => (
);
const customerFormatter = customerName => (
<Link to="pages/customer-details" className="font-weight-semi-bold">
<Link to="energystoragepowerstation/details" className="font-weight-semi-bold">
{customerName}
</Link>
);
......@@ -59,31 +57,31 @@ const powerFormatter = amount => <Fragment>{amount} kW</Fragment>;
const columns = [
{
dataField: 'customer',
text: '名称',
dataField: 'name',
text: 'Name',
formatter: customerFormatter,
classes: 'border-0 align-middle',
headerClasses: 'border-0',
sort: true
},
{
dataField: 'product',
text: '地址',
dataField: 'address',
text: 'Address',
classes: 'border-0 align-middle',
headerClasses: 'border-0',
sort: true
},
{
dataField: 'amount',
text: '额定容量',
dataField: 'rated_capacity',
text: 'Rated Capacity',
formatter: capacityFormatter,
classes: 'border-0 align-middle',
headerClasses: 'border-0',
sort: true,
},
{
dataField: 'amount',
text: '额定功率',
dataField: 'rated_power',
text: 'Rated Power',
formatter: powerFormatter,
classes: 'border-0 align-middle',
headerClasses: 'border-0',
......@@ -91,7 +89,7 @@ const columns = [
},
{
dataField: 'status',
text: '状态',
text: 'Status',
formatter: badgeFormatter,
classes: 'border-0 align-middle fs-0',
headerClasses: 'border-0',
......@@ -132,13 +130,8 @@ const selectRow = onSelect => ({
onSelectAll: onSelect
});
const options = {
custom: true,
sizePerPage: 6,
totalSize: purchases.length
};
const PurchasesTable = ({ setIsSelected }) => {
const EnergyStoragePowerStationTable = ({ setIsSelected, energyStoragePowerStationList }) => {
let table = createRef();
const handleNextPage = ({ page, onPageChange }) => () => {
onPageChange(page + 1);
......@@ -158,6 +151,12 @@ const PurchasesTable = ({ setIsSelected }) => {
});
};
const options = {
custom: true,
sizePerPage: 6,
totalSize: energyStoragePowerStationList.length
};
return (
<PaginationProvider pagination={paginationFactory(options)}>
{({ paginationProps, paginationTableProps }) => {
......@@ -170,7 +169,7 @@ const PurchasesTable = ({ setIsSelected }) => {
ref={table}
bootstrap4
keyField="id"
data={purchases}
data={energyStoragePowerStationList}
columns={columns}
selectRow={selectRow(onSelect)}
bordered={false}
......@@ -190,9 +189,9 @@ const PurchasesTable = ({ setIsSelected }) => {
iconAlign="right"
transform="down-1 shrink-4"
className="px-0 font-weight-semi-bold"
onClick={() => handleViewAll(paginationProps, purchases.length)}
onClick={() => handleViewAll(paginationProps, energyStoragePowerStationList.length)}
>
全部
view all
</ButtonIcon>
</Col>
<Col xs="auto" className="pr-3">
......@@ -203,7 +202,7 @@ const PurchasesTable = ({ setIsSelected }) => {
disabled={paginationProps.page === 1}
className="px-4"
>
前一页
Previous
</Button>
<Button
color={lastIndex >= paginationProps.totalSize ? 'light' : 'primary'}
......@@ -212,7 +211,7 @@ const PurchasesTable = ({ setIsSelected }) => {
disabled={lastIndex >= paginationProps.totalSize}
className="px-4 ml-2"
>
下一页
Next
</Button>
</Col>
</Row>
......@@ -223,4 +222,4 @@ const PurchasesTable = ({ setIsSelected }) => {
);
};
export default PurchasesTable;
export default EnergyStoragePowerStationTable;
import React, { useState } from 'react';
import PurchasesTable from './PurchasesTable';
import EnergyStoragePowerStationTable from './EnergyStoragePowerStationTable';
import FalconCardHeader from '../../common/FalconCardHeader';
import { InputGroup, CustomInput, Button, Card, CardBody } from 'reactstrap';
import ButtonIcon from '../../common/ButtonIcon';
const RecentPurchasesTable = () => {
const EnergyStoragePowerStationTableCard = ({ energyStoragePowerStationList }) => {
const [isSelected, setIsSelected] = useState(false);
return (
<Card className="mb-3">
<FalconCardHeader title="电站列表" light={false}>
<FalconCardHeader title="Energy Storage Power Station List" light={false}>
{isSelected ? (
<InputGroup size="sm" className="input-group input-group-sm">
<CustomInput type="select" id="bulk-select">
......@@ -37,10 +37,10 @@ const RecentPurchasesTable = () => {
)}
</FalconCardHeader>
<CardBody className="p-0">
<PurchasesTable setIsSelected={setIsSelected} />
<EnergyStoragePowerStationTable setIsSelected={setIsSelected} energyStoragePowerStationList={energyStoragePowerStationList}/>
</CardBody>
</Card>
);
};
export default RecentPurchasesTable;
export default EnergyStoragePowerStationTableCard;
import React, { useContext, useState } from 'react';
import { Card, CardBody, CustomInput } from 'reactstrap';
import PropTypes from 'prop-types';
import * as echarts from 'echarts/lib/echarts';
import ReactEchartsCore from 'echarts-for-react/lib/core';
import { getPosition, getGrays, themeColors, rgbaColor, isIterableArray, capitalize } from '../../../helpers/utils';
import CardDropdown from './CardDropdown';
import FalconCardHeader from '../../common/FalconCardHeader';
import Flex from '../../common/Flex';
import AppContext from '../../../context/Context';
import { BarChart } from 'echarts/charts';
import { TooltipComponent, LegendComponent} from 'echarts/components';
import { totalSalesByMonth } from '../../../data/dashboard/topProducts';
echarts.use([BarChart, TooltipComponent, LegendComponent]);
function getFormatter(params) {
const { name, value } = params[0];
return `${Object.keys(totalSalesByMonth)[0]} ${name}, ${value}`;
}
const getOption = (month, isDark) => {
const grays = getGrays(isDark);
return {
tooltip: {
trigger: 'axis',
padding: [7, 10],
backgroundColor: grays.white,
borderColor: grays['300'],
borderWidth: 1,
textStyle: { color: themeColors.dark },
formatter(params) {
return getFormatter(params);
},
transitionDuration: 0,
position(pos, params, dom, rect, size) {
return getPosition(pos, params, dom, rect, size);
}
},
xAxis: {
type: 'category',
data: [1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25],
boundaryGap: false,
axisPointer: {
lineStyle: {
color: grays['300'],
type: 'dashed'
}
},
splitLine: { show: false },
axisLine: {
lineStyle: {
color: rgbaColor('#000', 0.01),
type: 'dashed'
}
},
axisTick: { show: false },
axisLabel: {
color: grays['400'],
formatter: function(value) {
return `${capitalize(month.slice(0, 3))} ${value}`;
},
margin: 15
}
},
yAxis: {
type: 'value',
axisPointer: { show: false },
splitLine: {
lineStyle: {
color: grays['300'],
type: 'dashed'
}
},
boundaryGap: false,
axisLabel: {
show: true,
color: grays['400'],
margin: 15
},
axisTick: { show: false },
axisLine: { show: false }
},
series: [
{
type: 'line',
data: totalSalesByMonth[month],
lineStyle: { color: themeColors.primary },
itemStyle: {
color: grays['100'],
borderColor: themeColors.primary,
borderWidth: 2
},
symbol: 'circle',
symbolSize: 10,
smooth: false,
emphasis: {
scale: true
},
areaStyle: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{
offset: 0,
color: rgbaColor(themeColors.primary, 0.2)
},
{
offset: 1,
color: rgbaColor(themeColors.primary, 0)
}
]
}
}
}
],
animationDuration: 90000,
grid: { right: '28px', left: '40px', bottom: '15%', top: '5%' }
};
};
const TotalSales = ({ className }) => {
const { isDark } = useContext(AppContext);
const [month, setMonth] = useState('january');
const months = Object.keys(totalSalesByMonth);
return (
<Card className={className}>
<FalconCardHeader title="Total Sales" light={false} titleTag="h6" className="pb-0">
<Flex>
<CustomInput
type="select"
id="exampleCustomSelect"
bsSize="sm"
className="select-month mr-2"
value={month}
onChange={({ target }) => setMonth(target.value)}
>
{isIterableArray(months) &&
months.map((month, index) => (
<option key={index} value={month}>
{capitalize(month)}
</option>
))}
</CustomInput>
<CardDropdown />
</Flex>
</FalconCardHeader>
<CardBody className="h-100">
<ReactEchartsCore echarts={echarts} option={getOption(month, isDark)} style={{ minHeight: '18.75rem' }} />
</CardBody>
</Card>
);
};
TotalSales.propTypes = {
className: PropTypes.string
};
export default TotalSales;
import React from 'react';
import PropTypes from 'prop-types';
import { Card, CardBody, Col, Media, Row } from 'reactstrap';
import FalconCardHeader from '../../common/FalconCardHeader';
import weatherIcon from '../../../assets/img/icons/weather-icon.png';
import CardDropdown from './CardDropdown';
const Weather = ({
data: { city, condition, precipitation, temperature, highestTemperature, lowestTemperature },
...rest
}) => (
<Card {...rest}>
<FalconCardHeader title="天气" light={false} titleTag="h6" className="pb-0">
<CardDropdown />
</FalconCardHeader>
<CardBody className="pt-2">
<Row noGutters className="h-100 align-items-center">
<Col>
<Media className="media align-items-center">
<img className="mr-3" src={weatherIcon} alt="" height="60" />
<Media body>
<h6 className="mb-2">{city}</h6>
<div className="fs--2 font-weight-semi-bold">
<div className="text-warning">{condition}</div>
Precipitation: {precipitation}
</div>
</Media>
</Media>
</Col>
<Col xs="auto" className="text-center pl-2">
<div className="fs-4 font-weight-normal text-sans-serif text-primary mb-1 line-height-1">{temperature}°</div>
<div className="fs--1 text-800">
{highestTemperature}° / {lowestTemperature}°
</div>
</Col>
</Row>
</CardBody>
</Card>
);
Weather.propTypes = { data: PropTypes.object.isRequired, className: PropTypes.string };
export default Weather;
import React, { Fragment, useContext } from 'react';
import PropTypes from 'prop-types';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Badge, Card, CardBody, Col, Row, UncontrolledTooltip } from 'reactstrap';
import FalconCardHeader from '../../common/FalconCardHeader';
import Flex from '../../common/Flex';
import ReactEchartsCore from 'echarts-for-react/lib/core';
import * as echarts from 'echarts/lib/echarts';
import { GridComponent } from 'echarts/components';
import { themeColors, getPosition, numberFormatter, getGrays } from '../../../helpers/utils';
import { BarChart } from 'echarts/charts';
import { TooltipComponent } from 'echarts/components';
import AppContext from '../../../context/Context';
echarts.use([BarChart, TooltipComponent, GridComponent]);
const getOption = (data, dataBackground, isDark) => {
const grays = getGrays(isDark);
return {
tooltip: {
trigger: 'axis',
padding: [7, 10],
formatter: '{b1}: {c1}',
backgroundColor: grays.white,
borderColor: grays['300'],
borderWidth: 1,
textStyle: { color: themeColors.dark },
transitionDuration: 0,
position(pos, params, dom, rect, size) {
return getPosition(pos, params, dom, rect, size);
}
},
xAxis: {
type: 'category',
data: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
boundaryGap: false,
axisLine: { show: false },
axisLabel: { show: false },
axisTick: { show: false },
axisPointer: { type: 'none' }
},
yAxis: {
type: 'value',
splitLine: { show: false },
axisLine: { show: false },
axisLabel: { show: false },
axisTick: { show: false },
axisPointer: { type: 'none' }
},
series: [
{
type: 'bar',
barWidth: '5px',
barGap: '-100%',
itemStyle: {
color: grays['200'],
barBorderRadius: 10
},
data: dataBackground,
animation: false,
emphasis: { itemStyle: { color: grays['200'] } }
},
{
type: 'bar',
barWidth: '5px',
itemStyle: {
color: themeColors.primary,
barBorderRadius: 10
},
data: data,
emphasis: { itemStyle: { color: themeColors.primary } },
z: 10
}
],
grid: { right: 5, left: 10, top: 0, bottom: 0 }
};
};
const WeeklySales = ({ data }) => {
const { currency, isDark } = useContext(AppContext);
const total = data.reduce((total, currentValue) => total + currentValue, 0);
// Max value of data
const yMax = Math.max(...data);
const dataBackground = data.map(() => yMax);
return (
<Card className="h-md-100">
<FalconCardHeader
className="pb-0"
title={
<Fragment>
本周收益{' '}
<FontAwesomeIcon
icon={['far', 'question-circle']}
transform="shrink-1"
className="text-400"
id="weeklySalesTooltip"
/>
<UncontrolledTooltip placement="bottom" target="weeklySalesTooltip">
Calculated according to last week's sales
</UncontrolledTooltip>
</Fragment>
}
light={false}
titleTag="h6"
/>
<CardBody tag={Flex} align="end">
<Row className="flex-grow-1">
<Col>
<div className="fs-4 font-weight-normal text-sans-serif text-700 line-height-1 mb-1">
{currency}
{numberFormatter(total, 0)}
</div>
<Badge pill color="soft-success" className="fs--2">
+3.5%
</Badge>
</Col>
<Col xs="auto" className="pl-0">
<ReactEchartsCore
echarts={echarts}
option={getOption(data, dataBackground, isDark)}
style={{ width: '8.5rem', height: '100%' }}
/>
</Col>
</Row>
</CardBody>
</Card>
);
};
WeeklySales.propTypes = { data: PropTypes.array.isRequired };
export default WeeklySales;
import product12 from '../../../assets/img/products/12.jpg';
import product10 from '../../../assets/img/products/10.jpg';
import product11 from '../../../assets/img/products/11.jpg';
import product14 from '../../../assets/img/products/14.jpg';
import product13 from '../../../assets/img/products/13.jpg';
const result = [
{
id: 1,
img: product12,
title: '储能电站1',
type: 'Landing',
unit: 19,
price: 69,
progress: 38,
time: '12:50:00',
color: 'warning'
},
{
id: 2,
img: product10,
title: '储能电站2',
type: 'Portfolio',
unit: 10,
price: 86,
progress: 79,
time: '25:20:00',
color: 'info'
},
{
id: 3,
img: product11,
title: '储能电站3',
type: 'Admin',
unit: 11,
price: 49,
progress: 90,
time: '58:20:00',
color: 'primary'
},
{
id: 4,
img: product14,
title: '储能电站4',
type: 'Builder',
unit: 5,
price: 49,
progress: 40,
time: '21:20:00',
color: 'danger'
},
{
id: 5,
img: product13,
title: '储能电站5',
type: 'Agency',
unit: 6,
price: 39,
progress: 78,
time: '31:50:00',
color: 'success'
}
];
export default result;
import React from 'react';
const result = [
{
id: 1,
customer: '储能电站1',
product: 'Slick - Drag & Drop Bootstrap Generator',
status: 'charging',
amount: 99
},
{
id: 2,
customer: '储能电站2',
product: 'Bose SoundSport Wireless Headphones',
status: 'charging',
amount: 634
},
{
id: 3,
customer: '储能电站3',
product: 'All-New Fire HD 8 Kids Edition Tablet',
status: 'offline',
amount: 199
},
{
id: 4,
customer: '储能电站4',
product: 'Apple iPhone XR (64GB)',
status: 'charging',
amount: 798
},
{
id: 5,
customer: '储能电站5',
product: 'ASUS Chromebook C202SA-YS02 11.6"',
status: 'offline',
amount: 318
},
{
id: 6,
customer: '储能电站6',
product: 'Mirari OK to Wake! Alarm Clock & Night-Light',
status: 'discharging',
amount: 11
},
{
id: 7,
customer: '储能电站7',
product: 'Summer Infant Contoured Changing Pad',
status: 'charging',
amount: 31
},
{
id: 8,
customer: '储能电站8',
product: 'Munchkin 6 Piece Fork and Spoon Set',
status: 'idling',
amount: 43
},
{
id: 9,
customer: '储能电站9',
product: 'Falcon - Responsive Dashboard Template',
status: 'charging',
amount: 57
},
{
id: 10,
customer: '储能电站10',
product: 'Apple iPhone XR (64GB)',
status: 'offline',
amount: 999
},
{
id: 11,
customer: '储能电站11',
product: 'All-New Fire HD 8 Kids Edition Tablet',
status: 'idling',
amount: 199
},
{
id: 12,
customer: '储能电站12',
product: 'ASUS Chromebook C202SA-YS02 11.6"',
status: 'idling',
amount: 200
}
];
export default result;
......@@ -120,7 +120,8 @@ const MicrogridReporting = ({ setRedirect, setRedirectUrl, t }) => {
const [microgridSerialNumber, setMicrogridSerialNumber] = useState();
const [microgridAddress, setMicrogridAddress] = useState();
const [microgridPostalCode, setMicrogridPostalCode] = useState();
const [microgridCapacity, setMicrogridCapacity] = useState();
const [microgridRatedCapacity, setMicrogridRatedCapacity] = useState();
const [microgridRatedPower, setMicrogridRatedPower] = useState();
const [microgridLatitude, setMicrogridLatitude] = useState();
const [microgridLongitude, setMicrogridLongitude] = useState();
const [microgridSVG, setMicrogridSVG] = useState();
......@@ -293,7 +294,8 @@ const MicrogridReporting = ({ setRedirect, setRedirectUrl, t }) => {
setMicrogridSerialNumber(json['microgrid']['serial_number']);
setMicrogridAddress(json['microgrid']['address']);
setMicrogridPostalCode(json['microgrid']['postal_code']);
setMicrogridCapacity(json['microgrid']['capacity']);
setMicrogridRatedCapacity(json['microgrid']['rated_capacity']);
setMicrogridRatedPower(json['microgrid']['rated_power']);
setMicrogridLatitude(json['microgrid']['latitude']);
setMicrogridLongitude(json['microgrid']['longitude']);
setMicrogridSVG({ __html: json['microgrid']['svg'] });
......
......@@ -14,7 +14,7 @@ const CustomTotal = ({ sizePerPage, totalSize, page, lastIndex }) => (
);
const customerFormatter = customerName => (
<Link to="pages/customer-details" className="font-weight-semi-bold">
<Link to="microgrid/details" className="font-weight-semi-bold">
{customerName}
</Link>
);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册