159 lines
4.1 KiB
Vue
159 lines
4.1 KiB
Vue
<script setup>
|
|
import { computed, ref, watch } from "vue";
|
|
import { useLookupOptions } from "./select/useLookupOptions";
|
|
|
|
defineOptions({ inheritAttrs: false });
|
|
|
|
const props = defineProps({
|
|
modelValue: { type: null, default: "" },
|
|
label: { type: String, default: "" },
|
|
labelKey: { type: String, default: "b_name" },
|
|
valueKey: { type: String, default: "b_id" },
|
|
viewName: { type: String, required: true },
|
|
searchCondition: { type: String, default: "" },
|
|
searchColumns: { type: Array, default: () => [] },
|
|
orderBy: { type: String, default: "" },
|
|
pageSize: { type: Number, default: 20 },
|
|
searchDelay: { type: Number, default: 300 },
|
|
allowClear: { type: Boolean, default: false },
|
|
});
|
|
|
|
const emit = defineEmits(["update:modelValue", "update:label", "change"]);
|
|
const lookup = useLookupOptions(props);
|
|
const inputValue = ref("");
|
|
const clearedByInput = ref(false);
|
|
|
|
const options = computed(() => {
|
|
const items = lookup.rows.value.map((row) => {
|
|
const label = String(row[props.labelKey] ?? "");
|
|
const value = row[props.valueKey];
|
|
return {
|
|
value: label,
|
|
label,
|
|
key: String(value ?? label),
|
|
rawValue: value,
|
|
record: row,
|
|
};
|
|
});
|
|
|
|
if (props.modelValue !== "" && props.modelValue != null && props.label) {
|
|
const exists = items.some((item) => String(item.rawValue) === String(props.modelValue));
|
|
if (!exists) {
|
|
items.unshift({
|
|
value: props.label,
|
|
label: props.label,
|
|
key: String(props.modelValue),
|
|
rawValue: props.modelValue,
|
|
record: null,
|
|
});
|
|
}
|
|
}
|
|
|
|
return items;
|
|
});
|
|
|
|
watch(
|
|
() => [props.modelValue, props.label],
|
|
() => {
|
|
if (props.modelValue === "" || props.modelValue == null) {
|
|
if (!props.label) inputValue.value = "";
|
|
return;
|
|
}
|
|
clearedByInput.value = false;
|
|
inputValue.value = props.label || "";
|
|
},
|
|
{ immediate: true },
|
|
);
|
|
|
|
function onSearch(value) {
|
|
inputValue.value = String(value ?? "");
|
|
if (!inputValue.value) {
|
|
clearSelection();
|
|
return;
|
|
}
|
|
lookup.search(value);
|
|
}
|
|
|
|
function onInputChange(value) {
|
|
inputValue.value = String(value ?? "");
|
|
if (!inputValue.value) {
|
|
clearSelection();
|
|
return;
|
|
}
|
|
clearedByInput.value = false;
|
|
}
|
|
|
|
function clearSelection() {
|
|
inputValue.value = "";
|
|
clearedByInput.value = true;
|
|
emit("update:modelValue", "");
|
|
emit("update:label", "");
|
|
emit("change", null);
|
|
}
|
|
|
|
function onBlur() {
|
|
if (clearedByInput.value || !inputValue.value) return;
|
|
inputValue.value = props.label || "";
|
|
}
|
|
|
|
function onOpenChange(open) {
|
|
if (open) lookup.open();
|
|
else {
|
|
lookup.resetAfterClose();
|
|
if (clearedByInput.value || !inputValue.value) return;
|
|
inputValue.value = props.label || "";
|
|
}
|
|
}
|
|
|
|
function onSelect(_value, option) {
|
|
const record = option.record ?? null;
|
|
const value = record ? record[props.valueKey] : option.rawValue;
|
|
const label = record ? String(record[props.labelKey] ?? "") : String(option.label ?? "");
|
|
inputValue.value = label;
|
|
clearedByInput.value = false;
|
|
emit("update:modelValue", value ?? "");
|
|
emit("update:label", label);
|
|
emit("change", record);
|
|
}
|
|
|
|
function onInputKeydown(event) {
|
|
if (event.key !== "Backspace" && event.key !== "Delete") return;
|
|
const checkCleared = () => {
|
|
const target = event.target;
|
|
const value = target && "value" in target ? String(target.value ?? "") : inputValue.value;
|
|
if (!value) clearSelection();
|
|
};
|
|
if (typeof requestAnimationFrame === "function") {
|
|
requestAnimationFrame(checkCleared);
|
|
} else {
|
|
setTimeout(checkCleared, 0);
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<a-auto-complete
|
|
v-bind="$attrs"
|
|
class="fms-select"
|
|
:value="inputValue"
|
|
:options="options"
|
|
:show-search="{ onSearch }"
|
|
:not-found-content="lookup.loading.value ? '加载中...' : '暂无数据'"
|
|
:allow-clear="allowClear"
|
|
@change="onInputChange"
|
|
@clear="clearSelection"
|
|
@blur="onBlur"
|
|
@focus="lookup.open"
|
|
@input-keydown="onInputKeydown"
|
|
@open-change="onOpenChange"
|
|
@popup-scroll="lookup.onPopupScroll"
|
|
@select="onSelect"
|
|
/>
|
|
</template>
|
|
|
|
<style scoped lang="scss">
|
|
.fms-select {
|
|
width: 100%;
|
|
}
|
|
</style>
|