168 lines
4.0 KiB
Vue
168 lines
4.0 KiB
Vue
<template>
|
|
<div class="remote-select-wrapper">
|
|
<el-select
|
|
ref="selectRef"
|
|
v-model="selectedLabel"
|
|
filterable
|
|
remote
|
|
clearable
|
|
remote-show-suffix
|
|
:style="{ minWidth: minWidth }"
|
|
:remote-method="debouncedSearch"
|
|
:loading="loading"
|
|
:placeholder="placeholder"
|
|
@change="handleSelectionChange"
|
|
>
|
|
<el-option
|
|
v-for="item in dataList"
|
|
:key="item.b_id"
|
|
:label="item[labelKey]"
|
|
:value="item[labelKey]"
|
|
/>
|
|
</el-select>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, watch, onMounted, onBeforeUnmount } from 'vue'
|
|
import axios from '@/utils/axios'
|
|
import { debounce } from 'lodash-es'
|
|
|
|
const props = defineProps({
|
|
modelValue: String, // v-model 直接是 labelKey 的值
|
|
tablename: { type: String, required: true },
|
|
labelKey: { type: String, default: 'b_name' }, // 指定显示字段
|
|
initialLabel: String,
|
|
placeholder: { type: String, default: '请输入关键词搜索' },
|
|
minWidth: { type: String, default: '80px' },
|
|
where: { type: String, default: '' },
|
|
})
|
|
|
|
const emit = defineEmits(['update:modelValue', 'change','update:assignment_other_Field'])
|
|
|
|
// 状态
|
|
const loading = ref(false)
|
|
const selectedLabel = ref(props.modelValue || props.initialLabel)
|
|
const dataList = ref([])
|
|
const selectRef = ref()
|
|
|
|
// 初始化
|
|
const initDataList = () => {
|
|
if (props.initialLabel) {
|
|
selectedLabel.value = props.initialLabel
|
|
}
|
|
}
|
|
|
|
// 远程搜索
|
|
const fetchBusinessData = async (query = '') => {
|
|
//console.log(props.where)
|
|
loading.value = true
|
|
try {
|
|
const response = await axios.get('/selectbasicbyfieldname', {
|
|
params: {
|
|
tableName: props.tablename,
|
|
fieldName: props.labelKey,
|
|
where: props.where,
|
|
query,
|
|
_: Date.now(), // 防缓存
|
|
},
|
|
})
|
|
|
|
dataList.value = response.data?.success ? response.data.data.records : []
|
|
// console.log(dataList.value)
|
|
} catch (error) {
|
|
console.error('搜索失败:', error)
|
|
dataList.value = []
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
const debouncedSearch = debounce(fetchBusinessData, 300)
|
|
|
|
// 选择变化
|
|
const handleSelectionChange = (val) => {
|
|
emit('update:modelValue', val)
|
|
emit('change', { label: val })
|
|
|
|
const selected = dataList.value.find(i => i.b_name === val)
|
|
|
|
if(props.tablename === 'b_vessel'){
|
|
const selected_vessel = dataList.value.find(i => i.b_vessel_name === val)
|
|
emit('update:assignment_other_Field', selected_vessel?.b_voy || '')
|
|
}
|
|
if(props.tablename === 'b_money'){
|
|
emit('update:assignment_other_Field', selected?.b_hl || '')
|
|
}
|
|
if(props.tablename === 'v_cw_account'){
|
|
emit('update:assignment_other_Field', selected?.b_account || '')
|
|
}
|
|
}
|
|
|
|
// 输入框选区修复
|
|
const handleSelectCope = () => {
|
|
const root = selectRef.value?.$el
|
|
if (!root) return
|
|
const input = root.querySelector('input')
|
|
|
|
const stopIfSelecting = (e) => {
|
|
let hasSelection = false
|
|
if (
|
|
input &&
|
|
typeof input.selectionStart === 'number' &&
|
|
typeof input.selectionEnd === 'number'
|
|
) {
|
|
hasSelection = input.selectionEnd - input.selectionStart > 0
|
|
}
|
|
if (!hasSelection) {
|
|
const sel = window.getSelection()
|
|
hasSelection = !!sel && !sel.isCollapsed
|
|
}
|
|
if (hasSelection) {
|
|
e.preventDefault()
|
|
e.stopPropagation()
|
|
e.stopImmediatePropagation?.()
|
|
}
|
|
}
|
|
|
|
input?.addEventListener('click', stopIfSelecting, true)
|
|
root.addEventListener('click', stopIfSelecting, true)
|
|
|
|
onBeforeUnmount(() => {
|
|
input?.removeEventListener('click', stopIfSelecting, true)
|
|
root.removeEventListener('click', stopIfSelecting, true)
|
|
})
|
|
}
|
|
|
|
// 监听
|
|
watch(
|
|
() => props.modelValue,
|
|
(newVal) => {
|
|
selectedLabel.value = newVal
|
|
},
|
|
)
|
|
|
|
watch(
|
|
() => props.initialLabel,
|
|
(newVal) => {
|
|
if (newVal) {
|
|
selectedLabel.value = newVal
|
|
}
|
|
},
|
|
)
|
|
|
|
// 初始化
|
|
onMounted(() => {
|
|
handleSelectCope()
|
|
initDataList()
|
|
})
|
|
</script>
|
|
|
|
<style scoped>
|
|
.remote-select-wrapper {
|
|
width: 100%;
|
|
max-width: 500px;
|
|
margin: 0 auto;
|
|
}
|
|
</style>
|