Card.vue 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. <template>
  2. <div class="doc-container van-hairline--bottom" @click="clickCard">
  3. <div class="docs-card oneline" v-if="cardType === 'oneline'" key="docs-card">
  4. <div class="docs-header flex-r-c center">
  5. <van-icon :name="docTypeIcon" />
  6. <div class="d-title flex van-ellipsis" v-html="hightLightTitle"></div>
  7. <Price :price="price" />
  8. </div>
  9. </div>
  10. <div class="docs-card image flex-r-c" v-else-if="cardType === 'image'" key="docs-card">
  11. <div class="image-container">
  12. <img v-lazy="imageSrc" />
  13. <van-icon class="doc-type-icon" :name="docTypeIcon" />
  14. </div>
  15. <div class="image-info-container flex-c-c flex">
  16. <div class="d-title van-multi-ellipsis--l2">{{ title }}</div>
  17. <div class="card-info-item">
  18. <div>
  19. <div class="card-info-item uploader" v-if="uploader">贡献者:{{ uploader }}</div>
  20. <div class="subinfo-container subinfo-items">
  21. <span class="subinfo-item" :class="index === subInfo.length - 1 ? 'last' : ''"
  22. v-for="(item, index) in subInfo" :key="index">{{ item }}</span>
  23. </div>
  24. </div>
  25. <div class="card-info-item price">
  26. <slot name="price">
  27. <Price :price="price" v-if="price !== -1" />
  28. </slot>
  29. </div>
  30. </div>
  31. </div>
  32. </div>
  33. <div class="docs-card" v-else key="docs-card">
  34. <div class="docs-header flex-r-c">
  35. <van-icon :name="docTypeIcon" />
  36. <div class="d-title flex van-ellipsis" v-html="hightLightTitle"></div>
  37. </div>
  38. <div class="docs-content docs-desc van-multi-ellipsis--l2" v-if="hightLightDesc" v-html="hightLightDesc"></div>
  39. <div class="docs-footer flex-r-c center">
  40. <div class="c-f-left subinfo-container">
  41. <span class="f-l-item subinfo-item card-time" :class="index === subInfo.length - 1 ? 'last' : ''"
  42. v-for="(item, index) in subInfo" :key="index">{{ item }}</span>
  43. <slot name="leftEnd">
  44. <span class="type-tag"
  45. v-if="productType"
  46. :class="productType === 2 ? 'boutique' : 'free'">{{ productType === 2 ? '付费精品' : '会员免费' }}</span>
  47. </slot>
  48. </div>
  49. <div class="c-f-right flex-r-c">
  50. <slot name="price">
  51. <Price :price="price" v-if="price !== -1" />
  52. </slot>
  53. </div>
  54. </div>
  55. </div>
  56. </div>
  57. </template>
  58. <script lang="ts">
  59. import { Component, Vue, Prop } from 'vue-property-decorator'
  60. import Price from '@/components/docs-card/Price.vue'
  61. import { Icon } from 'vant'
  62. import { replaceKeyword, docTypeConvert } from '@/utils/globalFunctions'
  63. @Component({
  64. name: 'docs-card',
  65. components: {
  66. [Icon.name]: Icon,
  67. Price
  68. }
  69. })
  70. export default class DocsCard extends Vue {
  71. @Prop({ default: '' }) title!: string;
  72. @Prop({ default: '' }) cardType?: string | undefined; // oneline, image
  73. @Prop({ default: '' }) desc?: string | undefined;
  74. @Prop({ default: 'pdf' }) docType?: string | undefined; // 文档类型
  75. @Prop({ default: '' }) imageSrc?: string | undefined;
  76. @Prop({ default: '' }) uploader?: string | undefined;
  77. @Prop({ default: -1 }) price?: string | number;
  78. @Prop({ default: false }) isVip?: boolean;
  79. @Prop({ default: 0 }) productType?: number;
  80. @Prop({
  81. type: Array,
  82. default () {
  83. return []
  84. }
  85. }) subInfo?: Array<string>;
  86. @Prop({
  87. type: Array,
  88. default () {
  89. return []
  90. }
  91. }) highlightKey?: Array<string>;
  92. get docTypeIcon () {
  93. return `diy-${docTypeConvert(this.docType)}`
  94. }
  95. get hightLightTitle () {
  96. return replaceKeyword(this.title, this.highlightKey, [
  97. '<span class="highlight-text">',
  98. '</span>'
  99. ])
  100. }
  101. get hightLightDesc () {
  102. return replaceKeyword(this.desc, this.highlightKey, [
  103. '<span class="highlight-text">',
  104. '</span>'
  105. ])
  106. }
  107. clickCard () {
  108. this.$emit('onClick')
  109. }
  110. }
  111. </script>
  112. <style lang="scss" scoped>
  113. .docs-card {
  114. padding: 16px;
  115. box-sizing: border-box;
  116. background-color: #fff;
  117. .type-tag {
  118. padding: 4px 5px;
  119. border-radius: 2px;
  120. font-size: 10px;
  121. white-space: nowrap;
  122. &.free {
  123. background: linear-gradient(98deg, #FFA674 0%, #F01212 100%);
  124. color: #fff;
  125. }
  126. &.boutique{
  127. background: linear-gradient(270deg, #F1D090 0%, #FAE7CA 100%);
  128. color: #C26F33;
  129. }
  130. }
  131. &.oneline {
  132. padding: 8px 16px;
  133. .docs-header {
  134. .d-title {
  135. margin: 0 6px;
  136. }
  137. }
  138. }
  139. .docs-desc,
  140. .d-title {
  141. ::v-deep {
  142. em {
  143. color: $color_main;
  144. }
  145. }
  146. }
  147. @include diy-icon('pdf');
  148. @include diy-icon('word');
  149. @include diy-icon('excel');
  150. @include diy-icon('ppt');
  151. @include diy-icon('txt');
  152. .docs-header {
  153. .d-title {
  154. margin-left: 4px;
  155. font-size: 16px;
  156. color: #171826;
  157. }
  158. }
  159. .docs-content {
  160. margin-top: 8px;
  161. font-size: 13px;
  162. line-height: 20px;
  163. color: #5F5E64;
  164. }
  165. .docs-footer {
  166. margin-top: 8px;
  167. justify-content: space-between;
  168. }
  169. .subinfo-container {
  170. color: #999;
  171. font-size: 12px;
  172. line-height: 18px;
  173. .subinfo-item {
  174. position: relative;
  175. margin-right: 16px;
  176. &.last {
  177. margin-right: 8px;
  178. }
  179. &.noline:after,
  180. &.last:after {
  181. content: unset;
  182. }
  183. &:after {
  184. content: "";
  185. position: absolute;
  186. top: 50%;
  187. right: -8px;
  188. margin-top: -6px;
  189. width: 1px;
  190. height: 12px;
  191. background-color: rgba($color: #000, $alpha: 0.05);
  192. }
  193. }
  194. }
  195. .image-container {
  196. position: relative;
  197. width: 100px;
  198. height: 124px;
  199. border: 1px solid rgba($color: #000, $alpha: 0.05);
  200. border-radius: 6px;
  201. overflow: hidden;
  202. img {
  203. width: 100%;
  204. height: 100%;
  205. }
  206. .doc-type-icon {
  207. position: absolute;
  208. right: 2px;
  209. bottom: 3px;
  210. }
  211. }
  212. .image-info-container {
  213. margin-left: 17px;
  214. .card-info-item {
  215. margin-top: 2px;
  216. }
  217. .uploader {
  218. color: #999;
  219. font-size: 12px;
  220. line-height: 18px;
  221. }
  222. .price {
  223. margin-top: 8px;
  224. }
  225. }
  226. &:active {
  227. background-color: #f5f6f7;
  228. }
  229. }
  230. </style>