u
This commit is contained in:
1 parent
3400068aa0
commit
a2c6812ed0
6 files changed
+369
-246
No files matched your search
@@ -1,241 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import { useFormPopout, useIndeterminate } from 'sard-uniapp'
|
||||
import { computed, ref, watch } from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
type: {
|
||||
type: String as PropType<'radio' | 'multiple'>,
|
||||
default: 'radio',
|
||||
},
|
||||
label: {
|
||||
value: String,
|
||||
default: '',
|
||||
},
|
||||
value: {
|
||||
type: null as unknown as PropType<any | any[]>,
|
||||
default: undefined,
|
||||
},
|
||||
labelField: {
|
||||
type: String,
|
||||
default: 'label',
|
||||
},
|
||||
valueField: {
|
||||
type: String,
|
||||
default: 'value',
|
||||
},
|
||||
viewname: {
|
||||
type: String,
|
||||
},
|
||||
})
|
||||
|
||||
const _visible = ref(false)
|
||||
const searchValue = ref('')
|
||||
|
||||
// 内部状态
|
||||
const _value = ref(
|
||||
props.type === 'multiple' ? (Array.isArray(props.value) ? [...props.value] : []) : props.value,
|
||||
)
|
||||
|
||||
const _options = ref([
|
||||
{ label: '选项 1', value: 'option1', disabled: false },
|
||||
{ label: '选项 2', value: 'option2', disabled: false },
|
||||
{ label: '选项 3', value: 'option3', disabled: false },
|
||||
{ label: '选项 4', value: 'option4', disabled: false },
|
||||
{ label: '选项 5', value: 'option5', disabled: false },
|
||||
{ label: '选项 1', value: 'option1', disabled: false },
|
||||
{ label: '选项 2', value: 'option2', disabled: false },
|
||||
{ label: '选项 3', value: 'option3', disabled: false },
|
||||
{ label: '选项 4', value: 'option4', disabled: false },
|
||||
{ label: '选项 5', value: 'option5', disabled: false },
|
||||
{ label: '选项 1', value: 'option1', disabled: false },
|
||||
{ label: '选项 2', value: 'option2', disabled: false },
|
||||
{ label: '选项 3', value: 'option3', disabled: false },
|
||||
{ label: '选项 4', value: 'option4', disabled: false },
|
||||
{ label: '选项 5', value: 'option5', disabled: false },
|
||||
])
|
||||
|
||||
const { allChecked, isIndeterminate, onAllChange } = useIndeterminate(
|
||||
_value,
|
||||
_options,
|
||||
)
|
||||
|
||||
function select(option, toggle) {
|
||||
if (!option.disabled) {
|
||||
toggle(option.value)
|
||||
}
|
||||
}
|
||||
|
||||
// 显示数量
|
||||
const count = computed(() => {
|
||||
if (props.type === 'multiple') {
|
||||
return `${(_value.value).length || 0} / ${_options.value.length}`
|
||||
}
|
||||
else {
|
||||
return _value.value != null ? `1 / ${_options.value.length}` : `0 / ${_options.value.length}`
|
||||
}
|
||||
})
|
||||
|
||||
function handleAfterEnter() {
|
||||
console.log('enter')
|
||||
}
|
||||
|
||||
function showPopout() {
|
||||
_visible.value = true
|
||||
}
|
||||
|
||||
function onOverlayClick() {
|
||||
_visible.value = false
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<sar-popout-input
|
||||
multiline
|
||||
@click="showPopout"
|
||||
>
|
||||
<sar-popout
|
||||
v-model:visible="_visible"
|
||||
v-bind="$attrs"
|
||||
title="请选择"
|
||||
:show-footer="false"
|
||||
@after-enter="handleAfterEnter"
|
||||
@overlay-click="onOverlayClick"
|
||||
>
|
||||
<template v-if="props.type === 'multiple'" #title-prepend>
|
||||
<view class="sar-checkbox-popout__check-all">
|
||||
<sar-checkbox
|
||||
v-model:checked="allChecked"
|
||||
:indeterminate="isIndeterminate"
|
||||
@change="onAllChange"
|
||||
>
|
||||
{{ count }}
|
||||
</sar-checkbox>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<template #visible="{ already }">
|
||||
<view v-if="already">
|
||||
<sar-list-item>
|
||||
<sar-input
|
||||
v-model="searchValue"
|
||||
placeholder="请输入搜索的值"
|
||||
clearable
|
||||
>
|
||||
<template #prepend>
|
||||
<sar-icon family="sari" name="search" />
|
||||
</template>
|
||||
</sar-input>
|
||||
</sar-list-item>
|
||||
|
||||
<view class="sar-checkbox-popout__container">
|
||||
<scroll-view
|
||||
class="sar-checkbox-popout__scroll_searchable sar-checkbox-popout__scroll"
|
||||
scroll-y
|
||||
trap-scroll
|
||||
:upper-threshold="0"
|
||||
:lower-threshold="0"
|
||||
:throttle="false"
|
||||
>
|
||||
<sar-checkbox-group
|
||||
v-if="props.type === 'multiple'"
|
||||
v-model="_value"
|
||||
:validate-event="false"
|
||||
>
|
||||
<template #custom="{ toggle }">
|
||||
<sar-list inlaid>
|
||||
<sar-list-item
|
||||
v-for="option in _options"
|
||||
:key="option.value"
|
||||
:title="option.label"
|
||||
@click="select(option, toggle)"
|
||||
>
|
||||
<template #icon>
|
||||
<sar-checkbox
|
||||
readonly
|
||||
:value="option.value"
|
||||
:validate-event="false"
|
||||
/>
|
||||
</template>
|
||||
</sar-list-item>
|
||||
</sar-list>
|
||||
</template>
|
||||
</sar-checkbox-group>
|
||||
|
||||
<sar-radio-group
|
||||
v-else
|
||||
v-model="_value"
|
||||
:validate-event="false"
|
||||
>
|
||||
<template #custom="{ toggle }">
|
||||
<sar-list inlaid>
|
||||
<sar-list-item
|
||||
v-for="option in _options"
|
||||
:key="option.value"
|
||||
:title="option.label"
|
||||
:hover="!option.disabled"
|
||||
@click="select(option, toggle)"
|
||||
>
|
||||
<template #icon>
|
||||
<sar-radio
|
||||
readonly
|
||||
:disabled="option.disabled"
|
||||
:value="option.value"
|
||||
/>
|
||||
</template>
|
||||
</sar-list-item>
|
||||
</sar-list>
|
||||
</template>
|
||||
</sar-radio-group>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="sar-popout__footer">
|
||||
<sar-pagination
|
||||
:total="43"
|
||||
:page-size="10"
|
||||
type="simple"
|
||||
style="width: 100%;"
|
||||
/>
|
||||
</view>
|
||||
</template>
|
||||
</sar-popout>
|
||||
</sar-popout-input>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.sar-checkbox-popout__check-all {
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
flex-direction: column;
|
||||
position: absolute;
|
||||
left: 1rem;
|
||||
z-index: 2;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
color: var(--sar-tertiary-color);
|
||||
font-size: var(--sar-text-sm);
|
||||
}
|
||||
.sar-checkbox-popout__container {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.sar-checkbox-popout__scroll_searchable {
|
||||
height: var(--sar-checkbox-popout-max-height);
|
||||
}
|
||||
|
||||
.sar-checkbox-popout__scroll {
|
||||
max-height: var(--sar-checkbox-popout-max-height);
|
||||
}
|
||||
|
||||
.sar-popout__footer {
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-direction: row;
|
||||
gap: var(--sar-popout-button-gap);
|
||||
align-items: center;
|
||||
padding: var(--sar-popout-footer-gap-y) var(--sar-popout-footer-gap-x);
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,39 @@
|
||||
<script setup lang="ts">
|
||||
import PickerSelect from '../picker-select/index.vue'
|
||||
|
||||
const props = defineProps({
|
||||
type: {
|
||||
type: String as PropType<'radio' | 'multiple'>,
|
||||
default: 'radio',
|
||||
},
|
||||
label: {
|
||||
value: String,
|
||||
default: '',
|
||||
},
|
||||
value: {
|
||||
type: null as unknown as PropType<any | any[]>,
|
||||
default: undefined,
|
||||
},
|
||||
labelField: {
|
||||
type: String,
|
||||
default: 'label',
|
||||
},
|
||||
valueField: {
|
||||
type: String,
|
||||
default: 'value',
|
||||
},
|
||||
viewname: {
|
||||
type: String,
|
||||
},
|
||||
})
|
||||
|
||||
const _visible = ref(false)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<sar-popout-input
|
||||
@click="_visible = true"
|
||||
>
|
||||
<PickerSelect v-model:visible="_visible" />
|
||||
</sar-popout-input>
|
||||
</template>
|
||||
@@ -0,0 +1,304 @@
|
||||
<script setup lang="ts">
|
||||
import { useIndeterminate } from 'sard-uniapp'
|
||||
import { computed, ref } from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
type: {
|
||||
type: String as PropType<'radio' | 'multiple'>,
|
||||
default: 'radio',
|
||||
},
|
||||
label: {
|
||||
value: String,
|
||||
default: '',
|
||||
},
|
||||
value: {
|
||||
type: null as unknown as PropType<any | any[]>,
|
||||
default: undefined,
|
||||
},
|
||||
labelField: {
|
||||
type: String,
|
||||
default: 'label',
|
||||
},
|
||||
valueField: {
|
||||
type: String,
|
||||
default: 'value',
|
||||
},
|
||||
viewname: {
|
||||
type: String,
|
||||
},
|
||||
})
|
||||
const emit = defineEmits(['update:visible', 'update:value'])
|
||||
|
||||
const _visible = computed({
|
||||
get: () => props.visible,
|
||||
set: (val: boolean) => {
|
||||
emit('update:visible', val)
|
||||
},
|
||||
})
|
||||
|
||||
const _loading = ref(false)
|
||||
const searchValue = ref('')
|
||||
|
||||
const _pagation = ref({
|
||||
current: 1,
|
||||
pageSize: 10,
|
||||
total: 20,
|
||||
})
|
||||
|
||||
const isPrevDisabled = computed(() => _pagation.value.current <= 1)
|
||||
const isNextDisabled = computed(() =>
|
||||
_pagation.value.current >= Math.ceil(_pagation.value.total / _pagation.value.pageSize),
|
||||
)
|
||||
|
||||
// 内部 value,双向绑定 props.value
|
||||
const _value = computed({
|
||||
get: () => {
|
||||
// 如果是多选,保证返回数组
|
||||
return props.type === 'multiple'
|
||||
? (Array.isArray(props.value) ? [...props.value] : [])
|
||||
: props.value
|
||||
},
|
||||
set: (val) => {
|
||||
emit('update:value', val)
|
||||
},
|
||||
})
|
||||
|
||||
const _options = ref<any[]>([])
|
||||
|
||||
function setOptions(val: any[]) {
|
||||
_options.value = val.map(item => ({
|
||||
label: item[props.labelField] ?? '',
|
||||
value: item[props.valueField] ?? undefined,
|
||||
disabled: !!item.disabled,
|
||||
...item,
|
||||
}))
|
||||
}
|
||||
|
||||
const { allChecked, isIndeterminate, onAllChange } = useIndeterminate(
|
||||
_value,
|
||||
_options,
|
||||
)
|
||||
|
||||
function select(option, toggle) {
|
||||
if (!option.disabled) {
|
||||
toggle(option.value)
|
||||
if (props.type === 'radio') {
|
||||
_visible.value = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 显示数量
|
||||
const count = computed(() => {
|
||||
if (props.type === 'multiple') {
|
||||
return `${(_value.value).length || 0} / ${_options.value.length}`
|
||||
}
|
||||
else {
|
||||
return _value.value != null ? `1 / ${_options.value.length}` : `0 / ${_options.value.length}`
|
||||
}
|
||||
})
|
||||
|
||||
function handleAfterEnter() {
|
||||
// _loading.value = true
|
||||
}
|
||||
|
||||
function handlePagationChange(page: number) {
|
||||
_pagation.value.current = page
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<sar-popout
|
||||
v-model:visible="_visible"
|
||||
title="请选择"
|
||||
:show-footer="false"
|
||||
@after-enter="handleAfterEnter"
|
||||
>
|
||||
<template v-if="props.type === 'multiple'" #title-prepend>
|
||||
<view class="sar-checkbox-popout__check-all">
|
||||
<sar-checkbox
|
||||
v-model:checked="allChecked"
|
||||
:indeterminate="isIndeterminate"
|
||||
@change="onAllChange"
|
||||
>
|
||||
{{ count }}
|
||||
</sar-checkbox>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<template #visible="{ already }">
|
||||
<view v-if="already">
|
||||
<sar-list-item>
|
||||
<sar-input
|
||||
v-model="searchValue"
|
||||
placeholder="请输入搜索的值"
|
||||
clearable
|
||||
>
|
||||
<template #prepend>
|
||||
<sar-icon family="sari" name="search" />
|
||||
</template>
|
||||
</sar-input>
|
||||
</sar-list-item>
|
||||
|
||||
<view class="sar-checkbox-popout__container">
|
||||
<scroll-view
|
||||
class="sar-checkbox-popout__scroll_searchable sar-checkbox-popout__scroll"
|
||||
scroll-y
|
||||
trap-scroll
|
||||
:upper-threshold="0"
|
||||
:lower-threshold="0"
|
||||
:throttle="false"
|
||||
>
|
||||
<sar-empty
|
||||
v-if="_options.length === 0"
|
||||
:root-style="{ height: '100%' }"
|
||||
/>
|
||||
|
||||
<sar-checkbox-group
|
||||
v-else-if="props.type === 'multiple'"
|
||||
v-model="_value"
|
||||
:validate-event="false"
|
||||
>
|
||||
<template #custom="{ toggle }">
|
||||
<sar-list inlaid>
|
||||
<sar-list-item
|
||||
v-for="option in _options"
|
||||
:key="option.value"
|
||||
:title="option.label"
|
||||
@click="select(option, toggle)"
|
||||
>
|
||||
<template #icon>
|
||||
<sar-checkbox
|
||||
readonly
|
||||
:value="option.value"
|
||||
:validate-event="false"
|
||||
/>
|
||||
</template>
|
||||
</sar-list-item>
|
||||
</sar-list>
|
||||
</template>
|
||||
</sar-checkbox-group>
|
||||
|
||||
<sar-radio-group
|
||||
v-else
|
||||
v-model="_value"
|
||||
:validate-event="false"
|
||||
>
|
||||
<template #custom="{ toggle }">
|
||||
<sar-list inlaid>
|
||||
<sar-list-item
|
||||
v-for="option in _options"
|
||||
:key="option.value"
|
||||
:title="option.label"
|
||||
:hover="!option.disabled"
|
||||
@click="select(option, toggle)"
|
||||
>
|
||||
<template #icon>
|
||||
<sar-radio
|
||||
readonly
|
||||
:disabled="option.disabled"
|
||||
:value="option.value"
|
||||
/>
|
||||
</template>
|
||||
</sar-list-item>
|
||||
</sar-list>
|
||||
</template>
|
||||
</sar-radio-group>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="sar-popout__footer">
|
||||
<sar-pagination
|
||||
:current="_pagation.current"
|
||||
:total="_pagation.total"
|
||||
:page-size="_pagation.pageSize"
|
||||
type="simple"
|
||||
root-class="picker-select__pagination-root"
|
||||
@change="handlePagationChange"
|
||||
>
|
||||
<template #prev>
|
||||
<sar-button type="default" :disabled="isPrevDisabled" size="mini">
|
||||
上一页
|
||||
</sar-button>
|
||||
</template>
|
||||
<template #next>
|
||||
<sar-button type="default" :disabled="isNextDisabled" size="mini">
|
||||
下一页
|
||||
</sar-button>
|
||||
</template>
|
||||
</sar-pagination>
|
||||
|
||||
<sar-button
|
||||
v-if="props.type === 'multiple'"
|
||||
:root-style="{ width: '100%' }"
|
||||
>
|
||||
确认
|
||||
</sar-button>
|
||||
</view>
|
||||
|
||||
<view v-if="_loading" class="sar-popout__mask">
|
||||
<sar-loading
|
||||
size="48rpx"
|
||||
text-size="36rpx"
|
||||
color="var(--sar-primary)"
|
||||
text-color="var(--sar-primary)"
|
||||
text="加载中"
|
||||
/>
|
||||
</view>
|
||||
</template>
|
||||
</sar-popout>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.sar-popout__mask {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: rgba(255, 255, 255, 0.7);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-top-left-radius: var(--sar-popout-border-top-radius);
|
||||
border-top-right-radius: var(--sar-popout-border-top-radius);
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
.sar-checkbox-popout__check-all {
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
flex-direction: column;
|
||||
position: absolute;
|
||||
left: 1rem;
|
||||
z-index: 2;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
color: var(--sar-tertiary-color);
|
||||
font-size: var(--sar-text-sm);
|
||||
}
|
||||
.sar-checkbox-popout__container {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.sar-checkbox-popout__scroll_searchable {
|
||||
height: var(--sar-checkbox-popout-max-height);
|
||||
}
|
||||
|
||||
.sar-checkbox-popout__scroll {
|
||||
max-height: var(--sar-checkbox-popout-max-height);
|
||||
}
|
||||
|
||||
.sar-popout__footer {
|
||||
width: 100%;
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
align-items: center;
|
||||
padding: var(--sar-popout-footer-gap-y) var(--sar-popout-footer-gap-x);
|
||||
}
|
||||
</style>
|
||||
@@ -1,15 +1,27 @@
|
||||
<script setup lang="ts">
|
||||
import type { PopupProps } from 'sard-uniapp'
|
||||
import { ref } from 'vue'
|
||||
|
||||
const visible = ref(false)
|
||||
function show() {
|
||||
visible.value = !visible.value
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<custom-select
|
||||
title="123"
|
||||
<picker-select
|
||||
v-model:visible="visible"
|
||||
/>
|
||||
<sar-list card>
|
||||
<sar-list-item hover arrow title="底部划出" @click="show('slide-bottom')" />
|
||||
<sar-list-item hover arrow title="底部划出" @click="show()" />
|
||||
</sar-list>
|
||||
<sar-form label-width="240rpx">
|
||||
<sar-form-item label="Activity name">
|
||||
<picker-select-input />
|
||||
</sar-form-item>
|
||||
<sar-form-item label="Activity name">
|
||||
<picker-select-input />
|
||||
</sar-form-item>
|
||||
</sar-form>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
@@ -1 +1,9 @@
|
||||
@import 'sard-uniapp/index.scss';
|
||||
|
||||
.picker-select__pagination-root {
|
||||
width: 100%;
|
||||
.sar-pagination__item,
|
||||
.sar-pagination__ratio {
|
||||
height: auto !important;
|
||||
}
|
||||
}
|
||||
+2
-1
@@ -7,6 +7,7 @@ export {}
|
||||
|
||||
declare module 'vue' {
|
||||
export interface GlobalComponents {
|
||||
CustomSelect: typeof import('./../components/custom-select/index.vue')['default']
|
||||
PickerSelect: typeof import('./../components/picker-select/index.vue')['default']
|
||||
PickerSelectInput: typeof import('./../components/picker-select-input/index.vue')['default']
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user