97 lines
2.6 KiB
TypeScript
97 lines
2.6 KiB
TypeScript
import { QSelect } from 'quasar';
|
|
import { Ref, watch } from 'vue';
|
|
|
|
export type SelectProps<T extends (...args: any[]) => any> = {
|
|
params?: Parameters<T>[0];
|
|
creatable?: boolean;
|
|
creatableDisabled?: boolean;
|
|
creatableDisabledText?: string;
|
|
label?: string;
|
|
placeholder?: string;
|
|
readonly?: boolean;
|
|
required?: boolean;
|
|
disabled?: boolean;
|
|
clearable?: boolean;
|
|
autoSelectOnSingle?: boolean;
|
|
};
|
|
|
|
export const createSelect = <T extends Record<string, any>>(
|
|
state: {
|
|
value: Ref<string | null | undefined>;
|
|
valueOption: Ref<T | undefined>;
|
|
selectOptions: Ref<T[]>;
|
|
getByValue: (id: string) => Promise<T | void> | T | void;
|
|
getList: (query?: string) => Promise<T[] | void> | T[] | void;
|
|
},
|
|
opts?: {
|
|
valueField?: keyof T;
|
|
},
|
|
) => {
|
|
const { value, valueOption, selectOptions, getList, getByValue } = state;
|
|
|
|
const valueField = opts?.valueField || 'value';
|
|
|
|
let cache: T[];
|
|
let previousSearch = '';
|
|
|
|
watch(value, (v) => {
|
|
if (!v || (cache && cache.find((opt) => opt[valueField] === v))) return;
|
|
getSelectedOption();
|
|
});
|
|
|
|
async function getOptions(query?: string) {
|
|
if (cache && selectOptions.value.length > 0 && previousSearch === query) {
|
|
selectOptions.value = JSON.parse(JSON.stringify(cache));
|
|
return;
|
|
}
|
|
const ret = await getList(query);
|
|
if (ret) {
|
|
cache = ret;
|
|
selectOptions.value = JSON.parse(JSON.stringify(cache));
|
|
previousSearch = query || previousSearch;
|
|
}
|
|
getSelectedOption();
|
|
}
|
|
|
|
async function setFirstValue() {
|
|
if (value.value) return;
|
|
const first = selectOptions.value.at(0);
|
|
if (first) value.value = first[valueField];
|
|
}
|
|
|
|
async function getSelectedOption() {
|
|
const currentValue = value.value;
|
|
|
|
if (!currentValue) return;
|
|
if (selectOptions.value.find((v) => v[valueField] === currentValue)) return;
|
|
if (valueOption.value && valueOption.value[valueField] === currentValue) {
|
|
return selectOptions.value.unshift(valueOption.value);
|
|
}
|
|
|
|
const ret = await getByValue(currentValue);
|
|
|
|
if (ret) {
|
|
selectOptions.value.unshift(ret);
|
|
valueOption.value = ret;
|
|
}
|
|
}
|
|
|
|
type QuasarSelectUpdate = (
|
|
callback: () => void,
|
|
afterFn?: ((ref: QSelect) => void) | undefined,
|
|
) => void;
|
|
|
|
function filter(value: string, update: QuasarSelectUpdate) {
|
|
update(
|
|
() => getOptions(value),
|
|
(ref) => {
|
|
if (!!value && ref.options && ref.options.length > 0) {
|
|
ref.setOptionIndex(-1);
|
|
ref.moveOptionSelection(1, true);
|
|
}
|
|
},
|
|
);
|
|
}
|
|
|
|
return { getOptions, setFirstValue, getSelectedOption, filter };
|
|
};
|