| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433 |
- import React, { useCallback, useEffect, useState, useRef } from 'react'
- import styles from './index.module.scss'
- import A21vrOff from './components/A21vrOff'
- import A22hotListWrap from './components/A22hotListWrap'
- import A23pinTop from './components/A23pinTop'
- import A24drawerList from './components/A24drawerList'
- import { useSelector } from 'react-redux'
- import { RootState } from '@/store'
- import classNames from 'classnames'
- import A3hotList from '../A3hotList'
- import { message } from 'antd'
- // import isMobile from '@/utils/isMobile'
- const imgArrTemp = ['like.png', 'likeAc.png']
- const imgArr = imgArrTemp.map(item => require(`@/assets/img/${item}`))
- const SCENE_CODE = 'SG-WVqbTpbkApi_96'
- const LIKE_STORAGE_KEY = `count_like_${SCENE_CODE}`
- const VIEW_STORAGE_KEY = `count_view_${SCENE_CODE}`
- const DEFAULT_LIKE_NUM = 100
- const DEFAULT_VIEW_NUM = 300
- const getLocalCount = (key: string, fallback: number) => {
- try {
- const raw = window.localStorage.getItem(key)
- if (raw == null) return fallback
- const n = Number(raw)
- return Number.isFinite(n) ? n : fallback
- } catch {
- return fallback
- }
- }
- const setLocalCount = (key: string, value: number) => {
- try {
- window.localStorage.setItem(key, String(value))
- } catch {
- // 隐私模式等无法写入时忽略
- }
- }
- const pickCount = (value: unknown) => (typeof value === 'number' && Number.isFinite(value) ? value : null)
- const fetchCountApi = async (url: string) => {
- const response = await fetch(url)
- if (!response.ok) throw new Error('count api failed')
- return response.json()
- }
- const bumpLocalView = () => {
- try {
- const stored = window.localStorage.getItem(VIEW_STORAGE_KEY)
- const next = stored == null ? DEFAULT_VIEW_NUM : getLocalCount(VIEW_STORAGE_KEY, DEFAULT_VIEW_NUM) + 1
- setLocalCount(VIEW_STORAGE_KEY, next)
- return next
- } catch {
- return DEFAULT_VIEW_NUM
- }
- }
- function A2main() {
- // 漫游的状态
- const { state3d } = useSelector((state: RootState) => state.three)
- // 点赞
- const [like, setLike] = useState(false)
- const [likeNum, setLikeNum] = useState(DEFAULT_LIKE_NUM)
- const [viewNum, setViewNum] = useState(DEFAULT_VIEW_NUM)
- const [isShowSection, setIsShowSection] = useState(false)
- useEffect(() => {
- fetchCountApi(`https://count.4dage.com/api/count/detail/${SCENE_CODE}`)
- .then(res => {
- const num = pickCount(res.data?.starSum)
- if (num != null) {
- setLikeNum(num)
- setLocalCount(LIKE_STORAGE_KEY, num)
- return
- }
- setLikeNum(getLocalCount(LIKE_STORAGE_KEY, DEFAULT_LIKE_NUM))
- })
- .catch(() => {
- setLikeNum(getLocalCount(LIKE_STORAGE_KEY, DEFAULT_LIKE_NUM))
- })
- fetchCountApi(`https://count.4dage.com/api/count/saveVisit/${SCENE_CODE}`)
- .then(res => {
- const num = pickCount(res.data?.visitSum)
- if (num != null) {
- setViewNum(num)
- setLocalCount(VIEW_STORAGE_KEY, num)
- return
- }
- setViewNum(bumpLocalView())
- })
- .catch(() => {
- setViewNum(bumpLocalView())
- })
- }, [])
- // 点击点赞
- const likeFu = useCallback(() => {
- if (like) return
- setLike(true)
- setTimeout(() => {
- const applyLocalLike = () => {
- setLikeNum(n => {
- const next = n + 1
- setLocalCount(LIKE_STORAGE_KEY, next)
- return next
- })
- setLike(false)
- }
- fetchCountApi(`https://count.4dage.com/api/count/saveStar/${SCENE_CODE}`)
- .then(res => {
- if (pickCount(res.data?.starSum) != null) {
- const num = pickCount(res.data.starSum)!
- setLikeNum(num)
- setLocalCount(LIKE_STORAGE_KEY, num)
- setLike(false)
- return
- }
- applyLocalLike()
- })
- .catch(applyLocalLike)
- }, 2000)
- }, [like])
- // 点击热点列表
- const [hotListShow, setHotListShow] = useState(false)
- // 点击分享
- const copyWithTextarea = (text: string) => {
- const textArea = document.createElement('textarea')
- textArea.value = text
- textArea.style.position = 'fixed'
- textArea.style.left = '-9999px'
- textArea.style.top = '-9999px'
- document.body.appendChild(textArea)
- textArea.select()
- const copyTXT = document.execCommand('copy')
- document.body.removeChild(textArea)
- return copyTXT
- }
- const handleShareClick = () => {
- if (navigator.clipboard && typeof navigator.clipboard.writeText === 'function') {
- navigator.clipboard.writeText(window.location.href)
- message.success('链接已复制到剪贴板')
- } else {
- copyWithTextarea(window.location.href)
- message.success('链接已复制到剪贴板')
- }
- }
- const sectionBoxRef = useRef<HTMLDivElement>(null);
- const [isActive, setIsActive] = useState(true)
- // 滚动到最左
- const scrollToLeft = () => {
- if (sectionBoxRef.current) {
- sectionBoxRef.current.scrollTo({
- left: 0,
- behavior: 'smooth'
- });
- setIsActive(true)
- }
- };
- // 滚动到最右
- const scrollToRight = () => {
- if (sectionBoxRef.current) {
- sectionBoxRef.current.scrollTo({
- left: sectionBoxRef.current.scrollWidth,
- behavior: 'smooth'
- });
- setIsActive(false)
- }
- };
- useEffect(() => {
- const sections = document.querySelectorAll('.section1, .section2, .section3, .section4, .section5')
- sections.forEach((section, index) => {
- section.setAttribute('data-index', index.toString());
- console.log(section)
- })
- }, [])
- return (
- <div className={styles.A2main} id='gui' style={{ display: 'none' }}>
- <A21vrOff />
- <A22hotListWrap />
- {/* 顶部介绍 */}
- <A23pinTop />
- {/* 主要修改的图标部分 */}
- <div className={classNames('pinBottom-container', state3d === 'panorama' ? '' : 'pinBottom-containerNo')}>
- <div className='pinBottom center'>
- <div id='view-controllers'></div>
- </div>
- <div className='pinBottom left'>
- <div className="logo"><img src={require('@/assets/img/logo.png')} alt="" /></div>
- <div id='gui-modes-map' className='ui-icon double active'>
- <div data-original-title='全景漫游' id='gui-modes-inside' rel='tooltip'>
- <img className='icon icon-inside' src={`images/inside${state3d === 'panorama' ? '_active' : ''}.png`} alt='' />
- {/* 鼠标移入 */}
- <div className='hoveImg'>全景漫游</div>
- </div>
- <div id='play' className='ui-icon' rel='tooltip' data-original-title='播放'>
- {/* eslint-disable-next-line jsx-a11y/anchor-is-valid */}
- <a style={{ width: '100%', height: '100%' }}>
- <img src='images/play.png' alt='' />
- </a>
- {/* 鼠标移入 */}
- <div className='hoveImg'>自动漫游</div>
- </div>
- <div id='pause' className='ui-icon' rel='tooltip' style={{ display: 'none' }}>
- {/* eslint-disable-next-line jsx-a11y/anchor-is-valid */}
- <a style={{ width: '100%', height: '100%' }}>
- <img rel='tooltip' src='images/pause.png' alt='' />
- </a>
- {/* 鼠标移入 */}
- <div className='hoveImg'>暂停漫游</div>
- </div>
- <div id='next' className='next desktop-only ui-icon wide' style={{ display: 'none' }}>
- {/* eslint-disable-next-line jsx-a11y/anchor-is-valid */}
- <a>
- <i rel='tooltip' title='' className='icon icon-dpad-right' data-original-title='下一个'></i>
- </a>
- </div>
- <div data-original-title='导览' id='pullTab' rel='tooltip' title=''>
- <img className='icon icon-inside' src='images/auto.png' alt='' />
- {/* 鼠标移入 */}
- <div className='hoveImg'>导览列表</div>
- </div>
- {/* 原始热点列表---隐藏 */}
- <div data-original-title='热点列表' id='hotList' rel='tooltip' style={{ display: 'none' }}>
- <img className='icon icon-inside' src='images/hotlist.png' title='热点列表' alt='' />
- </div>
- {/* 新的热点列表 */}
- <div
- className='A2hotIcon'
- rel='tooltip'
- onClick={() => {
- window.player.director.stopTour()
- setHotListShow(true)
- // hiddenMap(true)
- }}
- >
- <img src='images/hotlist.png' alt='' />
- <div className='hoveImg'>热点列表</div>
- </div>
- <div data-original-title='迷你模型' id='gui-modes-dollhouse' rel='tooltip'>
- <img className='icon icon-inside' src={`images/dollhouse${state3d === 'dollhouse' ? '_active' : ''}.png`} alt='' />
- {/* 鼠标移入 */}
- <div className='hoveImg'>迷你模型</div>
- </div>
- <div data-original-title='俯视图' id='gui-modes-floorplan' rel='tooltip'>
- <img className='icon icon-inside' src={`images/floor${state3d === 'floorplan' ? '_active' : ''}.png`} alt='' />
- {/* 鼠标移入 */}
- <div className='hoveImg'>顶部视图</div>
- </div>
- {/* <div
- data-original-title='VR'
- id='vr'
- rel='tooltip'
- title=''
- style={{ display: 'none' }}
- >
- <img className='icon icon-inside' src='images/VR.png' title='VR' alt='' />
- </div> */}
- {/* <div
- data-original-title='消除外壳'
- id='gui-remove-face'
- rel='tooltip'
- title=''
- style={{ display: 'none', float: 'left' }}
- >
- <img className='icon icon-inside' src='images/face.jpg' alt='' />
- </div> */}
- </div>
- <img className='splitImg' src={require('../../assets/img/splitImg.png')} alt='' draggable='false' />
- <div className='rightViewContainer clearfix'>
- <div className='gui-floor'>
- <div className='gui-floor-title'></div>
- <div className='gui-floor-icon'>
- <span className='gui-floor-number'></span>
- </div>
- <div className='container'></div>
- </div>
- <div id='volume' className='ui-icon wide'>
- {/* eslint-disable-next-line jsx-a11y/anchor-is-valid */}
- <a>
- <img src='images/Volume btn_on.png' alt='' />
- </a>
- <div className='hoveImg'>音乐开关</div>
- </div>
- {/* 地图 */}
- {/* <div
- className='A2_map_box'
- style={!isMobile() ? { display: 'none' } : {}}
- onClick={() => {
- if (!cad?.style.visibility) {
- hiddenMap(true)
- }
- const isShow = cad?.style.visibility === 'hidden'
- hiddenMap(!isShow)
- }}
- >
- <img src={require('@/assets/img/map.png')} alt='' />
- <div className='hoveImg'>地图</div>
- </div> */}
- {/* 点赞 */}
- <div className='likeBox' onClick={likeFu}>
- <img src={like ? imgArr[1] : imgArr[0]} alt='' />
- <div className='hoveImg'>点赞{likeNum}</div>
- <div className={classNames('likeMove', like ? 'likeMoveAc' : '')}>+1</div>
- </div>
- <div className='A2_share_box' onClick={handleShareClick}>
- <img src={require('@/assets/img/share.png')} alt='' />
- <div className='hoveImg'>分享</div>
- </div>
- <div className='A2_view_box'>
- <img src={require('@/assets/img/view.png')} alt='' />
- <div className='hoveImg'>浏览量{viewNum}</div>
- </div>
- <div id='vr' className='ui-icon wide hidden' style={{ display: 'none' }}>
- {/* eslint-disable-next-line jsx-a11y/anchor-is-valid */}
- <a>
- <i rel='tooltip' title='{[{ VIEW_IN_VR }]}' className='icon icon-webvr'></i>
- </a>
- </div>
- <div id='sharing' className='ui-icon wide hidden' style={{ display: 'none' }}>
- {/* eslint-disable-next-line jsx-a11y/anchor-is-valid */}
- <a>
- <i rel='tooltip' title='{[{ SOCIAL_SHARING }]}' className='icon icon-share'></i>
- </a>
- </div>
- <div id='gui-fullscreen' className='ui-icon wide' data-placement='top' rel='tooltip'>
- {/* eslint-disable-next-line jsx-a11y/anchor-is-valid */}
- <a>
- <img src='images/full.png' alt='' />
- </a>
- {/* 鼠标移入 */}
- <div className='hoveImg'>全屏</div>
- </div>
- <div id='gui-fullscreen-exit' className='ui-icon wide' data-placement='top' rel='tooltip' style={{ display: 'none' }}>
- {/* eslint-disable-next-line jsx-a11y/anchor-is-valid */}
- <a>
- <img src='images/fullx.png' alt='' />
- </a>
- {/* 鼠标移入 */}
- <div className='hoveImg'>关闭全屏</div>
- </div>
- <div className='pull-right terms terms2'>
- {/* eslint-disable-next-line jsx-a11y/anchor-is-valid */}
- <a>{'{[{ TERMS }]}'}</a>
- </div>
- </div>
- </div>
- </div>
- <div
- className='sectionIndex'
- style={{display:'none'}}
- onClick={() => {
- setIsShowSection(true)
- // hiddenMap(true)
- }}
- >
- <img className='sectionIndexImg' src={require('../../assets/img/section.png')} alt='' draggable='false' />
- </div>
- <div className='section' style={{
- pointerEvents: isShowSection ? 'auto' : 'none',
- opacity: isShowSection ? '1' : '0'
- }}>
- {/* <div className="arrL" style={{ opacity: isActive ? '0.1' : '1', cursor: isActive ? 'not-allowed' : 'pointer' }} onClick={scrollToLeft}><img src={require('../../assets/img/preP.png')} alt="" /></div> */}
- {/* <div className="arrR" style={{ opacity: isActive ? '1' : '0.1', cursor: isActive ? 'pointer' : 'not-allowed' }} onClick={scrollToRight}><img src={require('../../assets/img/nextP.png')} alt="" /></div> */}
- <div className='sectionBox' ref={sectionBoxRef} onClick={() => setIsShowSection(false)}>
- <div className='section1 sectionCont' >
- </div>
- <div className='section2 sectionCont'>
- </div>
- <div className='section3 sectionCont'>
- </div>
- <div className='section4 sectionCont'>
- </div>
- <div className='section5 sectionCont'>
- </div>
- </div>
- <div
- className='sectionClose'
- onClick={() => {
- setIsShowSection(false)
- setIsActive(true)
- // hiddenMap(false)
- }}
- >
- <img src={require('../../assets/img/close.png')} alt='' />
- </div>
- </div>
- {/* 底部导览列表 */}
- <A24drawerList />
- {/* 热点列表 */}
- <A3hotList
- show={hotListShow}
- setShow={setHotListShow}
- closeFu={() => {
- setHotListShow(false)
- // hiddenMap(false)
- }}
- />
- </div >
- )
- }
- const MemoA2main = React.memo(A2main)
- export default MemoA2main
|