EnergyCostComparison.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383
  1. // 能耗监测
  2. import ChartModule from '@/components/ManagementPage/chartModule';
  3. import PageContent from '@/components/PageContent';
  4. import PageTitle from '@/components/PageTitle';
  5. import { getComparisonData } from '@/services/OperationManagement';
  6. import { queryConditionSnapshot } from '@/services/SmartOps';
  7. import { UnityAction } from '@/utils/utils';
  8. import { LineChartOutlined } from '@ant-design/icons';
  9. import { history, useParams, useRequest } from '@umijs/max';
  10. import { message } from 'antd';
  11. import dayjs from 'dayjs';
  12. import { useEffect, useState } from 'react';
  13. import styles from './manage.less';
  14. const typeParams = [
  15. {
  16. // 计划吨水电耗
  17. type: '5',
  18. flag: '0',
  19. },
  20. {
  21. // 实际吨水电耗
  22. type: '5',
  23. flag: '1',
  24. },
  25. {
  26. // 计划用电量
  27. type: '6',
  28. flag: '0',
  29. },
  30. {
  31. // 实际用电量
  32. type: '6',
  33. flag: '1',
  34. },
  35. ];
  36. const CostComparison = () => {
  37. const [open, setOpen] = useState(false);
  38. return (
  39. <PageContent closeable={false}>
  40. <PageTitle onReturn={() => UnityAction.sendMsg('menuItem', '首页')}>
  41. 能耗数据
  42. <div
  43. onClick={(e) => {
  44. e.stopPropagation();
  45. setOpen(!open);
  46. }}
  47. style={{ marginLeft: '0.1rem' }}
  48. className={`password-eye ${open ? 'open' : ''}`}
  49. />
  50. </PageTitle>
  51. <EnergyCost open={open} />
  52. </PageContent>
  53. );
  54. };
  55. export default CostComparison;
  56. export const EnergyCost = ({ open, detailClick }) => {
  57. const { projectId } = useParams();
  58. const [chartData, setChartData] = useState([]);
  59. const [curElecPerCost, setElecPerCost] = useState(0); // 当前月实际吨水电耗
  60. const [curElecUsed, setCurElecUsed] = useState(0); // 当前月实际用电量
  61. const defaultTime = {
  62. s_time: `${dayjs().format('YYYY')}-${dayjs().startOf('year').format('MM')}`,
  63. e_time: `${dayjs().format('YYYY')}-${dayjs().endOf('year').format('MM')}`,
  64. };
  65. const defaultParams = {
  66. project_id: projectId,
  67. start: defaultTime.s_time,
  68. end: defaultTime.e_time,
  69. };
  70. const getValue = (str) => {
  71. const result = str?.match(/.*?(\d+(?:\.\d+)?)\D*$/);
  72. if (result && result[1]) return result[1];
  73. return 0;
  74. };
  75. const { data: snapshot } = useRequest(queryConditionSnapshot, {
  76. defaultParams: [{ project_id: projectId }],
  77. formatResult: (result) => {
  78. const elec = Number(getValue(result.data.elec_unit));
  79. let resultText = `当前电耗持平理论值 ${
  80. result?.data?.elec_unit_theory || 0
  81. }KWh/m³`;
  82. if (elec) {
  83. if (elec > result.data.elec_unit_theory) {
  84. resultText = `当前电耗高于理论值 ${result.data.elec_unit_theory}KWh/m³`;
  85. }
  86. if (elec === result.data.elec_unit_theory) {
  87. resultText = `当前电耗持平理论值 ${result.data.elec_unit_theory}KWh/m³`;
  88. }
  89. if (elec < result.data.elec_unit_theory) {
  90. resultText = `当前电耗低于理论值 ${result.data.elec_unit_theory}KWh/m³`;
  91. }
  92. }
  93. return { ...result.data, resultText };
  94. },
  95. });
  96. const getChartData = () => {
  97. // 构建请求列表
  98. const queryList = [];
  99. for (let index = 0; index < 4; index++) {
  100. queryList.push(
  101. getComparisonData({ ...defaultParams, ...typeParams[index] }),
  102. );
  103. }
  104. // 获取四组数据
  105. return Promise.all(queryList).catch(() => {
  106. message.error('请求数据失败');
  107. });
  108. };
  109. const getFixed = (maxValue) => {
  110. // 如果小于1,则保留最后两位不为0的数字
  111. // 如果大于1小于10,则保留三位
  112. // 大于10,保留两位
  113. // 大于100,保留一位
  114. // 大于1000,不保留
  115. if (maxValue === 0) {
  116. return 2;
  117. }
  118. let fixed = 0;
  119. if (maxValue < 1) {
  120. const decimal = maxValue.toFixed(100).toString().split('.')[1];
  121. const decimalArr = decimal.split('');
  122. for (let index = 0; index < decimalArr.length; index++) {
  123. if (decimalArr[index] === '0') {
  124. fixed++;
  125. } else {
  126. break;
  127. }
  128. }
  129. fixed += 2;
  130. } else if (maxValue < 10) {
  131. fixed = 3;
  132. } else if (maxValue < 100) {
  133. fixed = 2;
  134. } else if (maxValue < 1000) {
  135. fixed = 1;
  136. }
  137. return fixed;
  138. };
  139. const createChartData = async () => {
  140. const result = await getChartData().catch(() => {
  141. message.error('获取数据失败');
  142. });
  143. if (result && result.length) {
  144. const [planElecPerCost, actualElecPerCost, planElecUsed, actualElecUsed] =
  145. result;
  146. const elecPerCost = { yName: 'kwh/m³' };
  147. const elecUsed = { yName: 'kWh' };
  148. elecPerCost.xData = [
  149. ...new Set(
  150. [
  151. ...planElecPerCost.map((item) => item.month),
  152. ...actualElecPerCost.map((item) => item.month),
  153. ].map((item) => item),
  154. ),
  155. ].sort();
  156. let year = `${dayjs(elecPerCost.xData[0]).year()}`;
  157. elecPerCost.xData = [];
  158. for (let index = 0; index < 12; index++) {
  159. elecPerCost.xData.push(`${year}-${dayjs().month(index).format('MM')}`);
  160. }
  161. // 确定保留的小数点
  162. const elecPerCostValue = [...planElecPerCost, ...actualElecPerCost]
  163. .map((item) => item.value)
  164. .reduce((a, b) => Math.max(a, b));
  165. const elecPerCostFixed = getFixed(elecPerCostValue);
  166. elecPerCost.dataList = [
  167. {
  168. type: 0,
  169. yIndex: 1,
  170. name: '计划吨水电耗',
  171. data: elecPerCost.xData.map((month) => {
  172. const pItem = planElecPerCost.find((item) => item.month === month);
  173. if (pItem) {
  174. return pItem.value.toFixed(elecPerCostFixed);
  175. }
  176. return 0;
  177. }),
  178. },
  179. {
  180. type: 0,
  181. yIndex: 1,
  182. name: '实际吨水电耗',
  183. data: elecPerCost.xData.map((month) => {
  184. const aItem = actualElecPerCost.find(
  185. (item) => item.month === month,
  186. );
  187. if (aItem) {
  188. return aItem.value.toFixed(elecPerCostFixed);
  189. }
  190. return 0;
  191. }),
  192. },
  193. ];
  194. elecUsed.xData = [
  195. ...new Set(
  196. [
  197. ...planElecUsed.map((item) => item.month),
  198. ...actualElecUsed.map((item) => item.month),
  199. ].map((item) => item),
  200. ),
  201. ].sort();
  202. year = `${dayjs(elecUsed.xData[0]).year()}`;
  203. elecUsed.xData = [];
  204. for (let index = 0; index < 12; index++) {
  205. elecUsed.xData.push(`${year}-${dayjs().month(index).format('MM')}`);
  206. }
  207. // 确定保留的小数点
  208. const elecUsedMaxValue = [...planElecUsed, ...actualElecUsed]
  209. .map((item) => item.value)
  210. .reduce((a, b) => Math.max(a, b));
  211. const elecUsedFixed = getFixed(elecUsedMaxValue);
  212. elecUsed.dataList = [
  213. {
  214. type: 3,
  215. yIndex: 1,
  216. name: '计划用电量',
  217. data: elecUsed.xData.map((month) => {
  218. const pItem = planElecUsed.find((item) => item.month === month);
  219. if (pItem) {
  220. return pItem.value.toFixed(elecUsedFixed);
  221. }
  222. return 0;
  223. }),
  224. },
  225. {
  226. type: 3,
  227. yIndex: 1,
  228. name: '实际用电量',
  229. data: elecUsed.xData.map((month) => {
  230. const aItem = actualElecUsed.find((item) => item.month === month);
  231. if (aItem) {
  232. return aItem.value.toFixed(elecUsedFixed);
  233. }
  234. return 0;
  235. }),
  236. },
  237. ];
  238. elecUsed.chartType = 'bar';
  239. setChartData([elecPerCost, elecUsed]);
  240. let curElecPerCost = actualElecPerCost?.find((item) =>
  241. dayjs().isSame(item?.month, 'month'),
  242. );
  243. if (curElecPerCost)
  244. setElecPerCost(curElecPerCost?.value.toFixed(elecPerCostFixed));
  245. let curElecUsed = actualElecUsed?.find((item) =>
  246. dayjs().isSame(item?.month, 'month'),
  247. );
  248. if (curElecUsed)
  249. setCurElecUsed(curElecUsed?.value.toFixed(elecUsedFixed));
  250. } else {
  251. setChartData([]);
  252. }
  253. };
  254. useEffect(() => {
  255. createChartData();
  256. }, []);
  257. const goEnergyDetail = () => {
  258. if (detailClick) {
  259. detailClick();
  260. } else {
  261. history.push(`/home/energy/detail/${projectId}`);
  262. }
  263. };
  264. return (
  265. <div
  266. style={{ padding: '0.2rem', position: 'relative', marginTop: '0.1rem' }}
  267. >
  268. <div
  269. style={{
  270. fontSize: '0.28rem',
  271. position: 'absolute',
  272. top: '-0.6rem',
  273. right: '0.3rem',
  274. display: `${detailClick ? 'none' : ''}`,
  275. }}
  276. >
  277. {snapshot?.resultText}
  278. </div>
  279. <div className="card-box" style={{ padding: '0.1rem 0' }}>
  280. <LineChartOutlined
  281. style={{
  282. fontSize: '0.4rem',
  283. position: 'absolute',
  284. right: '0.3rem',
  285. color: '#0139f1',
  286. }}
  287. onClick={goEnergyDetail}
  288. />
  289. <div className={styles.curEnergyCost}>
  290. <div
  291. className={styles.item}
  292. style={{
  293. borderRight: '1px solid #eaeaea',
  294. borderBottom: '1px solid #eaeaea',
  295. }}
  296. >
  297. <div className={styles.value}>
  298. {open ? getValue(snapshot?.elec_unit || '') : '***'}
  299. <span className={styles.unit}>kWh/t</span>
  300. </div>
  301. <div className={styles.name}>近一小时吨水电耗</div>
  302. </div>
  303. <div
  304. className={styles.item}
  305. style={{
  306. borderBottom: '1px solid #eaeaea',
  307. }}
  308. >
  309. <div className={styles.value}>
  310. {open ? getValue(snapshot?.elec || '') : '***'}
  311. <span className={styles.unit}>kWh</span>
  312. </div>
  313. <div className={styles.name}>近一小时实际用电量</div>
  314. </div>
  315. <div
  316. className={styles.item}
  317. style={{
  318. borderRight: '1px solid #eaeaea',
  319. }}
  320. >
  321. <div className={styles.value}>
  322. {open ? curElecPerCost : '***'}
  323. <span className={styles.unit}>kWh/t</span>
  324. </div>
  325. <div className={styles.name}>当月吨水电耗</div>
  326. </div>
  327. <div className={styles.item}>
  328. <div className={styles.value}>
  329. {open ? curElecUsed : '***'}
  330. <span className={styles.unit}>kWh</span>
  331. </div>
  332. <div className={styles.name}>当月实际用电量</div>
  333. </div>
  334. </div>
  335. </div>
  336. {chartData.length !== 0 && (
  337. <div
  338. className="card-box"
  339. style={{
  340. height: '9.2rem',
  341. display: 'flex',
  342. flexDirection: 'column',
  343. justifyContent: 'space-between',
  344. padding: '0.6rem 0 0.4rem',
  345. marginTop: '0.1rem',
  346. }}
  347. >
  348. <div style={{ height: '3.5rem' }}>
  349. <ChartModule {...chartData[0]} />
  350. </div>
  351. <div style={{ height: '3.5rem' }}>
  352. <ChartModule {...chartData[1]} />
  353. </div>
  354. </div>
  355. )}
  356. </div>
  357. );
  358. };