CommonListCard.vue 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. <template>
  2. <view class="ui-list-card" @click="$emit('click')">
  3. <view class="card-header">
  4. <view class="title-wrap">
  5. <text class="title">{{ title || '未命名标题' }}</text>
  6. </view>
  7. <view
  8. class="status-tag"
  9. v-if="statusLabel"
  10. :class="['status-' + (statusType || 'default')]"
  11. >
  12. {{ statusLabel }}
  13. </view>
  14. </view>
  15. <view class="card-body">
  16. <slot></slot>
  17. </view>
  18. <view class="card-footer" v-if="$slots.footer">
  19. <slot name="footer"></slot>
  20. </view>
  21. <!-- 装饰性元素 -->
  22. <view class="card-accent" :class="['accent-' + (statusType || 'primary')]"></view>
  23. </view>
  24. </template>
  25. <script setup lang="ts">
  26. /**
  27. * UI 通用组件 - 列表卡片
  28. * 封装统一的阴影、圆角、标签定位以及左侧装饰条。
  29. * 适用于:项列表、待办项、审批单等。
  30. */
  31. defineProps<{
  32. /** 标题文字 */
  33. title: string;
  34. /** 状态文字(如:待审批、已完成) */
  35. statusLabel?: string;
  36. /** 状态对应的颜色类型 (success/error/warning/primary/info/default) */
  37. statusType?: string;
  38. }>();
  39. defineEmits(['click']);
  40. </script>
  41. <style lang="scss" scoped>
  42. .ui-list-card {
  43. background-color: #ffffff;
  44. border-radius: 20rpx;
  45. padding: 30rpx 36rpx;
  46. margin-bottom: 24rpx;
  47. box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.03);
  48. position: relative;
  49. overflow: hidden;
  50. transition: all 0.2s;
  51. &:active {
  52. transform: scale(0.985);
  53. background-color: #f8fafc;
  54. box-shadow: 0 2rpx 6rpx rgba(0, 0, 0, 0.02);
  55. }
  56. /* 左侧装饰条 */
  57. .card-accent {
  58. position: absolute;
  59. left: 0;
  60. top: 50%;
  61. transform: translateY(-50%);
  62. width: 8rpx;
  63. height: 100%;
  64. background-color: #1c9bfd;
  65. border-radius: 0 4rpx 4rpx 0;
  66. &.accent-success { background-color: #52c41a; }
  67. &.accent-error { background-color: #ff4d4f; }
  68. &.accent-warning { background-color: #faad14; }
  69. &.accent-info { background-color: #94a3b8; }
  70. &.accent-default { background-color: #e2e8f0; }
  71. }
  72. .card-header {
  73. display: flex;
  74. justify-content: space-between;
  75. align-items: flex-start;
  76. margin-bottom: 24rpx;
  77. padding-bottom: 20rpx;
  78. border-bottom: 2rpx dashed #f1f5f9;
  79. .title-wrap {
  80. flex: 1;
  81. margin-right: 20rpx;
  82. .title {
  83. font-size: 32rpx;
  84. font-weight: 600;
  85. color: #343a3f;
  86. line-height: 1.45;
  87. overflow: hidden;
  88. text-overflow: ellipsis;
  89. display: -webkit-box;
  90. -webkit-line-clamp: 2;
  91. -webkit-box-orient: vertical;
  92. line-clamp: 2;
  93. overflow: hidden;
  94. }
  95. }
  96. .status-tag {
  97. font-size: 24rpx;
  98. padding: 6rpx 18rpx;
  99. border-radius: 8rpx;
  100. white-space: nowrap;
  101. font-weight: 500;
  102. flex-shrink: 0;
  103. &.status-primary { color: #1c9bfd; background-color: rgba(28, 155, 253, 0.1); }
  104. &.status-success { color: #52c41a; background-color: rgba(82, 196, 26, 0.1); }
  105. &.status-error { color: #ff4d4f; background-color: rgba(255, 77, 79, 0.1); }
  106. &.status-warning { color: #faad14; background-color: rgba(250, 173, 20, 0.1); }
  107. &.status-info { color: #94a3b8; background-color: #f1f5f9; }
  108. &.status-default { color: #64748b; background-color: #f8fafc; border: 1rpx solid #e2e8f0; }
  109. }
  110. }
  111. .card-body {
  112. width: 100%;
  113. /* 配合 CommonInfoRow 使用效果最佳 */
  114. }
  115. .card-footer {
  116. margin-top: 24rpx;
  117. padding-top: 20rpx;
  118. border-top: 2rpx solid #f8fafc;
  119. display: flex;
  120. justify-content: flex-end;
  121. }
  122. }
  123. </style>