ua-timeline-item.vue 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. <!-- 自定义TimelineItem组件 -->
  2. <script setup>
  3. import { ref, computed, watch, inject } from 'vue'
  4. import { formatCls, isTrue, addUnit, Int } from './util.js'
  5. const props = defineProps({
  6. type: { type: String, default: '' },
  7. // 时间戳
  8. timestamp: { type: String, default: '' },
  9. // 隐藏时间戳
  10. hideTimestamp: { type: [Boolean, String], default: false },
  11. // 时间戳位置(top / bottom)
  12. placement: { type: String, default: 'bottom' },
  13. // 节点颜色
  14. color: String,
  15. // 节点图标
  16. icon: String,
  17. // 节点尺寸
  18. size: { type: [Number, String], default: 12 },
  19. // 分割线类型(solid / dashed / dotted)
  20. lineType: { type: String, default: 'solid' },
  21. // 分割线颜色
  22. lineColor: String
  23. })
  24. const emit = defineEmits(['click'])
  25. const preClass = formatCls(props, 've__timeline-item--', ['type'])
  26. const lineStyle = computed(() => {
  27. return `
  28. border-left-style: ${props.lineType};
  29. border-left-color: ${props.lineColor};
  30. `
  31. })
  32. const nodeStyle = computed(() => {
  33. return `
  34. background: ${props.color};
  35. height: ${addUnit(Int(props.size))};
  36. width: ${addUnit(Int(props.size))};
  37. left: ${Int(props.size) > 12 ? -(Int(props.size) - 12) / 2 + 'px' : (12 - Int(props.size)) / 2 + 'px'};
  38. `
  39. })
  40. // 事件
  41. const handleClick = (e) => {
  42. emit('click', e)
  43. }
  44. </script>
  45. <template>
  46. <li class="ve__timeline-item" :class="[preClass]">
  47. <!-- 时间线 -->
  48. <div class="ve__timeline-item__line" :style="lineStyle"></div>
  49. <!-- 时间线节点 -->
  50. <div v-if="!$slots.dot" class="ve__timeline-item__node" :style="nodeStyle">
  51. <i v-if="icon" :class="icon"></i>
  52. </div>
  53. <!-- 自定义时间线圆点dot -->
  54. <div v-if="$slots.dot" class="ve__timeline-item__dot" :style="{color}">
  55. <slot name="dot" />
  56. </div>
  57. <!-- 内容区 -->
  58. <div class="ve__timeline-item__body" :style="{'top': addUnit(Int(size) / 2 - 9)}">
  59. <div v-if="!isTrue(hideTimestamp) && placement == 'top'" class="ve__timeline-item__timestamp is-top">{{timestamp}}</div>
  60. <div class="ve__timeline-item__content">
  61. <slot />
  62. </div>
  63. <div v-if="!isTrue(hideTimestamp) && placement == 'bottom'" class="ve__timeline-item__timestamp is-bottom">{{timestamp}}</div>
  64. </div>
  65. </li>
  66. </template>
  67. <style lang="scss" scoped>
  68. $color-primary: #409eff;
  69. $color-success: #31c48d;
  70. $color-warning: #e6a23c;
  71. $color-danger: #f56c6c;
  72. $color-info: #909399;
  73. $color-white: #fff;
  74. $color-black: #000;
  75. /*Hover/Active Color*/
  76. $primary-outline-color: #d9ecff;
  77. /*Font Color*/
  78. $color-text-primary: #303133;
  79. $color-text-regular: #606266;
  80. $color-text-secondary: #909399;
  81. $color-text-placeholder: #c0c4cc;
  82. /*Border Color*/
  83. $border-color-base: #dcdfe6;
  84. $border-color-light: #e4e7ed;
  85. $border-color-lighter: #ebeef5;
  86. $border-color-extra-light: #f2f6fc;
  87. /*Background*/
  88. $background-color-base: #f5f7fa;
  89. /*Box-shadow*/
  90. $box-shadow: 0 3px 9px rgba(0,0,0,.08), 0 3px 3px rgba(0,0,0,.04);
  91. $box-shadow-base: 0 3px 6px -4px rgba(0, 0, 0, 0.12), 0 6px 16px 0 rgba(0, 0, 0, 0.08), 0 9px 28px 8px rgba(0, 0, 0, 0.05);
  92. $box-shadow-light: 0 4px 12px -8px rgba(0, 0, 0, 0.1), 0 6px 18px 0 rgba(0, 0, 0, 0.06), 0 8px 24px 16px rgba(0, 0, 0, 0.03);
  93. $box-shadow-lighter: 0 6px 16px -8px rgba(0, 0, 0, 0.08), 0 9px 28px 0 rgba(0, 0, 0, 0.04), 0 12px 48px 16px rgba(0, 0, 0, 0.03);
  94. $border-width-base: 1px;
  95. $border-style-base: solid;
  96. $border-color-hover: $color-text-placeholder;
  97. $border-base: $border-width-base $border-style-base $border-color-base;
  98. $border-radius-base: 4px;
  99. $border-radius-small: 2px;
  100. $border-radius-circle: 100%;
  101. $border-radius-zero: 0;
  102. $size-base: 14px;
  103. $font-size-extra-large: 18px;
  104. $font-size-large: 16px;
  105. $font-size-base: 14px;
  106. $font-size-small: 12px;
  107. $font-weight-primary: 500;
  108. $font-weight-secondary: 100;
  109. $font-line-height-primary: 24px;
  110. $font-line-height-secondary: 16px;
  111. $font-color-disabled-base: #bbb;
  112. $disabled-fill-base: $background-color-base;
  113. $disabled-color-base: $color-text-placeholder;
  114. $disabled-border-base: $border-color-light;
  115. $height-base: 32px;
  116. $large-height-base: 40px;
  117. $small-height-base: 24px;
  118. /* Timeline
  119. --------------------------------*/
  120. $timeline-font-size: $font-size-base;
  121. $timeline-node-color: $border-color-light;
  122. $timeline-node-size: $font-size-small;
  123. .ve__timeline {
  124. font-size: $timeline-font-size;
  125. margin: 0;
  126. padding: 0;
  127. list-style: none;
  128. }
  129. .ve__timeline-item {padding-bottom: 20px; position: relative;}
  130. .ve__timeline-item:last-child {padding-bottom: 0;}
  131. .ve__timeline-item__line {
  132. border-left: 2px solid $timeline-node-color;
  133. height: 100%;
  134. position: absolute;
  135. left: calc(($timeline-node-size - 2px) / 2);
  136. }
  137. .ve__timeline-item:last-child .ve__timeline-item__line {display: none;}
  138. .ve__timeline-item__node {
  139. display: inline-flex;
  140. align-items: center;
  141. justify-content: center;
  142. background-color: $timeline-node-color;
  143. border-radius: 50%;
  144. height: $timeline-node-size;
  145. width: $timeline-node-size;
  146. position: absolute;
  147. }
  148. .ve__timeline-item__node [class*=ve-icon-] {color: #fff; font-size: inherit;}
  149. .ve__timeline-item__dot {
  150. display: inline-flex;
  151. align-items: center;
  152. justify-content: center;
  153. position: absolute;
  154. }
  155. .ve__timeline-item__body {padding-left: calc($timeline-node-size + 18px); position: relative; top: calc($timeline-node-size / 2 - 9px);}
  156. .ve__timeline-item__content {color: $color-text-primary; font-size: inherit; font-family: system-ui; word-break: break-all;}
  157. .ve__timeline-item__timestamp {
  158. color: $color-text-secondary;
  159. font-size: 12px;
  160. line-height: 1;
  161. }
  162. .ve__timeline-item__timestamp.is-top {margin-bottom: 7px; padding-top: 3px;}
  163. .ve__timeline-item__timestamp.is-bottom {margin-top: 7px;}
  164. /*type*/
  165. .ve__timeline-item--primary .ve__timeline-item__node {background-color: $color-primary;}
  166. .ve__timeline-item--primary .ve__timeline-item__dot {color: $color-primary;}
  167. .ve__timeline-item--success .ve__timeline-item__node {background-color: $color-success;}
  168. .ve__timeline-item--success .ve__timeline-item__dot {color: $color-success;}
  169. .ve__timeline-item--warning .ve__timeline-item__node {background-color: $color-warning;}
  170. .ve__timeline-item--warning .ve__timeline-item__dot {color: $color-warning;}
  171. .ve__timeline-item--danger .ve__timeline-item__node {background-color: $color-danger;}
  172. .ve__timeline-item--danger .ve__timeline-item__dot {color: $color-danger;}
  173. .ve__timeline-item--info .ve__timeline-item__node {background-color: $color-info;}
  174. .ve__timeline-item--info .ve__timeline-item__dot {color: $color-info;}
  175. /*卡片card*/
  176. .ve__timeline--card .ve__timeline-item__content {
  177. border-radius: 4px;
  178. box-shadow: 0 1px 4px $border-color-base;
  179. padding: 20px;
  180. }
  181. </style>