| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262 |
- <script setup lang="ts">
- import type { AxiosRequestConfig } from "axios"
- import Rs from "@/core/services/RequestService"
- export interface SelectOptionProp {
- key: string | number
- value: string | number
- label?: string | number //若不设置则默认与value相同
- disabled?: boolean
- }
- export interface SelectProp {
- value: string | number | Array<string> | Array<number>
- name?: string
- url?: string
- method?: string
- configs?: AxiosRequestConfig
- formatFunction?: (data: any) => SelectOptionProp
- staticOptions?: Array<SelectOptionProp>
- data?: Array<any>
- placeholder?: string
- disabled?: boolean
- isSearch?: boolean
- autocomplete?: string
- size?: "large" | "default" | "small" //输入框尺寸
- effect?: "dark " | "light" //Tooltip 主题,内置了 dark / light 两种
- clearable?: boolean //是否可以清空选项
- clearIcon?: string //是否可以清空选项
- multiple?: boolean //是否多选
- multipleLimit?: number //为0时不限制
- placement?:
- | "top"
- | "top-start"
- | "top-end"
- | "bottom"
- | "bottom-start"
- | "bottom-end"
- | "left"
- | "left-start"
- | "left-end"
- | "right"
- | "right-start"
- | "right-end" //下拉框出现的位置
- filterable?: boolean //Select 组件是否可筛选
- filterMethod?: (v: string, o: Array<SelectOptionProp>) => any //自定义筛选方法
- remote?: boolean //其中的选项是否从服务器远程加载
- remoteShowSuffix?: boolean //远程搜索方法显示后缀图标
- remoteMethod?: (v: string, o: Array<SelectOptionProp>) => any //远程搜索方法显示后缀图标
- formatRemoteData?: (v: any) => any
- loading?: boolean //是否正在从远程获取数据
- loadingText?: string //从服务器加载内容时显示的文本
- noMatchText?: string //搜索条件无匹配时显示的文字,也可以使用 empty 插槽设置
- noDataText?: string //搜索条件无匹配时显示的文字,也可以使用 empty 插槽设置
- popperClass?: string //选择器下拉菜单的自定义类名
- suffixIcon?: string //后缀图标组件
- reserveKeyword?: boolean //当 multiple 和 filter被设置为 true 时,是否在选中一个选项后保留当前的搜索关键词
- defaultFirstOption?: boolean //是否在输入框按下回车时,选择第一个匹配项。 需配合 filterable 或 remote 使用
- popperAppendToBody?: boolean //是否将弹出框插入至 body 元素 当弹出框的位置出现问题时,你可以尝试将该属性设置为false
- teleported?: boolean //该下拉菜单是否使用teleport插入body元素
- persistent?: boolean //当下拉选择器未被激活并且persistent设置为false,选择器会被删除。
- automatiDropdown?: boolean //对于不可过滤的 Select 组件,此属性决定是否在输入框获得焦点后自动弹出选项菜单
- fitInputWidth?: boolean //下拉框的宽度是否与输入框相同
- validateEvent?: boolean //是否触发表单验证
- }
- const props = withDefaults(defineProps<SelectProp>(), {
- value: "",
- url: "",
- method: "get",
- configs: undefined,
- multiple: false,
- multipleLimit: 0,
- filterable: false,
- remote: false,
- formatRemoteData: (v: any) => {
- return v
- },
- loading: false,
- loadingText: "加载中...",
- noMatchText: "没有匹配项",
- noDataText: "未查询到数据",
- isSearch: false,
- disabled: false,
- clearable: false,
- clearIcon: "CircleClose",
- effect: "light",
- size: "default",
- placement: "bottom-start",
- autocomplete: "off",
- placeholder: "请选择",
- popperClass: "",
- suffixIcon: "ArrowDown",
- defaultFirstOption: false,
- reserveKeyword: true,
- popperAppendToBody: true,
- teleported: true,
- persistent: true,
- automatiDropdown: false,
- fitInputWidth: false,
- validateEvent: false,
- })
- const emits = defineEmits<{
- (e: "update:value", v: string | number | Array<string> | Array<number>): void
- (e: "change", v: string | number | Array<string> | Array<number>): void
- (e: "visible-change", v: boolean): void //下拉框出现/隐藏时触发 出现则为 true,隐藏则为 false
- (e: "remove-tag", v: string | number | Array<string> | Array<number>): void
- (e: "clear"): void
- (e: "blur", v: FocusEvent): void
- (e: "focus", v: FocusEvent): void
- }>()
- const { value, url } = toRefs(props)
- const loading = ref(props.loading)
- const remote = ref(props.remote)
- const filterable = ref(props.filterable)
- const _staticOptions = ref<Array<SelectOptionProp>>()
- const options = ref<Array<SelectOptionProp>>(_staticOptions.value ?? [])
- let remoteFunction: (v: string) => void
- function init() {
- _staticOptions.value = Object.assign([], props.staticOptions || [], formatSelectData(props.data) ?? [])
- if (props.remoteMethod) {
- filterable.value = true
- remote.value = true
- remoteFunction = (v: string) => {
- props.remoteMethod && props.remoteMethod(v, options.value)
- loading.value = false
- }
- } else if (props.url) {
- filterable.value = true
- remote.value = true
- const configs = Object.assign({}, { url: url.value, method: props.method, successAlert: false }, props.configs)
- remoteFunction = (query: string) => {
- options.value = Object.assign([], _staticOptions.value ?? [])
- console.log("======>", options.value, "=", _staticOptions.value)
- if (!props.isSearch || query) {
- loading.value = true
- Rs.request(configs).then((res: any) => {
- processData(res.data)
- })
- // if (props.method.toLowerCase() == "get") {
- // Rs.get(configs).then((res: any) => {
- // processData(res.data)
- // })
- // } else if (props.method.toLowerCase() == "post") {
- // Rs.get(configs).then((res: any) => {
- // processData(res.data)
- // })
- // }
- }
- function processData(data: any) {
- let result = formatSelectData(data)
- if (query) {
- result = result.filter((v: SelectOptionProp) => {
- return (
- (v.label as string).toLowerCase().includes(query.toLowerCase()) ||
- (v.value as string).toLowerCase().includes(query.toLowerCase())
- )
- })
- }
- options.value.push(...result)
- loading.value = false
- }
- }
- }
- }
- function formatSelectData(v: any) {
- const result: Array<SelectOptionProp> = []
- const data = props.formatRemoteData && typeof props.formatRemoteData == "function" ? props.formatRemoteData(v) : v
- if (data && data.length) {
- data.forEach((v: any) => {
- let item = {} as SelectOptionProp
- if (props.formatFunction) {
- item = props.formatFunction(v)
- } else {
- item = Object.assign({}, v)
- if ("value" in v) {
- item.key = v.value + ""
- item.value = v.value + ""
- } else if ("code" in v) {
- item.key = v.code + ""
- item.value = v.code + ""
- }
- if ("label" in v) {
- item.label = v.label + ""
- } else if ("name" in v) {
- item.label = v.name + ""
- } else if ("title" in v) {
- item.label = v.title + ""
- }
- }
- result.push(item)
- })
- }
- return result
- }
- function onChange(val: string | number | Array<string> | Array<number>) {
- emits("update:value", val)
- emits("change", val)
- }
- function onRemoveTag(val: string | number | Array<string> | Array<number>) {
- emits("remove-tag", val)
- }
- function onVisibleChange(val: boolean) {
- //下拉框出现/隐藏时触发 出现则为 true,隐藏则为 false
- emits("visible-change", val)
- }
- function onBlur(v: FocusEvent) {
- emits("blur", v)
- }
- function onFocus(v: FocusEvent) {
- emits("focus", v)
- }
- function onClear() {
- emits("clear")
- }
- onMounted(() => {
- init()
- })
- </script>
- <template>
- <el-select
- v-model="value"
- :placeholder="placeholder"
- :disabled="disabled"
- :multiple="multiple"
- :multiple-limit="multipleLimit"
- :clearable="clearable"
- :clear-icon="clearIcon"
- :suffix-icon="suffixIcon"
- :popper-class="popperClass"
- :autocomplete="autocomplete"
- :size="size"
- :effect="effect"
- :placement="placement"
- :filterable="filterable"
- :remote="remote"
- :remote-method="remoteFunction"
- :remote-show-suffix="remoteShowSuffix"
- :loading="loading"
- :loading-text="loadingText"
- :no-match-text="noMatchText"
- :no-data-text="noDataText"
- :default-first-option="defaultFirstOption"
- :popper-append-to-body="popperAppendToBody"
- :reserve-keyword="reserveKeyword"
- :teleported="teleported"
- :persistent="persistent"
- :automati-dropdown="automatiDropdown"
- :fit-input-width="fitInputWidth"
- :validate-event="validateEvent"
- @change="onChange"
- @remove-tag="onRemoveTag"
- @visible-change="onVisibleChange"
- @blur="onBlur"
- @focus="onFocus"
- @clear="onClear"
- >
- <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
- </el-select>
- </template>
|