index.vue 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. <template>
  2. <div class="avatars-wrap">
  3. <template v-if="tooltip">
  4. <el-tooltip
  5. v-for="(item, $index) in avatarsData"
  6. :key="$index"
  7. :content="item.text"
  8. placement="top"
  9. >
  10. <div
  11. :class="
  12. showAvatar ? 'avatars-item-img' : ['avatars-item', `avatars-${item.type || 'default'}`]
  13. "
  14. >
  15. <el-avatar v-if="showAvatar" :size="40" :src="item.url">
  16. <img :src="defaultImg" />
  17. </el-avatar>
  18. <span v-else>{{ item.text.substr(0, 1) }}</span>
  19. </div>
  20. </el-tooltip>
  21. <div v-if="max && data.length - max > 0" :class="['avatars-item', 'avatars-item-img']">
  22. <span>+{{ data.length - max }}</span>
  23. </div>
  24. </template>
  25. <template v-else>
  26. <div
  27. v-for="(item, $index) in avatarsData"
  28. :key="$index"
  29. :class="
  30. showAvatar ? 'avatars-item-img' : ['avatars-item', `avatars-${item.type || 'default'}`]
  31. "
  32. >
  33. <el-avatar v-if="showAvatar" :size="40" :src="item.url">
  34. <img :src="defaultImg" />
  35. </el-avatar>
  36. <span v-else>{{ item.text.substr(0, 1) }}</span>
  37. </div>
  38. <div v-if="max && data.length - max > 0" :class="['avatars-item', 'avatars-item-img']">
  39. <span>+{{ data.length - max }}</span>
  40. </div>
  41. </template>
  42. </div>
  43. </template>
  44. <script setup lang="ts" name="Avatars">
  45. import { PropType, computed } from 'vue'
  46. import { deepClone } from '@/utils'
  47. import { AvatarConfig } from './types'
  48. import defaultImg from '@/assets/img/default-avatar.png'
  49. const props = defineProps({
  50. // 展示的数据
  51. data: {
  52. type: Array as PropType<AvatarConfig[]>,
  53. default: () => []
  54. },
  55. // 最大展示数量
  56. max: {
  57. type: Number as PropType<number>,
  58. default: 0
  59. },
  60. // 是否使用头像
  61. showAvatar: {
  62. type: Boolean as PropType<boolean>,
  63. default: false
  64. },
  65. // 是否显示完整名称
  66. tooltip: {
  67. type: Boolean as PropType<boolean>,
  68. default: true
  69. }
  70. })
  71. const avatarsData = computed(() => {
  72. if (props.max) {
  73. if (props.data.length <= props.max) {
  74. return props.data
  75. } else {
  76. const data = deepClone(props.data).splice(0, props.max)
  77. return data
  78. }
  79. } else {
  80. return props.data
  81. }
  82. })
  83. </script>
  84. <style lang="less" scoped>
  85. .avatars-wrap {
  86. display: flex;
  87. .avatars-item {
  88. display: inline-block;
  89. width: 40px;
  90. height: 40px;
  91. line-height: 40px;
  92. color: #fff;
  93. text-align: center;
  94. background: #2d8cf0;
  95. border: 1px solid #fff;
  96. border-radius: 50%;
  97. }
  98. .avatars-item-img {
  99. display: inline-block;
  100. border-radius: 50%;
  101. .el-avatar--circle {
  102. border: 1px solid #fff;
  103. }
  104. }
  105. .avatars-item-img + .avatars-item-img {
  106. margin-left: -12px;
  107. }
  108. .avatars-item + .avatars-item {
  109. margin-left: -12px;
  110. }
  111. .avatars-default {
  112. color: #bae7ff;
  113. background: #096dd9;
  114. }
  115. .avatars-success {
  116. color: #f6ffed;
  117. background: #52c41a;
  118. }
  119. .avatars-danger {
  120. color: #fff1f0;
  121. background: #f5222d;
  122. }
  123. .avatars-warning {
  124. color: #fffbe6;
  125. background: #faad14;
  126. }
  127. }
  128. </style>