123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347 |
- <template>
- <view>
- <!-- <view @tap="handleOpen">
- <slot></slot>
- </view> -->
- <uni-popup ref="popup">
- <view class="popup-content" :style="props.popupStyle">
- <view class="popup-content-label">
- <view class="popup-content-label-item active">{{ label }}</view>
- </view>
- <view class="popup-content-body">
- <view v-for="(arr, i) in showList" :key="i" class="popup-content-body-list">
- <view class="popup-content-body-list-items">
- <view class="content">
- <view
- v-for="_arr in arr.data"
- :key="_arr[props.itemValue]"
- class="py-1 dFlex"
- :class="arr.choose === _arr[props.itemValue] || (Array.isArray(arr.choose) && arr.choose.includes(_arr[props.itemValue]))? 'active' : ''"
- @tap="handleNext(_arr, i)"
- >
- {{ _arr[props.itemLabel] }}
- <uni-icons
- v-if="Array.isArray(arr.choose) && arr.choose.includes(_arr[props.itemValue])"
- type="checkmarkempty"
- color="#00B760"
- size="16"
- />
- </view>
- </view>
- </view>
- </view>
- </view>
- <view class="popup-content-footer">
- <!-- <button class="btn cancel" @tap="reset">重置</button> -->
- <button class="btn submit" @tap="submit">确定</button>
- </view>
- </view>
- </uni-popup>
- </view>
- </template>
- <script setup>
- import { ref, watch } from 'vue'
- const emit = defineEmits(['change', 'init'])
- const props = defineProps({
- popupStyle: {
- type: [String, Object],
- default: ''
- },
- value: {
- type: [String, Array, Number, Object],
- default: null
- },
- items: { // 树结构
- type: Array,
- default: () => []
- },
- label: {
- type: String,
- default: ''
- },
- multiple: {
- type: Boolean,
- default: false
- },
- itemLabel: {
- type: String,
- default: 'label'
- },
- itemValue: {
- type: String,
- default: 'value'
- },
- children: {
- type: String,
- default: 'children'
- }
- })
- const popup = ref()
- const showList = ref([])
- watch(
- () => props.items,
- (val) => {
- // 初始化赋值
- showList.value = [{
- choose: -1,
- data: val
- }]
- },
- {
- immediate: true,
- deep: true
- }
- )
- const handleData = (val) => {
- if (!val) {
- showList.value = [{
- choose: -1,
- data: props.items
- }]
- return
- }
- // 单选 设置回显
- if (!props.multiple) {
- const item = findItem(val, props.items)
- if (!item) {
- showList.value = [{
- choose: -1,
- data: props.items
- }]
- return
- }
- showList.value = item.map(e => {
- return {
- choose: e[props.itemValue],
- data: e.data
- }
- })
- emit('init', item[item.length - 1][props.itemLabel])
- return
- }
- if (!Array.isArray(val)) {
- showList.value = [{
- choose: -1,
- data: props.items
- }]
- return
- }
- // 多选 设置回显
- const arr = []
- const label = []
- val.forEach(e => {
- const item = findItem(e, props.items)
- if (!item) {
- return
- }
- label.push(item[item.length - 1][props.itemLabel])
- if (!arr.length) {
- arr.push(...item.map((e, i) => {
- return {
- choose: i === item.length - 1 ? [e[props.itemValue]] : e[props.itemValue],
- data: e.data
- }
- }))
- return
- }
- arr[arr.length - 1].choose.push(item[item.length - 1][props.itemValue])
- })
- if (!arr.length) {
- showList.value = [{
- choose: -1,
- data: props.items
- }]
- return
- }
- showList.value = arr
- emit('init', label)
- }
- const findItem = (value, lists) => {
- let level = -1
- return check(value, lists)
- function check (val, items, arr = []) {
- let i = 0
- level++
- while (i < items.length) {
- arr[level] = {
- ...items[i],
- data: items
- }
- if (items[i][props.itemValue] === val) {
- return arr
- }
- if (items[i][props.children] && items[i][props.children].length > 0) {
- const data = check(val, items[i][props.children], arr)
- if (data) {
- return data
- }
- }
- i++
- }
- level--
- return false
- }
- }
- const handleOpen = () => {
- handleData(props.value)
- popup.value.open('bottom')
- }
- const handleNext = (item, index) => {
- const _i = index + 1
- // active.value = _i
- showList.value.splice(_i, showList.value.length - _i)
- showList.value[index].label = item[props.itemLabel]
- if (item[props.children] && item[props.children].length) {
- showList.value[index].choose = item[props.itemValue]
- showList.value.push({
- choose: -1,
- data: item[props.children]
- })
- return
- }
- if (!props.multiple) {
- showList.value[index].choose = item[props.itemValue]
- return
- }
- if (!Array.isArray(showList.value[index].choose)) {
- showList.value[index].choose = [item[props.itemValue]]
- return
- }
- if (!showList.value[index].choose.includes(item[props.itemValue])) {
- showList.value[index].choose.push(item[props.itemValue])
- return
- }
- const _index = showList.value[index].choose.indexOf(item[props.itemValue])
- showList.value[index].choose.splice(_index, 1)
- }
- const reset = () => {
- showList.value = [{
- choose: -1,
- data: props.items
- }]
- emit('change', props.multiple ? [] : null)
- popup.value.close()
- }
- const submit = () => {
- const item = showList.value[showList.value.length - 1]
- if (item.choose === -1) {
- const _item = showList.value[showList.value.length - 2]
- if (!item) {
- emit('change', props.multiple ? [] : null)
- popup.value.close()
- return
- }
- emit('change', props.multiple ? [_item.choose] : _item.choose, props.multiple ? showList.value[0].label : _item.label, item)
- popup.value.close()
- return
- }
- emit('change', item.choose, props.multiple ? showList.value[0].label : item.label, item)
- popup.value.close()
- }
- defineExpose({
- handleOpen
- })
- </script>
- <style lang="scss" scoped>
- .popup-content {
- height: 580px;
- background: #FFF;
- border-radius: 20rpx 20rpx 0 0;
- padding: 10px;
- box-sizing: border-box;
- display: flex;
- flex-direction: column;
- &-label {
- height: 50px;
- display: flex;
- font-size: 32rpx;
- font-weight: bold;
- margin-bottom: 10px;
- border-bottom: 2rpx solid #EEE;
- &-item {
- display: flex;
- align-items: center;
- padding: 0 15px;
- box-sizing: border-box;
- &.active {
- border-bottom: 2px solid #00B760;
- }
- }
- }
- &-body {
- flex: 1;
- height: 0;
- display: flex;
- &-list {
- height: 100%;
- min-width: 100px;
- margin-right: 20px;
- display: flex;
- flex-direction: column;
- &-label {
- border-bottom: 1px solid #eee;
- display: flex;
- align-items: center;
- justify-content: center;
- height: 50px;
- box-sizing: border-box;
- margin-bottom: 10px;
- &.active {
- border-bottom: 2px solid #00B760;
- }
- }
- &-items {
- flex: 1;
- height: 0;
- .content {
- height: 100%;
- overflow-x: hidden;
- overflow-y: auto;
- .active {
- color: #00B760;
- }
- }
- }
- }
- }
- &-footer {
- height: 50px;
- display: flex;
- align-items: center;
- .btn {
- font-size: 28rpx;
- height: 30px;
- line-height: 30px;
- &.cancel {
- width: 40%;
- margin-right: 10px;
- }
- &.submit {
- flex: 1;
- background: #00B760;
- color: #FFF ;
- }
- }
- }
- }
- .dFlex {
- display: flex;
- justify-content: space-between;
- height: 20px;
- }
- .py-1 {
- padding: 10px 0;
- }
- </style>
|