<template>
  <el-form :model="proxyData" ref="ruleForm">
    <el-table border :size="size" :data="proxyData">
      <el-table-column v-for="(column) in columns" :key="column.prop" v-bind="column">
        <template slot-scope="scope">
           <el-form-item :prop="`${scope.$index}.${column.prop}`" :rules="rules[column.prop]">
              <template v-if="column.type === 'index'">{{scope.$index + 1}}</template>
              <template v-else-if="column.type === 'image'">
                 <image-upload-field 
                   :url="scope.row[column.prop]" 
                   @update:url="val => handleValueChange(val, column.prop, scope.$index)" 
                   :disabled="!scope.row.editing"  
                 />
              </template>

              <template v-else-if="column.type === 'number'">
                 <digital-input
                   v-if="scope.row.editing"
                   :placeholder="column.placeholder ? column.placeholder : column.label"
                   :values="scope.row[column.prop]"
                   :size="size"
                   :position="'right'"
                   :controls="false"
                   :min="column.otherProps ? column.otherProps.min : 0"
                   :max="column.otherProps ? column.otherProps.max : 100000000"
                   :precision="column.otherProps ? column.otherProps.precision : 2"
                   :append="column.otherProps ? column.otherProps.append : ''"
                   @reschange="val => handleValueChange(val,column.prop,scope.$index)"
                 />
                 <p v-else>{{scope.row[column.prop]}}</p>
              </template>

              <template v-else-if="column.type === 'select'">
                 <el-select
                  style="width:100%"
                   v-if="scope.row.editing"
                   :placeholder="column.placeholder ? column.placeholder : column.label"
                   :size="size"
                   :value="scope.row[column.prop]" 
                   @input="val => handleValueChange(val,column.prop,scope.$index)" 
                 >
                    <el-option v-for="item in column.options ? column.options : []" :key="item.value" :value="item.value" :label="item.label" />
                 </el-select>
                 <p v-else>{{  ((column.options ? column.options : []).find(item => item.value === scope.row[column.prop]) || {}).label || '--'}}</p>
              </template>

              <template v-else>
                 <el-input
                   v-if="scope.row.editing"
                   :placeholder="column.placeholder ? column.placeholder : column.label"
                   :size="size"
                   :value="scope.row[column.prop]" 
                   @input="val => handleValueChange(val,column.prop,scope.$index)" 
                 />
                 <p v-else>{{scope.row[column.prop]}}</p>
              </template>
           </el-form-item>
        </template>
      </el-table-column>

      <el-table-column label="操作" width="100px" v-if="!readonly">
        <template #header>
          <div class="flex-between">
            <p>操作</p>
            <el-button v-if="!readonly" type="text" size="mini" @click="onInsertData">添加</el-button>
          </div>
        </template>

        <template slot-scope="scope">
          <template v-if="scope.row.editing">
            <el-button type="text" size="mini" @click="onCurrentRowSave(scope.row, scope.$index)">保存</el-button>
          </template>

          <template>
            <el-button type="text" size="mini" @click="onCurrentRowDelete(scope.$index)">删除</el-button>
            <el-button type="text" size="mini" @click="onCurrentRowEdit(scope.row, scope.$index)">编辑</el-button>
          </template>
        </template>
      </el-table-column>
    </el-table>

    <div class="flex-end" style="margin-top:10px">
      <slot />
    </div>

    <modal-mode
      :title="title"
      :size="size" 
      :rules="rules"
      :index="editIndex"
      :columns="columns" 
      :action="action"
      :data="_defaultData" 
      :visible.sync="modalVisible" 
      @save="onCurrentRowSave"
      @rowUpdate="onRowUpdate"
    />
  </el-form>
</template>

<script>
import ImageUploadField from "./_image.vue"
import ModalMode from "./_modal.vue"
export default {
  name:'TableEditor',
  components:{
    ImageUploadField,
    ModalMode
  },
  props:{
    title:{
      type:String
    },
    mode:{
      type:String, // "table" | 'modal'
      default:"table"
    },
    columns:{
      type:Array,
      default:() => ([])
    },
    data:{
      type:Array,
      default:() => ([])
    },
    size:{
      type:String,
      default:'mini'
    },
    rules:{
      type:Object,
      default:() => ({})
    },
    onConfirm:{
      type:Function
    },
    readonly:{
      type:Boolean
    }
  },
  watch:{
    proxyData:{
      handler(newVal){
        this.$emit('update:data',(newVal || []).map(({editing:_,...rest}) => ({...rest})))
      },
      deep:true,
      immediate:true,
    },
  },
  data(){
    return {
      action: "add", // add | edit
      editIndex: -1,
      proxyData:[],
      _defaultData: {},
      hasEditing: false,
      modalVisible: false
    }
  },
  mounted(){
    this.$nextTick(() => {
     this.update(this.data)
    })
  },
  methods:{
    handleValueChange(val,prop,index){
      this.$set(this.proxyData, index,{
        ...this.proxyData[index],
        [prop]:val
      })

      this.onRowUpdate(this.proxyData[index], index)
    },
    getDefaultData(){
      const columns = this.columns.filter(({type}) => type !== 'index')
      const data = columns.reduce((prev,current) => ({
        ...prev,
        [current.prop]:""
      }),({}))

      return  {
        ...data,
        editing:true
      }
    },
    update(data = []){
      this.proxyData = data.map(item => ({
          ...item,
          editing:false
      }))
    },
    onInsertData(){
      this.action = "add"
      this.editIndex = this.proxyData.length

      switch(this.mode){
        case 'table':
          if(this.isHasEditing()) return
          this.$set(this.proxyData, this.proxyData.length, this.getDefaultData())
          this.hasEditing = true
          break
        case 'modal':
          this._defaultData = this.getDefaultData()
          this.modalVisible = true
          break
        default:
          break
      }
    },
    onCurrentRowDelete(index){
      if(this.mode === 'table' && this.isHasEditing()){
        return
      }

      this.proxyData.splice(index,1)
    },
    onCurrentRowEdit(row, index){
      this.action = "edit"
      this.editIndex = index

      switch(this.mode){
        case 'table':
          if(this.isHasEditing()) return
          this.$set(this.proxyData,index,{ ...row, editing: true })
          this.hasEditing = true
          break
        case 'modal':
          this._defaultData = {...this.proxyData[index]}
          this.modalVisible = true
          break
        default:
          break
      }
    },
    onRowUpdate(row,index){
      this.$emit('rowUpdate',{
        row,
        index
      })
    },
    isHasEditing(){
      if(this.hasEditing){
        this.$message.warning('请先保存编辑中的数据')
      }
      return this.hasEditing
    },
    validate(){
      return !this.isHasEditing()
    },
    onCurrentRowSave(row, index){
      const updateFn = () => {
        this.$set(this.proxyData,index,{ ...row, editing: false })
        this.editIndex = -1
        this.hasEditing = false
      } 
      
      this.mode === 'table' 
        ? this.$refs.ruleForm.isHasEditing(isValid => isValid && updateFn()) 
        : updateFn()
    }
  }
}
</script>
