<template>
  <div>
    <el-dialog
      title="校验"
      :close-on-click-modal="false"
      :visible.sync="submitVerificationDialog"
      v-if="submitVerificationDialog"
      width="65%"
      :append-to-body="true"
    >
      <div>
        <div class="explain">
          <p>校验规则：</p>
          <p>
            <span>*正则表达式：</span
            >按照Object格式来编写校验表达式,两个参数，第一个参数为正则表达式，第二个参数为校验未通过时的提示信息（例如：{regex:{exp:'^[0-9]+$',message:'校验失败，请输入数字。'}}）<br />
            注意：字符串格式的表达式以英文逗号‘,’来分割参数
          </p>
          <p style="margin-top:10px;">
            <span>后端检验：</span
            >两个参数，第一个参数为后端url地址，第二个参数为校验未通过时的提示信息,两个参数以英文逗号隔开（例如：${portal}/sys/test/v1/user/validIsAccountExist?param=,后端校验失败）<br />注意：接口是post请求，参数在url中使用param接收，返回格式{valid:false/true}
          </p>
        </div>
        <div class="btn">
          <el-button
            type="primary"
            @click="addValidata"
            size="small"
            icon="el-icon-plus"
            >添加校验规则</el-button
          ><span class="tips">进行校验时，会按照从上至下的顺序依次校验</span>
        </div>
        <el-form
          data-vv-scope="validateRulesForm"
          class="form__property-content"
        >
          <draggable
            tag="ul"
            class="column-ul"
            :list="data.validateList"
            v-bind="{
              group: {name: 'options'},
              ghostClass: 'ghost',
              handle: '.drag-item'
            }"
            @end="end"
            handle=".drag-item"
          >
            <li v-for="(item, index) in data.validateList" :key="index">
              <i class="drag-item icon-drag2"></i>
              <div class="validate-rule__container">
                <ht-select
                  v-model="item.key"
                  :options="validateList"
                  :props="{key: 'key', value: 'name'}"
                  placeholder="请选择"
                  validate="required"
                  name="validatorSelect"
                  filterable
                  @visible-change="visibleChangeValidate"
                  @change="changeValidate(item)"
                ></ht-select>
                <el-button
                  class="el-icon-edit"
                  @click="methodClick(index)"
                  v-if="item.inputType == 'button'"
                  >编写方法</el-button
                >
                <div
                  class="two-input__container"
                  v-if="item.inputType == 'twoInput'"
                >
                  <ht-input
                    @input="appendValidate(item)"
                    name="validatorValueStart"
                    v-model="item.start"
                    validate="required"
                  />
                  <ht-input
                    style=" margin-left: 15px;"
                    @input="appendValidate(item)"
                    name="validatorValueEnd"
                    v-model="item.end"
                    validate="required"
                  />
                </div>
                <ht-input
                  style=" margin-left: 15px;"
                  @input="appendValidate(item)"
                  name="validatorValue"
                  v-model="item.value"
                  validate="required"
                  v-if="item.inputType == 'input' && item.key !== 'decimal'"
                  :class="{
                    longClass: item.key == 'backendValidate' || item.key == 'regex'
                  }"
                />
                <ht-select
                  style=" margin-left: 15px;"
                  :validate="item.key == 'row_unique' ? '' : 'required'"
                  v-model="item.value"
                  :options="boData.filter(val => val.name != data.name)"
                  :multiple="item.key == 'row_unique' ? true : false"
                  :props="{key: 'name', value: 'desc'}"
                  @change="appendValidate(item)"
                  name="validatorSelectInput"
                  v-if="item.inputType == 'select' || item.key == 'row_unique'"
                >
                  <el-option
                    v-for="item in boData.filter(val => val.name != data.name)"
                    :key="item.name"
                    :label="item.cm"
                    :value="'searchForm.' + item.name"
                  ></el-option>
                </ht-select>
              </div>
              <el-button
                @click="removeValidata(index)"
                circle
                class="grid-remove-button"
                size="mini"
                icon="el-icon-close"
              ></el-button>
            </li>
          </draggable>
        </el-form>
      </div>
      <span slot="footer" class="dialog-footer">
        <el-button @click="handleClose(false)">取 消</el-button>
        <el-button type="primary" @click="handleClose(true)">确 定</el-button>
      </span>
    </el-dialog>
    <el-dialog
      title="方法校验"
      :visible.sync="dialogMethodVisible"
      v-if="dialogMethodVisible"
      append-to-body
      class="urgent-text"
      width="55%"
      :close-on-click-modal="false"
    >
      <div style="margin-top: 15px; margin-bottom: 25px">
        <code>
          <span style="color: red; margin-left: 15px">
            编辑的脚本内容会直接填充到function(value,searchForm){...}里面；value
            是当前控件输入值 searchForm是查询字段中的数据列
          </span>
          <br />
          <span style="color: red; margin-left: 15px"
            >如需使用到查询字段中的数据列： searchForm.实体表字段(可以直接选择查询字段)</span
          >
          <br />
          <span style="color: red; margin-left: 15px"
            >返回true 校验通过 false 校验不通过</span
          >
          <br />
          <span style="color: red; margin-left: 15px">
            返回值也可以是一个对象 {valid:true} 或者 {valid:false,data:{message:
            i18n.t("login.login") }} 使用国际化的方式
          </span>
          <br />
          <span style="color: red; margin-left: 15px">
            返回值也可以是一个对象 {valid:false,data:{message:
            "身份证号和出生日期不一致，请重新填写" }}
          </span>
          <br />
          <span style="color: red; margin-left: 15px">
            例如： if(searchForm.djbh == value ){ return true; }else{
              return {valid:false,data:{message: "校验失败" }}}
          </span>
        </code>
      </div>
      <div>
        查询字段:
        <el-select
          clearable
          placeholder="选择查询字段"
          v-model="diyScript"
          @change="diyScriptChange"
        >
          <el-option
            v-for="item in boData"
            :key="item.name"
            :label="item.cm"
            :value="'searchForm.' + item.name"
          ></el-option>
        </el-select>
      </div>
      <div style="width: 100%; height: 100%;margin-top:15px;">
        <codemirror
          ref="scriptText"
          v-model="toolmethod"
          :options="cmOptions"
          class="code"
          style="width: 99%; height: 100%"
        ></codemirror>
      </div>
      <div slot="footer" class="dialog-footer">
        <el-button @click="dialogMethodVisible = false">取 消</el-button>
        <el-button type="primary" @click="methodOk()">确 定</el-button>
      </div>
    </el-dialog>
  </div>
</template>
<script>
import utils from '@/hotent-ui-util.js'
import Draggable from 'vuedraggable'
import {Base64} from 'js-base64'
import {validateRules} from '@/api/controlsConfig.js'
export default {
  name: 'ValidateDialog',
  components: {Draggable},
  props: {
    boData: {
      type: Array
    }
  },
  data() {
    return {
      validateRules,
      submitVerificationDialog: false,
      isFilter: false,
      specialValidate: ['confirmed', 'isAfter', 'isBefore', 'isStart', 'isEnd'],
      dialogMethodVisible: false,
      cmOptions: {
        value: '',
        mode: 'javascript',
        readOnly: false,
        tabSize: 2,
        theme: 'base16-light',
        lineNumbers: true,
        line: true
      },
      diyScript: '',
      methodIndex: 0,
      toolmethod: '',
      data: {}
    }
  },
  computed: {
    validateList: function() {
      var rule = this.data.validateType
      if (!rule) {
        return []
      }
      //判断是否只有一个必填校验规并且选择了必填校验
      if (rule == 'required' && this.data.validate == "'required'") {
        return this.data.validateList
      }
      const filterRule = rule.split('|')
      return this.validateRules.filter(val => {
        var res = true
        if (filterRule.indexOf(val.key) != -1) {
          if (this.isFilter) {
            const showValidate = this.data.validateList.find(function(obj) {
              return obj.key == val.key
            })
            if (showValidate != undefined) {
              res = false
            }
          }
        } else {
          res = false
        }
        return res
      })
    }
  },
  mounted() {
    this.$validator = this.$root.$validator
  },
  methods: {
    handleClose(status) {
      if (status) {
        utils.validateForm(this, 'validateRulesForm').then(result => {
          if (!result) {
            return false
          }
          this.$emit('onConfirm', this.data)
          this.submitVerificationDialog = false
        })
      } else {
        this.submitVerificationDialog = false
      }
    },
    handleOpen(item) {
      this.submitVerificationDialog = true
      this.isFilter = false
      this.data = _.cloneDeep(item)
    },

    addValidata() {
      this.isFilter = true
      utils
        .validateForm(this, 'validateRulesForm')
        .then(result => {
          if (!result) {
            return
          }
          if (
            this.data.validateType == 'required' &&
            this.data.validateList.length == 1
          ) {
            this.$message.warning('当前选择的控件只有一个必填校验')
            return
          }
          if (this.data.validateList == undefined) {
            this.data.validateList = []
          } else if (this.data.validateList.length > 0) {
            const validata = this.data.validateList[
              this.data.validateList.length - 1
            ]
            if (
              validata.inputType == 'button' &&
              (validata.value == undefined || validata.value.length == 0)
            ) {
              this.$message.warning('请输入js方法校验')
              return
            }
          }

          this.$nextTick(() => {
            setTimeout(() => {
              this.data.validateList.push({key: '', name: ''})
            })
          })
        })
        .catch(() => {})
    },
    newMergeValidate(validateList) {
      var ref = false
      var validateObj1 = ''
      var validateObj2 = []
      validateList.forEach(obj => {
        const validate = this.getValidate(obj)
        validateObj2.push(validate)
        const key = utils.stringSplit(validate, ':')[0]
        const value = utils.stringSplit(validate, ':')[1]
        var splitVar = ''
        var op = ''
        if (validateObj1 != '') {
          op = '|'
          splitVar = '+'
        }
        if (this.specialValidate.indexOf(key) > -1) {
          validateObj1 =
            validateObj1 + splitVar + "'" + op + key + ":'+" + value
          ref = true
        } else {
          validateObj1 = validateObj1 + splitVar + "'" + op + validate + "'"
        }
      })
      var validateStr = ''
      if (ref) {
        validateStr = validateObj1
      } else {
        if (validateObj2.length == 0) {
          validateStr = ''
        } else {
          validateStr = "'" + validateObj2.join('|') + "'"
        }
      }
      return validateStr
    },
    getValidate(item) {
      const {key, value, inputType, isInput, name} = item
      let validate = null
      if (isInput) {
        if (inputType == 'twoInput') {
          return `between:${item.start},${item.end}`
        } else if (inputType == 'select') {
          if (
            name == '相同的值' ||
            name == '日期不晚于' ||
            name == '日期晚于' ||
            name == '日期早于' ||
            name == '日期不早于'
          ) {
            if (value.split('.').length == 4) {
              //子表
              validate = `item.${item.value.split('.')[3]}`
            } else if (value.split('.').length == 5) {
              //孙表
              validate = `item.${item.value.split('.')[4]}`
            } else {
              validate = value
            }
          }
        }
        if (validate === null) {
          validate = value
        }
      }
      if (validate !== null) {
        // 如果是正则表达式，将表达式内容做base64编码
        if (key == 'regex') {
          const regexBase64 = Base64.encode(validate)
          validate = `${key}:${regexBase64}`
        } else {
          validate = `${key}:${validate}`
        }
      } else {
        validate = key
      }
      return validate
    },
    //切换校验
    changeValidate(item) {
      const showValidate = this.validateRules.find(function(obj) {
        return obj.key == item.key
      })
      item.inputType = showValidate.inputType
      item.name = showValidate.name
      item.isInput = showValidate.isInput
      item.type = showValidate.type
      if (this.validateList.length != 1) {
        delete item.value
      }
      if (!item.isInput) {
        let validateList = this.data.validateList
        this.data.validate = this.newMergeValidate(validateList)
      }
    },
    visibleChangeValidate() {
      this.isFilter = true
    },
    appendValidate(item) {
      let validateList = this.data.validateList
      this.data.validate = this.newMergeValidate(validateList)
    },
    methodClick(index) {
      this.methodIndex = index
      this.dialogMethodVisible = true
      if (this.data.validateList[index].value) {
        this.toolmethod = Base64.decode(this.data.validateList[index].value)
      } else {
        this.toolmethod = ''
      }
    },
    removeValidata(index) {
      this.isFilter = false
      this.data.validateList.splice(index, 1)
      this.data.validate = this.newMergeValidate(this.data.validateList)
    },
    end(evt) {
      this.isFilter = false
      let validateList = this.data.validateList
      this.data.validate = this.newMergeValidate(validateList)
    },
    //js校验
    methodOk() {
      this.data.validateList[this.methodIndex].value = Base64.encode(
        this.toolmethod
      )
      this.data.validate = this.newMergeValidate(this.data.validateList)
      this.dialogMethodVisible = false
    },
    async diyScriptChange(myValue) {
      const myField = this.$refs.scriptText
      var value = myValue
      if (myField.selectionStart || myField.selectionStart === 0) {
        var startPos = myField.selectionStart
        var endPos = myField.selectionEnd
        this.toolmethod =
          myField.value.substring(0, startPos) +
          value +
          myField.value.substring(endPos, myField.value.length)
        await this.$nextTick() // 这句是重点, 圈起来
        myField.focus()
        myField.setSelectionRange(endPos + value.length, endPos + value.length)
      } else {
        this.toolmethod += value
      }
    }
  }
}
</script>

<style lang="scss" scoped>
.explain {
  background: rgba(64, 158, 255, 0.1);
  padding: 16px;
  color: #409eff;
  font-weight: 400;
  p {
    line-height: 30px;
  }
  span {
    color: #e55555;
  }
}
.btn {
  margin: 24px 0;
  .tips {
    margin-left: 10px;
    color: #999;
  }
}
.column-ul li {
  display: flex;
  justify-self: start;
  align-items: center;
  height: 64px;
  background-color: #f9f9f9;
  .longClass {
    width: 350px;
  }
}
.icon-drag2 {
  color: #409eff;
  padding: 0 24px;
}
.grid-remove-button {
  margin: 0 16px;
}
.inputs {
  position: relative;
}
.two-input__container {
  display: inline-block;
  margin-left: 15px;
}
.validate-rule__container {
  display: flex;
  flex: 1;
  .inputs {
    flex: 1;
  }
}
</style>
