404 lines
9.7 KiB
Vue
404 lines
9.7 KiB
Vue
<script setup lang="ts">
|
|
import type { PropType } from 'vue'
|
|
import { useIndeterminate } from 'sard-uniapp'
|
|
import { computed, ref } from 'vue'
|
|
import { getAutocompleteDataApi, getAutocompleteDataExApi } from '@/request/api'
|
|
|
|
const props = defineProps({
|
|
visible: {
|
|
type: Boolean,
|
|
default: false,
|
|
},
|
|
type: {
|
|
type: String as PropType<'radio' | 'multiple'>,
|
|
default: 'radio',
|
|
},
|
|
value: {
|
|
type: null as unknown as PropType<any | any[]>,
|
|
default: undefined,
|
|
},
|
|
labelField: {
|
|
type: String,
|
|
required: true,
|
|
},
|
|
labelField2: {
|
|
type: String,
|
|
required: false,
|
|
},
|
|
valueField: {
|
|
type: String,
|
|
required: true,
|
|
},
|
|
viewname: {
|
|
type: String,
|
|
},
|
|
searchcondition: {
|
|
type: String,
|
|
required: false,
|
|
},
|
|
userid: {
|
|
type: String,
|
|
required: false,
|
|
},
|
|
field1: {
|
|
type: String,
|
|
required: true,
|
|
},
|
|
field2: {
|
|
type: String,
|
|
required: true,
|
|
},
|
|
searchType: {
|
|
type: String as PropType<'default' | 'ex' | 'single'>,
|
|
default: 'default',
|
|
required: false,
|
|
},
|
|
})
|
|
const emit = defineEmits(['update:visible', 'update:value', 'change'])
|
|
|
|
const _visible = ref(props.visible)
|
|
|
|
watch(() => props.visible, val => _visible.value = val)
|
|
|
|
const loading = ref(true)
|
|
|
|
const searchValue = ref('')
|
|
const pagination = ref({
|
|
current: 1,
|
|
pageSize: 10,
|
|
total: 0,
|
|
})
|
|
|
|
const isPrevDisabled = computed(() => pagination.value.current <= 1)
|
|
const isNextDisabled = computed(() =>
|
|
pagination.value.current >= Math.ceil(pagination.value.total / pagination.value.pageSize),
|
|
)
|
|
|
|
// 内部 value,双向绑定 props.value
|
|
const _value = computed({
|
|
get: () => {
|
|
if (props.type === 'multiple') {
|
|
return Array.isArray(props.value) ? props.value : []
|
|
}
|
|
return props.value ?? null
|
|
},
|
|
set: (val) => {
|
|
emit('update:value', val)
|
|
},
|
|
})
|
|
|
|
const options = ref<any[]>([])
|
|
|
|
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 selectedOption = options.value.find(
|
|
o => o.value === option.value,
|
|
)
|
|
|
|
_visible.value = false
|
|
emit('update:visible', false)
|
|
emit('change', selectedOption)
|
|
}
|
|
}
|
|
}
|
|
|
|
// 显示数量
|
|
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() {
|
|
getData()
|
|
}
|
|
|
|
function handlePagationChange(page: number) {
|
|
pagination.value.current = page
|
|
|
|
getData()
|
|
}
|
|
|
|
function handleSearch() {
|
|
pagination.value.current = 1
|
|
pagination.value.total = 0
|
|
pagination.value.pageSize = 10
|
|
|
|
getData()
|
|
}
|
|
|
|
function getData() {
|
|
if (props.searchType === 'ex') {
|
|
getAutocompleteDataEx()
|
|
}
|
|
else if (props.searchType === 'single') {
|
|
getAutocompleteDataSingle()
|
|
}
|
|
else {
|
|
getAutocompleteData()
|
|
}
|
|
}
|
|
|
|
function getAutocompleteData() {
|
|
loading.value = true
|
|
|
|
getAutocompleteDataApi({
|
|
q: searchValue.value,
|
|
page: pagination.value.current,
|
|
limit: pagination.value.pageSize,
|
|
viewname: props.viewname,
|
|
field1: props.field1,
|
|
field2: props.field2,
|
|
}).then((res) => {
|
|
pagination.value.total = res.data.total
|
|
|
|
options.value = res.data.rows.map((item) => {
|
|
const label1 = item[props.labelField] ?? ''
|
|
const label2 = props.labelField2
|
|
? item[props.labelField2] ?? ''
|
|
: ''
|
|
|
|
return {
|
|
label: label2 ? `${label1} | ${label2}` : label1,
|
|
value: item[props.valueField] ?? undefined,
|
|
disabled: !!item.disabled,
|
|
...item,
|
|
}
|
|
})
|
|
|
|
console.log(res.data.rows)
|
|
}).finally(() => {
|
|
loading.value = false
|
|
})
|
|
}
|
|
|
|
function getAutocompleteDataEx() {
|
|
loading.value = true
|
|
|
|
getAutocompleteDataExApi({
|
|
q: searchValue.value,
|
|
page: pagination.value.current,
|
|
limit: pagination.value.pageSize,
|
|
viewname: props.viewname,
|
|
field1: props.field1,
|
|
field2: props.field2,
|
|
userid: props.userid,
|
|
searchcondition: props.searchcondition,
|
|
}).then((res) => {
|
|
pagination.value.total = res.data.total
|
|
|
|
options.value = res.data.rows.map((item) => {
|
|
const label1 = item[props.labelField] ?? ''
|
|
const label2 = props.labelField2
|
|
? item[props.labelField2] ?? ''
|
|
: ''
|
|
|
|
return {
|
|
label: label2 ? `${label1} | ${label2}` : label1,
|
|
value: item[props.valueField] ?? undefined,
|
|
disabled: !!item.disabled,
|
|
...item,
|
|
}
|
|
})
|
|
}).finally(() => {
|
|
loading.value = false
|
|
})
|
|
}
|
|
|
|
function getAutocompleteDataSingle() {
|
|
|
|
}
|
|
|
|
function handleCancel() {
|
|
_visible.value = false
|
|
emit('update:visible', false)
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<sar-popout
|
|
:visible="_visible"
|
|
:show-footer="false"
|
|
title="请选择"
|
|
@after-enter="handleAfterEnter"
|
|
@close="handleCancel"
|
|
>
|
|
<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
|
|
@confirm="handleSearch"
|
|
>
|
|
<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
|
|
:key="option.value"
|
|
readonly
|
|
:disabled="option.disabled"
|
|
:value="option.value"
|
|
/>
|
|
</template>
|
|
</sar-list-item>
|
|
</sar-list>
|
|
</template>
|
|
</sar-radio-group>
|
|
</scroll-view>
|
|
</view>
|
|
|
|
<view class="sar-popout__footer">
|
|
<sar-pagination
|
|
:current="pagination.current"
|
|
:total="pagination.total"
|
|
:page-size="pagination.pageSize"
|
|
type="simple"
|
|
root-class="picker-select__pagination-root"
|
|
@change="handlePagationChange"
|
|
>
|
|
<template #prev>
|
|
<sar-button type="default" :disabled="isPrevDisabled" size="mini" :loading="loading">
|
|
上一页
|
|
</sar-button>
|
|
</template>
|
|
<template #next>
|
|
<sar-button type="default" :disabled="isNextDisabled" size="mini" :loading="loading">
|
|
下一页
|
|
</sar-button>
|
|
</template>
|
|
</sar-pagination>
|
|
|
|
<sar-button
|
|
v-if="props.type === 'multiple'"
|
|
:root-style="{ width: '100%' }"
|
|
>
|
|
确认
|
|
</sar-button>
|
|
</view>
|
|
</view>
|
|
</template>
|
|
</sar-popout>
|
|
</template>
|
|
|
|
<style lang="scss" scoped>
|
|
.sar-checkbox-popout__check-all {
|
|
position: relative;
|
|
box-sizing: border-box;
|
|
flex-direction: column;
|
|
position: absolute;
|
|
left: 32rpx;
|
|
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: 16rpx;
|
|
align-items: center;
|
|
padding: var(--sar-popout-footer-gap-y) var(--sar-popout-footer-gap-x);
|
|
}
|
|
</style>
|