/*
 * @Author: zhuangmw
 * @Email: zhuangmw@hxmec.com
 * @Date: 2020-06-10 16:31:27
 * @Last Modified by: zhuangmw
 * @Last Modified time: 2020-08-28 10:53:33
 * @Description: 地址选择器
 */
<template>
    <div>
        <div v-if="!readonly">
            <el-select ref="province"
                       v-model="value[provinceField]"
                       @change="addressSelect(provinceField, $event)"
                       class="areaField-select"
                       placeholder="选择省">
                <el-option
                    v-for="item in provinceOptions"
                    :key="item.value"
                    :label="setMaterialOptionsLabelByConfig(item, 'label')"
                    :value="setMaterialOptionsLabelByConfig(item, 'value')" />
            </el-select>
            <el-select ref="city"
                       v-model="value[cityField]"
                       @change="addressSelect(cityField, $event)"
                       class="areaField-select"
                       placeholder="选择市">
                <el-option
                    v-for="item in cityOptions"
                    :key="item.value"
                    :label="setMaterialOptionsLabelByConfig(item, 'label')"
                    :value="setMaterialOptionsLabelByConfig(item, 'value')" />
            </el-select>
            <el-select ref="area"
                       v-model="value[areaField]"
                       @change="addressSelect(areaField, $event)"
                       class="areaField-select"
                       placeholder="选择区/县">
                <el-option
                    v-for="item in areaOptions"
                    :key="item.value"
                    :label="setMaterialOptionsLabelByConfig(item, 'label')"
                    :value="setMaterialOptionsLabelByConfig(item, 'value')" />
            </el-select>
            <el-input v-model="value[addressField]"
                      placeholder="请输入街道门牌号，如：海沧达到669号"
                      class="areaField-input" />
        </div>
        <div v-else>
            {{ readonlyFormatter }}
        </div>
    </div>
</template>

<script>
export default {
    name: 'BkAddressSelect',
    props: {
        materialConfig: {
            type: Object,
            default: () => ({})
        },
        value: {
            type: Object,
            default: () => ({})
        },
        readonly: {
            type: Boolean,
            default: false
        }
    },
    data() {
        return {
            provinceOptions: [],
            cityOptions: [],
            areaOptions: [],
            provinceField: 'provinceId', // 省份的字段
            cityField: 'cityId', // 市的字段
            areaField: 'areaId', // 区，县的字段
            addressField: 'addressField', // 详细地址
            provinceSelectedLabel: '', // 省份的选择结果
            citySelectedLabel: '', // 市的选择结果
            areaSelectedLabel: '' // 区的选择结果
        };
    },
    computed: {
        readonlyFormatter() {
            const formatter = [
                this.provinceSelectedLabel, 
                this.citySelectedLabel, 
                this.areaSelectedLabel, this.value[this.addressField]].join(this.materialConfig.separator || '-');
            return formatter;
        }
    },
    watch: {
        value() {
            this.initFlow();
        }
    },
    created() {
        this.initFlow();
    },
    methods: {
        initFlow() {
            const { extraFields } = this.materialConfig; // 自定义各个选择框的字段
            let parentId;
            if (extraFields && Array.isArray(extraFields)) {
                [this.provinceField, this.cityField, this.areaField, this.addressField] = extraFields;
            }
            this.fetchCascadeSelect().then(res => {
                if (res && res.code === 0) {
                    this.provinceOptions = res.data;
                    this.provinceSelectedLabel = this.selectedLabelFilter(this.value[this.provinceField], this.provinceOptions);
                }
            });
            if (this.value[this.cityField]) {
                parentId = this.value[this.provinceField];
                this.fetchCascadeSelect(parentId).then(res => {
                    if (res.code === 0) {
                        this.cityOptions = res.data;
                        this.citySelectedLabel = this.selectedLabelFilter(this.value[this.cityField], this.cityOptions);
                    }
                });
            }
            if (this.value[this.areaField]) {
                parentId = this.value[this.cityField];
                this.fetchCascadeSelect(parentId).then(res => {
                    if (res.code === 0) {
                        this.areaOptions = res.data;
                        this.areaSelectedLabel = this.selectedLabelFilter(this.value[this.areaField], this.areaOptions);
                    }
                });
            }
        },
        addressSelect(field, target) {
            const val = String(target);
            const request = this.fetchCascadeSelect(val);
            if (field === this.provinceField) {
                this.provinceSelectedLabel = this.selectedLabelFilter(val, this.provinceOptions);
                this.$set(this.value, this.cityField, '');
                this.$set(this.value, this.areaField, '');
                this.$set(this.value, this.addressField, '');
                request.then(res => {
                    this.cityOptions = res.data;
                });
            } else if (field === this.cityField) {
                this.citySelectedLabel = this.selectedLabelFilter(val, this.cityOptions);
                this.$set(this.value, this.areaField, '');
                this.$set(this.value, this.addressField, '');
                request.then(res => {
                    this.areaOptions = res.data;
                });
            } else if (field === this.areaField) {
                this.areaSelectedLabel = this.selectedLabelFilter(val, this.areaOptions);
                this.value[this.addressField] = '';
            }
        },
        fetchCascadeSelect(parentId = 1) {
            const { http } = this.materialConfig;
            const {
                url, params, method, onBefore, onSuccess, onFaild 
            } = http || {};

            let finalParams = Object.assign(
                {},
                {
                    [(params && params.default) || 'parentId']: parentId
                },
                params || {}
            );
            if (finalParams.default) delete finalParams.default;

            // 调用请求发送前函数钩子
            if (typeof onBefore === 'function') {
                const result = onBefore(finalParams, this);
                if (result === false) return null;
                if (typeof result === 'object') finalParams = result;
            }
            return this.$fetch({
                url,
                method,
                params: finalParams
            }).then(res => {
                if (!res) {
                    if (typeof onFaild === 'function') onFaild(res, this);
                    return Promise.reject();
                }
                // 成功回调
                if (typeof onSuccess === 'function') {
                    onSuccess(res, this);
                }
                return Promise.resolve(res);
            }).catch(err => {
                // 失败回调
                if (typeof onFaild === 'function') {
                    onFaild(err, this);
                }
            });
        },
        /**
         * @Description 根据配置的属性获取数据对象的值
         * @params [Object] obj 数据对象
         * @params [String] key 配置的属性值
         */
        setMaterialOptionsLabelByConfig(obj, key) {
            const { props, type, valueObj } = this.materialConfig;
            // 针对select多选时值为选中的整个数据对象
            if (type === 'select' && key === 'value' && valueObj) {
                return obj;
            }
            if (props && props[key]) {
                return obj[props[key]];
            }
            return obj[key];
        },
        selectedLabelFilter(targetId, options) {
            const { props } = this.materialConfig;
            const { label, value } = props;
            const target = options.find(item => {
                if (item[value] === targetId) {
                    return true;
                }
                return false;
            });
            if (target) {
                return target[label];
            }
            return '';
        }
    }
};
</script>
