更新:登录功能
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
@import '../common/abstracts/variable';
|
||||
@import '../common/abstracts/mixin';
|
||||
|
||||
.wot-theme-dark {
|
||||
@include b(select-picker) {
|
||||
:deep(.wd-select-picker__arrow),
|
||||
:deep(.wd-select-picker__close),
|
||||
:deep(.wd-select-picker__clear) {
|
||||
color: $-dark-color;
|
||||
}
|
||||
|
||||
:deep(.wd-select-picker__cell--placeholder) {
|
||||
.wd-cell__value {
|
||||
color: $-dark-color-gray;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@include b(select-picker) {
|
||||
@include edeep(cell) {
|
||||
@include when(disabled) {
|
||||
.wd-cell__value {
|
||||
color: $-input-disabled-color;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
@include when(error) {
|
||||
.wd-cell__value {
|
||||
color: $-input-error-color;
|
||||
}
|
||||
.wd-select-picker__arrow {
|
||||
color: $-input-error-color;
|
||||
}
|
||||
}
|
||||
|
||||
@include m(placeholder) {
|
||||
.wd-cell__value {
|
||||
color: $-input-placeholder-color;
|
||||
}
|
||||
}
|
||||
|
||||
@include when(large) {
|
||||
.wd-select-picker__arrow,
|
||||
.wd-select-picker__clear {
|
||||
font-size: $-cell-icon-size-large;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@include edeep(arrow, clear) {
|
||||
display: block;
|
||||
font-size: $-cell-icon-size;
|
||||
color: $-cell-arrow-color;
|
||||
line-height: $-cell-line-height;
|
||||
}
|
||||
|
||||
@include edeep(clear) {
|
||||
color: $-cell-clear-color;
|
||||
}
|
||||
|
||||
@include e(loading) {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 3;
|
||||
background: $-picker-loading-bg;
|
||||
}
|
||||
|
||||
@include edeep(header) {
|
||||
height: 72px;
|
||||
line-height: 72px;
|
||||
}
|
||||
@include e(wrapper) {
|
||||
padding: 0 10px;
|
||||
position: relative;
|
||||
max-height: 356px;
|
||||
box-sizing: border-box;
|
||||
overflow: auto;
|
||||
|
||||
@include when(filterable) {
|
||||
height: 314px;
|
||||
max-height: 314px;
|
||||
}
|
||||
|
||||
@include when(loading) {
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
@include e(text-active) {
|
||||
color: $-color-theme;
|
||||
}
|
||||
|
||||
@include e(footer) {
|
||||
padding: 24px 15px;
|
||||
}
|
||||
}
|
||||
123
uni_modules/wot-design-uni/components/wd-select-picker/types.ts
Normal file
123
uni_modules/wot-design-uni/components/wd-select-picker/types.ts
Normal file
@@ -0,0 +1,123 @@
|
||||
import type { ComponentPublicInstance, ExtractPropTypes, PropType } from 'vue'
|
||||
import { baseProps, makeArrayProp, makeBooleanProp, makeNumberProp, makeRequiredProp, makeStringProp } from '../common/props'
|
||||
import type { FormItemRule } from '../wd-form/types'
|
||||
|
||||
export type SelectPickerType = 'checkbox' | 'radio'
|
||||
|
||||
export const selectPickerProps = {
|
||||
...baseProps,
|
||||
/** 选择器左侧文案 */
|
||||
label: String,
|
||||
/** 设置左侧标题宽度 */
|
||||
labelWidth: makeStringProp('33%'),
|
||||
/** 禁用 */
|
||||
disabled: makeBooleanProp(false),
|
||||
/** 只读 */
|
||||
readonly: Boolean,
|
||||
/** 选择器占位符 */
|
||||
placeholder: String,
|
||||
/** 弹出层标题 */
|
||||
title: String,
|
||||
/** 选择器的值靠右展示 */
|
||||
alignRight: makeBooleanProp(false),
|
||||
/** 是否为错误状态,错误状态时右侧内容为红色 */
|
||||
error: makeBooleanProp(false),
|
||||
/** 必填样式 */
|
||||
required: makeBooleanProp(false),
|
||||
/**
|
||||
* 使用 label 插槽时设置该选项
|
||||
* @deprecated 可以直接使用标签插槽,无需配置此选项
|
||||
*/
|
||||
useLabelSlot: makeBooleanProp(false),
|
||||
/**
|
||||
* 使用默认插槽时设置该选项
|
||||
* @deprecated 可以直接使用默认插槽,无需配置此选项
|
||||
*/
|
||||
useDefaultSlot: makeBooleanProp(false),
|
||||
/** 设置选择器大小 */
|
||||
size: String,
|
||||
/**
|
||||
* 是否垂直居中
|
||||
*/
|
||||
center: makeBooleanProp(false),
|
||||
/** 选中的颜色(单/复选框) */
|
||||
checkedColor: String,
|
||||
/** 最小选中的数量(仅在复选框类型下生效,`type`类型为`checkbox`) */
|
||||
min: makeNumberProp(0),
|
||||
/** 最大选中的数量,0 为无限数量,默认为 0(仅在复选框类型下生效,`type`类型为`checkbox`) */
|
||||
max: makeNumberProp(0),
|
||||
/** 设置 picker 内部的选项组尺寸大小 (单/复选框) */
|
||||
selectSize: String,
|
||||
/** 加载中 */
|
||||
loading: makeBooleanProp(false),
|
||||
/** 加载的颜色,只能使用十六进制的色值写法,且不能使用缩写 */
|
||||
loadingColor: makeStringProp('#4D80F0'),
|
||||
/** 点击遮罩是否关闭 */
|
||||
closeOnClickModal: makeBooleanProp(true),
|
||||
/** 选中项,`type`类型为`checkbox`时,类型为 array;`type`为`radio` 时 ,类型为 number / boolean / string */
|
||||
modelValue: makeRequiredProp([String, Number, Boolean, Array] as PropType<string | number | boolean | (string | number | boolean)[]>),
|
||||
/** 选择器数据,一维数组 */
|
||||
columns: makeArrayProp<Record<string, any>>(),
|
||||
/** 单复选选择器类型 */
|
||||
type: makeStringProp<SelectPickerType>('checkbox'),
|
||||
/** 选项对象中,value 对应的 key */
|
||||
valueKey: makeStringProp('value'),
|
||||
/** 选项对象中,展示的文本对应的 key */
|
||||
labelKey: makeStringProp('label'),
|
||||
/** 确认按钮文案 */
|
||||
confirmButtonText: String,
|
||||
/** 自定义展示文案的格式化函数,返回一个字符串 */
|
||||
displayFormat: Function as PropType<SelectPickerDisplayFormat>,
|
||||
/** 确定前校验函数,接收 (value, resolve) 参数,通过 resolve 继续执行 picker,resolve 接收 1 个 boolean 参数 */
|
||||
beforeConfirm: Function as PropType<SelectPickerBeforeConfirm>,
|
||||
/** 弹窗层级 */
|
||||
zIndex: makeNumberProp(15),
|
||||
/** 弹出面板是否设置底部安全距离(iphone X 类型的机型) */
|
||||
safeAreaInsetBottom: makeBooleanProp(true),
|
||||
/** 可搜索(目前只支持本地搜索) */
|
||||
filterable: makeBooleanProp(false),
|
||||
/** 搜索框占位符 */
|
||||
filterPlaceholder: String,
|
||||
/** 是否超出隐藏 */
|
||||
ellipsis: makeBooleanProp(false),
|
||||
/** 重新打开是否滚动到选中项 */
|
||||
scrollIntoView: makeBooleanProp(true),
|
||||
/** 表单域 `model` 字段名,在使用表单校验功能的情况下,该属性是必填的 */
|
||||
prop: String,
|
||||
/** 表单验证规则,结合`wd-form`组件使用 */
|
||||
rules: makeArrayProp<FormItemRule>(),
|
||||
/** 自定义内容样式类 */
|
||||
customContentClass: makeStringProp(''),
|
||||
/** 自定义标签样式类 */
|
||||
customLabelClass: makeStringProp(''),
|
||||
/** 自定义值样式类 */
|
||||
customValueClass: makeStringProp(''),
|
||||
/** 是否显示确认按钮(radio类型生效),默认值为:true */
|
||||
showConfirm: makeBooleanProp(true),
|
||||
/**
|
||||
* 显示清空按钮
|
||||
*/
|
||||
clearable: makeBooleanProp(false),
|
||||
/**
|
||||
* 是否从页面中脱离出来,用于解决各种 fixed 失效问题 (H5: teleport, APP: renderjs, 小程序: root-portal)
|
||||
*/
|
||||
rootPortal: makeBooleanProp(false),
|
||||
/**
|
||||
* 必填标记位置,可选值:before、after
|
||||
*/
|
||||
markerSide: makeStringProp<'before' | 'after'>('before')
|
||||
}
|
||||
export type SelectPickerProps = ExtractPropTypes<typeof selectPickerProps>
|
||||
|
||||
export type SelectPickerDisplayFormat = (items: string | number | boolean | (string | number | boolean)[], columns: Record<string, any>[]) => string
|
||||
|
||||
export type SelectPickerBeforeConfirm = (value: string | number | boolean | (string | number | boolean)[], resolve: (isPass: boolean) => void) => void
|
||||
|
||||
export type SelectPickerExpose = {
|
||||
// 打开picker弹框
|
||||
open: () => void
|
||||
// 关闭picker弹框
|
||||
close: () => void
|
||||
}
|
||||
|
||||
export type SelectPickerInstance = ComponentPublicInstance<SelectPickerExpose, SelectPickerProps>
|
||||
@@ -0,0 +1,432 @@
|
||||
<template>
|
||||
<view :class="`wd-select-picker ${customClass}`" :style="customStyle">
|
||||
<wd-cell
|
||||
v-if="!$slots.default"
|
||||
:title="label"
|
||||
:value="showValue || placeholder || translate('placeholder')"
|
||||
:required="required"
|
||||
:size="size"
|
||||
:title-width="labelWidth"
|
||||
:prop="prop"
|
||||
:rules="rules"
|
||||
:clickable="!disabled && !readonly"
|
||||
:value-align="alignRight ? 'right' : 'left'"
|
||||
:center="center"
|
||||
:custom-class="cellClass"
|
||||
:custom-style="customStyle"
|
||||
:custom-title-class="customLabelClass"
|
||||
:custom-value-class="customValueClass"
|
||||
:ellipsis="ellipsis"
|
||||
:use-title-slot="!!$slots.label"
|
||||
:marker-side="markerSide"
|
||||
@click="open"
|
||||
>
|
||||
<template v-if="$slots.label" #title>
|
||||
<slot name="label"></slot>
|
||||
</template>
|
||||
<template #right-icon>
|
||||
<wd-icon v-if="showArrow" custom-class="wd-select-picker__arrow" name="arrow-right" />
|
||||
<view v-else-if="showClear" @click.stop="handleClear">
|
||||
<wd-icon custom-class="wd-select-picker__clear" name="error-fill" />
|
||||
</view>
|
||||
</template>
|
||||
</wd-cell>
|
||||
<view v-else @click="open">
|
||||
<slot></slot>
|
||||
</view>
|
||||
<wd-action-sheet
|
||||
v-model="pickerShow"
|
||||
:duration="250"
|
||||
:title="title || translate('title')"
|
||||
:close-on-click-modal="closeOnClickModal"
|
||||
:z-index="zIndex"
|
||||
:safe-area-inset-bottom="safeAreaInsetBottom"
|
||||
:root-portal="rootPortal"
|
||||
@close="close"
|
||||
@opened="scrollIntoView ? setScrollIntoView() : ''"
|
||||
custom-header-class="wd-select-picker__header"
|
||||
>
|
||||
<wd-search
|
||||
v-if="filterable"
|
||||
v-model="filterVal"
|
||||
:placeholder="filterPlaceholder || translate('filterPlaceholder')"
|
||||
hide-cancel
|
||||
placeholder-left
|
||||
@change="handleFilterChange"
|
||||
/>
|
||||
<scroll-view
|
||||
:class="`wd-select-picker__wrapper ${filterable ? 'is-filterable' : ''} ${loading ? 'is-loading' : ''} ${customContentClass}`"
|
||||
:scroll-y="!loading"
|
||||
:scroll-top="scrollTop"
|
||||
:scroll-with-animation="true"
|
||||
>
|
||||
<!-- 多选 -->
|
||||
<view v-if="type === 'checkbox' && isArray(selectList)" id="wd-checkbox-group">
|
||||
<wd-checkbox-group v-model="selectList" cell :size="selectSize" :checked-color="checkedColor" :min="min" :max="max" @change="handleChange">
|
||||
<view v-for="item in filterColumns" :key="item[valueKey]" :id="'check' + item[valueKey]">
|
||||
<wd-checkbox :modelValue="item[valueKey]" :disabled="item.disabled">
|
||||
<block v-if="filterable && filterVal">
|
||||
<block v-for="text in item[labelKey]" :key="text.label">
|
||||
<text v-if="text.type === 'active'" class="wd-select-picker__text-active">{{ text.label }}</text>
|
||||
<block v-else>{{ text.label }}</block>
|
||||
</block>
|
||||
</block>
|
||||
<block v-else>
|
||||
{{ item[labelKey] }}
|
||||
</block>
|
||||
</wd-checkbox>
|
||||
</view>
|
||||
</wd-checkbox-group>
|
||||
</view>
|
||||
<!-- 单选 -->
|
||||
<view v-if="type === 'radio' && !isArray(selectList)" id="wd-radio-group">
|
||||
<wd-radio-group v-model="selectList" cell :size="selectSize" :checked-color="checkedColor" @change="handleChange">
|
||||
<view v-for="(item, index) in filterColumns" :key="index" :id="'radio' + item[valueKey]">
|
||||
<wd-radio :value="item[valueKey]" :disabled="item.disabled">
|
||||
<block v-if="filterable && filterVal">
|
||||
<block v-for="text in item[labelKey]" :key="text.label">
|
||||
<text :class="`${text.type === 'active' ? 'wd-select-picker__text-active' : ''}`">{{ text.label }}</text>
|
||||
</block>
|
||||
</block>
|
||||
<block v-else>
|
||||
{{ item[labelKey] }}
|
||||
</block>
|
||||
</wd-radio>
|
||||
</view>
|
||||
</wd-radio-group>
|
||||
</view>
|
||||
<view v-if="loading" class="wd-select-picker__loading" @touchmove="noop">
|
||||
<wd-loading :color="loadingColor" />
|
||||
</view>
|
||||
</scroll-view>
|
||||
<!-- 确认按钮 -->
|
||||
<view v-if="showConfirm" class="wd-select-picker__footer">
|
||||
<wd-button block size="large" @click="onConfirm" :disabled="loading">{{ confirmButtonText || translate('confirm') }}</wd-button>
|
||||
</view>
|
||||
</wd-action-sheet>
|
||||
</view>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'wd-select-picker',
|
||||
options: {
|
||||
addGlobalClass: true,
|
||||
virtualHost: true,
|
||||
styleIsolation: 'shared'
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import wdActionSheet from '../wd-action-sheet/wd-action-sheet.vue'
|
||||
import wdCheckbox from '../wd-checkbox/wd-checkbox.vue'
|
||||
import wdCheckboxGroup from '../wd-checkbox-group/wd-checkbox-group.vue'
|
||||
import wdRadio from '../wd-radio/wd-radio.vue'
|
||||
import wdRadioGroup from '../wd-radio-group/wd-radio-group.vue'
|
||||
import wdButton from '../wd-button/wd-button.vue'
|
||||
import wdLoading from '../wd-loading/wd-loading.vue'
|
||||
import wdCell from '../wd-cell/wd-cell.vue'
|
||||
|
||||
import { getCurrentInstance, onBeforeMount, ref, watch, nextTick, computed } from 'vue'
|
||||
import { getRect, isArray, isDef, isFunction, pause } from '../common/util'
|
||||
import { useTranslate } from '../composables/useTranslate'
|
||||
import { selectPickerProps, type SelectPickerExpose } from './types'
|
||||
|
||||
const { translate } = useTranslate('select-picker')
|
||||
|
||||
const props = defineProps(selectPickerProps)
|
||||
const emit = defineEmits(['change', 'cancel', 'confirm', 'clear', 'update:modelValue', 'open', 'close'])
|
||||
|
||||
const pickerShow = ref<boolean>(false)
|
||||
const selectList = ref<Array<number | boolean | string> | number | boolean | string>([])
|
||||
const isConfirm = ref<boolean>(false)
|
||||
const lastSelectList = ref<Array<number | boolean | string> | number | boolean | string>([])
|
||||
const filterVal = ref<string>('')
|
||||
const filterColumns = ref<Array<Record<string, any>>>([])
|
||||
const scrollTop = ref<number>(0) // 滚动位置
|
||||
|
||||
const showValue = computed(() => {
|
||||
const value = valueFormat(props.modelValue)
|
||||
let showValueTemp: string = ''
|
||||
|
||||
if (props.displayFormat) {
|
||||
showValueTemp = props.displayFormat(value, props.columns)
|
||||
} else {
|
||||
const { type, labelKey } = props
|
||||
if (type === 'checkbox') {
|
||||
const selectedItems = (isArray(value) ? value : []).map((item) => {
|
||||
return getSelectedItem(item)
|
||||
})
|
||||
showValueTemp = selectedItems
|
||||
.map((item) => {
|
||||
return item[labelKey]
|
||||
})
|
||||
.join(', ')
|
||||
} else if (type === 'radio') {
|
||||
const selectedItem = getSelectedItem(value as string | number | boolean)
|
||||
showValueTemp = selectedItem[labelKey]
|
||||
} else {
|
||||
showValueTemp = value as string
|
||||
}
|
||||
}
|
||||
return showValueTemp
|
||||
})
|
||||
|
||||
const cellClass = computed(() => {
|
||||
const classes = ['wd-select-picker__cell']
|
||||
if (props.disabled) classes.push('is-disabled')
|
||||
if (props.readonly) classes.push('is-readonly')
|
||||
if (props.error) classes.push('is-error')
|
||||
if (!showValue.value) classes.push('wd-select-picker__cell--placeholder')
|
||||
return classes.join(' ')
|
||||
})
|
||||
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(newValue) => {
|
||||
if (newValue === selectList.value) return
|
||||
selectList.value = valueFormat(newValue)
|
||||
lastSelectList.value = valueFormat(newValue)
|
||||
},
|
||||
{
|
||||
deep: true,
|
||||
immediate: true
|
||||
}
|
||||
)
|
||||
|
||||
watch(
|
||||
() => props.columns,
|
||||
(newValue) => {
|
||||
if (props.filterable && filterVal.value) {
|
||||
formatFilterColumns(newValue, filterVal.value)
|
||||
} else {
|
||||
filterColumns.value = newValue
|
||||
}
|
||||
},
|
||||
{
|
||||
deep: true,
|
||||
immediate: true
|
||||
}
|
||||
)
|
||||
|
||||
watch(
|
||||
() => props.displayFormat,
|
||||
(fn) => {
|
||||
if (fn && !isFunction(fn)) {
|
||||
console.error('The type of displayFormat must be Function')
|
||||
}
|
||||
},
|
||||
{
|
||||
deep: true,
|
||||
immediate: true
|
||||
}
|
||||
)
|
||||
|
||||
watch(
|
||||
() => props.beforeConfirm,
|
||||
(fn) => {
|
||||
if (fn && !isFunction(fn)) {
|
||||
console.error('The type of beforeConfirm must be Function')
|
||||
}
|
||||
},
|
||||
{
|
||||
deep: true,
|
||||
immediate: true
|
||||
}
|
||||
)
|
||||
|
||||
onBeforeMount(() => {
|
||||
selectList.value = valueFormat(props.modelValue)
|
||||
filterColumns.value = props.columns
|
||||
})
|
||||
|
||||
const { proxy } = getCurrentInstance() as any
|
||||
|
||||
async function setScrollIntoView() {
|
||||
let wraperSelector: string = ''
|
||||
let selectorPromise: Promise<UniApp.NodeInfo>[] = []
|
||||
if (isDef(selectList.value) && selectList.value !== '' && !isArray(selectList.value)) {
|
||||
wraperSelector = '#wd-radio-group'
|
||||
selectorPromise = [getRect(`#radio${selectList.value}`, false, proxy)]
|
||||
} else if (isArray(selectList.value) && selectList.value.length > 0) {
|
||||
selectList.value.forEach((value) => {
|
||||
selectorPromise.push(getRect(`#check${value}`, false, proxy))
|
||||
})
|
||||
wraperSelector = '#wd-checkbox-group'
|
||||
}
|
||||
if (wraperSelector) {
|
||||
await pause(2000 / 30)
|
||||
Promise.all([getRect('.wd-select-picker__wrapper', false, proxy), getRect(wraperSelector, false, proxy), ...selectorPromise]).then((res) => {
|
||||
if (isDef(res) && isArray(res)) {
|
||||
const scrollView = res[0]
|
||||
const wraper = res[1]
|
||||
const target = res.slice(2) || []
|
||||
if (isDef(wraper) && isDef(scrollView)) {
|
||||
const index = target.findIndex((item) => {
|
||||
return item.bottom! > scrollView.top! && item.top! < scrollView.bottom!
|
||||
})
|
||||
if (index < 0) {
|
||||
scrollTop.value = -1
|
||||
nextTick(() => {
|
||||
scrollTop.value = Math.max(0, target[0].top! - wraper.top! - scrollView.height! / 2)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function noop() {}
|
||||
|
||||
function getSelectedItem(value: string | number | boolean) {
|
||||
const { valueKey, labelKey, columns } = props
|
||||
|
||||
const selecteds = columns.filter((item) => {
|
||||
return item[valueKey] === value
|
||||
})
|
||||
|
||||
if (selecteds.length > 0) {
|
||||
return selecteds[0]
|
||||
}
|
||||
|
||||
return {
|
||||
[valueKey]: value,
|
||||
[labelKey]: ''
|
||||
}
|
||||
}
|
||||
|
||||
function valueFormat(value: string | number | boolean | (string | number | boolean)[]) {
|
||||
return props.type === 'checkbox' ? (isArray(value) ? value : []) : value
|
||||
}
|
||||
|
||||
function handleChange({ value }: { value: string | number | boolean | (string | number | boolean)[] }) {
|
||||
selectList.value = value
|
||||
emit('change', { value })
|
||||
if (props.type === 'radio' && !props.showConfirm) {
|
||||
onConfirm()
|
||||
}
|
||||
}
|
||||
|
||||
function close() {
|
||||
pickerShow.value = false
|
||||
// 未确定选项时,数据还原复位
|
||||
if (!isConfirm.value) {
|
||||
selectList.value = valueFormat(lastSelectList.value)
|
||||
}
|
||||
emit('cancel')
|
||||
emit('close')
|
||||
}
|
||||
|
||||
function open() {
|
||||
if (props.disabled || props.readonly) return
|
||||
selectList.value = valueFormat(props.modelValue)
|
||||
pickerShow.value = true
|
||||
isConfirm.value = false
|
||||
emit('open')
|
||||
}
|
||||
|
||||
function onConfirm() {
|
||||
if (props.loading) {
|
||||
pickerShow.value = false
|
||||
emit('confirm')
|
||||
emit('close')
|
||||
return
|
||||
}
|
||||
if (props.beforeConfirm) {
|
||||
props.beforeConfirm(selectList.value, (isPass: boolean) => {
|
||||
isPass && handleConfirm()
|
||||
})
|
||||
} else {
|
||||
handleConfirm()
|
||||
}
|
||||
}
|
||||
|
||||
function handleConfirm() {
|
||||
isConfirm.value = true
|
||||
pickerShow.value = false
|
||||
lastSelectList.value = valueFormat(selectList.value)
|
||||
let selectedItems: Record<string, any> = {}
|
||||
if (props.type === 'checkbox') {
|
||||
selectedItems = (isArray(lastSelectList.value) ? lastSelectList.value : []).map((item) => {
|
||||
return getSelectedItem(item)
|
||||
})
|
||||
} else {
|
||||
selectedItems = getSelectedItem(lastSelectList.value as string | number | boolean)
|
||||
}
|
||||
emit('update:modelValue', lastSelectList.value)
|
||||
emit('confirm', {
|
||||
value: lastSelectList.value,
|
||||
selectedItems
|
||||
})
|
||||
emit('close')
|
||||
}
|
||||
|
||||
function getFilterText(label: string, filterVal: string) {
|
||||
const reg = new RegExp(`(${filterVal})`, 'g')
|
||||
|
||||
return label.split(reg).map((text) => {
|
||||
return {
|
||||
type: text === filterVal ? 'active' : 'normal',
|
||||
label: text
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function handleFilterChange({ value }: { value: string }) {
|
||||
if (value === '') {
|
||||
filterColumns.value = []
|
||||
filterVal.value = value
|
||||
nextTick(() => {
|
||||
filterColumns.value = props.columns
|
||||
})
|
||||
} else {
|
||||
filterVal.value = value
|
||||
formatFilterColumns(props.columns, value)
|
||||
}
|
||||
}
|
||||
|
||||
function formatFilterColumns(columns: Record<string, any>[], filterVal: string) {
|
||||
const filterColumnsTemp = columns.filter((item) => {
|
||||
return item[props.labelKey].indexOf(filterVal) > -1
|
||||
})
|
||||
|
||||
const formatFilterColumns = filterColumnsTemp.map((item) => {
|
||||
return {
|
||||
...item,
|
||||
[props.labelKey]: getFilterText(item[props.labelKey], filterVal)
|
||||
}
|
||||
})
|
||||
filterColumns.value = []
|
||||
nextTick(() => {
|
||||
filterColumns.value = formatFilterColumns
|
||||
})
|
||||
}
|
||||
|
||||
const showConfirm = computed(() => {
|
||||
return (props.type === 'radio' && props.showConfirm) || props.type === 'checkbox'
|
||||
})
|
||||
|
||||
// 是否展示清除按钮
|
||||
const showClear = computed(() => {
|
||||
return props.clearable && !props.disabled && !props.readonly && showValue.value.length
|
||||
})
|
||||
|
||||
function handleClear() {
|
||||
emit('update:modelValue', props.type === 'checkbox' ? [] : '')
|
||||
emit('clear')
|
||||
}
|
||||
|
||||
// 是否展示箭头
|
||||
const showArrow = computed(() => {
|
||||
return !props.disabled && !props.readonly && !showClear.value
|
||||
})
|
||||
|
||||
defineExpose<SelectPickerExpose>({
|
||||
close,
|
||||
open
|
||||
})
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@import './index.scss';
|
||||
</style>
|
||||
Reference in New Issue
Block a user