PaintingList.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463
  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. return item['作者']
  194. })
  195. return Array.from(new Set(temp))
  196. }
  197. function getPaintingSizeStringForShow({ width, height }) {
  198. return `${width}\u00D7${height} 厘米`
  199. }
  200. const paintingWidthWhenDesign = 240
  201. const paintingMarginWhenDesin = 75
  202. const specialDescWidthWhenDesin = 444
  203. function getHiddenContentWidth(paintingGroup, ageName) {
  204. let temp = paintingGroup.length * (paintingWidthWhenDesign + paintingMarginWhenDesin) + paintingMarginWhenDesin
  205. if (ageName === '宋') {
  206. temp += specialDescWidthWhenDesin
  207. }
  208. return `${temp / windowSizeWhenDesignForRef.value * Number(windowSizeInCssForRef.value.substring(0, windowSizeInCssForRef.value.length - 2))}px`
  209. }
  210. const expandedAgeNameList = ref(new Set())
  211. function onClickAge(ageName) {
  212. if (expandedAgeNameList.value.has(ageName)) {
  213. expandedAgeNameList.value.delete(ageName)
  214. } else {
  215. expandedAgeNameList.value.add(ageName)
  216. const menuItemEl = document.getElementById(`menu-item-${ageName}`)
  217. setTimeout(() => {
  218. menuEl.value.scrollLeft = menuItemEl.offsetLeft
  219. }, 200)
  220. }
  221. }
  222. const specialDesc = configExcel['其他'][4]['修篁树石图'][1]['作品简介'].split('\n')[0]
  223. const isShowPaintingStyleDesc = ref(false)
  224. const isShowOperationTip = ref(true)
  225. watch(menuElScrollLeft, (v) => {
  226. if (v > 0) {
  227. isShowOperationTip.value = false
  228. }
  229. })
  230. </script>
  231. <style lang="less" scoped>
  232. .painting-list{
  233. position: absolute;
  234. left: 0;
  235. top: 0;
  236. width: 100%;
  237. height: 100%;
  238. background-color: #99ab8e;
  239. >ul{
  240. position: absolute;
  241. left: 0;
  242. top: 0;
  243. width: 100%;
  244. height: 100%;
  245. display: flex;
  246. overflow: auto;
  247. scroll-behavior: smooth;
  248. >.menu-item{
  249. flex: 0 0 auto;
  250. height: 100%;
  251. display: flex;
  252. align-items: center;
  253. >.cover{
  254. flex: 0 0 auto;
  255. height: calc(534 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  256. padding-left: calc(22 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  257. padding-right: calc(22 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  258. writing-mode: vertical-lr;
  259. background-size: cover;
  260. background-repeat: no-repeat;
  261. background-position: center center;
  262. >.age{
  263. margin-top: calc(171 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  264. width: calc(34 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  265. height: calc(44 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  266. }
  267. >.age-en{
  268. margin-top: calc(176 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  269. font-family: KingHwa_OldSong, KingHwa_OldSong;
  270. font-weight: 400;
  271. font-size: calc(20 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  272. color: #FFFFFF;
  273. line-height: calc(23 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  274. }
  275. >.author-list{
  276. margin-top: calc(176 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  277. font-family: KaiTi, KaiTi;
  278. font-weight: 400;
  279. font-size: calc(16 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  280. color: #FFFFFF;
  281. line-height: calc(19 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  282. letter-spacing: 0.2em;
  283. height: 20em;
  284. overflow: hidden;
  285. white-space: pre;
  286. text-overflow: ellipsis;
  287. }
  288. }
  289. >.splitter{
  290. height: calc(534 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  291. width: 1px;
  292. background-color: #fff;
  293. }
  294. >.hidden-content{
  295. transition: width 1s;
  296. overflow: hidden;
  297. display: flex;
  298. align-items: flex-end;
  299. padding-bottom: calc(230 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  300. background-color: #f9f7f2;
  301. height: 100%;
  302. >.special-desc{
  303. flex: 0 0 auto;
  304. width: calc(v-bind('specialDescWidthWhenDesin') / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  305. display: flex;
  306. justify-content: center;
  307. align-items: center;
  308. >img.title{
  309. flex: 0 0 auto;
  310. width: calc(133 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  311. height: calc(133 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  312. margin-right: calc(12 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  313. }
  314. >p.desc{
  315. writing-mode: vertical-lr;
  316. font-family: KaiTi, KaiTi;
  317. font-weight: 400;
  318. font-size: calc(20 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  319. color: #476446;
  320. line-height: 2;
  321. text-align: justify;
  322. height: calc(552 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  323. letter-spacing: 0.15em;
  324. }
  325. >button.see-more{
  326. width: calc(34 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  327. height: calc(94 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  328. background-image: url(@/assets/images/see-more-btn.png);
  329. background-size: contain;
  330. background-repeat: no-repeat;
  331. background-position: center center;
  332. margin-left: calc(20 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  333. transform: translateY(180%);
  334. }
  335. }
  336. >.painting-item:last-of-type {
  337. margin-right: calc(v-bind('paintingMarginWhenDesin') / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  338. }
  339. >.painting-item{
  340. flex: 0 0 auto;
  341. margin-left: calc(v-bind('paintingMarginWhenDesin') / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  342. width: calc(v-bind('paintingWidthWhenDesign') / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  343. display: flex;
  344. flex-direction: column;
  345. align-items: center;
  346. >.top-wrap{
  347. margin-bottom: calc(29 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  348. position: relative;
  349. display: flex;
  350. justify-content: center;
  351. align-items: center;
  352. >.author{
  353. writing-mode: vertical-lr;
  354. font-family: KingHwa_OldSong, KingHwa_OldSong;
  355. font-weight: 400;
  356. font-size: calc(34 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  357. color: #474747;
  358. white-space: pre;
  359. transform: translateY(-50%);
  360. margin-right: calc(11 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  361. position: relative;
  362. letter-spacing: 0.3em;
  363. >img.bg{
  364. width: calc(27 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  365. position: absolute;
  366. left: 0;
  367. top: 50%;
  368. transform: translate(-34%, 9%);
  369. z-index: -1;
  370. }
  371. }
  372. >.author.long{
  373. transform: translateY(0);
  374. letter-spacing: initial;
  375. }
  376. >.title{
  377. writing-mode: vertical-lr;
  378. font-family: KingHwa_OldSong, KingHwa_OldSong;
  379. font-weight: 400;
  380. font-size: calc(13 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  381. color: #474747;
  382. white-space: pre;
  383. margin-right: calc(9 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  384. letter-spacing: 0.2em;
  385. }
  386. >.type{
  387. writing-mode: vertical-lr;
  388. font-family: KingHwa_OldSong, KingHwa_OldSong;
  389. font-weight: 400;
  390. font-size: calc(13 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  391. color: #474747;
  392. white-space: pre;
  393. letter-spacing: 0.2em;
  394. }
  395. }
  396. >.img-wrap{
  397. width: calc(240 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  398. height: calc(240 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  399. border-radius: 50%;
  400. overflow: hidden;
  401. margin-bottom: calc(21 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  402. position: relative;
  403. >img.thumb{
  404. width: 100%;
  405. height: 100%;
  406. object-fit: cover;
  407. }
  408. >img.border{
  409. position: absolute;
  410. left: 0;
  411. top: 0;
  412. width: 100%;
  413. height: 100%;
  414. }
  415. }
  416. >.size{
  417. font-family: KingHwa_OldSong, KingHwa_OldSong;
  418. font-weight: 400;
  419. font-size: 13px;
  420. color: #474747;
  421. line-height: 15px;
  422. margin-bottom: 0.5em;
  423. }
  424. >.position{
  425. font-family: KingHwa_OldSong, KingHwa_OldSong;
  426. font-weight: 400;
  427. font-size: 13px;
  428. color: #474747;
  429. line-height: 15px;
  430. }
  431. }
  432. }
  433. }
  434. }
  435. >.operation-tip{
  436. position: absolute;
  437. right: calc(20 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  438. bottom: calc(20 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  439. transform: translateX(-50%);
  440. z-index: 10;
  441. }
  442. }
  443. </style>