RelicList.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467
  1. <template>
  2. <div class="relic-list">
  3. <button
  4. class="return"
  5. @click="router.go(-1)"
  6. />
  7. <el-cascader
  8. v-model="cascaderValue"
  9. :options="cameraTree"
  10. :props="{
  11. expandTrigger: 'hover',
  12. }"
  13. />
  14. <div class="search-ui">
  15. <input
  16. v-model.trim="keyword"
  17. type="text"
  18. placeholder="请输入要搜索内容"
  19. @keydown.enter="onSearch"
  20. >
  21. <button
  22. class="search"
  23. />
  24. </div>
  25. <div class="the-list">
  26. <div
  27. ref="listEl"
  28. class="content-wrap"
  29. >
  30. <div
  31. v-for="(item, idx) in relicData"
  32. :key="idx"
  33. class="relic-item"
  34. :class="{
  35. hide: !(item.isPassedSearch && item.isPassedSelect)
  36. }"
  37. @click="onClickItem(idx)"
  38. >
  39. <img
  40. class=""
  41. :src="getRelicThumbUrl(idx)"
  42. alt=""
  43. draggable="false"
  44. >
  45. <div
  46. class="name"
  47. :title="item['名称']"
  48. >
  49. {{ item['名称'] }}
  50. </div>
  51. </div>
  52. </div>
  53. </div>
  54. </div>
  55. </template>
  56. <script setup>
  57. /**
  58. * todo: 自动恢复上次滚动位置
  59. */
  60. import { ref, computed, watch, watchEffect, onMounted, nextTick } from "vue"
  61. import { useRoute, useRouter } from "vue-router"
  62. import { useStore } from "vuex"
  63. import useSmoothSwipe from '@/useFunctions/useSmoothSwipe.js'
  64. import { useElementSize } from '@vueuse/core'
  65. const route = useRoute()
  66. const router = useRouter()
  67. const store = useStore()
  68. const cascaderValueInit = (route.query.sceneIdx && route.query.cameraIdx) ? [route.query.sceneIdx, route.query.cameraIdx] : ['all']
  69. const cascaderValue = ref(cascaderValueInit)
  70. const cameraTree = ref([
  71. {
  72. value: 'all',
  73. label: '全部',
  74. },
  75. {
  76. value: '0',
  77. label: '大汗之城',
  78. children: [
  79. {
  80. value: 'all',
  81. label: '全部',
  82. },
  83. {
  84. value: '0',
  85. label: '雄伟帝都',
  86. },
  87. {
  88. value: '1',
  89. label: '大都宫阙',
  90. },
  91. {
  92. value: '2',
  93. label: '大都览胜',
  94. },
  95. ]
  96. },
  97. {
  98. value: '1',
  99. label: '河润大都',
  100. children: [
  101. {
  102. value: 'all',
  103. label: '全部',
  104. },
  105. {
  106. value: '0',
  107. label: '通惠河畅',
  108. },
  109. {
  110. value: '1',
  111. label: '舳舻蔽水',
  112. },
  113. {
  114. value: '2',
  115. label: '繁华富庶',
  116. },
  117. ]
  118. },
  119. {
  120. value: '2',
  121. label: '大都风华',
  122. children: [
  123. {
  124. value: 'all',
  125. label: '全部',
  126. },
  127. {
  128. value: '0',
  129. label: '文人雅集',
  130. },
  131. {
  132. value: '1',
  133. label: '曲苑杂剧',
  134. },
  135. ]
  136. },
  137. ])
  138. const keyword = ref('')
  139. const sceneIdx = computed(() => {
  140. return route.query.sceneIdx
  141. })
  142. const cameraIdx = computed(() => {
  143. return route.query.cameraIdx
  144. })
  145. const relicData = computed(() => {
  146. return store.getters.relicData.map((item) => {
  147. if (cascaderValue.value[0] === 'all') {
  148. item.isPassedSelect = true
  149. } else {
  150. const selectedSceneIdx = Number(cascaderValue.value[0])
  151. const itemSceneIdx = Number(item['镜头ID'].split('-')[0]) - 1
  152. if (selectedSceneIdx !== itemSceneIdx) {
  153. item.isPassedSelect = false
  154. } else {
  155. if (cascaderValue.value[1] === 'all') {
  156. item.isPassedSelect = true
  157. } else {
  158. const selectedCameraIdx = Number(cascaderValue.value[1])
  159. const itemCameraIdx = Number(item['镜头ID'].split('-')[1]) - 1
  160. if (selectedCameraIdx === itemCameraIdx) {
  161. item.isPassedSelect = true
  162. } else {
  163. item.isPassedSelect = false
  164. }
  165. }
  166. }
  167. }
  168. if (!keyword.value) {
  169. item.isPassedSearch = true
  170. } else {
  171. if (item['名称'].includes(keyword.value)) {
  172. item.isPassedSearch = true
  173. } else {
  174. item.isPassedSearch = false
  175. }
  176. }
  177. return item
  178. })
  179. })
  180. function getRelicThumbUrl(idx) {
  181. if (Array.isArray(relicData.value[idx]['图片名']) && relicData.value[idx]['图片名'][0]) {
  182. return `${process.env.BASE_URL}relic-data/small-photo/${relicData.value[idx]['图片名'][0]}`
  183. } else {
  184. return ''
  185. }
  186. }
  187. const listEl = ref(null)
  188. const { width: listWidth, height: listHeight } = useElementSize(listEl)
  189. const { hasOperatedThisTime, updateWidth } = useSmoothSwipe({
  190. scrollTargetRef: listEl,
  191. viewportWidth: listWidth,
  192. })
  193. watch(relicData, (vNew) => {
  194. nextTick(() => {
  195. updateWidth()
  196. })
  197. }, {
  198. deep: true
  199. })
  200. function onClickItem(idx) {
  201. if (!hasOperatedThisTime.value) {
  202. router.push({
  203. name: 'RelicDetail',
  204. query: {
  205. sceneIdx: route.query.sceneIdx,
  206. cameraIdx: route.query.cameraIdx,
  207. relicIdx: idx,
  208. }
  209. })
  210. }
  211. }
  212. </script>
  213. <style lang="less" scoped>
  214. @page-height-design-px: 970;
  215. .relic-list {
  216. height: 100%;
  217. background-image: url(@/assets/images/relic-list-bg.jpg);
  218. background-size: cover;
  219. background-repeat: no-repeat;
  220. background-position: center center;
  221. >button.return {
  222. position: absolute;
  223. width: 58px;
  224. height: 58px;
  225. left: 42px;
  226. top: 68px;
  227. background-image: url(@/assets/images/btn-return.png);
  228. background-size: contain;
  229. background-repeat: no-repeat;
  230. background-position: center center;
  231. }
  232. ::v-deep {
  233. .el-cascader {
  234. position: absolute;
  235. width: 200px;
  236. height: 58px;
  237. left: 160px;
  238. top: 68px;
  239. .el-input {
  240. height: 100%;
  241. background-image: url(@/assets/images/cascader-bg.png);
  242. background-size: 100% 100%;
  243. border: 0;
  244. .el-input__wrapper {
  245. background: none;
  246. border: 0;
  247. box-shadow: none;
  248. .el-input__inner {
  249. height: 100%;
  250. font-size: 30px;
  251. text-align: center;
  252. font-family: 'SourceHanSerifCN-Heavy';
  253. color: #6A3906;
  254. }
  255. .el-input__suffix {
  256. color: #6A3906;
  257. }
  258. }
  259. .icon-arrow-down {
  260. font-size: 24px;
  261. margin-top: 10px;
  262. }
  263. }
  264. }
  265. .el-popper .is-light {
  266. background: red;
  267. }
  268. }
  269. // >menu{
  270. // position: absolute;
  271. // width: 524px;
  272. // height: 66px;
  273. // left: 150px;
  274. // top: 64px;
  275. // background-image: url(@/assets/images/relic-list-page-menu-bg.png);
  276. // background-size: contain;
  277. // background-repeat: no-repeat;
  278. // background-position: center center;
  279. // >button.scene-select{
  280. // position: absolute;
  281. // top: 50%;
  282. // left: 10px;
  283. // transform: translateY(-50%);
  284. // width: 220px;
  285. // height: 50px;
  286. // padding-left: 10px;
  287. // font-size: 30px;
  288. // font-family: Source Han Serif CN, Source Han Serif CN;
  289. // font-weight: bold;
  290. // color: #43310E;
  291. // line-height: 46px;
  292. // letter-spacing: 6px;
  293. // }
  294. // >button.camera-select{
  295. // position: absolute;
  296. // top: 50%;
  297. // left: 230px;
  298. // transform: translateY(-50%);
  299. // width: 160px;
  300. // height: 50px;
  301. // font-size: 24px;
  302. // font-family: Source Han Sans CN, Source Han Sans CN;
  303. // font-weight: 500;
  304. // color: #FFF7D9;
  305. // line-height: 36px;
  306. // letter-spacing: 5px;
  307. // }
  308. // >button.all{
  309. // position: absolute;
  310. // top: 50%;
  311. // left: 400px;
  312. // transform: translateY(-50%);
  313. // width: 100px;
  314. // height: 50px;
  315. // font-size: 24px;
  316. // font-family: Source Han Sans CN, Source Han Sans CN;
  317. // font-weight: 500;
  318. // color: rgba(255,247,217,0.7);
  319. // line-height: 36px;
  320. // letter-spacing: 5px;
  321. // }
  322. // }
  323. >.search-ui {
  324. position: absolute;
  325. top: 65px;
  326. right: 27px;
  327. width: 406px;
  328. height: 62px;
  329. background-image: url(@/assets/images/search-bg.png);
  330. background-size: cover;
  331. background-repeat: no-repeat;
  332. background-position: center center;
  333. >input {
  334. position: absolute;
  335. left: 50px;
  336. top: 50%;
  337. transform: translateY(-50%);
  338. height: 35px;
  339. width: 250PX;
  340. font-size: 24px;
  341. font-family: Source Han Sans CN, Source Han Sans CN;
  342. font-weight: 400;
  343. color: rgba(255, 255, 255, 0.7);
  344. line-height: 28px;
  345. &::placeholder {
  346. font-size: 24px;
  347. font-family: Source Han Sans CN, Source Han Sans CN;
  348. font-weight: 400;
  349. color: rgba(255, 255, 255, 0.3);
  350. line-height: 28px;
  351. }
  352. }
  353. >button.search {
  354. position: absolute;
  355. width: 31px;
  356. height: 31px;
  357. position: absolute;
  358. top: 50%;
  359. right: 53px;
  360. transform: translateY(-50%);
  361. background-image: url(@/assets/images/icon-search.png);
  362. background-size: cover;
  363. background-repeat: no-repeat;
  364. background-position: center center;
  365. }
  366. }
  367. >.the-list {
  368. position: absolute;
  369. left: 0;
  370. top: 150px;
  371. width: 100%;
  372. height: calc(650 / @page-height-design-px * 100vh);
  373. background-image: url(@/assets/images/relic-list-bg-1.png);
  374. background-size: auto 100%;
  375. background-repeat: no-repeat;
  376. background-position: left center;
  377. padding-left: calc(56 / @page-height-design-px * 100vh);
  378. box-sizing: border-box;
  379. >.content-wrap {
  380. &::-webkit-scrollbar {
  381. height: 0;
  382. }
  383. box-sizing: border-box;
  384. height: 100%;
  385. width: 100%;
  386. overflow: auto;
  387. user-select: none;
  388. display: flex;
  389. align-items: center;
  390. background-image: url(@/assets/images/relic-list-bg-2.png);
  391. background-size: auto 92%;
  392. background-repeat: repeat no-repeat;
  393. background-position: left 44%;
  394. background-attachment: local;
  395. padding-top: calc(50 / @page-height-design-px * 100vh);
  396. >.relic-item {
  397. flex: 0 0 auto;
  398. width: calc(290 / @page-height-design-px * 100vh);
  399. height: 80%;
  400. padding: calc(10 / @page-height-design-px * 100vh);
  401. margin-right: calc(100 / @page-height-design-px * 100vh);
  402. display: flex;
  403. flex-direction: column;
  404. justify-content: center;
  405. align-items: center;
  406. cursor: pointer;
  407. >img {
  408. flex: 0 0 auto;
  409. width: 100%;
  410. height: calc(290 / @page-height-design-px * 100vh);
  411. object-fit: contain;
  412. margin-bottom: calc(10 / @page-height-design-px * 100vh);
  413. }
  414. >.name {
  415. text-align: center;
  416. flex: 0 0 auto;
  417. height: 4em;
  418. width: 100%;
  419. font-size: calc(26 / @page-height-design-px * 100vh);
  420. font-family: Source Han Serif CN, Source Han Serif CN;
  421. font-weight: 500;
  422. color: #281D0C;
  423. line-height: calc(32 / @page-height-design-px * 100vh);
  424. display: -webkit-box;
  425. -webkit-box-orient: vertical;
  426. -webkit-line-clamp: 3;
  427. overflow: hidden;
  428. }
  429. }
  430. >.relic-item.hide {
  431. display: none;
  432. }
  433. }
  434. }
  435. }
  436. </style>