Files
ruoyi-vue/src/components/MobileButtonGroup/index.vue
2026-01-05 18:32:29 +08:00

189 lines
3.9 KiB
Vue

<template>
<div class="mobile-button-group" :class="{ 'sticky': sticky }">
<!-- 移动端按钮组 -->
<div v-if="isMobile" class="mobile-buttons">
<!-- 主要操作按钮 -->
<div class="primary-actions" v-if="primaryButtons.length > 0">
<el-button
v-for="btn in primaryButtons"
:key="btn.key || btn.label"
:type="btn.type || 'primary'"
:size="btn.size || 'medium'"
:icon="btn.icon"
:disabled="btn.disabled"
:loading="btn.loading"
@click="handleClick(btn)"
class="action-btn"
>
{{ btn.label }}
</el-button>
</div>
<!-- 更多操作下拉菜单 -->
<el-dropdown
v-if="moreButtons.length > 0"
trigger="click"
placement="top-end"
@command="handleCommand"
>
<el-button
type="default"
size="medium"
icon="el-icon-more"
class="more-btn"
>
更多
</el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item
v-for="btn in moreButtons"
:key="btn.key || btn.label"
:command="btn.key || btn.label"
:disabled="btn.disabled"
:divided="btn.divided"
>
<i :class="btn.icon" v-if="btn.icon"></i>
{{ btn.label }}
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
<!-- 桌面端按钮组 -->
<div v-else class="desktop-buttons">
<slot>
<el-button
v-for="btn in allButtons"
:key="btn.key || btn.label"
:type="btn.type || 'default'"
:size="btn.size || 'mini'"
:icon="btn.icon"
:disabled="btn.disabled"
:loading="btn.loading"
:plain="btn.plain"
@click="handleClick(btn)"
>
{{ btn.label }}
</el-button>
</slot>
</div>
</div>
</template>
<script>
import { mapGetters } from 'vuex'
export default {
name: 'MobileButtonGroup',
props: {
buttons: {
type: Array,
default: () => []
},
primaryCount: {
type: Number,
default: 2
},
sticky: {
type: Boolean,
default: false
}
},
computed: {
...mapGetters(['device']),
isMobile() {
return this.device === 'mobile' || window.innerWidth < 768
},
allButtons() {
return this.buttons || []
},
primaryButtons() {
return this.allButtons.slice(0, this.primaryCount).filter(btn => !btn.hide)
},
moreButtons() {
return this.allButtons.slice(this.primaryCount).filter(btn => !btn.hide)
}
},
methods: {
handleClick(btn) {
if (btn.handler) {
btn.handler()
}
this.$emit('button-click', btn)
},
handleCommand(command) {
const btn = this.moreButtons.find(b => (b.key || b.label) === command)
if (btn) {
this.handleClick(btn)
}
}
}
}
</script>
<style lang="scss" scoped>
.mobile-button-group {
width: 100%;
&.sticky {
position: sticky;
top: 0;
z-index: 100;
background: #fff;
padding: 12px;
margin: -12px -12px 12px -12px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
}
}
.mobile-buttons {
display: flex;
gap: 12px;
padding: 12px;
background: #fff;
border-bottom: 1px solid #e4e7ed;
.primary-actions {
flex: 1;
display: flex;
gap: 12px;
.action-btn {
flex: 1;
height: 44px;
font-size: 15px;
border-radius: 8px;
}
}
.more-btn {
flex-shrink: 0;
width: 60px;
height: 44px;
padding: 0;
border-radius: 8px;
}
}
.desktop-buttons {
display: flex;
gap: 10px;
flex-wrap: wrap;
}
// 桌面端隐藏移动端组件
@media (min-width: 769px) {
.mobile-buttons {
display: none;
}
}
// 移动端隐藏桌面端组件
@media (max-width: 768px) {
.desktop-buttons {
display: none;
}
}
</style>