Overview.vue 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. <template>
  2. <div
  3. ref="wrapRef"
  4. class="exh-detail-overview"
  5. :style="{ height: hasMore ? `${height}px` : 'auto' }"
  6. >
  7. <div
  8. class="exh-detail-overview-hd"
  9. data-aria-viewport-area
  10. tabindex="0"
  11. aria-description="You've reached the section of exhibition title, please use the tab key to navigate through the content."
  12. >
  13. <p class="title">{{ detail?.name }}</p>
  14. <div>
  15. <div v-if="detail?.dateStart">
  16. <img :src="DateIcon" style="width: 18px; height: 20px" />
  17. <p style="padding: 0 15px">{{ date }}</p>
  18. </div>
  19. <div v-if="detail?.typeRemark">
  20. <img :src="ClockIcon" style="width: 20px; height: 20px" />
  21. <p style="padding: 0 15px">
  22. {{ detail.typeRemark }}
  23. </p>
  24. </div>
  25. <div>
  26. <img :src="AddressIcon" style="width: 14px; height: 20px" />
  27. <p style="padding-left: 15px">{{ detail?.address }}</p>
  28. </div>
  29. </div>
  30. </div>
  31. <div
  32. ref="mainRef"
  33. class="exh-detail-overview-main"
  34. data-aria-viewport-area
  35. tabindex="0"
  36. aria-description="You've reached the section of exhibition overview, please use the tab key to go through the content."
  37. >
  38. <p class="exh-detail__title" tabindex="0">
  39. <span>Exhibition Overview</span>
  40. </p>
  41. <div
  42. v-for="item in rtf"
  43. :key="item.id"
  44. class="exh-detail-overview__content"
  45. >
  46. <p tabindex="0">{{ item.name }}</p>
  47. <div
  48. v-html="item.txt"
  49. tabindex="0"
  50. :aria-audio-url="
  51. item.fileInfo.filePath ? baseUrl + item.fileInfo.filePath : ''
  52. "
  53. />
  54. </div>
  55. </div>
  56. <div v-if="hasMore" class="exh-detail-overview__more">
  57. <div
  58. tabindex="0"
  59. aria-label="Button"
  60. @click="showMore"
  61. @keydown.enter.passive="showMore"
  62. >
  63. Click here to see more
  64. </div>
  65. </div>
  66. </div>
  67. </template>
  68. <script lang="ts" setup>
  69. import DateIcon from "@/assets/images/bg_5.png";
  70. import ClockIcon from "@/assets/images/bg_6.png";
  71. import AddressIcon from "@/assets/images/bg_7.png";
  72. import { computed, nextTick, ref, watch } from "vue";
  73. import { type ExhibitionDetail } from "@/api";
  74. import { MONTHS } from "@/utils/date";
  75. import { getBaseURL } from "@dage/service";
  76. const props = defineProps<{
  77. detail: null | ExhibitionDetail;
  78. }>();
  79. const baseUrl = getBaseURL();
  80. const wrapRef = ref();
  81. const mainRef = ref();
  82. const hasMore = ref(true);
  83. const height = ref(600);
  84. const rtf = computed<
  85. { id: number; txt: string; name: string; fileInfo: { filePath: string } }[]
  86. >(() => (props.detail ? JSON.parse(props.detail.rtf).txtArr : []));
  87. const date = computed(() => {
  88. if (!props.detail || !props.detail.dateStart) return;
  89. const start = new Date(props.detail.dateStart);
  90. const end = new Date(props.detail.dateEnd);
  91. if (start.getFullYear() === end.getFullYear()) {
  92. return `${MONTHS[start.getDay()]} ${start.getDate()} - ${
  93. MONTHS[end.getDay()]
  94. } ${end.getDate()}, ${end.getFullYear()}`;
  95. }
  96. return `${
  97. MONTHS[start.getDay()]
  98. } ${start.getDate()}, ${start.getFullYear()} - ${
  99. MONTHS[end.getDay()]
  100. } ${end.getDate()}, ${end.getFullYear()}`;
  101. });
  102. watch(
  103. () => props.detail,
  104. (v) => {
  105. if (!v) return;
  106. nextTick(() => {
  107. if (mainRef.value.offsetHeight <= 600) {
  108. hasMore.value = false;
  109. }
  110. });
  111. }
  112. );
  113. const showMore = () => {
  114. const _h = mainRef.value.offsetHeight;
  115. if (height.value + 400 > _h) {
  116. height.value = _h;
  117. hasMore.value = false;
  118. } else {
  119. height.value += 400;
  120. }
  121. };
  122. defineExpose({
  123. wrapRef,
  124. });
  125. </script>
  126. <style lang="scss" scoped>
  127. .exh-detail {
  128. &-overview {
  129. position: relative;
  130. margin-bottom: 40px;
  131. overflow: hidden;
  132. background: var(--white-bg);
  133. border: 1px solid #e0e0e0;
  134. &__content {
  135. > p {
  136. font-weight: bold;
  137. }
  138. :deep(p) {
  139. margin-top: 24px;
  140. font-size: 18px;
  141. line-height: 26px;
  142. word-break: break-all;
  143. color: var(--black2-text-color);
  144. }
  145. }
  146. &-hd {
  147. padding: 40px 210px 20px 40px;
  148. border-bottom: 1px solid #e0e0e0;
  149. .title {
  150. margin-bottom: 10px;
  151. font-size: 30px;
  152. line-height: 44px;
  153. font-weight: bold;
  154. }
  155. > div {
  156. display: flex;
  157. flex-wrap: wrap;
  158. align-items: center;
  159. font-size: 14px;
  160. line-height: 36px;
  161. color: var(--gray-text-color);
  162. width: 940px;
  163. > div {
  164. display: flex;
  165. align-items: center;
  166. }
  167. }
  168. }
  169. &-main {
  170. padding: 30px 40px;
  171. }
  172. &__more {
  173. position: absolute;
  174. bottom: 0;
  175. left: 0;
  176. width: 100%;
  177. height: 100px;
  178. z-index: 98;
  179. &::before {
  180. content: "";
  181. display: block;
  182. height: 50px;
  183. background-image: linear-gradient(
  184. hsla(0, 0%, 100%, 0.4),
  185. var(--white-bg)
  186. );
  187. }
  188. div {
  189. cursor: pointer;
  190. height: 50px;
  191. line-height: 50px;
  192. font-size: 20px;
  193. color: var(--van-primary-color);
  194. text-align: center;
  195. background: var(--white-bg);
  196. }
  197. }
  198. }
  199. }
  200. </style>