<template>
  <div>
    <div
      :id="uid"
      style="margin: auto"
      :style="{ height: setting.chartHeight ? setting.chartHeight + 'px' : '400px', width: setting.chartWidth ? setting.chartWidth + 'px' : '95%' }"
    ></div>
    <div>
      <Button class="ivu-fr" type="error" :title="$t('Front_Btn_Setting')" custom-icon="fa fa-cog" v-if="allow('permission/tableView')" @click="openSetting()"></Button>
    </div>
    <modal-form ref="setting" view-code="ChartSetting">
      <template slot="column" slot-scope="{ code }">
        <template v-if="code == 'chartXCode' || code == 'chartGroupCode' || code == 'chartValueCode'">
          <Input type="text" :readonly="true" :clearable="true" v-model="$refs.setting.data[code]" @click.native="columnCheck(tableView, $refs.setting.data, code)">
            <Button slot="prepend" custom-icon="fa fa-search" @click="columnCheck(tableView, $refs.setting.data, code)"></Button>
          </Input>
        </template>
      </template>
      <template slot="tableColumn" slot-scope="{ table, tableCode, row, code }">
        <template v-if="tableCode == 'chartSeries' && (code == 'property' || code == 'nameProperty')">
          <Input type="text" size="small" :readonly="true" v-model="row[code]" @click.native="columnCheck(tableView, row, code, table)">
            <Button slot="prepend" size="small" custom-icon="fa fa-search" @click="columnCheck(tableView, row, code, table)"></Button>
          </Input>
        </template>
      </template>
      <template slot="footer">
        <Button type="primary" custom-icon="fa fa-save" @click="saveSetting">{{ $t('Front_Btn_Save') }}</Button>
      </template>
    </modal-form>
    <column-check ref="columnCheck" />
  </div>
</template>
<script>
  import mixinPage from '../../mixins/page';
  import modelApi from '../../api/model';
  import customModelApi from '../../api/customModel';
  import dataSourceApi from '../../api/dataSource';
  import { mapActions } from 'vuex';
  import columnCheck from './column-check.vue';

  /**
   * @displayName view-chart 图表视图
   */
  export default {
    mixins: [mixinPage],
    components: { columnCheck },
    data() {
      return {
        uid: 'chart_' + (((1 + Math.random()) * 0x10000) | 0).toString(16),
        data: null,
        setting: null,
        tableView: null,
        chart: null
      };
    },
    props: {
      /**
       * 视图代码
       */
      viewCode: {
        type: String
      },
      /**
       * 是否静态数据
       */
      static: {
        type: Boolean,
        default: false
      },
      /**
       * 筛选
       */
      filter: {
        type: Object,
        default() {
          return {};
        }
      }
    },
    computed: {},
    created() {
      if (this.viewCode) {
        this.init(this.viewCode);
      }
    },
    watch: {},
    methods: {
      ...mapActions('admin/dataView', { loadDataView: 'load', saveDataViewSetting: 'saveSetting' }),
      /**
       * 初始化
       *
       * @param {string} viewCode 视图代码
       * @public
       */
      async init(viewCode, callback) {
        // 加载表格视图
        let view = await this.loadDataView(viewCode);

        if (view == null) {
          this.error('Front_Msg_View_Code_Not_Exist|' + viewCode);
          return;
        }

        this.tableView = view.dataView;
        if (!!(this.tableView.chartSetting || '').trim()) {
          this.setting = JSON.parse(this.tableView.chartSetting);
        } else {
          this.setting = {};
        }

        setTimeout(() => {
          this.chart = this.$echarts.init(document.getElementById(this.uid));

          this.$emit('on-ready', view);

          if (typeof callback === 'function') {
            callback(view);
          } else {
            this.loadData();
          }
        });
      },
      /**
       * 根据表格初始化
       *
       * @param {object} tableView 表格视图
       * @param {object} data 数据
       * @public
       */
      async initWithTable(tableView) {
        this.tableView = tableView;

        if (!!(this.tableView.chartSetting || '').trim()) {
          this.setting = JSON.parse(this.tableView.chartSetting);
        } else {
          this.setting = {};
        }

        // 图表
        setTimeout(() => {
          this.chart = this.$echarts.init(document.getElementById(this.uid));
        });
      },
      /**
       * 加载数据
       *
       * @param {array} staticData 静态数据或筛选条件
       * @public
       */
      async loadData(staticData) {
        if (this.static) {
          this.data = staticData;
        } else {
          let filter = {};

          // 默认筛选条件
          if (this.tableView.filtering) {
            filter = JSON.parse(this.tableView.filtering);
          }

          // 属性筛选条件
          for (let key in this.filter) {
            filter[key] = this.filter[key];
          }

          // 传入筛选条件
          for (let key in staticData) {
            filter[key] = staticData[key];
          }

          // 排序
          if (this.tableView.sorting) {
            // 排序
            let obj = JSON.parse(this.tableView.sorting);
            let arr = [];
            for (let key in obj) {
              if (obj[key] === 'desc') {
                arr.push('-' + key);
              } else {
                arr.push('+' + key);
              }
            }

            filter.orderBy = arr.join(',');
          }

          if (this.tableView.isGroupBy) {
            filter.isGroupBy = true;
            filter.groupColumn = JSON.parse(this.tableView.groupColumn);
            filter.groupMethod = JSON.parse(this.tableView.groupMethod);
          }

          if (this.tableView.isCustom) {
            let res = await customModelApi.query(this.tableView.model, filter);

            this.total = res.totalCount;
            this.data = res.data;
          } else if (this.tableView.isDataSource) {
            let res = await dataSourceApi.query(this.tableView.dataSource, filter);

            this.total = res.totalCount;
            this.data = res.table;
          } else {
            let res = await modelApi.query(this.tableView.model, filter, this.tableView.functionName, this.tableView.functionType);

            this.total = res.totalCount;
            this.data = res.data;
          }
        }

        setTimeout(() => {
          if (this.data) {
            this.loadChart();
          }
        });
      },
      /**
       * 加载图表
       *
       * @public
       */
      async loadChart(data) {
        if (data) {
          this.data = data;
        }

        // 加载图表
        if (this.setting.chartXCode) {
          var option = {
            title: {
              text: this.setting.chartTitle,
              subtext: this.setting.chartSubtitle,
              left: this.setting.chartTitleAlign == null ? 'left' : this.setting.chartTitleAlign
            },
            tooltip: {
              // trigger: 'item'
            },
            legend: {
              show: !!this.setting.chartShowLegend,
              orient: this.setting.chartLegendOrient == null ? null : this.setting.chartLegendOrient,
              left: this.setting.chartLegendAlign == null ? 'right' : this.setting.chartLegendAlign
            }
          };

          // 预先加载枚举值
          if (this.setting.chartGroupCodeType && this.setting.chartGroupCodeType.indexOf('Enum:') === 0) {
            await this.loadEnum(this.setting.chartGroupCodeType.replace('Enum:', ''));
          }

          if (!this.setting.chartCustomSeries) {
            if (this.setting.chartType != 'Pie') {
              let xAxis = Array.from(
                new Set(
                  this.data.map(item => {
                    return this.parseData(item, this.setting.chartXCode);
                  })
                )
              );

              // 柱状图或折线图
              option.xAxis = {
                data: xAxis
              };
              option.yAxis = {};

              let group = [null];

              if (this.setting.chartGroupCode) {
                // 有分组
                group = Array.from(
                  new Set(
                    this.data.map(item => {
                      let value = this.parseData(item, this.setting.chartGroupCode);

                      if (this.setting.chartGroupCodeType && this.setting.chartGroupCodeType.indexOf('Enum:') === 0) {
                        value = this.getEnum(this.setting.chartGroupCodeType.replace('Enum:', ''), value);
                      }

                      return value;
                    })
                  )
                );

                option.legend.data = group;
              }

              option.series = group.map(item => {
                let keyData = {};
                this.data
                  .filter(data => {
                    let value = this.parseData(data, this.setting.chartGroupCode);

                    if (this.setting.chartGroupCodeType && this.setting.chartGroupCodeType.indexOf('Enum:') === 0) {
                      value = this.getEnum(this.setting.chartGroupCodeType.replace('Enum:', ''), value);
                    }

                    return (item == null && group.length == 1) || value == item;
                  })
                  .forEach(data => {
                    let key = this.parseData(data, this.setting.chartXCode);
                    let value = this.parseData(data, this.setting.chartValueCode);

                    if (key in keyData) {
                      keyData[key] += value == null ? 0 : value;
                    } else {
                      keyData[key] = value == null ? 0 : value;
                    }
                  });

                return {
                  name: item,
                  type: this.setting.chartType.substr(0, 1).toLowerCase() + this.setting.chartType.substr(1),
                  data: xAxis.map(item => {
                    return {
                      name: item,
                      value: keyData[item]
                    };
                  })
                };
              });
            } else {
              let group = [null];
              if (this.setting.chartGroupCode) {
                // 有分组
                group = Array.from(
                  new Set(
                    this.data.map(item => {
                      let value = this.parseData(item, this.setting.chartGroupCode);

                      if (this.setting.chartGroupCodeType && this.setting.chartGroupCodeType.indexOf('Enum:') === 0) {
                        value = this.getEnum(this.setting.chartGroupCodeType.replace('Enum:', ''), value);
                      }

                      return value;
                    })
                  )
                );
              }

              let count = group.length;

              option.series = group.map((item, index) => {
                let keyData = {};
                this.data
                  .filter(data => {
                    let value = this.parseData(data, this.setting.chartGroupCode);

                    if (this.setting.chartGroupCodeType && this.setting.chartGroupCodeType.indexOf('Enum:') === 0) {
                      value = this.getEnum(this.setting.chartGroupCodeType.replace('Enum:', ''), value);
                    }

                    return (item == null && group.length == 1) || value == item;
                  })
                  .forEach(data => {
                    let key = this.parseData(data, this.setting.chartXCode);
                    let value = this.parseData(data, this.setting.chartValueCode);

                    if (key in keyData) {
                      keyData[key] += value == null ? 0 : value;
                    } else {
                      keyData[key] = value == null ? 0 : value;
                    }
                  });

                return {
                  type: 'pie',
                  radius: (this.setting.chartItemWidth == null ? 70 : this.setting.chartItemWidth) / count,
                  center: [(100 / (count + 1)) * (index + 1) + '%', '50%'],
                  datasetIndex: index,
                  data: Object.keys(keyData).map(key => {
                    return {
                      name: key,
                      value: keyData[key]
                    };
                  }),
                  emphasis: {
                    itemStyle: {
                      shadowBlur: 10,
                      shadowOffsetX: 0,
                      shadowColor: 'rgba(0, 0, 0, 0.5)'
                    }
                  }
                };
              });
            }
          } else {
            // 自定义分组
            let chartSeries = JSON.parse(this.setting.chartSeries);
            let isPie = false;

            if (
              chartSeries.some(item => {
                return item.chartType == 'Pie';
              })
            ) {
              // 饼图
              isPie = true;
              chartSeries = chartSeries.filter(item => {
                return item.chartType == 'Pie';
              });
            }

            // 指定图表的配置项和数据
            if (!isPie) {
              option.xAxis = {
                data: this.data.map(item => {
                  return this.parseData(item, this.setting.chartXCode);
                })
              };
              option.yAxis = {};
              option.legend.data = chartSeries.map(item => {
                return item.name;
              });
              option.series = chartSeries.map(item => {
                return {
                  name: item.name,
                  type: item.chartType.substr(0, 1).toLowerCase() + item.chartType.substr(1),
                  data: this.data.map(data => {
                    return this.parseData(data, item.property);
                  })
                };
              });
            } else {
              let count = chartSeries.length;

              option.series = chartSeries.map((item, index) => {
                return {
                  type: 'pie',
                  radius: (this.setting.chartItemWidth == null ? 70 : this.setting.chartItemWidth) / count,
                  center: [(100 / (count + 1)) * (index + 1) + '%', '50%'],
                  datasetIndex: index,
                  data: this.data.map(data => {
                    return {
                      name: this.parseData(data, item.nameProperty),
                      value: this.parseData(data, item.property)
                    };
                  }),
                  emphasis: {
                    itemStyle: {
                      shadowBlur: 10,
                      shadowOffsetX: 0,
                      shadowColor: 'rgba(0, 0, 0, 0.5)'
                    }
                  }
                };
              });
            }
          }

          // 使用刚指定的配置项和数据显示图表。
          this.chart.clear();
          this.chart.setOption(option);
        }
      },
      // 打开设置
      openSetting() {
        if (Object.keys(this.setting).length == 0) {
          this.$refs.setting.openDefault();
        } else {
          this.$refs.setting.open(this.setting);
        }
      },
      // 保存设置
      async saveSetting() {
        let isOK = await this.$refs.setting.validate();

        if (!isOK) {
          this.error('Front_Msg_Form_Validate_Fail');
        } else {
          this.confirm('Front_Msg_Sure_To_Save_Setting', async () => {
            this.tableView.chartSetting = JSON.stringify(this.$refs.setting.data);
            await this.saveDataViewSetting(this.tableView);
            this.success('Front_Msg_Success', () => {
              this.$refs.setting.close();
              window.location.reload();
            });
          });
        }
      },
      // 打开字段选择
      columnCheck(tableView, row, code, table) {
        this.$refs.columnCheck.openView(tableView, checked => {
          row[code] = checked.code;
          row[code + 'Type'] = checked.dataType;

          this.$forceUpdate();

          if (table) {
            table.loadData();
          }
        });
      }
    }
  };
</script>
