aiflowy-ui-admin/app/src/components/headerSearch/HeaderSearch.vue

222 lines
4.7 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<script setup>
import { computed, ref } from 'vue';
import { ArrowDown } from '@element-plus/icons-vue';
import {
ElButton,
ElDropdown,
ElDropdownItem,
ElDropdownMenu,
ElIcon,
ElInput,
} from 'element-plus';
import { hasPermission } from '#/api/common/hasPermission.ts';
import { $t } from '#/locales';
// 定义组件属性
const props = defineProps({
// 按钮配置数组
buttons: {
type: Array,
default: () => [],
validator: (value) => {
return value.every((button) => {
return (
typeof button.text === 'string' &&
(button.key || typeof button.key === 'string')
);
});
},
},
// 最大显示按钮数量(不包括下拉菜单)
maxVisibleButtons: {
type: Number,
default: 3,
},
// 搜索框占位符
searchPlaceholder: {
type: String,
default: $t('common.searchPlaceholder'),
},
});
const emit = defineEmits(['search', 'button-click', 'buttonClick']);
// 搜索值
const searchValue = ref('');
// 计算显示的按钮
const visibleButtons = computed(() => {
return props.buttons.slice(0, props.maxVisibleButtons);
});
// 计算下拉菜单中的按钮
const dropdownButtons = computed(() => {
const dropdownButtonsTemp = props.buttons.slice(props.maxVisibleButtons);
if (dropdownButtonsTemp.length === 0) {
return [];
}
return dropdownButtonsTemp.value.filter((action) => {
return hasPermission([action.permission]);
});
});
// 处理搜索
const handleSearch = () => {
emit('search', searchValue.value);
};
const handleReset = () => {
searchValue.value = '';
emit('search', '');
};
// 处理按钮点击
const handleButtonClick = (button) => {
emit('buttonClick', {
type: 'button',
key: button.key,
button,
data: button.data,
});
};
// 处理下拉菜单点击
const handleDropdownClick = (button) => {
emit('buttonClick', {
type: 'dropdown',
key: button.key,
button,
data: button.data,
});
};
</script>
<template>
<div class="custom-header">
<!-- 左侧搜索区域 -->
<div class="header-left">
<div class="search-container">
<div>
<ElInput
v-model="searchValue"
:placeholder="$t('common.searchPlaceholder')"
class="search-input"
@keyup.enter="handleSearch"
clearable
/>
</div>
<div>
<ElButton type="primary" auto-insert-space @click="handleSearch">
{{ $t('button.query') }}
</ElButton>
</div>
<div>
<ElButton auto-insert-space @click="handleReset">
{{ $t('button.reset') }}
</ElButton>
</div>
</div>
</div>
<!-- 右侧按钮区域 -->
<div class="header-right">
<!-- 显示的按钮最多3个 -->
<template
v-for="(button, index) in visibleButtons"
:key="button.key || index"
>
<ElButton
:type="button.type || 'default'"
:icon="button.icon"
:disabled="button.disabled"
v-access:code="button.permission"
@click="handleButtonClick(button)"
>
{{ button.text }}
</ElButton>
</template>
<!-- 下拉菜单(隐藏的按钮) -->
<ElDropdown
v-if="dropdownButtons.length > 0"
@command="handleDropdownClick"
>
<ElButton>
{{ $t('button.more')
}}<ElIcon class="el-icon--right"><ArrowDown /></ElIcon>
</ElButton>
<template #dropdown>
<ElDropdownMenu>
<ElDropdownItem
v-for="button in dropdownButtons"
:key="button.key"
:command="button"
:disabled="button.disabled"
>
<ElIcon v-if="button.icon">
<component :is="button.icon" />
</ElIcon>
<span style="margin-left: 8px">{{ button.text }}</span>
</ElDropdownItem>
</ElDropdownMenu>
</template>
</ElDropdown>
</div>
</div>
</template>
<style scoped>
/* 响应式设计 */
@media (max-width: 768px) {
.custom-header {
flex-direction: column;
gap: 16px;
padding: 12px 16px;
}
.header-left,
.header-right {
justify-content: center;
width: 100%;
}
.search-container {
width: 100%;
}
.header-right {
flex-wrap: wrap;
}
}
.custom-header {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
}
.header-left {
display: flex;
align-items: center;
}
.search-container {
display: flex;
gap: 12px;
}
.search-input {
width: 300px;
border-radius: 4px;
}
.header-right {
display: flex;
gap: 12px;
align-items: center;
}
</style>