124 lines
3.2 KiB
TypeScript
124 lines
3.2 KiB
TypeScript
import { isEqual } from "lodash-es";
|
|
import { toRef, computed, watch } from "vue";
|
|
import type { Ref } from "vue";
|
|
|
|
interface UsePickerOptions {
|
|
/** 选中的值 */
|
|
value?: unknown[] | Ref<unknown[]>;
|
|
show?: boolean | Ref<boolean>;
|
|
/** 选中的值 */
|
|
indexes?: Array<number | null> | Ref<Array<number | null>>;
|
|
columns?: UViewPlus.PickerColumns | Ref<UViewPlus.PickerColumns>;
|
|
textName?: string;
|
|
valueName?: string;
|
|
placeholder?: string;
|
|
separator?: string;
|
|
}
|
|
|
|
/**
|
|
* 多列 picker
|
|
* @param options 选项
|
|
* @returns
|
|
*/
|
|
export function usePicker(options: UsePickerOptions) {
|
|
const value = toRef(options.value ?? []);
|
|
const show = toRef(options.show ?? false);
|
|
const indexes = toRef(options.indexes ?? []);
|
|
const columns = toRef(options.columns ?? [[]]);
|
|
const textName = toRef(options.textName ?? "text");
|
|
const valueName = toRef(options.valueName ?? "value");
|
|
const placeholder = toRef(options.placeholder ?? "请选择");
|
|
const separator = toRef(options.separator ?? " ");
|
|
|
|
const text = computed(() => {
|
|
const textArray = indexes.value.map((i, index) => {
|
|
if (i == null) return null;
|
|
|
|
const item = columns.value[index][i];
|
|
return item?.[textName.value] ?? null;
|
|
});
|
|
|
|
if (textArray.some((v) => v == null)) {
|
|
return placeholder.value;
|
|
}
|
|
return textArray.join(separator.value);
|
|
});
|
|
|
|
// 监听 indexes 变化,更新 value
|
|
watch(
|
|
[indexes, columns],
|
|
([newIndexes, newColumns]) => {
|
|
console.log("indexes changed:", newIndexes, newColumns);
|
|
if (!newIndexes.length) return;
|
|
const newValue = newIndexes.map((index, columnIndex) => {
|
|
if (index == null) return null;
|
|
const item = newColumns[columnIndex]?.[index];
|
|
return item?.[valueName.value] ?? null;
|
|
});
|
|
|
|
if (!isEqual(newValue, value.value)) {
|
|
value.value = newValue;
|
|
}
|
|
},
|
|
{ immediate: true, deep: true },
|
|
);
|
|
|
|
// 监听 value 变化,更新 indexes
|
|
watch(
|
|
[value, columns],
|
|
([newValue, newColumns]) => {
|
|
console.log("value changed:", newValue, newColumns);
|
|
const newIndexes = newColumns.map((column, columnIndex) => {
|
|
const index = column.findIndex(
|
|
(item) => item[valueName.value] === newValue?.[columnIndex],
|
|
);
|
|
return index >= 0 ? index : null;
|
|
});
|
|
|
|
if (!isEqual(newIndexes, indexes.value)) {
|
|
indexes.value = newIndexes;
|
|
}
|
|
},
|
|
{ immediate: true, deep: true },
|
|
);
|
|
|
|
function handleConfirm(e: UViewPlus.PickerConfirmEvent) {
|
|
console.log("handleConfirm:", e);
|
|
indexes.value = e.indexs;
|
|
}
|
|
|
|
function columnValueToText(v: unknown, colIndex = 0) {
|
|
const currentItem = columns.value[colIndex].find(
|
|
(item) => item[valueName.value] === v,
|
|
);
|
|
return currentItem?.[textName.value];
|
|
}
|
|
|
|
function valueToText(v: unknown[]) {
|
|
return v.map((item, index) => columnValueToText(item, index));
|
|
}
|
|
|
|
function showPicker() {
|
|
show.value = true;
|
|
}
|
|
|
|
function hidePicker() {
|
|
show.value = false;
|
|
}
|
|
|
|
return {
|
|
text,
|
|
value,
|
|
indexes,
|
|
columns,
|
|
handleConfirm,
|
|
valueToText,
|
|
columnValueToText,
|
|
textName,
|
|
valueName,
|
|
show,
|
|
showPicker,
|
|
hidePicker,
|
|
};
|
|
}
|