index.tsx 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402
  1. import React, { useState, useEffect, useCallback, useRef } from 'react';
  2. import PageHeader from '@/sagacare_components/PageHeader';
  3. import Map from '@/sagacare_components/map';
  4. import TopNavigator from '@/sagacare_components/topNavigator';
  5. import RunNavRight from './components/topNavRight';
  6. import { FormattedMessage, history, useModel } from 'umi';
  7. import { Spin } from 'antd';
  8. import { Popover } from 'antd';
  9. import styles from './index.less';
  10. import mapstyles from '@/sagacare_components/map/index.less';
  11. import Icon from '@/tenants-ui/SgIcon';
  12. import SearchInput from '@/sagacare_components/SearchInput';
  13. import moment from 'moment';
  14. import cx from 'classnames';
  15. import { getMaxScale } from '@/hooks/useMap';
  16. import { getMapList, queryDeviceTimeManage } from '@/services/sagacare_service/environment';
  17. type runtimeNavType = {
  18. normalRun: any;
  19. overtimeWork: number;
  20. meetingBook: number;
  21. };
  22. const Runtime: React.FC = () => {
  23. // const { maptemp6 } = equipImageMap;
  24. const { changeLastFloorId } = useModel('sagacare_buildFloor');
  25. const { searchSpace } = useModel('sagacare_searchInfo');
  26. const { getSpaceFunc } = useModel('sagacare_spaceFunc');
  27. const [loading, setLoading] = useState<boolean>(false);
  28. const [runtimeNav, setRuntimeNav] = useState<runtimeNavType>({});
  29. const [mapList, setMapList] = useState<API.MapInfo[]>([]);
  30. const mapListCopy = useRef<any[]>();
  31. const [mapSize, setMapSize] = useState<any>({});
  32. const [scale, setScale] = useState<number>(0.8);
  33. const [maxScale, setMaxScale] = useState<number>(1);
  34. const [transXInit, setTransXInit] = useState<number>(0);
  35. const [mapCombineList, setMapCombineList] = useState<any[]>([]);
  36. const [selFloorId, setSelFloorId] = useState<string>();
  37. const [selTime, setSelTime] = useState<string>(moment().format('YYYYMMDD'));
  38. const [spaceTimeList, setSpaceTimeList] = useState<any[]>([]);
  39. //楼层切换的回调
  40. const changeFloorId = (data: string) => {
  41. setSelFloorId(data);
  42. };
  43. const checkRecord = () => {
  44. history.push('/runtime/recordList');
  45. console.log('showR');
  46. };
  47. //时间切换的回调
  48. const changeTime = (time) => {
  49. var timeStr = time.format('YYYYMMDD');
  50. setSelTime(timeStr);
  51. };
  52. //获取地图 mapList
  53. useEffect(() => {
  54. if (selFloorId) {
  55. changeLastFloorId(selFloorId);
  56. setLoading(true);
  57. getMapList({
  58. floorId: selFloorId,
  59. //floorId: 'Fl11010802593241ec348ecb4148806b9034c8957454',
  60. })
  61. .then((res) => {
  62. setLoading(false);
  63. var data: API.MapInfo[] = (res.data || {}).spaceList || [];
  64. var bodyWidth = document.body.offsetWidth;
  65. var mapWidth = (res.data || {}).width || 800;
  66. if (mapWidth < bodyWidth) {
  67. var mscale = 1;
  68. setTransXInit((bodyWidth - mapWidth) / 2);
  69. } else {
  70. var mscale = Number((bodyWidth / mapWidth).toFixed(4));
  71. setTransXInit(0);
  72. }
  73. var mapSize: any = {
  74. width: mapWidth * mscale,
  75. height: (res.data || {}).height * mscale,
  76. };
  77. setMapSize(mapSize);
  78. data.forEach((item, index) => {
  79. item.width = item.width * mscale;
  80. item.height = item.height * mscale;
  81. item.left = item.left * mscale;
  82. item.top = item.top * mscale;
  83. });
  84. var maxScaleTemp = getMaxScale(data);
  85. setMaxScale(maxScaleTemp);
  86. setMapList(data);
  87. mapListCopy.current = data;
  88. })
  89. .catch(() => {
  90. setLoading(false);
  91. });
  92. } else {
  93. setMapList([]);
  94. }
  95. }, [selFloorId]);
  96. const changeMapList = useCallback(
  97. (scale, moveWidth, moveHeight) => {
  98. setScale(scale);
  99. var mapListTemp = JSON.parse(JSON.stringify(mapListCopy.current));
  100. var mapListTemp2 = mapListTemp.map((item, index) => {
  101. if (index == 0) {
  102. console.log('mapListTemp', scale, item.width, item.width * scale);
  103. }
  104. item.width = item.width * scale;
  105. item.height = item.height * scale;
  106. item.left = item.left * scale - moveWidth;
  107. item.top = item.top * scale - moveHeight;
  108. return item;
  109. });
  110. setMapList(mapListTemp2);
  111. },
  112. [mapListCopy],
  113. );
  114. const getDeviceTime = () => {
  115. setLoading(true);
  116. queryDeviceTimeManage({
  117. floorId: selFloorId,
  118. //floorId: 'Fl11010802593241ec348ecb4148806b9034c8957454',
  119. date: selTime,
  120. })
  121. .then(function (res) {
  122. setLoading(false);
  123. if (!setTimer.current) return;
  124. var resdata = res || {};
  125. setRuntimeNav({
  126. normalRun: resdata.workTimeNum,
  127. overtimeWork: resdata.overTimeNum,
  128. meetingBook: resdata.meetTimeNum,
  129. });
  130. var resList = res.content || [];
  131. resList.forEach((ritem) => {
  132. ritem.runTimeStatus = ''; //正常工作
  133. ritem.hasWorkTime = false;
  134. var timeList = [];
  135. var allTimeArr = [];
  136. if (ritem.hasOwnProperty('workTimeStartTime')) {
  137. // var timeStrArr = [ritem.workTimeStartTime, ritem.workTimeEndTime];
  138. //timeList.push(timeStrArr);
  139. ritem.hasWorkTime = true;
  140. allTimeArr.push(ritem.workTimeStartTime, ritem.workTimeEndTime);
  141. }
  142. if (ritem.hasOwnProperty('meetTime')) {
  143. ritem.runTimeStatus = 'meetingBook'; //会议预约
  144. ritem.meetTime.forEach((meetitem) => {
  145. var timeStrArr = [meetitem.meetTimeStartTime, meetitem.meetTimeEndTime];
  146. timeList.push(timeStrArr);
  147. allTimeArr.push(meetitem.meetTimeStartTime, meetitem.meetTimeEndTime);
  148. });
  149. }
  150. if (ritem.hasOwnProperty('overTime')) {
  151. ritem.runTimeStatus = 'overtimeWork'; //加班
  152. ritem.overTime.forEach((overitem) => {
  153. var timeStrArr = [overitem.overTimeStartTime, overitem.overTimeEndTime];
  154. timeList.push(timeStrArr);
  155. allTimeArr.push(overitem.overTimeStartTime, overitem.overTimeEndTime);
  156. });
  157. }
  158. ritem.showTimeList = timeList;
  159. allTimeArr.sort((a, b) => {
  160. var a1 = Date.parse('2008-08-08 ' + a);
  161. var b1 = Date.parse('2008-08-08 ' + b);
  162. return a1 - b1;
  163. });
  164. ritem.showTimeStr =
  165. allTimeArr.length > 1 ? allTimeArr[0] + '-' + allTimeArr[allTimeArr.length - 1] : '';
  166. });
  167. setSpaceTimeList(resList);
  168. })
  169. .catch(() => {
  170. setLoading(false);
  171. });
  172. };
  173. let setTimer = useRef<Timer>(null);
  174. //获取时间列表 spaceTimeList
  175. useEffect(() => {
  176. if (selFloorId && selTime) {
  177. //setLoading(true);
  178. getDeviceTime(); //第一次执行
  179. if (setTimer.current) {
  180. clearInterval(setTimer.current);
  181. setTimer.current = null;
  182. }
  183. //循环调接口
  184. setTimer.current = setInterval(() => {
  185. //getDeviceTime();
  186. }, 10000);
  187. return () => {
  188. clearInterval(setTimer.current);
  189. setTimer.current = null;
  190. };
  191. }
  192. }, [selFloorId, selTime]);
  193. useEffect(() => {
  194. //mapList,spaceTimeList 这两个数据的结合
  195. //console.log('dfsd-------');
  196. // if (mapList && mapList.length > 0 && spaceTimeList && spaceTimeList.length > 0) {
  197. var combineList: any = [];
  198. mapList.map(function (mitem) {
  199. var spaceId = mitem.spaceId;
  200. var filterSpace = spaceTimeList.filter((ele) => {
  201. return ele.id == spaceId;
  202. });
  203. var combine = Object.assign({}, mitem, filterSpace[0]);
  204. combineList.push(combine);
  205. });
  206. setMapCombineList(combineList);
  207. // }
  208. }, [mapList, spaceTimeList]);
  209. return (
  210. <>
  211. <PageHeader
  212. title={<FormattedMessage id="menu.runtime" />}
  213. action={
  214. // <div className={styles.headerRight}>
  215. // <div className={styles.check} onClick={checkRecord} style={{ display: 'none' }}>
  216. // <Icon className="" style={{ marginRight: 6 }} type="document" />
  217. // <span>查看加班记录</span>
  218. // </div>
  219. // </div>
  220. <SearchInput />
  221. }
  222. />
  223. <TopNavigator
  224. type={'runtime'}
  225. action={<RunNavRight runtimeNav={runtimeNav} changeTime={changeTime}></RunNavRight>}
  226. changeFloorId={changeFloorId}
  227. ></TopNavigator>
  228. <div className={styles.maptop}>
  229. <div className={styles.right}></div>
  230. </div>
  231. {/* <div className={styles.map}>
  232. <div className={styles.specialRoom}></div>
  233. <img src={mapImg}></img>
  234. </div> */}
  235. {/* <div
  236. className={mapstyles.house}
  237. style={{
  238. width: 180,
  239. height: 100,
  240. }}
  241. >
  242. <div className={mapstyles.allTime}>08:00-23:00</div>
  243. <div className={mapstyles.content}>
  244. <Icon className="" type="office" style={{ fontSize: 20 }}></Icon>
  245. <div className={mapstyles.name}>Jozy Zone</div>
  246. </div>
  247. </div> */}
  248. <Spin spinning={loading} wrapperClassName={mapstyles.spinnclass}>
  249. <Map
  250. mapList={mapCombineList}
  251. maxscale={maxScale}
  252. transXInit={transXInit}
  253. changeMapList={changeMapList}
  254. mapSize={mapSize}
  255. selFloorId={selFloorId}
  256. type={'runtime'}
  257. render={(item, index) => {
  258. return (
  259. <div
  260. className={mapstyles.houseWrap}
  261. key={index + 'house'}
  262. style={{
  263. left: item.left,
  264. top: item.top,
  265. width: item.width,
  266. height: item.height,
  267. }}
  268. >
  269. <div
  270. key={index + 'house'}
  271. className={cx(mapstyles.house, {
  272. [mapstyles.notclick]: !item.roomFuncType,
  273. [mapstyles.searchSel]: item.spaceId && item.spaceId === searchSpace.spaceId,
  274. })}
  275. style={{
  276. background: item.roomFuncType
  277. ? item.runTimeStatus == 'meetingBook'
  278. ? 'rgba(0, 220, 35, 0.2)'
  279. : item.runTimeStatus == 'overtimeWork'
  280. ? 'rgba(94, 139, 207, 0.2)'
  281. : 'rgba(196, 196, 196, 0.2)'
  282. : '',
  283. }}
  284. >
  285. <div className={mapstyles.allTime}>
  286. {/* {(item.timeList || []).map(function (titem: string, tindex: number) {
  287. return <span key={tindex + 'time'}>{titem},</span>;
  288. })} */}
  289. {item.showTimeList && item.showTimeList.length > 0 && (
  290. <Popover
  291. content={
  292. <div>
  293. {item.hasWorkTime && (
  294. <>
  295. <div className={styles.popTitle}>工作时间:</div>
  296. <div>
  297. {item.workTimeStartTime}-{item.workTimeEndTime}
  298. </div>
  299. </>
  300. )}
  301. <div className={styles.popTitle}>
  302. {item.runTimeStatus == 'overtimeWork' ? '加班时间' : '会议时间'}:
  303. </div>
  304. {(item.showTimeList || []).map((timeItem, index) => {
  305. // if (index > 0) {
  306. return (
  307. <div key={'time' + index}>
  308. {timeItem[0]}-{timeItem[1]}
  309. </div>
  310. );
  311. // }
  312. })}
  313. </div>
  314. }
  315. trigger="hover"
  316. style={{ color: 'none' }}
  317. >
  318. <span
  319. className={cx({
  320. [mapstyles.overworkTime]: item.runTimeStatus == 'overtimeWork',
  321. [mapstyles.meetTime]: item.runTimeStatus == 'meetingBook',
  322. })}
  323. >
  324. {item.showTimeStr}
  325. </span>
  326. </Popover>
  327. )}
  328. {item.showTimeList && item.showTimeList.length == 0 && (
  329. <span title={item.showTimeStr}>{item.showTimeStr}</span>
  330. )}
  331. </div>
  332. <div className={mapstyles.content}>
  333. <Icon
  334. className=""
  335. type={getSpaceFunc(item.roomFuncType)}
  336. style={{
  337. fontSize: 18,
  338. display: item.width > 28 && item.height > 50 ? 'block' : 'none',
  339. }}
  340. ></Icon>
  341. <div
  342. className={mapstyles.name}
  343. style={{
  344. display:
  345. (item.width > 64 && item.height > 80) ||
  346. item.height > 140 ||
  347. item.width > 120 ||
  348. scale == maxScale
  349. ? 'block'
  350. : 'none',
  351. }}
  352. >
  353. {item.localName}
  354. </div>
  355. {(getSpaceFunc(item.roomFuncType) || item.localName) &&
  356. !(
  357. (getSpaceFunc(item.roomFuncType) && item.width > 28 && item.height > 50) ||
  358. (item.localName &&
  359. ((item.width > 64 && item.height > 80) ||
  360. item.height > 140 ||
  361. item.width > 120 ||
  362. scale == maxScale))
  363. ) && <div className={mapstyles.pointer}>.</div>}
  364. </div>
  365. </div>
  366. </div>
  367. );
  368. }}
  369. ></Map>
  370. </Spin>
  371. </>
  372. );
  373. };
  374. export default Runtime;