index.tsx 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. import React, { useState, useEffect, useRef, useMemo } from 'react'
  2. import styles from './index.module.scss'
  3. import Select from 'antd/es/select'
  4. import Pagination from 'antd/es/pagination'
  5. import { isMobileFu } from '@/utils/history'
  6. import store from '@/store'
  7. import { Swiper, SwiperSlide } from 'swiper/react'
  8. import 'media-chrome';
  9. import 'swiper/css'
  10. import 'swiper/css/effect-coverflow'
  11. import 'swiper/css/pagination'
  12. import 'swiper/css/navigation'
  13. import { EffectCoverflow, Pagination as SwiperPagination, Navigation } from 'swiper/modules'
  14. function Appreciate({
  15. style,
  16. setHidenComplete
  17. }: {
  18. style?: React.CSSProperties
  19. setHidenComplete: (hidenComplete: boolean) => void
  20. }) {
  21. const [currentIndex, setCurrentIndex] = useState<number | undefined>(undefined)
  22. const [isShowInfo, setIsShowInfo] = useState<boolean>(true)
  23. const [oreData1, setOreData1] = useState(oreData)
  24. const [searchText, setSearchText] = useState('')
  25. const [textureFilter, setTextureFilter] = useState('all')
  26. const [typeFilter, setTypeFilter] = useState('all')
  27. // 添加分页状态
  28. const [currentPage, setCurrentPage] = useState(1)
  29. const pageSize = 12
  30. const swiperRef = useRef<any>(null);
  31. const [paginatedData, setPaginatedData] = useState(oreData.slice(0, pageSize))
  32. const filteredData = useMemo(() => {
  33. return oreData
  34. .filter(item => textureFilter === 'all' || item.texture === textureFilter)
  35. .filter(item => typeFilter === 'all' || item.type === typeFilter)
  36. .filter(item => item.title.includes(searchText))
  37. }, [searchText, textureFilter, typeFilter])
  38. useEffect(() => {
  39. setOreData1(filteredData)
  40. // 添加边界检查:如果当前页超出范围,自动跳转到第一页
  41. if (currentPage > Math.ceil(filteredData.length / pageSize) && filteredData.length > 0) {
  42. setCurrentPage(1);
  43. return;
  44. }
  45. // 计算当前页数据
  46. const startIndex = (currentPage - 1) * pageSize
  47. const endIndex = startIndex + pageSize
  48. setPaginatedData(filteredData.slice(startIndex, endIndex))
  49. }, [filteredData, currentPage, pageSize])
  50. // 缓存文物类别选项
  51. const typeOptions = useMemo(() => [
  52. { value: 'all', label: '全部' },
  53. ...Array.from(new Set(oreData.map(item => item.type))).map(type => ({
  54. value: type,
  55. label: type
  56. }))
  57. ], []);
  58. // 缓存质地选项(同理优化)
  59. const textureOptions = useMemo(() => [
  60. { value: 'all', label: '全部' },
  61. ...Array.from(new Set(oreData.map(item => item.texture))).map(texture => ({
  62. value: texture,
  63. label: texture
  64. }))
  65. ], []);
  66. return (
  67. <div className={styles.Appreciate} style={style}>
  68. <div className='top_A'>
  69. {isMobileFu() && <div className='txt_A'>文物赏析</div>}
  70. <div className='search'>
  71. <input
  72. type='text'
  73. value={searchText}
  74. onChange={e => setSearchText(e.target.value)}
  75. placeholder='请输入要查找的文字信息'
  76. />
  77. <img src={require('@/assets/img/search.png')} alt='' />
  78. </div>
  79. <div className='type'>
  80. <div className='label'>文物类别:</div>
  81. <Select
  82. defaultValue={typeFilter}
  83. options={[
  84. ...typeOptions
  85. ]}
  86. onChange={value => setTypeFilter(value)}
  87. />
  88. </div>
  89. <div className='texture'>
  90. <div className='label'>质地:</div>
  91. <Select
  92. defaultValue={textureFilter}
  93. options={[
  94. ...textureOptions
  95. ]}
  96. onChange={value => setTextureFilter(value)}
  97. />
  98. </div>
  99. <div className='total'>文物总数:{oreData.length}件</div>
  100. </div>
  101. <div className='content'>
  102. <div className='scroll'>
  103. {paginatedData.map((item) => (
  104. <div
  105. className={`item`}
  106. key={oreData.indexOf(item)}
  107. onClick={() => { setCurrentIndex(oreData.indexOf(item)); console.log(oreData.indexOf(item)) }}
  108. >
  109. <div className='img'>
  110. <img
  111. src={item.img}
  112. alt=''
  113. loading='lazy'
  114. />
  115. </div>
  116. <div className='txt'>{item.title}</div>
  117. </div>
  118. ))}
  119. </div>
  120. </div>
  121. <div className='page'>
  122. <Pagination
  123. defaultCurrent={1}
  124. total={oreData1.length || 0} // 显示过滤后的总条数
  125. pageSize={pageSize}
  126. onChange={(page) => setCurrentPage(page)} // 页码变化时更新currentPage
  127. />
  128. </div>
  129. {currentIndex !== undefined && (oreData[currentIndex].type === '三维' ? (
  130. <div className='detail'>
  131. <iframe
  132. title='文物展示'
  133. src={oreData[currentIndex]?.modelSrc}
  134. allow='fullscreen'
  135. />
  136. <div className={`info ${isShowInfo ? 'showInfo' : 'hideInfo'}`}>
  137. <div
  138. className='arrow'
  139. onClick={() => {
  140. isMobileFu() ? setIsShowInfo(true) : setIsShowInfo(false)
  141. }}
  142. >
  143. <img
  144. src={require(`@/assets/img/${isMobileFu() ? 'up' : 'left'}.png`)}
  145. alt=''
  146. />
  147. </div>
  148. <div className='content'>
  149. <div className='title'>{oreData[currentIndex]?.title}</div>
  150. {/* <div className="time">年代:{oreData[currentIndex]?.year}</div> */}
  151. <div className='texture'>质地:{oreData[currentIndex]?.texture}</div>
  152. <div className='size'>尺寸:{oreData[currentIndex]?.size}</div>
  153. </div>
  154. <div
  155. className='arrow arrowR'
  156. onClick={() => {
  157. isMobileFu() ? setIsShowInfo(false) : setIsShowInfo(true)
  158. }}
  159. >
  160. <img
  161. src={require(`@/assets/img/${isMobileFu() ? 'down' : 'right'}.png`)}
  162. alt=''
  163. />
  164. </div>
  165. </div>
  166. <div className='close' onClick={() => setCurrentIndex(undefined)}></div>
  167. {/* <div className='bigger' onClick={handleScrollLeft}></div>
  168. <div className='smaller' onClick={handleScrollRight}></div> */}
  169. </div>
  170. ) : (
  171. <div className='detail2'>
  172. <div className='close' onClick={() => setCurrentIndex(undefined)}></div>
  173. <Swiper
  174. ref={swiperRef}
  175. loop={false}
  176. loopPreventsSliding={false}
  177. effect={'slide'}
  178. grabCursor={true}
  179. centeredSlides={true}
  180. slidesPerView={'1'}
  181. coverflowEffect={{
  182. rotate: 0,
  183. stretch: 0,
  184. depth: 0,
  185. modifier: 1,
  186. }}
  187. pagination={{ el: '.swiper-pagination', clickable: true }}
  188. navigation={{
  189. prevEl: '.swiper-button-prev.swiper-button-arr-custom',
  190. nextEl: '.swiper-button-next.swiper-button-arr-custom',
  191. }}
  192. modules={[EffectCoverflow, SwiperPagination, Navigation]}
  193. className='swiper_container'
  194. onTransitionEnd={(swiper: unknown) => {
  195. const swiperInternal = swiper as { loopFix: () => void }
  196. swiperInternal.loopFix()
  197. }}
  198. >
  199. {currentIndex !== undefined && oreData[currentIndex].imgList?.map((item: string, index: number) => (
  200. <SwiperSlide key={index}>
  201. <div
  202. className='itemCard'
  203. key={index}
  204. >
  205. <div className='itemImage'>
  206. <img
  207. onClick={() =>
  208. store.dispatch({
  209. type: 'layout/lookBigImg',
  210. payload: {
  211. url: item,
  212. show: true
  213. }
  214. })
  215. }
  216. src={item}
  217. alt=''
  218. />
  219. </div>
  220. </div>
  221. </SwiperSlide>
  222. ))}
  223. </Swiper>
  224. {/* 添加左右箭头元素 */}
  225. <div className="swiper-button-prev swiper-button-arr-custom">
  226. <img src={require('@/assets/img/left.png')} alt="上一张" />
  227. </div>
  228. <div className="swiper-button-next swiper-button-arr-custom">
  229. <img src={require('@/assets/img/right.png')} alt="下一张" />
  230. </div>
  231. <div className="detail2Info">
  232. <div className="title">{oreData[currentIndex]?.title}</div>
  233. <div className="text">
  234. <div className="texture">质地:{oreData[currentIndex]?.texture}</div>
  235. <div className="size">尺寸:{oreData[currentIndex]?.size}</div>
  236. </div>
  237. </div>
  238. </div>
  239. ))
  240. }
  241. </div >
  242. )
  243. }
  244. const MemoAppreciate = React.memo(Appreciate)
  245. export default MemoAppreciate