z-choose.vue 4.21 KB
<template>
  <view class="z-choose" :class="{ 'z-choose--disabled': disabled }">
    <template v-if="mode === 'radio'">
      <template v-for="(item, index) in dictOptions">
        <view :key="index" class="z-choose__item" :class="{ checked: isChecked(item) }" @click="onCheck(item)">
          <render-svg class="z-choose__icon" :name="isChecked(item) ? 'icon-radio-checked' : 'icon-radio'" size="40rpx" />
          <text class="z-choose__label">{{ item.valueName }}</text>
        </view>
      </template>
    </template>
    <template v-else-if="mode === 'tag'">
      <template v-for="(item, index) in dictOptions">
        <view :key="index" class="z-choose__tag" :class="{ checked: isChecked(item) }" @click="onCheck(item)">{{ item.valueName }}</view>
      </template>
    </template>
    <template v-else-if="mode === 'group'">
      <template v-for="(item, index) in dictOptions">
        <view :key="index" class="z-choose__group" :class="{ checked: isChecked(item) }" @click="onCheck(item)">{{ item.valueName }}</view>
      </template>
    </template>
  </view>
</template>

<script>
import { mapGetters } from 'vuex';

export default {
  name: 'ZChoose',
  props: {
    dict: String,
    mode: {
      type: String,
      default: 'radio',
    },
    value: [String, Number, Boolean],
    readonly: Boolean,
    disabled: {
      type: Boolean,
      default: null,
    },
    options: {
      type: Array,
      default: () => [],
    },
    excludes: Array,
    type: {
      type: String,
      default: 'text', // text, boolean
    },
    booleanOptions: Array,
  },
  computed: {
    ...mapGetters(['dictList']),
    dictOptions({ dict, dictList, excludes = [], options = [], type, booleanOptions }) {
      if (type === 'boolean') {
        return (
          booleanOptions || [
            { valueCode: true, valueName: '是' },
            { valueCode: false, valueName: '否' },
          ]
        );
      }
      let hash = {};
      const matchDictList = dictList(dict) || [];
      return [...matchDictList, ...options]
        .reduce((result, item) => {
          if (!hash[`${item.valueCode}`]) {
            hash[`${item.valueCode}`] = true;
            if (`${item.valueCode || ''}` && `${item.valueName || ''}` && !excludes.includes(item.valueCode)) {
              result.push(item);
            }
          }
          return result; // 返回结果数组
        }, [])
        .sort((a, b) => a.sort - b.sort);
    },
    _readonly({ form, readonly }) {
      if (form && form.readonly) {
        return true;
      }
      return readonly;
    },
  },
  methods: {
    isChecked(item) {
      return `${this.value}` === `${item.valueCode}`;
    },
    onCheck(item) {
      if (this._readonly || this.disabled) return;
      this.$emit('input', item.valueCode);
      this.$emit('change', item.valueCode, item);
    },
  },
};
</script>

<style lang="scss">
.z-choose {
  box-sizing: border-box;
  height: 40px;
  display: inline-flex;
  align-items: center;
  width: 100%;
  &--disabled {
    filter: grayscale(100%);
  }
  &__tag {
    background-color: #F2F2F6;
    color: #2b2a27;
    border-radius: 8rpx;
    padding: 10rpx 20rpx;
    margin-right: 20rpx;
    margin-bottom: 20rpx;
    &.checked {
      background-color: $color-primary;
      color: #ffffff;
    }
  }
  &__group {
    background: #f6f8fb;
    color: #2b2a27;
    height: 64rpx;
    padding: 20rpx 30rpx;
    box-sizing: border-box;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    &.checked {
      background-color: $color-primary;
      color: #ffffff;
    }
    &:first-child {
      padding-left: 40rpx;
      border-top-left-radius: 35rpx;
      border-bottom-left-radius: 35rpx;
    }
    &:last-child {
      padding-right: 40rpx;
      border-top-right-radius: 35rpx;
      border-bottom-right-radius: 35rpx;
    }
  }
  &__item {
    display: inline-flex;
    align-items: center;
    flex: 1;
    margin-left: 10px;
    .z-choose__icon {
      margin-right: 10px;
      transition: all 200ms;
    }
    .z-choose__label {
      font-size: 14px;
      font-weight: 400;
      color: #999999;
      white-space: nowrap;
      word-break: break-all;
    }
    &.checked {
      .z-choose__label {
        color: #2b2a27;
      }
    }
  }
}
</style>