20260730231110

This commit is contained in:
oneao committed 2026-07-30 23:11:10 +08:00
1 parent 4929b78434
commit 318fa0d9e1
23 files changed
+4026 -506

No files matched your search

+105 -31
View File
@@ -1,5 +1,5 @@
<script setup>
import { computed } from "vue";
import { computed, ref, watch } from "vue";
import { useLookupOptions } from "./select/useLookupOptions";
defineOptions({ inheritAttrs: false });
@@ -15,69 +15,143 @@ const props = defineProps({
orderBy: { type: String, default: "" },
pageSize: { type: Number, default: 20 },
searchDelay: { type: Number, default: 300 },
allowClear: { type: Boolean, default: true },
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) => ({
value: row[props.valueKey],
label: String(row[props.labelKey] ?? ""),
record: row,
}));
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 &&
!items.some((item) => item.value === props.modelValue)
) {
items.unshift({ value: props.modelValue, label: props.label, record: null });
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;
});
function onOpenChange(open) {
if (open) lookup.open();
else lookup.resetAfterClose();
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 onSelect(value, option) {
emit("update:modelValue", value);
emit("update:label", String(option.label ?? ""));
emit("change", option.record ?? null);
function onInputChange(value) {
inputValue.value = String(value ?? "");
if (!inputValue.value) {
clearSelection();
return;
}
clearedByInput.value = false;
}
function onChange(value) {
if (value !== undefined && value !== null) return;
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-select
<a-auto-complete
v-bind="$attrs"
class="fms-select"
:value="modelValue === '' ? undefined : modelValue"
:value="inputValue"
:options="options"
:loading="lookup.loading.value"
:filter-option="false"
:show-search="{ onSearch }"
:not-found-content="lookup.loading.value ? '加载中...' : '暂无数据'"
:allow-clear="allowClear"
show-search
@search="lookup.search"
@change="onInputChange"
@clear="clearSelection"
@blur="onBlur"
@focus="lookup.open"
@input-keydown="onInputKeydown"
@open-change="onOpenChange"
@popup-scroll="lookup.onPopupScroll"
@select="onSelect"
@change="onChange"
/>
</template>
<style scoped>
<style scoped lang="scss">
.fms-select {
width: 100%;
}