84 lines
2.5 KiB
Vue
84 lines
2.5 KiB
Vue
<template>
|
|
<view class="menu-grid">
|
|
<view
|
|
v-for="m in menus"
|
|
:key="m.id"
|
|
class="menu-card"
|
|
:class="{ 'menu-card--text-only': !m.icon }"
|
|
@click="$emit('select', m)"
|
|
>
|
|
<view
|
|
v-if="m.icon"
|
|
class="menu-icon"
|
|
:class="[toneClass(m), plainClass(m)]"
|
|
:style="iconBoxStyle(m)"
|
|
>
|
|
<VanIcon :name="m.icon" :color="iconFg(m)" :size="iconSize(m)" />
|
|
<text v-if="badgeText(m)" class="menu-badge">{{ badgeText(m) }}</text>
|
|
</view>
|
|
<text
|
|
v-if="showGroupTitle && m.groupTitle"
|
|
class="menu-group-title"
|
|
>{{ m.groupTitle }}</text>
|
|
<text class="menu-title">{{ m.title }}</text>
|
|
</view>
|
|
</view>
|
|
</template>
|
|
|
|
<script>
|
|
import VanIcon from './van-icon/van-icon.vue'
|
|
import { resolveMenuIconColors } from '../utils/menu-icon-colors.js'
|
|
import { formatOaBadgeCount } from '../utils/oa-badge.js'
|
|
|
|
export default {
|
|
name: 'MenuGrid',
|
|
components: { VanIcon },
|
|
props: {
|
|
menus: { type: Array, default: () => [] },
|
|
/** 分区标题栏展示区域名时,卡片内不再重复 groupTitle 胶囊 */
|
|
showGroupTitle: { type: Boolean, default: true }
|
|
},
|
|
emits: ['select'],
|
|
methods: {
|
|
badgeText(m) {
|
|
if (!m) return ''
|
|
if (m.badge != null && String(m.badge).trim() !== '' && String(m.badge).trim() !== '0') {
|
|
if (typeof m.badge === 'number') return formatOaBadgeCount(m.badge)
|
|
return String(m.badge).trim()
|
|
}
|
|
return formatOaBadgeCount(m.badgeCount)
|
|
},
|
|
colors(m) {
|
|
return resolveMenuIconColors(m)
|
|
},
|
|
iconFg(m) {
|
|
return this.colors(m).iconFg || ''
|
|
},
|
|
isPlainIcon(m) {
|
|
const bg = String(this.colors(m).iconBg || '').trim().toLowerCase()
|
|
return bg === 'transparent' || bg === 'none'
|
|
},
|
|
plainClass(m) {
|
|
return this.isPlainIcon(m) ? 'menu-icon--plain' : ''
|
|
},
|
|
iconSize(m) {
|
|
return this.isPlainIcon(m) ? '56rpx' : '52rpx'
|
|
},
|
|
iconBoxStyle(m) {
|
|
const { iconBg, iconFg } = this.colors(m)
|
|
const style = {}
|
|
if (iconBg) style.background = iconBg
|
|
if (this.isPlainIcon(m)) style.boxShadow = 'none'
|
|
if (iconFg) style.color = iconFg
|
|
return style
|
|
},
|
|
/** 有自定义色时不再套 tone-*,避免绿底覆盖 */
|
|
toneClass(m) {
|
|
const { iconBg, iconFg } = this.colors(m)
|
|
if (iconBg || iconFg) return ''
|
|
return m.tone || ''
|
|
}
|
|
}
|
|
}
|
|
</script>
|