FamilyMemberCard.vue 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. <template>
  2. <view class="member-card" :class="{ 'member-card--selected': isSelected }" @click="handleClick">
  3. <view class="member-card__avatar" :class="'avatar-color-' + (member.id % 6)">
  4. <image v-if="member.avatar" class="member-card__avatar-img" :src="member.avatar" mode="aspectFill" />
  5. <text v-else class="member-card__avatar-text">{{ member.nickname && member.nickname[0] || '?' }}</text>
  6. </view>
  7. <text class="member-card__name">{{ member.nickname }}</text>
  8. <view class="member-card__tags">
  9. <text class="member-card__role">{{ member.roleLabel }}</text>
  10. <text v-if="member.danLevel" class="member-card__dan">{{ member.danLevel }}</text>
  11. </view>
  12. <view v-if="isSelected" class="member-card__check">
  13. <text class="member-card__check-icon">✓</text>
  14. </view>
  15. </view>
  16. </template>
  17. <script>
  18. export default {
  19. name: 'FamilyMemberCard',
  20. props: {
  21. member: { type: Object, required: true },
  22. isSelected: { type: Boolean, default: false }
  23. },
  24. methods: {
  25. handleClick() {
  26. this.$emit('select', this.member)
  27. }
  28. }
  29. }
  30. </script>
  31. <style scoped>
  32. .member-card {
  33. display: inline-flex;
  34. flex-direction: column;
  35. align-items: center;
  36. width: 120rpx;
  37. padding: 16rpx 8rpx 12rpx;
  38. border-radius: 16rpx;
  39. background: #FFFFFF;
  40. border: 2rpx solid transparent;
  41. position: relative;
  42. transition: all 0.2s ease;
  43. }
  44. .member-card--selected {
  45. border-color: #5B9BD5;
  46. background: #EBF5FF;
  47. }
  48. .member-card__avatar {
  49. width: 72rpx;
  50. height: 72rpx;
  51. border-radius: 50%;
  52. display: flex;
  53. align-items: center;
  54. justify-content: center;
  55. margin-bottom: 8rpx;
  56. overflow: hidden;
  57. }
  58. .member-card__avatar-img {
  59. width: 72rpx;
  60. height: 72rpx;
  61. border-radius: 50%;
  62. }
  63. .member-card__avatar-text {
  64. font-size: 32rpx;
  65. font-weight: 600;
  66. color: #FFFFFF;
  67. }
  68. .member-card__name {
  69. font-size: 22rpx;
  70. color: #1E293B;
  71. font-weight: 500;
  72. max-width: 104rpx;
  73. overflow: hidden;
  74. text-overflow: ellipsis;
  75. white-space: nowrap;
  76. text-align: center;
  77. line-height: 1.3;
  78. }
  79. .member-card__tags {
  80. display: flex;
  81. flex-direction: column;
  82. align-items: center;
  83. margin-top: 4rpx;
  84. }
  85. .member-card__role {
  86. font-size: 18rpx;
  87. color: #64748B;
  88. line-height: 1.3;
  89. }
  90. .member-card__dan {
  91. font-size: 18rpx;
  92. color: #F97316;
  93. font-weight: 600;
  94. line-height: 1.3;
  95. }
  96. .member-card__check {
  97. position: absolute;
  98. bottom: 0;
  99. right: 0;
  100. width: 32rpx;
  101. height: 32rpx;
  102. background: #5B9BD5;
  103. border-radius: 50% 0 16rpx 0;
  104. display: flex;
  105. align-items: center;
  106. justify-content: center;
  107. }
  108. .member-card__check-icon {
  109. font-size: 18rpx;
  110. color: #FFFFFF;
  111. font-weight: 700;
  112. }
  113. /* Avatar color palette */
  114. .avatar-color-0 { background: #5B9BD5; }
  115. .avatar-color-1 { background: #F08A7A; }
  116. .avatar-color-2 { background: #4CAF50; }
  117. .avatar-color-3 { background: #FFB74D; }
  118. .avatar-color-4 { background: #AB47BC; }
  119. .avatar-color-5 { background: #26A69A; }
  120. </style>