MenuGrid.vue 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. <template>
  2. <view class="menu-grid">
  3. <view
  4. v-for="m in menus"
  5. :key="m.id"
  6. class="menu-card"
  7. :class="{ 'menu-card--text-only': !m.icon }"
  8. @click="$emit('select', m)"
  9. >
  10. <view
  11. v-if="m.icon"
  12. class="menu-icon"
  13. :class="[toneClass(m), plainClass(m)]"
  14. :style="iconBoxStyle(m)"
  15. >
  16. <VanIcon :name="m.icon" :color="iconFg(m)" :size="iconSize(m)" />
  17. <text v-if="badgeText(m)" class="menu-badge">{{ badgeText(m) }}</text>
  18. </view>
  19. <text
  20. v-if="showGroupTitle && m.groupTitle"
  21. class="menu-group-title"
  22. >{{ m.groupTitle }}</text>
  23. <text class="menu-title">{{ m.title }}</text>
  24. </view>
  25. </view>
  26. </template>
  27. <script>
  28. import VanIcon from './van-icon/van-icon.vue'
  29. import { resolveMenuIconColors } from '../utils/menu-icon-colors.js'
  30. import { formatOaBadgeCount } from '../utils/oa-badge.js'
  31. export default {
  32. name: 'MenuGrid',
  33. components: { VanIcon },
  34. props: {
  35. menus: { type: Array, default: () => [] },
  36. /** 分区标题栏展示区域名时,卡片内不再重复 groupTitle 胶囊 */
  37. showGroupTitle: { type: Boolean, default: true }
  38. },
  39. emits: ['select'],
  40. methods: {
  41. badgeText(m) {
  42. if (!m) return ''
  43. if (m.badge != null && String(m.badge).trim() !== '' && String(m.badge).trim() !== '0') {
  44. if (typeof m.badge === 'number') return formatOaBadgeCount(m.badge)
  45. return String(m.badge).trim()
  46. }
  47. return formatOaBadgeCount(m.badgeCount)
  48. },
  49. colors(m) {
  50. return resolveMenuIconColors(m)
  51. },
  52. iconFg(m) {
  53. return this.colors(m).iconFg || ''
  54. },
  55. isPlainIcon(m) {
  56. const bg = String(this.colors(m).iconBg || '').trim().toLowerCase()
  57. return bg === 'transparent' || bg === 'none'
  58. },
  59. plainClass(m) {
  60. return this.isPlainIcon(m) ? 'menu-icon--plain' : ''
  61. },
  62. iconSize(m) {
  63. return this.isPlainIcon(m) ? '56rpx' : '52rpx'
  64. },
  65. iconBoxStyle(m) {
  66. const { iconBg, iconFg } = this.colors(m)
  67. const style = {}
  68. if (iconBg) style.background = iconBg
  69. if (this.isPlainIcon(m)) style.boxShadow = 'none'
  70. if (iconFg) style.color = iconFg
  71. return style
  72. },
  73. /** 有自定义色时不再套 tone-*,避免绿底覆盖 */
  74. toneClass(m) {
  75. const { iconBg, iconFg } = this.colors(m)
  76. if (iconBg || iconFg) return ''
  77. return m.tone || ''
  78. }
  79. }
  80. }
  81. </script>