ContactCard.vue 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. <template>
  2. <view class="contact-card" @click="$emit('click', contact)">
  3. <view class="card-avatar" :style="{ background: avatarColor }">
  4. <text class="avatar-text">{{ initial }}</text>
  5. </view>
  6. <text class="card-name">{{ contact.name }}</text>
  7. <view class="card-type-tag" :style="{ background: typeColor + '20', color: typeColor }">
  8. {{ typeLabel }}
  9. </view>
  10. <text class="card-known" v-if="contact.knownSince">
  11. 认识 {{ knownYears }} 年
  12. </text>
  13. <text class="card-phone" v-if="contact.phone">{{ contact.phone }}</text>
  14. <view class="card-intimacy">
  15. <text class="intimacy-heart">❤️</text>
  16. <text class="intimacy-value">{{ contact.intimacyLevel }}</text>
  17. </view>
  18. <text class="card-birthday" v-if="contact.birthdayCountdown">
  19. 🎂 {{ contact.birthdayLabel }} · {{ contact.birthdayCountdown }}
  20. </text>
  21. </view>
  22. </template>
  23. <script>
  24. export default {
  25. props: {
  26. contact: { type: Object, required: true }
  27. },
  28. computed: {
  29. initial: function() {
  30. return this.contact.name ? this.contact.name[0] : '?'
  31. },
  32. typeLabel: function() {
  33. var map = { family: '家人', friend: '朋友', partner: '伴侣', colleague: '同事', other: '其他' }
  34. return map[this.contact.relationshipType] || '其他'
  35. },
  36. typeColor: function() {
  37. var map = { family: '#10B981', friend: '#F59E0B', partner: '#FF6B35', colleague: '#3B82F6', other: '#94A3B8' }
  38. return map[this.contact.relationshipType] || '#94A3B8'
  39. },
  40. avatarColor: function() {
  41. var colors = ['#FF6B35', '#667eea', '#10B981', '#F59E0B', '#8B5CF6', '#EC4899']
  42. var idx = (this.contact.id || 0) % colors.length
  43. return colors[idx]
  44. },
  45. knownYears: function() {
  46. if (!this.contact.knownSince) return 0
  47. var now = new Date()
  48. var known = new Date(this.contact.knownSince)
  49. return Math.floor((now - known) / (365.25 * 86400000))
  50. }
  51. }
  52. }
  53. </script>
  54. <style scoped>
  55. .contact-card {
  56. width: 240rpx;
  57. flex-shrink: 0;
  58. background: #fff;
  59. border-radius: 20rpx;
  60. padding: 24rpx;
  61. margin-right: 16rpx;
  62. box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.06);
  63. display: flex;
  64. flex-direction: column;
  65. align-items: center;
  66. }
  67. .contact-card:active { opacity: 0.7; }
  68. .card-avatar {
  69. width: 80rpx;
  70. height: 80rpx;
  71. border-radius: 40rpx;
  72. display: flex;
  73. align-items: center;
  74. justify-content: center;
  75. margin-bottom: 12rpx;
  76. }
  77. .avatar-text {
  78. font-size: 32rpx;
  79. font-weight: bold;
  80. color: #fff;
  81. }
  82. .card-name {
  83. font-size: 28rpx;
  84. font-weight: bold;
  85. color: #333;
  86. margin-bottom: 8rpx;
  87. }
  88. .card-type-tag {
  89. font-size: 20rpx;
  90. padding: 2rpx 14rpx;
  91. border-radius: 10rpx;
  92. margin-bottom: 8rpx;
  93. }
  94. .card-known { font-size: 22rpx; color: #999; margin-bottom: 4rpx; }
  95. .card-phone { font-size: 22rpx; color: #bbb; margin-bottom: 8rpx; }
  96. .card-intimacy {
  97. display: flex;
  98. align-items: center;
  99. margin-bottom: 6rpx;
  100. }
  101. .intimacy-heart { font-size: 22rpx; margin-right: 4rpx; }
  102. .intimacy-value {
  103. font-size: 28rpx;
  104. font-weight: bold;
  105. color: #FF6B35;
  106. }
  107. .card-birthday {
  108. font-size: 20rpx;
  109. color: #EC4899;
  110. }
  111. </style>