index.vue 8.03 KB
<template>
  <div class="choose_store_multi">
    <div v-transfer-dom>
      <x-dialog :show.sync="show" class="dialog-demo">
        <div class="store-title">{{title}}</div>
        <div class="wrap-scroll">
          <div class="store-wrapper">
            <check-icon class="store-all-checked">
              <!-- {{caption}}(<span style="color: #8EA8CF;">{{category_num}}</span>/{{category_sum}}) -->
              所有品牌的门店(<span style="color: #8EA8CF;">{{category_num}}</span>/{{category_sum}})
            </check-icon>
          </div>
          <div class="store-classify">
            <div v-for="(b, bi) in data_list" :key="bi">
              <div style="border-top: 1px dashed #eee; width: 100%;"></div>
              <flexbox class="brand-classify-title">
                <flexbox-item style="text-indent:2px;" :span="10">
                  <check-icon class="brand-classify-checked" :value.sync="b.checked">
                    {{b.name}}(<span style="color: #8EA8CF;">{{b.num}}</span>/{{b.city_count}})
                  </check-icon>
                </flexbox-item>
                <flexbox-item @click.native="fold(bi, 'brand')">
                  <div style="padding-top: 0.2rem; padding-left: 0.5rem;">
                    <i class="fa fa-chevron-down" style="font-size: 0.7rem; color: #838383;"></i>
                  </div>
                </flexbox-item>
              </flexbox>
              <div class="brand-content">
                <div class="store-classify">
                  <div v-for="(c, ci) in b.city_list" :key="ci">
                    <div style="border-top: 1px dashed #eee; width: 100%;"></div>
                    <flexbox class="store-classify-title">
                      <flexbox-item style="text-indent:4px;" :span="10">
                        <check-icon class="store-classify-checked" :value.sync="c.checked">
                          {{c.name}}(<span style="color: #8EA8CF;">{{c.num}}</span>/{{c.store_count}})
                        </check-icon>
                      </flexbox-item>
                      <flexbox-item @click.native="fold(bi, 'store', ci)">
                        <div style="padding-top: 0.2rem; padding-left: 0.5rem;">
                          <i class="fa fa-chevron-down" style="font-size: 0.7rem; color: #838383;"></i>
                        </div>
                      </flexbox-item>
                    </flexbox>
                    <div class="store-content">
                      <div class="store-list">
                        <div v-for="(s, si) in c.store_list" :key="si" @click="itemCheck(s)">
                          <div v-if="!+s.disabled"
                          :class="[s.checked ? 'flex-checked' : '', 'flex-store']">
                          {{s.name}}
                          </div>
                        </div>
                      </div>
                    </div>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
        <div class="control-wrapper">
          <flexbox>
            <flexbox-item>
              <x-button class="close-btn" @click.native="cancel" mini>关闭</x-button>
            </flexbox-item>
            <flexbox-item>
              <x-button class="confirm-btn" @click.native="confirm" mini>确定</x-button>
            </flexbox-item>
          </flexbox>
        </div>
      </x-dialog>
    </div>
  </div>
</template>

<script>
import { XDialog, TransferDomDirective as TransferDom, Flexbox, FlexboxItem, CheckIcon, XButton } from 'vux'
import { Observable } from 'rxjs/Rx'
export default {
  directives: { TransferDom },
  components: { XDialog, Flexbox, FlexboxItem, CheckIcon, XButton },
  props: ['show', 'list', 'title', 'checkList'],
  data () {
    return {
      data_list: [],
      category_num: 0
    }
  },
  watch: {
    list () {
      this.data_list = [];
      Observable.from([...this.list])
        .map(b => {
          // 品牌
          b.checked = false;
          b.num = 0;
          b.city_count = b.city_list.length;
          b.city_list.forEach(c => {
            // 城市
            c.checked = false;
            c.num = 0;
            c.store_count = c.store_list.length;
            c.store_list.forEach(s => {
              // 门店
              s.num = 0;
              s.checked = false;
            })
          })
          return b;
        }).subscribe(v => {
          v.city_list.forEach(c => {
            c.store_list.forEach(s => {
              this.checkList.forEach(checkStore => {
                if (checkStore.store_id === s.store_id) {
                  s.checked = true;
                }
              })
            })
          })
          this.data_list.push(v);
          // 分别计算已选中的
        }).unsubscribe();
    }
  },
  computed: {
    category_sum () {
      // 获取门店总数
      let sum = 0;
      this.data_list.forEach(b => {
        b.city_list.forEach(c => {
          sum += c.store_count;
        })
      })
      return sum;
    }
  },
  methods: {
    fold (index, str, i) {
      let has_class = $($(`.${str}-classify-title`)[index]).siblings(`.${str}-content`).hasClass('fold-content');
      if (i && index - 1 >= 0) {
        // 不为第一组品牌中的城市
        index = this.data_list[index - 1].city_count + i;
      } else {
        // 不是城市或是第一组品牌中的城市
        i ? index = i : '';
      }
      if (has_class) {
        // 展开
        $($(`.${str}-classify-title`)[index]).siblings(`.${str}-content`).removeClass('fold-content');
        $($(`.${str}-classify-title`)[index]).find('i').addClass('fa-chevron-down').removeClass('fa-chevron-right');
      } else {
        // 折叠
        $($(`.${str}-classify-title`)[index]).siblings(`.${str}-content`).addClass('fold-content');
        $($(`.${str}-classify-title`)[index]).find('i').addClass('fa-chevron-right').removeClass('fa-chevron-down');
      }
    },
    itemCheck (item, method) {
      // 选中/取消选中单条
      item.checked = !item.checked;
      let arr = [...this.data_list];
      this.data_list.splice(0, [...arr]);
    },
    cancel () {
      this.$emit('cancel');
    },
    confirm () {
      let data = [];
      Observable.create(store$ => {
        this.data_list.forEach(b => {
          b.city_list.forEach(c => {
            c.store_list.forEach(s => {
              if (s.checked) {
                store$.next(s);
              }
            })
          })
        })
      }).subscribe(v => {
        data.push(v);
      }).unsubscribe();
      this.$emit('confirm', data);
    }
  }
}
</script>

<style lang="less">
.choose_store_multi {
}
.store-title {
  padding: 0.5rem;
  font-size: 18px;
  border-bottom: 1px solid #eee;
}
.wrap-scroll {
  max-height: 30rem;
  overflow-y: auto;
}
.store-wrapper {
  text-align: left;
  .store-all-checked {
    font-size: 0.9rem;
    padding: 0.5rem 0.2rem;
  }
}

.store-classify {
  .store-classify-checked,
  .brand-classify-checked {
    font-size: 0.9rem;
    padding: 0.4rem 0.2rem 0.1rem 0.85rem;
  }
  .store-classify-title,
  .brand-classify-title {
    margin-bottom: 0.5rem;
  }
  .store-content,
  .brand-content {
    border-bottom: 1px dashed #eee;
    .store-list {
      &:after {
        display: block;
        content: "";
        clear: both;
      }
      &>div {
        float: left;
        margin-left: .4rem;
        width: 48%;
        padding-bottom: 10px;
        .flex-store {
          text-align: center;
          background-color: #eee;
        }
        .flex-checked {
          color: white;
          background-color: #8EA8CF;
        }
        .flex-disabled {
          color: #cfcfcf;
          background-color: #ebeef7;
        }
      }
    }
  }
  .store-content {
    padding: 0 1rem;
  }
  .fold-content {
    height: 0;
    overflow: hidden;
    padding-bottom: 0;
  }
}
.control-wrapper {
  padding: 10px;
  .close-btn {
    background-color: #ffffff;
    color: #8EA8CF;
    border: 1px solid #8EA8CF;
    width: 100%;
  }
  .confirm-btn {
    background-color: #8EA8CF;
    color: #ffffff;
    border: 1px solid #8EA8CF;
    width: 100%;
  }
}
</style>