|
|
@@ -1,262 +0,0 @@
|
|
|
-<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>
|