MenuGrid.vue 2.2 KB

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