<template>
  <div class="app-container">
    <el-card class="app-container__search">
      <div slot="header" v-if="pageTitle">{{pageTitle}}</div>
      <xd-search
        v-if="searchStatus"
        dateFilter
        time-type
        :mainFilter="searchTabList"
        :mainFilterKey="searchTabKey"
        :mainFilterIndex="searchTabIndex"
        v-model="searchParams"
        :list="searchForm"
        @onSearch="handleSearch"
        @onDone="handleInit"
        @onTabClick="handlerSearchTabChanged"
        :remoteSearch="handleRemoteSearch"
      >
      </xd-search>
    </el-card>
    <el-card class="app-container__list">
      <div class="app-container__list-pagination">
        <div class="back">
          <slot name="left"></slot>
          <template v-if="isBack">
            <el-button
              @click="$router.back()"
              :size="size"
              icon="el-icon-back"
            >返回</el-button>
          </template>
        </div>
        <div class="operation">
          <slot name="right"></slot>
          <template v-if="isAddAndEdit">
            <el-button
              type="primary"
              @click="handleAdd"
              :size="size"
            >{{isAddName}}</el-button>
          </template>
          <template v-if="isAllDelete">
            <el-button
              type="danger"
              @click="handleAllDelete"
              :disabled="disabledDelete"
              :size="size"
            >批量删除</el-button>
          </template>
        </div>
      </div>
      <div class="app-container__list-table">
        <xd-table
          :ref="tableRef"
          :headers="tablesHeaders"
          :list="tablesList"
          :get-link="toLink"
          is-border
          @onClick="onClickOperation"
          @onSelect="handlerTableSelect"
          @onSortChange="(data)=>{handleEventChange(data,'onSort')}"
          @handleCustom="handleRowCustom"
          @onEdit="handleRowEdit"
          :customFunction="handleRowCheckBtn"
        >
        </xd-table>
      </div>
      <div class="app-container__list-pagination" v-if="isPaginationStatus">
        <xd-pagination
          :total="page_total"
          :limit.sync="page_size"
          :page="page_token"
          :auto-scroll="false"
          @onPagination="handlePagination"
        ></xd-pagination>
      </div>
    </el-card>
    <xd-dialog
      v-if="dialogStatus"
      @onConfirm="handleSubmit"
      @onCancel="clearAdd"
      @onClose="clearAdd"
      :show.sync="dialogStatus"
      :title="dialogName"
      :width="dialogWidth"
    >
      <xd-base-dynamic-field
        :ref="formRef"
        v-model="formValue"
        :label-width="dialogFormStatus"
        v-if="dialogFormStatus"
        :list="formList"
        :key="dialogKey"
        @success="handleSuccess"
        @onApiSuccessUrl="handleApiSuccessUrl"
        @onGetParamsAndHeader="handleGetParamsAndHeader"
      ></xd-base-dynamic-field>
    </xd-dialog>
  </div>
</template>

<script>
import XdSearch from "@/components/XdSearch"
import XdPagination from "@/components/XdPagination.vue"
import XdTable from "@/components/XdTable"
import XdDialog from "@/components/XdDialog.vue";
import XdBaseDynamicField from "@/components/XdBaseDynamicField.vue";
import {Loading} from "element-ui";

export default {
  name: "XdTableList",
  components:{
    XdPagination,
    XdSearch,
    XdTable,
    XdDialog,
    XdBaseDynamicField
  },
  props:{
    pageTitle:{
      type:String,
      default:'',
    },

    getLink:{
      type:Function|null,
      default:null,
    },

    //主键（唯一ID）
    mainKey:{
      type: String,
      default:'id',
    },

    computedHeaders:{
      type: Function,
      required: true
    },

    //搜索
    computedSearchParams:{
      type: Function|null,
      default:null,
    },
    computedSearchConfig:{
      type: Function,
      required: true
    },
    //搜索功能自定义方法
    handleSearchCustom:{
      type: Function|null,
      default:null,
    },

    //检查按钮是否显示
    checkBtnStatus:{
      type: Function|null,
      default:null,
    },


    //主条件搜索设置
    searchTabList:{
      type:Array,
      default(){
        return [
          {
            label: "待审核",
            value: "U",
          },
          {
            label: "已通过",
            value: "Y",
          },
          {
            label: "已拒绝",
            value: "N",
          },
        ];
      }
    },
    searchTabKey:{
      type:String,
      default:'tab'
    },
    searchTabIndex:{
      type:String|Number|Boolean,
      default() {
        return 'Y';
      }
    },

    //是否启动搜索组件加载完全触发获取列表功能(否则在created生命周期中执行获取列表共)
    isSearchDoneLoading:{
      type: Boolean,
      default: true,
    },

    //是否启用翻页功能
    isPagination:{
      type: Boolean,
      default: true,
    },
    //启动当前列表总数小于每页显示数量，隐藏翻页功能
    isPaginationTotalLessPageSizeHide:{
      type: Boolean,
      default: true,
    },

    //删除
    isAllDelete:{
      type: Boolean,
      default: true,
    },
    isAllDeleteFilter:{
      type: Boolean,
      default: false, //true=> 条件搜索删除 false=> 本页选中删除
    },

    //开启新增与编辑(大数据创建功能请使用页面跳转操作)
    isAddAndEdit:{
      type: Boolean,
      default: false,
    },
    isAddName:{
      type:String,
      default:'新增'
    },
    dialogName:{
      type:String,
      default:'',
    },
    dialogWidth:{
      type:String,
      default:'800px'
    },
    //列表记录转换为创建对象数据
    computedFormRowToConfig:{
      type: Function|null,
      default:null,
    },
    //获取传教参数方法
    computedFormConfig:{
      type: Function|null,
      default:null,
    },
    formLabelWidth:{
      type:String,
      default:'120px'
    },
    //需要监听字段
    formWatch:{
      type:Array,
      default(){
        return []
      }
    },

    isBack:{
      type: Boolean,
      default: true,
    },
    size: {
      type: String,
      default:'medium'
    }
  },
  data(){
    return {

      //翻页功能
      page_token: 1,
      page_size: 20,
      page_total: 0,

      //搜索区域
      searchForm: [], //搜索区域模块表单
      searchParams: {}, //搜索参数
      searchStatus: false,

      tablesList:[],
      tablesHeaders:[],
      tablesSelectList:[],
      tablesSelectIds:[],

      //ref
      tableRef:'',
      formRef:'',

      //新增与编辑
      dialogStatus: false,
      dialogFormStatus: '120px',
      dialogKey: 'dialogKey',

      //form
      formValue: {},
      formList: [],

      //保存编辑对象
      item:null,

    }
  },
  watch:{
    formValue:{
      handler(value, oldValue){
        if(this.checkEqual(value, oldValue)) return;
        if(this.formWatch.length > 0) {
          let hasChange = [];
          this.formWatch.map(key=>{
            if(!this.checkEqual(value[key],oldValue[key])) {
              hasChange.push(key);
            }
          });
          //有变化
          if(hasChange.length > 0) {
            this.initDialogForm(this.formValue)
          }
        }
      },
      deep:true
    }
  },
  computed:{
    isPaginationStatus(){
      if(this.isPagination === false) return false;
      else {
        if(this.isPaginationTotalLessPageSizeHide) {
          return this.page_size < this.page_total;
        }
        return true
      }
    },
    disabledDelete(){
      if(this.isAllDeleteFilter === false) {
        return  this.tablesSelectList.length === 0
      }
      return false
    }
  },
  created() {
    if(typeof this.computedHeaders !== 'function') {
      throw new Error('props.computedHeaders not is function')
    }

    this.tableRef = `table_${this.$xdHelper.randomChar(10)}`;
    this.formRef =`form_${this.$xdHelper.randomChar(10)}`;

    //未启动搜索列表初始化完成时刻加载列表数据
    if(this.isSearchDoneLoading === false) {
      this.handleList();
    }

    //获取搜索条件列表
    if(typeof this.computedSearchConfig === 'function') {
      this.searchForm = this.computedSearchConfig() || [];
      this.searchStatus = true;
    }
  },
  methods:{
    /**
     * @description 检查值是否相同
     * @param val
     * @param old
     * @return {boolean}
     */
    checkEqual(val,old){
      console.log(val,old);
      let valType = this.$xdHelper.checkVarType(val);
      let oldType = this.$xdHelper.checkVarType(old);

      //初始化值为null不检查
      if(old === null) return true;

      //类型不等式定义未：变化
      if(valType !== oldType) return false;

      //对象与数组判断
      if(valType === 'array' || valType === 'object') {
        return JSON.stringify(val) === JSON.stringify(old);
      }

      return val === old;
    },
    /**
     * @description 获取大表哥数据
     * @return {*}
     */
    getTableData(){
      return this.$refs[this.tableRef].getTableData();
    },

    //==新增与编辑====
    initDialogForm(params={}){
      this.formList = this.computedFormConfig(params);
      this.dialogKey = Date.now();
    },
    handleAdd(){
      if(typeof this.computedFormConfig === 'function') {
        this.initDialogForm({});
        this.dialogStatus = true;
      }
      else{
        throw new Error('props.computedFormConfig not is function')
      }
    },
    handleSubmit(){
      this.$refs[this.formRef].submitAll()
        .then(res=>{
          let data = this.$xdHelper.cloneDeep(this.$refs[this.formRef].getAllFormData());
          let action = 'create';
          if(this.item === null) {
            action = 'edit';
          }
          this.handleEventChange({data,item: this.item}, 'onSave' ,action, ()=>{
            this.clearAdd();
          });
        })
        .catch(err=>{

        })
    },
    handleEdit(row){
      if(typeof this.computedFormConfig === 'function') {
        this.item = this.$xdHelper.cloneDeep(row);
        if(typeof this.computedFormRowToConfig === 'function') {
          row = this.computedFormRowToConfig(row);
        }
        this.initDialogForm(row);
        this.dialogStatus = true;
      }
      else{
        throw new Error('props.computedFormConfig not is function')
      }
    },
    clearAdd(){
      this.dialogStatus = false;
      this.formRef = `form_${this.$xdHelper.randomChar(10)}`;
      this.item = null;
      this.formValue = {};
      this.formList = [];
    },
    //==新增与编辑====


    /**
     * @description 编辑列值
     * @param header
     * @param row
     * @param cb {Function} 返回true=>保存成功 false=> 保存失败
     */
    handleRowEdit({header, row, cb}){
      this.$emit('onRowEdit',{
        data: {header, row},
        cb
      });
    },

    /**
     * @description 在行上面触发的事件
     * @example 比如：操作列启用禁用｜排序输入
     * @param cb {Function} 操作成功回调地址 返回1=>成功 2=>失败
     * @param prop
     * @param value
     * @param row
     */
    handleRowCustom({ value, prop, cb, row }){
      this.$emit('onRowCustomEvent',{value, prop, cb, row});
    },

    /**
     * @description 检查行操作按钮是发显示
     * @param action
     * @param data
     * @return {*|boolean}
     */
    handleRowCheckBtn({action, data}){
      if(action === 'btn') {
        if(typeof this.checkBtnStatus  === 'function') {
          return this.checkBtnStatus(data);
        }
        return true
      }
    },

    /**
     * @description 初始化获取列表方法
     * @param action
     * @param form
     */
    handleInit({ action, form }){
      if(this.isSearchDoneLoading === false) return;
      this.handleList()
    },

    /**
     * @description 搜索事件
     * @param action
     * @param form
     */
    handleSearch ({ action, form }) {
      this.handleList()
    },

    /**
     * @description 改变主搜索条件触发事件
     * @param tab
     */
    handlerSearchTabChanged(tab){
      if(typeof this.handleSearchCustom === 'function'){
        this.handleSearchCustom({action:'tab', value:tab});
      }
    },

    /**
     * @description 针对远程搜索功能
     */
    handleRemoteSearch(){

    },

    /**
     * @description 选中列表功能
     * @param ids
     * @param select
     */
    handlerTableSelect({ids, select}){
      this.tablesSelectIds = ids;
      this.tablesSelectList = this.$xdHelper.cloneDeep(select);
    },

    /**
     * @description 事件管理方法
     * @param data
     * @param event {String} onSort｜onSave | onRowEdit
     * @param action
     * @param cb
     */
    handleEventChange(data,event, action = '', cb = null){
      let loading = Loading.service({});
      this.$emit(event,{
        data:data,
        action,
        success:()=>{
          loading.close();
          this.$message({
            message:'操作成功！',
            duration: 2000,
            type:'success',
            onClose:()=>{
              this.getList(false);
            }
          });
          if(typeof cb === 'function') cb()
        },
        error:()=>{
          loading.close();
        }
      })
    },


    /**
     * @description 点击按钮事件
     * @param row
     * @param value
     * @param index
     * @param rowIndex
     */
    onClickOperation({ row, value, index, rowIndex }){
      //有删除标识
      if(value.name.indexOf('删除') !== -1
        || value.event === 'delete'
        || value.event === 'remove'
        || value.event === 'del'
      ) {
        this.handleDelConfirm(row);
        return;
      }

      //有编辑标识
      if(this.isAddAndEdit
        && (value.name.indexOf('编辑') !== -1 || value.event === 'edit')
      ) {
        this.handleEdit(row);
        return;
      }

      this.$emit('onClickOperation',{ row, value, index, rowIndex })
    },

    /**
     * @description 设置链接地址
     * @param row
     * @param value
     * @param idx
     * @return {string}
     */
    toLink({row, value, idx}){
      if(value.ui === 'link' || value.ui === 'text-link') {
         if(typeof this.getLink === 'function') {
           this.getLink({row, value, idx})
         }
      }
      return '';
    },

    headers(){
      let search = this.searchParams;
      if(typeof this.computedHeaders === 'function') {
        let headers = this.computedHeaders(search);
        if(this.isAllDeleteFilter === false) {
          let selectionStatus = false;
          headers.map(item=>{
            if(item.type === 'selection') selectionStatus = true;
          });
          if(selectionStatus === false) headers = [{type: 'selection'}].concat(headers)
        }
        headers = headers.map(item=>{
          if(item.type === 'operate') {
            //设置默认值
            let width = 10;
            //元素边距
            let margin = 32;
            //icon宽度
            let icon = 0;
            if(item.icon) icon = 16;

            item.values.map(i=>{
              //不显示文本
              let w  = i.name.length * 12;
              if(i.ui === 'link' || i.ui === 'button')  w = 0;
              //右边距
              let right = i.name.length * 16;
              let size =  w + margin + icon + right;
              width += size;
            });
            item.width = width;
            console.log('headers',item);
            return item;
          }
          return item;
        });
        return headers;
      }
      return [];
    },

    handleList(){
      let search = this.searchParams;
      search[this.searchTabKey] = search[this.searchTabKey]||this.searchTabIndex;
      this.tablesHeaders = this.headers(this.$xdHelper.cloneDeep(this.computedHeaders(search)));
      this.getList();
    },

    /**
     * @description 记录删除
     */
    handleDelConfirm (row) {
      this.$confirm('您确定要将当前记录删除吗?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      })
        .then(() => {
          let loading = Loading.service({});
          let params = {};
          params[this.mainKey] = row[this.mainKey];
          this.$emit('onDel', {
            data: params,
            success:()=>{
              loading.close();
              this.$message({
                message:'删除成功！',
                duration: 2000,
                type:'success',
                onClose:()=>{
                  this.getList(false);
                }
              });
            },
            error:()=>{
              loading.close();
            }
          })
        })
        .catch(() => {
        })
    },

    /**
     * @description 批量删除
     */
    handleAllDelete(){
      this.$confirm('你确定要进行批量删除操作吗?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      })
        .then(() => {
          let loading = Loading.service({});
          let params = null;
          let select = null;
          if(this.isAllDeleteFilter) params = this.getParams();
          else select = {
            ids: this.tablesSelectIds,
            selects: this.tablesSelectList
          };
          this.$emit('onBatchDel', {
            data: params || select,
            success:()=>{
              loading.close();
              this.$message({
                message:'批量删除成功！',
                duration: 2000,
                type:'success',
                onClose:()=>{
                  this.getList(false);
                }
              });
            },
            error:()=>{
              loading.close();
            }
          })
        })
        .catch(() => {
        })
    },

    /**
     * @description 获取页面列表
     */
    getList(isOpenLoading = true){
      let params = this.getParams();
      let loading = null;
      if(isOpenLoading) loading = Loading.service({});
      this.$emit('onList',{
        data: this.$xdHelper.cloneDeep(params),
        success:(list,page_token,page_total)=>{
          if(loading) loading.close();
          this.tablesList = this.$xdHelper.cloneDeep(list).map(item=>{
            if(!item.id)  item.id = item[this.mainKey];
            return item
          });
          this.page_token = page_token;
          this.page_total = page_total;
        },
        error:()=>{
          this.tablesList = [];
          if(loading) loading.close();
        }
      })
    },


    /**
     * @description 获取搜索条件参数方法
     * @return {*}
     */
    getParams(){
      let search = this.searchParams;
      let paginationParams = {
        page_token:this.page_token,
        page_size:this.page_size,
      };

      //不启用翻页功能
      if(this.isPagination === false) paginationParams = {};

      //页面自定义设置参数格式
      if(typeof this.computedSearchParams === 'function') {
        return this.computedSearchParams(search,paginationParams);
      }

      //默认返回
      return {
        ...search,
        ...paginationParams
      };
    },

    /**
     * @description 翻页处理方法
     * @param page {Number} 访问页面页码数
     */
    handlePagination (page) {
      this.page_token = page;
      this.getList()
    },
  }
}
</script>



<style scoped lang="scss">
  .back,.operation {
    display: flex;
    justify-content: flex-start;
    align-items: center;
  }
  .operation {
    justify-content: flex-end;
  }
</style>
