automated_uniapp/uni_modules/cool-ui/components/cl-select/cl-select.vue
2025-01-09 16:16:11 +08:00

237 lines
4.9 KiB
Vue

<template>
<picker
class="cl-select__wrap"
:mode="mode"
:value="index"
:range="options"
:range-key="rangeKey"
:disabled="disabled"
:end="end"
:start="start"
:fields="fields"
@change="onChange"
@columnchange="onColumnChange"
@cancel="onCancel"
>
<slot :label="text" :value="index">
<cl-select-inner
:height="height"
:placeholder="placeholder"
:disabled="disabled"
:border="border"
:round="round"
:backgroundColor="backgroundColor"
:borderRadius="borderRadius"
:arrowIcon="arrowIcon"
:padding="padding"
:text="text"
/>
</slot>
</picker>
</template>
<script lang="ts">
import { computed, defineComponent, ref, watch, type PropType } from "vue";
import { parseRpx } from "/@/cool/utils";
import { isArray, isEmpty } from "lodash-es";
import { Props } from "../cl-select-inner/config";
export default defineComponent({
name: "cl-select",
props: {
// 绑定值
modelValue: null,
// 模式
mode: {
type: String as PropType<"selector" | "multiSelector" | "region" | "time" | "date">,
default: "selector",
},
// 选项列表
options: {
type: Array as PropType<{ label: string; value: any }[]>,
default: () => [],
},
labelKey: {
type: String,
default: "label",
},
valueKey: {
type: String,
default: "value",
},
separator: {
type: String,
default: "/",
},
fields: {
type: String as PropType<"year" | "month" | "day">,
default: "day",
},
// 开始时间
start: String,
// 结束时间
end: String,
// 默认选中第一个
defaultFirstOption: {
type: Boolean,
default: true,
},
// 设置选项列表时是否解析值
setOptionsIsParseValue: Boolean,
...Props,
},
emits: ["update:modelValue", "confirm", "change", "column-change", "cancel"],
setup(props, { emit }) {
// 选中下标
const index = ref<any>();
// 文本
const text = ref("");
// key
const rangeKey = computed(() => (props.mode == "region" ? "" : props.labelKey));
// 解析值
function parse(val: any) {
// 取下标
index.value = (() => {
switch (props.mode) {
// 返回下标
case "selector":
return props.options.findIndex(
(e: any) => String(e[props.valueKey]) == String(val),
);
// 返回数组
case "multiSelector":
return (isArray(val) ? val : [val]).map((v, i) => {
//@ts-ignore
return props.options[i].findIndex(
(e: any) => String(e[props.valueKey]) == String(v),
);
});
default:
return val;
}
})();
// 取文本值
text.value = (() => {
switch (props.mode) {
case "selector":
return props.options[index.value]
? //@ts-ignore
props.options[index.value][props.labelKey]
: "";
case "multiSelector":
return index.value
.filter((v: any) => v >= 0)
.map(
(v: any, i: number) =>
//@ts-ignore
props.options[i][v][props.labelKey],
)
.join(props.separator);
case "region":
console.warn("请使用 cl-select-region 代替");
default:
return index.value;
}
})();
}
// 监听值
function onChange({ detail }: any) {
if (detail.value < 0 || detail.value === undefined) {
return false;
}
// 返回的完整数据
let data: any = null;
// 返回的唯一数据
let value: any = null;
switch (props.mode) {
case "selector":
data = props.options[detail.value];
value = data ? data[props.valueKey] : null;
break;
case "multiSelector":
data = detail.value
.map((v: any) => (v < 0 ? 0 : v))
.map(
(v: any, i: number) =>
//@ts-ignore
props.options[i][v],
);
value = data.map((e: any) => e[props.valueKey]);
break;
default:
value = detail.value;
}
emit("update:modelValue", value);
emit("confirm", data);
emit("change", value);
}
// 监听列
function onColumnChange({ detail }: any) {
index.value = index.value.map((v: any, i: number) =>
i < detail.column ? v : i === detail.column ? detail.value : 0,
);
emit("column-change", { ...detail, selects: index.value });
}
// 取消
function onCancel() {
emit("cancel");
}
watch(() => props.modelValue, parse, {
immediate: true,
});
watch(
() => props.options,
(arr: any[]) => {
// 避免重复设置 options 异常问题
if (!props.setOptionsIsParseValue) {
parse(props.modelValue);
}
// 为空时,默认返回列表第一个
if (!isEmpty(arr) && props.defaultFirstOption) {
if (
index.value === undefined ||
index.value < 0 ||
index.value === "" ||
index.value === null
) {
emit("update:modelValue", arr[0][props.valueKey]);
}
}
},
{
immediate: true,
},
);
return {
index,
text,
rangeKey,
parse,
onChange,
onColumnChange,
onCancel,
parseRpx,
};
},
});
</script>