<template>
  <!-- 
    整页表单的分片表单
    v 1.0
    2021-05-12
    Lufthafen
  -->
  <a-form-model
    :label-col="labelCol"
    :model="form"
    :rules="rules"
    :wrapper-col="wrapperCol"
    ref="form"
  >
    <a-spin :spinning="loading">
      <a-icon slot="indicator" spin type="loading" />
      <!-- 表单控件 -->
      <!-- ... -->
      <a-form-model-item class="ant-row-flex" label="房屋性质" prop="type">
        <a-radio-group
          :disabled="!!form.id"
          @change="onTypeChange"
          button-style="solid"
          v-model="form.type"
        >
          <a-radio-button
            :key="item.code"
            :value="+item.code"
            v-for="item in codes.houseType"
          >{{ item.value }}</a-radio-button>
        </a-radio-group>
      </a-form-model-item>
      <a-form-model-item class="ant-row-flex" label="所属行业、系统" prop="industry">
        <a-radio-group :disabled="form.type == 1" button-style="solid" v-model="form.industry">
          <a-radio-button
            :key="item.code"
            :value="+item.code"
            v-for="item in codes.houseIndustry"
          >{{ item.value }}</a-radio-button>
        </a-radio-group>
      </a-form-model-item>
      <a-form-model-item class="ant-row-flex" label="房屋编码" prop="no">
        <a-row :gutter="8" align="top" type="flex">
          <a-col flex="1">
            <a-form-model-item class="mb-none" prop="areaCode">
              <a-cascader
                :display-render="({labels}) => labels.join(' - ')"
                :field-names="{ label: 'name', value: 'code', children: 'children' }"
                :options="options.areaTree"
                @change="onAreaCodeChange()"
                expand-trigger="hover"
                placeholder="请选择所在区域"
                v-model="form.areaCode"
              />
            </a-form-model-item>
          </a-col>
          <a-col>
            <span>-</span>
          </a-col>
          <a-col flex="1">
            <a-form-model-item class="mb-none" prop="projectId">
              <a-select @change="onProjectChange" placeholder="请选择项目" v-model="form.projectId">
                <a-select-option
                  :key="item.id"
                  :value="item.id"
                  v-for="item in options.projects"
                >{{ item.name }}</a-select-option>
              </a-select>
            </a-form-model-item>
          </a-col>
          <a-col>
            <span>-</span>
          </a-col>
          <a-col flex="1">
            <a-form-model-item class="mb-none" prop="no">
              <a-input-number
                :formatter="(number) => `000${number}`.slice(-3)"
                :max="999"
                :min="1"
                :precision="0"
                :step="1"
                class="w-100-p"
                placeholder="请输入房屋序号"
                v-model="form.no"
              />
            </a-form-model-item>
          </a-col>
          <a-col v-if="codeSuffix">
            <span>- {{ codeSuffix }}</span>
          </a-col>
        </a-row>
      </a-form-model-item>
      <a-form-model-item :colon="false" :label="true" class="ant-row-flex" v-if="houseCode">
        <a-tag :key="index" color="purple" v-for="(item, index) in houseCode">{{ item}}</a-tag>
      </a-form-model-item>
      <a-form-model-item class="ant-row-flex" label="所属片区" prop="zoneId">
        <a-select placeholder="请选择所属片区" v-model="form.zoneId">
          <a-select-option
            :key="item.id"
            :value="item.id"
            v-for="item in options.zones"
          >{{ item.name }}</a-select-option>
        </a-select>
      </a-form-model-item>
      <a-form-model-item class="ant-row-flex" label="房屋地址" prop="address">
        <a-input placeholder="请输入房屋地址或在地图上选择地点" v-model="form.address" />
      </a-form-model-item>
      <a-form-model-item class="ant-row-flex" label="地理坐标" required>
        <a-row :gutter="16">
          <a-col :span="12">
            <a-form-model-item class="mb-none" prop="lng">
              <a-input
                class="yo-input-prefix-2"
                disabled
                placeholder="请在地图中选择坐标"
                prefix="经度"
                v-model="form.lng"
              />
            </a-form-model-item>
          </a-col>
          <a-col :span="12">
            <a-form-model-item class="mb-none" prop="lat">
              <a-input
                class="yo-input-prefix-2"
                disabled
                placeholder="请在地图中选择坐标"
                prefix="纬度"
                v-model="form.lat"
              />
            </a-form-model-item>
          </a-col>
        </a-row>
      </a-form-model-item>
      <a-form-model-item :colon="false" :label="true" class="ant-row-flex">
        <div class="yo-map-container">
          <div class="yo-map--search">
            <a-input-search allow-clear placeholder="请输入关键字" ref="map-search" />
          </div>
          <div class="h-500" ref="map"></div>
        </div>
      </a-form-model-item>
    </a-spin>
  </a-form-model>
</template>
<script>
import { CITY } from '@/util/global';

/* 表单内容默认值 */
const defaultForm = {
  /* ... */
  type: '1',
  no: '001',
};

export default {
  props: ['param'],

  data() {
    const validatorIndustry = (rule, value, callback) => {
      if (this.form.type == 2 && !value) {
        callback(new Error('请选择所属行业、系统'));
      } else {
        callback();
      }
    };

    return {
      labelCol: { flex: '150px' },
      wrapperCol: { flex: '1' },

      /** 表单数据 */
      form: {},
      /** 验证格式 */
      rules: {
        /* ... */
        type: [{ required: true, message: '请选择房屋性质' }],
        industry: [{ validator: validatorIndustry }],
        areaCode: [{ required: true, message: '请选择房屋所在区域' }],
        projectId: [{ required: true, message: '请选择项目' }],
        no: [{ required: true, message: '请输入房屋序号', trigger: 'blur' }],
        zoneId: [{ required: true, message: '请选择片区' }],
        address: [{ required: true, message: '请输入房屋地址', trigger: 'blur' }],
        lng: [{ required: true, message: '请在地图中选择坐标' }],
        lat: [{ required: true, message: '请在地图中选择坐标' }],
      },

      /** 加载异步数据状态 */
      loading: false,

      /** 其他成员属性 */
      /* ... */
      codes: {
        houseType: [],
        houseIndustry: [],
      },

      options: {
        areaTree: [],
        projects: [],
        zones: [],
      },
    };
  },

  computed: {
    /**
     * 房屋完整编号,仅展示
     */
    houseCode() {
      const houseCode = [];
      if (this.form.areaCode && this.form.areaCode.length === 4) {
        let deep = this.$_.cloneDeep(this.options.areaTree);
        this.form.areaCode.forEach((p, i) => {
          const _deep = deep.find((m) => m.code === p);
          if (i === 3) {
            deep = _deep;
          } else {
            deep = _deep.children;
          }
        });
        houseCode.push(...deep.adCode.split(''));
      } else {
        houseCode.push(...'XXXXXXXXXXXX'.split(''));
      }

      /** bug 练级选择,导致此处项目列表未加载 */
      if (this.form.projectId && this.options.projects.length) {
        const project = this.options.projects.find((p) => p.id === this.form.projectId);
        houseCode.push(...`000${project.sort}`.slice(-3).split(''));
      } else {
        houseCode.push(...'XXX'.split(''));
      }

      if (this.form.no) {
        houseCode.push(...`000${this.form.no}`.slice(-3).split(''));
      } else {
        houseCode.push(...'XXX'.split(''));
      }

      if (this.codeSuffix) {
        houseCode.push(this.codeSuffix);
      }

      return houseCode;
    },
    /**
     * 非住宅编号后缀,仅展示
     */
    codeSuffix() {
      if (this.form.industry) {
        const houseIndustry = this.codes.houseIndustry.find((p) => p.code == this.form.industry);
        return houseIndustry.extCode.tag;
      }
      return '';
    },
  },

  async created() {
    await this.onInit();
    this.onFillData();
  },

  beforeDestroy() {
    if (this.map) this.map.destroy();
  },

  methods: {
    /**
     * 必要的方法
     * 在打开编辑页时允许填充数据
     */
    onFillData() {
      /** 将默认数据覆盖到form */
      const record = this.param && this.param.record;

      let areaCode = [];
      if (record) {
        areaCode = [
          record.areaCode.substr(0, 4),
          record.areaCode.substr(0, 6),
          record.areaCode.substr(0, 9),
          record.areaCode,
        ];
      }

      this.form = this.$_.cloneDeep({
        ...defaultForm,
        ...record,
        /** 在此处添加其他默认数据转换 */
        /* ... */
        areaCode,
      });

      if (this.form.id) {
        this.onAreaCodeChange(true);
      }

      this.$nextTick(async () => {
        await this.onMapInit();
        if (this.form.lng && this.form.lat) {
          this.setMarker([this.form.lng, this.form.lat]);
          this.map.setCenter([this.form.lng, this.form.lat]);
        }
      });
    },

    /**
     * 必要方法
     * 验证表单并获取表单数据
     */
    onGetData() {
      return new Promise((reslove, reject) => {
        this.$refs.form.validate((valid) => {
          if (valid) {
            const record = this.$_.cloneDeep(this.form);

            /** 验证通过后可以对数据进行转换得到想要提交的格式 */
            /* ... */
            record.areaCode = record.areaCode[3];

            reslove(record);
          } else {
            reject();
          }
        });
      });
    },

    /**
     * 必要的方法
     * 在外部窗口进行保存时调用表单验证
     */
    onValidate(callback) {
      this.$refs.form.validate(callback);
    },

    /**
     * 必要的方法
     * 在外部窗口关闭或重置时对表单验证进行初始化
     */
    onResetFields() {
      setTimeout(() => {
        this.$refs.form.resetFields();

        /** 在这里可以初始化当前组件中其他属性 */
        /* ... */
      }, 300);
    },

    /**
     * 必要方法
     * 加载当前表单中所需要的异步数据
     */
    async onInit() {
      this.loading = true;
      /** 可以在这里await获取一些异步数据 */
      /* ... */
      await this.onLoadCodes();
      await this.onLoadAreaTree();
      this.loading = false;
    },

    /** 当前组件的其他方法 */
    /* ... */
    onLoadCodes() {
      return this.$api
        .$queue([
          this.$api.sysDictTypeDropDownAwait({ code: 'dic_house_type' }),
          this.$api.sysDictTypeDropDownAwait({ code: 'dic_house_industry' }),
        ])
        .then(([dic_house_type, dic_house_industry]) => {
          this.codes.houseType = dic_house_type.data;
          this.codes.houseIndustry = dic_house_industry.data;
        });
    },

    onMapInit() {
      return new Promise((resolve) => {
        const city = CITY;

        const district = new AMap.DistrictSearch({
          subdistrict: 0,
          extensions: 'all',
          level: 'city',
        });

        district.search(city, (status, result) => {
          const bounds = result.districtList[0].boundaries;
          const mask = [];
          for (let i = 0; i < bounds.length; i += 1) {
            mask.push([bounds[i]]);
          }

          // 挂载map到this,但不监听
          this.map = new AMap.Map(this.$refs.map, {
            mask,
            zoom: 12,
          });

          const geocoder = new AMap.Geocoder({ city });

          this.map.on('click', (e) => {
            this.setMarker(e.lnglat, geocoder);
          });

          this.map.on('complete', () => {
            this.map.setFitView();
            this.map.setZoom(12);
            resolve();
          });

          const auto = new AMap.AutoComplete({
            input: this.$refs['map-search'].$el.querySelector('input'),
            city,
            citylimit: true,
          });

          const placeSearch = new AMap.PlaceSearch({
            city,
            citylimit: true,
            pageSize: 1,
          });

          auto.on('select', ({ poi: { name: keywords, adcode } }) => {
            this.map.clearMap();
            this.marker = null;
            placeSearch.search(keywords, (status, result) => {
              const {
                poiList: { pois },
              } = result;
              pois.forEach((p) => {
                this.setMarker(p.location, geocoder);
              });

              this.map.setFitView();
            });
          });

          for (let i = 0; i < bounds.length; i += 1) {
            new AMap.Polyline({
              path: bounds[i],
              strokeColor: '#ccc',
              strokeWeight: 4,
              map: this.map,
            });
          }
        });
      });
    },

    setMarker(position, geocoder) {
      if (this.marker) {
        this.marker.setPosition(position);
      } else {
        this.marker = new AMap.Marker({
          map: this.map,
          icon: '//a.amap.com/jsapi_demos/static/demo-center/icons/poi-marker-default.png',
          position,
          offset: new AMap.Pixel(-13, -30),
        });
      }

      if (geocoder) {
        geocoder.getAddress(position, (status, result) => {
          if (status === 'complete' && result.regeocode) {
            this.onSetPosition(result.regeocode.formattedAddress, position);
          } else {
            console.error('根据经纬度查询地址失败');
          }
        });
      }
    },

    onSetPosition(address, { lng, lat }) {
      this.$set(this.form, 'address', address);
      this.$set(this.form, 'lng', lng);
      this.$set(this.form, 'lat', lat);
    },

    onLoadAreaTree() {
      return this.$api.getAreaTree().then(({ data }) => {
        this.options.areaTree = data;
      });
    },

    /**
     * 切换房屋性质
     */
    async onTypeChange() {
      if (this.form.industry) {
        this.form.industry = undefined;
      }
      this.loading = true;
      await this.getProjects();
      this.loading = false;
    },

    /**
     * 切换区域
     */
    async onAreaCodeChange(autoChange = false) {
      if (this.form.areaCode.length != 4) {
        this.form.areaCode = [];
      }

      this.loading = true;
      try {
        await this.getProjects(autoChange);
        await this.getZones(autoChange);
      } finally {
        this.loading = false;
      }
    },

    async getProjects(autoChange = false) {
      if (this.form.projectId && !autoChange) {
        this.form.projectId = undefined;
      }
      if (this.form.areaCode && this.form.areaCode.length === 4) {
        const projects = await this.$api
          .houseProjectList({
            areaCode: this.form.areaCode[3],
            type: this.form.type,
          })
          .then(({ data }) => {
            return data;
          });
        this.options.projects = projects;
      }
    },

    /**
     * 切换项目
     */
    async onProjectChange() {
      this.loading = true;
      const no = await this.$api
        .houseCodeNo({
          projectId: this.form.projectId,
        })
        .then(({ data }) => {
          return data;
        });
      this.$set(this.form, 'no', no);
      this.loading = false;
    },

    async getZones(autoChange = false) {
      if (this.form.zoneId && !autoChange) {
        this.form.zoneId = undefined;
      }
      if (this.form.areaCode && this.form.areaCode.length === 4) {
        const zones = await this.$api
          .houseZoneList({
            areaCode: this.form.areaCode[3],
          })
          .then(({ data }) => {
            return data;
          });

        this.options.zones = zones;
      }
    },
  },
};
</script>