| import React, { useState, useRef, useEffect } from 'react'; | 
| import * as THREE from 'three' | 
| import { Spin, Descriptions, Button } from 'antd'; | 
| import { FormattedMessage, useIntl, useModel } from '@umijs/max'; | 
| import { LoadingOutlined } from '@ant-design/icons'; | 
| import { createStyles } from 'antd-style'; | 
| import * as Utils from '../../utils' | 
| import Http from '@/utils/http'; | 
| import ShelfThree from './shelfThree' | 
| import BoolValueIcon from '@/components/BoolValueIcon'; | 
|   | 
| const useStyles = createStyles(({ token, css }) => { | 
|     return { | 
|         infoBox: { | 
|             height: '100%', | 
|             display: 'flex', | 
|             gap: '0px', | 
|         }, | 
|         threeInfo: { | 
|             height: '100%', | 
|             width: '60%', | 
|         }, | 
|         spinWrapper: { | 
|             height: '100%', | 
|         }, | 
|         threeContainer: { | 
|             zIndex: 99, | 
|             width: '100%', | 
|             height: '100%', | 
|         }, | 
|         tableInfo: { | 
|             height: '100%', | 
|             width: '40%', | 
|             padding: '0 10px 0 15px', | 
|             overflow: 'auto', | 
|         }, | 
|         tableButton: { | 
|             width: '100%', | 
|             marginBottom: '10px', | 
|             fontWeight: 'bold', | 
|             letterSpacing: '1px', | 
|         } | 
|     } | 
| }) | 
|   | 
| let shelfThree; | 
|   | 
| const startThree = (dom) => { | 
|     shelfThree = new ShelfThree(dom); | 
|     shelfThree.startup(); | 
| } | 
|   | 
| const endThree = () => { | 
|     if (shelfThree) { | 
|         shelfThree.destroy(); | 
|         shelfThree = null; | 
|     } | 
| } | 
|   | 
| const fetchShelfGroup = async (locNo) => { | 
|     const res = await Http.doGet('/api/map/shelf/group', { locNo: locNo }); | 
|     if (res?.data && shelfThree) { | 
|         shelfThree.generateMesh((loader, addObject) => { | 
|             const promises = []; | 
|             const singleHeight = 123; | 
|             for (const item of res.data) { | 
|                 const { lev } = Utils.parseLocNo(item.locNo); | 
|                 promises.push(new Promise((resolve) => { | 
|                     loader.load('model/shelf.fbx', (mesh) => { | 
|                         mesh.position.set(0, singleHeight * (lev - 1), 0); | 
|                         mesh.scale.set(5, 5, 5); | 
|                         mesh.name = item.locNo; | 
|                         mesh.traverse(function (child) { | 
|                             if (child.isMesh) { | 
|                                 if (child.name === '货架') { | 
|                                     child.material.color.set(0x4680BF); | 
|                                 } | 
|                                 let palletVisible = true, cargoVisible = true; | 
|                                 switch (item.locSts) { | 
|                                     case 'D': | 
|                                         cargoVisible = false; | 
|                                         break; | 
|                                     case 'O': | 
|                                         palletVisible = false; | 
|                                         cargoVisible = false; | 
|                                         break; | 
|                                     default: | 
|                                         break; | 
|                                 } | 
|                                 if (child.name === '托盘') { | 
|                                     child.visible = palletVisible; | 
|                                     child.material.color.set(0xBEBEBE); | 
|                                 } | 
|                                 if (child.name === '不规则') { | 
|                                     child.visible = cargoVisible; | 
|                                     child.material.color.set(0xE8B67E); | 
|                                 } | 
|                                 child.name = item.locNo | 
|                                 child.castShadow = true; | 
|                                 child.receiveShadow = true; | 
|                             } | 
|                         }); | 
|                         addObject(mesh); | 
|                         resolve(); | 
|                     }) | 
|                 })); | 
|             } | 
|   | 
|             Promise.all(promises).then(() => { | 
|                 shelfThree.setNewSelectedMesh(locNo); | 
|                 shelfThree.rePerspective(singleHeight * res.data.length, 500); | 
|             }).catch(error => { | 
|                 console.error(error); | 
|             }); | 
|         }) | 
|     } | 
| } | 
|   | 
| const ShelfView = (props) => { | 
|     const intl = useIntl(); | 
|     const { styles } = useStyles(); | 
|     const refContainer = useRef(); | 
|   | 
|     const { data, curFloor, curLocNo, setCurLocNo } = props; | 
|     const [loading, setLoading] = React.useState(false); | 
|     const [info, setInfo] = React.useState(null); | 
|   | 
|     useEffect(() => { | 
|         // init curLocNo | 
|         const originLocNo = data.no + '-' + curFloor; | 
|         setCurLocNo(originLocNo); | 
|   | 
|         endThree(); | 
|         setLoading(true); | 
|   | 
|         setTimeout(() => { | 
|             startThree(refContainer.current); | 
|             shelfThree.handleClick = (objName) => { | 
|                 setCurLocNo(objName); | 
|             }; | 
|             fetchShelfGroup(originLocNo); | 
|             setLoading(false); | 
|         }, 300) | 
|   | 
|         return endThree; | 
|     }, [data]); | 
|   | 
|     useEffect(() => { | 
|         if (!curLocNo) { | 
|             return; | 
|         } | 
|         const fetchShelfInfo = async (locNo) => { | 
|             const res = await Http.doGet('/api/map/shelf/info', { locNo: locNo }); | 
|             if (res?.data) { | 
|                 setInfo(res.data); | 
|             } | 
|         } | 
|         fetchShelfInfo(curLocNo); | 
|     }, [curLocNo]) | 
|   | 
|     return ( | 
|         <> | 
|             <div className={styles.infoBox}> | 
|                 <div className={`${styles.threeInfo} three-spin`}> | 
|                     <Spin | 
|                         spinning={loading} | 
|                         indicator={<LoadingOutlined spin />} | 
|                         size={'large'} | 
|                         wrapperClassName={styles.spinWrapper} | 
|                     > | 
|                         <div ref={refContainer} className={styles.threeContainer}></div> | 
|                     </Spin> | 
|                 </div> | 
|                 <div className={styles.tableInfo}> | 
|                     <Descriptions | 
|                         bordered | 
|                         layout="vertical" | 
|                         column={1} | 
|                         items={ | 
|                             [ | 
|                                 { | 
|                                     label: intl.formatMessage({ id: 'map.loc.no', defaultMessage: '库位号' }), | 
|                                     children: curLocNo, | 
|                                 }, | 
|                                 { | 
|                                     label: intl.formatMessage({ id: 'map.loc.sts', defaultMessage: '库位状态' }), | 
|                                     children: info?.locSts, | 
|                                 }, | 
|                                 { | 
|                                     label: intl.formatMessage({ id: 'map.pallet.barcode', defaultMessage: '托盘条码' }), | 
|                                     children: info?.zpallet, | 
|                                 }, | 
|                                 { | 
|                                     label: intl.formatMessage({ id: 'map.is.enable', defaultMessage: '是否启用' }), | 
|                                     children: <BoolValueIcon value={info?.enable} />, | 
|                                 }, | 
|                                 { | 
|                                     label: intl.formatMessage({ id: 'map.loc.operation', defaultMessage: '库位操作' }), | 
|                                     children: ( | 
|                                         <> | 
|                                             <Button className={styles.tableButton} size='large' type="primary" danger> | 
|                                                 <FormattedMessage id='map.loc.lock' defaultMessage='锁定' /> | 
|                                             </Button> | 
|                                             <Button className={styles.tableButton} size='large' disabled> | 
|                                                 <FormattedMessage id='map.loc.unlock' defaultMessage='解锁' /> | 
|                                             </Button> | 
|                                             <Button className={styles.tableButton} size='large'> | 
|                                                 <FormattedMessage id='map.loc.reset' defaultMessage='清除库位' /> | 
|                                             </Button> | 
|                                         </> | 
|                                     ) | 
|                                 }, | 
|                             ] | 
|                         } | 
|                     /> | 
|                 </div> | 
|             </div> | 
|         </> | 
|     ) | 
| } | 
|   | 
| export default ShelfView; |