PaintingList.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468
  1. <template>
  2. <div
  3. class="painting-list"
  4. >
  5. <ul
  6. ref="menuEl"
  7. >
  8. <div
  9. v-for="(paintingGroup, ageName) in menuInfo"
  10. :id="`menu-item-${ageName}`"
  11. :key="ageName"
  12. class="menu-item"
  13. >
  14. <div
  15. class="cover"
  16. :style="{
  17. backgroundImage: `url(${ageRenderInfo[ageName].coverBg})`,
  18. }"
  19. @click="onClickAge(ageName)"
  20. >
  21. <img
  22. class="age"
  23. :src="ageRenderInfo[ageName].artFontImg"
  24. alt=""
  25. draggable="false"
  26. >
  27. <div class="age-en">
  28. {{ `${ageRenderInfo[ageName].En} dynasty` }}
  29. </div>
  30. <div class="author-list">
  31. {{ getAuthorList(paintingGroup).join('\\') }}
  32. </div>
  33. </div>
  34. <div
  35. v-if="ageName !== '清' && !expandedAgeNameList.has(ageName)"
  36. class="splitter"
  37. />
  38. <div
  39. class="hidden-content"
  40. :style="{
  41. width: expandedAgeNameList.has(ageName) ? getHiddenContentWidth(paintingGroup, ageName) : '0',
  42. }"
  43. >
  44. <div
  45. v-if="ageName === '宋'"
  46. class="special-desc"
  47. >
  48. <img
  49. class="title"
  50. src="@/assets/images/painting-menu-special-content-title.png"
  51. alt=""
  52. draggable="false"
  53. >
  54. <p class="desc">
  55. {{ specialDesc }}
  56. </p>
  57. <button
  58. class="see-more"
  59. @click="isShowPaintingStyleDesc = true"
  60. />
  61. </div>
  62. <div
  63. v-for="item in paintingGroup"
  64. :key="item['标题']"
  65. class="painting-item"
  66. @click="router.push({
  67. name: 'PaintingDetailList',
  68. query: {
  69. idx: Number(item['序号']) - 1,
  70. }
  71. })"
  72. >
  73. <div class="top-wrap">
  74. <div
  75. class="author"
  76. :class="{
  77. long: item['作者'].length >= 6,
  78. }"
  79. >
  80. <img
  81. class="bg"
  82. src="@/assets/images/decoration-sun.png"
  83. alt=""
  84. draggable="false"
  85. >
  86. {{ item['作者'] }}
  87. </div>
  88. <div class="title">
  89. {{ item['标题(展示)'].split('\n').join('') }}
  90. </div>
  91. <div class="type">
  92. {{ item['装裱\/材质\/笔类型'] }}
  93. </div>
  94. </div>
  95. <div class="img-wrap">
  96. <img
  97. class="thumb"
  98. :src="`${$env.BASE_URL}configMultiMedia/paintings-thumb/${item['标题']}.jpg`"
  99. alt=""
  100. draggable="false"
  101. >
  102. <img
  103. class="border"
  104. src="@/assets/images/painting-thumb-border.png"
  105. alt=""
  106. draggable="false"
  107. >
  108. </div>
  109. <div class="size">
  110. {{ getPaintingSizeStringForShow(getPaintingSize(item['尺寸'])) }}
  111. </div>
  112. <div class="position">
  113. {{ item['馆藏'] }}
  114. </div>
  115. </div>
  116. </div>
  117. </div>
  118. </ul>
  119. <BtnBack
  120. class="button-back"
  121. @click="router.go(-1)"
  122. />
  123. <OperationTip
  124. class="operation-tip"
  125. direction="h"
  126. :is-show="isShowOperationTip"
  127. />
  128. <Transition name="fade-in-out">
  129. <PaintingStyleDesc
  130. v-if="isShowPaintingStyleDesc"
  131. @close="isShowPaintingStyleDesc = false"
  132. />
  133. </Transition>
  134. </div>
  135. </template>
  136. <script setup>
  137. import { ref, computed, watch, onMounted, inject } from "vue"
  138. import { useRoute, useRouter } from "vue-router"
  139. import { useStore } from "vuex"
  140. import useSizeAdapt from "@/useFunctions/useSizeAdapt"
  141. import PaintingStyleDesc from "@/views/PaintingStyleDesc.vue"
  142. const getPaintingSize = utils.getPaintingSize
  143. const route = useRoute()
  144. const router = useRouter()
  145. const store = useStore()
  146. const $env = inject('$env')
  147. const {
  148. windowSizeInCssForRef,
  149. windowSizeWhenDesignForRef,
  150. } = useSizeAdapt()
  151. const menuEl = ref(null)
  152. const menuElScrollLeft = ref(0)
  153. onMounted(() => {
  154. menuEl.value.addEventListener('scroll', (e) => {
  155. menuElScrollLeft.value = menuEl.value.scrollLeft
  156. })
  157. })
  158. const menuInfo = {}
  159. const temp = configExcel['画作'].map((item) => {
  160. return item['朝代']
  161. })
  162. const ageList = Array.from(new Set(temp))
  163. for (const painting of configExcel['画作']) {
  164. if (!menuInfo[painting['朝代']]) {
  165. menuInfo[painting['朝代']] = []
  166. }
  167. menuInfo[painting['朝代']].push(painting)
  168. }
  169. const ageRenderInfo = {
  170. '宋': {
  171. En: 'Song',
  172. artFontImg: require(`@/assets/images/painting-menu-item-title-song.png`),
  173. coverBg: require(`@/assets/images/painting-menu-item-cover-bg-song.png`),
  174. },
  175. '元': {
  176. En: 'Yuan',
  177. artFontImg: require(`@/assets/images/painting-menu-item-title-yuan.png`),
  178. coverBg: require(`@/assets/images/painting-menu-item-cover-bg-yuan.png`),
  179. },
  180. '明': {
  181. En: 'Ming',
  182. artFontImg: require(`@/assets/images/painting-menu-item-title-ming.png`),
  183. coverBg: require(`@/assets/images/painting-menu-item-cover-bg-ming.png`),
  184. },
  185. '清': {
  186. En: 'Qing',
  187. artFontImg: require(`@/assets/images/painting-menu-item-title-qing.png`),
  188. coverBg: require(`@/assets/images/painting-menu-item-cover-bg-qing.png`),
  189. },
  190. }
  191. function getAuthorList(paintingGroup) {
  192. const temp = paintingGroup.map((item) => {
  193. let author = item['作者']
  194. return author.split('(')[0]
  195. })
  196. return Array.from(new Set(temp))
  197. }
  198. function getPaintingSizeStringForShow({ width, height }) {
  199. return `${width}\u00D7${height} 厘米`
  200. }
  201. const paintingWidthWhenDesign = 240
  202. const paintingMarginWhenDesin = 75
  203. const specialDescWidthWhenDesin = 444
  204. function getHiddenContentWidth(paintingGroup, ageName) {
  205. let temp = paintingGroup.length * (paintingWidthWhenDesign + paintingMarginWhenDesin) + paintingMarginWhenDesin
  206. if (ageName === '宋') {
  207. temp += specialDescWidthWhenDesin
  208. }
  209. return `${temp / windowSizeWhenDesignForRef.value * Number(windowSizeInCssForRef.value.substring(0, windowSizeInCssForRef.value.length - 2))}px`
  210. }
  211. const expandedAgeNameList = ref(new Set())
  212. function onClickAge(ageName) {
  213. if (expandedAgeNameList.value.has(ageName)) {
  214. expandedAgeNameList.value.delete(ageName)
  215. } else {
  216. expandedAgeNameList.value.add(ageName)
  217. const menuItemEl = document.getElementById(`menu-item-${ageName}`)
  218. setTimeout(() => {
  219. menuEl.value.scrollLeft = menuItemEl.offsetLeft
  220. }, 200)
  221. }
  222. }
  223. const specialDesc = configExcel['其他'][4]['修篁树石图'][1]['作品简介'].split('\n')[0]
  224. const isShowPaintingStyleDesc = ref(false)
  225. const isShowOperationTip = ref(true)
  226. watch(menuElScrollLeft, (v) => {
  227. if (v > 0) {
  228. isShowOperationTip.value = false
  229. }
  230. })
  231. </script>
  232. <style lang="less" scoped>
  233. .painting-list{
  234. position: absolute;
  235. left: 0;
  236. top: 0;
  237. width: 100%;
  238. height: 100%;
  239. background-color: #798F69;
  240. >ul{
  241. position: absolute;
  242. left: 0;
  243. top: 0;
  244. width: 100%;
  245. height: 100%;
  246. display: flex;
  247. overflow: auto;
  248. scroll-behavior: smooth;
  249. >.menu-item{
  250. flex: 0 0 auto;
  251. height: 100%;
  252. display: flex;
  253. align-items: center;
  254. >.cover{
  255. flex: 0 0 auto;
  256. height: calc(534 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  257. padding-left: calc(22 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  258. padding-right: calc(22 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  259. writing-mode: vertical-lr;
  260. background-size: cover;
  261. background-repeat: no-repeat;
  262. background-position: center center;
  263. >.age{
  264. margin-top: calc(171 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  265. width: calc(34 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  266. height: calc(44 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  267. }
  268. >.age-en{
  269. margin-top: calc(176 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  270. font-family: KingHwa_OldSong, KingHwa_OldSong;
  271. font-weight: 400;
  272. font-size: calc(20 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  273. color: #FFFFFF;
  274. line-height: calc(23 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  275. }
  276. >.author-list{
  277. margin-top: calc(176 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  278. font-family: KaiTi, KaiTi;
  279. font-weight: 400;
  280. font-size: calc(16 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  281. color: #FFFFFF;
  282. line-height: calc(19 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  283. letter-spacing: 0.2em;
  284. height: 20em;
  285. overflow: hidden;
  286. white-space: pre;
  287. text-overflow: ellipsis;
  288. }
  289. }
  290. >.splitter{
  291. height: calc(534 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  292. width: 1px;
  293. background-color: #fff;
  294. }
  295. >.hidden-content{
  296. transition: width 1s;
  297. overflow: hidden;
  298. display: flex;
  299. align-items: flex-end;
  300. background-color: #f9f7f2;
  301. height: 100%;
  302. background-image: url(@/assets/images/bg-paper.jpg);
  303. background-size: auto 100%;
  304. background-repeat: repeat;
  305. >.special-desc{
  306. flex: 0 0 auto;
  307. align-self: center;
  308. width: calc(v-bind('specialDescWidthWhenDesin') / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  309. display: flex;
  310. justify-content: center;
  311. align-items: center;
  312. >img.title{
  313. flex: 0 0 auto;
  314. width: calc(133 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  315. height: calc(133 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  316. margin-right: calc(12 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  317. }
  318. >p.desc{
  319. writing-mode: vertical-lr;
  320. font-family: KaiTi, KaiTi;
  321. font-weight: 400;
  322. font-size: calc(20 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  323. color: #476446;
  324. line-height: 2;
  325. text-align: justify;
  326. height: calc(552 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  327. letter-spacing: 0.15em;
  328. }
  329. >button.see-more{
  330. width: calc(34 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  331. height: calc(94 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  332. background-image: url(@/assets/images/see-more-btn.png);
  333. background-size: contain;
  334. background-repeat: no-repeat;
  335. background-position: center center;
  336. margin-left: calc(20 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  337. transform: translateY(180%);
  338. }
  339. }
  340. >.painting-item:last-of-type {
  341. margin-right: calc(v-bind('paintingMarginWhenDesin') / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  342. }
  343. >.painting-item{
  344. flex: 0 0 auto;
  345. margin-left: calc(v-bind('paintingMarginWhenDesin') / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  346. width: calc(v-bind('paintingWidthWhenDesign') / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  347. display: flex;
  348. flex-direction: column;
  349. align-items: center;
  350. margin-bottom: calc(230 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  351. >.top-wrap{
  352. margin-bottom: calc(29 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  353. position: relative;
  354. display: flex;
  355. justify-content: center;
  356. align-items: center;
  357. >.author{
  358. writing-mode: vertical-lr;
  359. font-family: KingHwa_OldSong, KingHwa_OldSong;
  360. font-weight: 400;
  361. font-size: calc(34 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  362. color: #474747;
  363. white-space: pre;
  364. transform: translateY(-50%);
  365. margin-right: calc(11 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  366. position: relative;
  367. letter-spacing: 0.3em;
  368. >img.bg{
  369. width: calc(27 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  370. position: absolute;
  371. left: 0;
  372. top: 50%;
  373. transform: translate(-34%, 9%);
  374. z-index: -1;
  375. }
  376. }
  377. >.author.long{
  378. transform: translateY(0);
  379. letter-spacing: initial;
  380. }
  381. >.title{
  382. writing-mode: vertical-lr;
  383. font-family: KingHwa_OldSong, KingHwa_OldSong;
  384. font-weight: 400;
  385. font-size: calc(13 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  386. color: #474747;
  387. white-space: pre;
  388. margin-right: calc(9 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  389. letter-spacing: 0.2em;
  390. }
  391. >.type{
  392. writing-mode: vertical-lr;
  393. font-family: KingHwa_OldSong, KingHwa_OldSong;
  394. font-weight: 400;
  395. font-size: calc(13 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  396. color: #474747;
  397. white-space: pre;
  398. letter-spacing: 0.2em;
  399. }
  400. }
  401. >.img-wrap{
  402. width: calc(240 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  403. height: calc(240 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  404. border-radius: 50%;
  405. overflow: hidden;
  406. margin-bottom: calc(21 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  407. position: relative;
  408. >img.thumb{
  409. width: 100%;
  410. height: 100%;
  411. object-fit: cover;
  412. }
  413. >img.border{
  414. position: absolute;
  415. left: 0;
  416. top: 0;
  417. width: 100%;
  418. height: 100%;
  419. }
  420. }
  421. >.size{
  422. font-family: KingHwa_OldSong, KingHwa_OldSong;
  423. font-weight: 400;
  424. font-size: 13px;
  425. color: #474747;
  426. line-height: 15px;
  427. margin-bottom: 0.5em;
  428. }
  429. >.position{
  430. font-family: KingHwa_OldSong, KingHwa_OldSong;
  431. font-weight: 400;
  432. font-size: 13px;
  433. color: #474747;
  434. line-height: 15px;
  435. }
  436. }
  437. }
  438. }
  439. }
  440. >.operation-tip{
  441. position: absolute;
  442. right: calc(20 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  443. bottom: calc(20 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  444. transform: translateX(-50%);
  445. z-index: 10;
  446. }
  447. }
  448. </style>