web/src/components/SearchInput.vue

208 lines
4.3 KiB
Vue

<template>
<el-popover placement="bottom-start" :visible="isVisible" :width="props.width" ref="popoverRef"
:trigger-keys="[]" style="height: 500px" popper-class="type-popper">
<template #reference>
<el-input
ref="inputRef"
v-model="keyword"
:prefix-icon="Plus"
:placeholder="props.placeholder"
style="width: 100%;height: 100%"
clearable
@input="changeInput"
class="no-border-input"
:disabled="disabled"
@focus="focus"
@blur="handlerBlur"
@click="changeInput"
/>
</template>
<div class="container">
<el-scrollbar>
<table class="table" style="width: 100%; border-collapse: collapse;max-height: 50px">
<!-- 表头 -->
<thead>
<tr class="table-title">
<th
v-for="item in showConfig"
:key="item.prop"
style="background-color: #f5f7fa; padding: 8px;"
>
{{ item.label }}
</th>
</tr>
</thead>
<!-- 表体 -->
<tbody>
<tr class="table-body"
v-for="(item, index) in searchList"
:key="index"
@click="clickRow(item)"
style="cursor: pointer; transition: background-color 0.2s;"
>
<td
v-for="showItem in showConfig"
:key="showItem.prop"
style="vertical-align: middle; padding: 8px;"
>
{{ item[showItem.prop] }}
</td>
</tr>
</tbody>
</table>
</el-scrollbar>
</div>
</el-popover>
</template>
<script setup lang="ts">
import {ref, unref} from "vue";
import {post} from "@/utils/request.ts";
import {Plus} from "@element-plus/icons-vue";
const keyword = ref("");
const popoverRef = ref();
const inputRef = ref();
interface showConfig {
prop: string;
label: string;
}
const props = defineProps({
requestApi: {
type: String,
default: ""
},
width: {
type: Number,
default: 800
},
showConfig: {
type: Array as () => showConfig[],
default: () => []
},
showHeader: {
type: Boolean,
default: true
},
placeholder: {
type: String,
default: ""
},
disabled: {
type: Boolean,
default: false
}
});
const searchList = ref([]);
const changeInput = (inputStr: string) => {
unref(popoverRef).popperRef?.delayHide?.()
if (!props.requestApi || props.requestApi === "") {
return;
}
post(props.requestApi, {keyword: keyword.value}).then((res: any) => {
searchList.value = res;
});
};
const emit = defineEmits(['selectedCallBack', 'focus']);
const clickRow = (row: any) => {
emit('selectedCallBack', row);
popoverRef.value.hide();
keyword.value = ""
};
const beforeShow = () => {
if (searchList.value.length === 0) {
popoverRef.value.hide();
}
};
const isVisible = ref(false)
const focus = () => {
isVisible.value = true
changeInput("")
emit('focus', true)
}
const handlerBlur = () => {
isVisible.value = false
}
</script>
<style scoped lang="scss">
.no-border-input {
:deep(.el-input__wrapper) {
border: none !important;
box-shadow: none !important;
}
:deep(.el-input__inner) {
border: none !important;
box-shadow: none !important;
}
&:hover {
border: 1px solid #409eff !important;
}
}
.table {
th {
background: none !important;
}
.table-title {
height: 52px;
font-weight: 500;
font-size: 14px;
color: #333333;
font-style: normal;
th {
text-align: left;
&:nth-child(1) {
width: 200px;
text-align: left;
border-radius: 8px 8px 0 0;
padding-left: 24px !important;
}
}
}
.table-body {
height: 52px;
font-weight: 500;
font-size: 14px;
color: #666666;
font-style: normal;
td {
&:nth-child(1) {
width: 200px;
text-align: left;
padding-left: 30px !important;
white-space: nowrap; /* 防止文本换行 */
overflow: hidden; /* 隐藏溢出的文本 */
text-overflow: ellipsis; /* 显示省略号 */
}
}
&:last-child {
border-radius: 0 0 8px 8px;
}
&:hover {
background-color: #4D6DE4;
color: #fff;
}
}
}
</style>