<template>
  <div :id="$style.formulaPage">
    <!-- 公式编辑区域 -->
    <div
      :id="$style.formulaView"
      ref="formulaView"
      :class="$style.formulaView"
      @click.stop="recordPosition"
    >
      <div
        v-for="(item, index) in formulaList"
        :key="index"
        :class="$style.contentItem"
        @click.stop="recordPosition(index)"
      >
        <div v-if="item.type === 'placeholder'" :class="$style.placeholder"> &zwj;</div>
        <div v-if="item.type === 'num'" :class="$style.num"> &zwj;{{ item.value }} </div>
        <div v-if="item.type === 'bd'" :class="$style.num"> &zwj;{{ item.value }} </div>
        <div v-else-if="item.type === 'plain'" :class="$style.plain"> &zwj;{{ item.value }} </div>
        <div v-else-if="item.type === 'obj'" :class="$style.obj"> &zwj;{{ item.value }} </div>

        <!--光标-->
        <div v-if="item.cursor" :class="$style.cursor"></div>
      </div>
      <div
        v-if="formulaList.length === 0"
        style="color: rgb(178, 178, 178);padding-left: 45%;padding-top: 10px;"
        >点击此处创建公式</div
      >
    </div>

    <div v-show="!readOnly" class="tab mt_10 flex-lr">
      <div class="">
        <div class="" style="display:inline-block;position:relative;padding: 0 10px;">
          <a-button type="primary" :class="classStyle" @click="selectZb">选择指标</a-button>
        </div>
        <div class="" style="display:inline-block;position:relative;">
          <a-button :class="classStyle" @click="deleteItem">退格</a-button>
        </div>
        <div class="" style="display:inline-block;position:relative;padding: 0 10px;">
          <a-button :class="classStyle" @click="deleteItem('kh')">清空括号</a-button>
        </div>
        <div class="" style="display:inline-block;position:relative;">
          <a-button :class="classStyle" @click="clearAll">清空公式</a-button>
        </div>
        <div class="" style="display:inline-block;position:relative;padding: 0 10px;">
          <a-button :class="$style.classStylejygs" @click="checkformula">校验公式</a-button>
        </div>
      </div>
    </div>
    <a-modal v-model="ModalVisible" title="手动录入数字" @ok="ModalHandleOk">
      <a-form-model ref="ModalForm" :model="ModalForm">
        <a-form-model-item label="数字" prop="num">
          <a-input v-model="ModalForm.num" />
        </a-form-model-item>
      </a-form-model>
    </a-modal>

    <!-- <iam-audit-modal
      :single="true"
      :check-type="'radio'"
      select-type="table"
      :visible="visible"
      :treeparams="{
        configId: '41',
      }"
      :columns="columns"
      @listSelected="listSelected"
      @getCheckNode="getCheckNode"
      @handleCancel="handleCancel"
    ></iam-audit-modal> -->

    <a-modal
      title="选择指标"
      :visible="visible"
      :confirm-loading="confirmLoading"
      width="1000px"
      @ok="handleOk"
      @cancel="handleCancel"
    >
      <sd-data-table-ex
        ref="zblist"
        :data-url="zbDataUrl"
        :process-req="processReq"
        form-id="kpiIndiDef"
        page-id="kpi/def/definition/kpiIndiDef"
        :columns="zbColumns"
        :search-fields="['indiName']"
        :filter-expressions="zbExpressions"
        :checkType="'radio'"
        show-selection
      >
      </sd-data-table-ex>
    </a-modal>
  </div>
</template>

<script>
import { message, Modal } from 'ant-design-vue'
// import iamAuditModal from '@product/iam/components/iam-audit-modal.vue'
import kpiService from '../kpi-service'
import components from './_import-components/kpi-formula-editor-import'

export default {
  name: 'KpiFormulaEditor',
  metaInfo: {
    title: 'KpiFormulaEditor',
  },
  components: {
    ...components,
  },
  props: {
    dataList: {
      type: Array,
      default() {
        return []
      },
    },
    defaultList: {
      type: Array,
      default() {
        return []
      },
    },
    readOnly: {
      type: Boolean,
      default: false,
    },
    zbid: {
      type: String,
      default: '',
    },
  },
  data() {
    return {
      confirmLoading: false,
      ModalForm: {
        num: '', // 数字
      },
      currentEntryField: '', // 当前录入的表单字段
      ModalVisible: false,
      num: [],
      // 公式字符串
      formulaStr: '',
      zbDataUrl: 'api/xcoa-mobile/v1/kpi-indi-def/getIndisByAttr',
      dataId: '',
      operatorId: '',
      formulaList: [],
      // 运算符
      operatorList: [
        {
          name: '+',
          id: '+',
        },
        {
          name: '-',
          id: '-',
        },
        {
          name: '*',
          id: '*',
        },
        {
          name: '/',
          id: '/',
        },
        {
          name: '()',
          id: '()',
        },
      ],
      classStyle: '',
      flag: true,
      visible: false,
      zbColumns: [
        {
          title: '序号',
          dataIndex: 'sortNum',
          customRender: (text, record, index) => `${index + 1}`,
          width: '80px',
        },
        {
          title: '指标名称',
          dataIndex: 'indiName',
        },
        {
          title: '业务分类',
          dataIndex: 'busiClassName',
        },
        {
          title: '维护单位',
          dataIndex: 'createDeptName',
        },
      ],
      zbExpressions: [],
      selectedRowKeys: [],
      selectZbkey: 0,
      searchValInit: '',
      // sdataList: [],
      selectList: [],
    }
  },
  watch: {
    formulaList(val) {
      this.$emit('change', val)
      if (!this.flag) {
        this.$emit('change', '')
      }
    },
  },
  created() {
    if (this.defaultList.length > 0) {
      this.formulaList = [...this.defaultList]
    }
    // this.sdataList = [...this.dataList]
    // 监听鼠标事件
    this.$nextTick(function() {
      // document.addEventListener('keydown', this.keydown, false)
      document.addEventListener('keypress', this.keypress, false)
      document.addEventListener('click', this.formulaBlur)
    })
    this.zbExpressions.push({
      dataType: 'str',
      name: 'id',
      op: 'ne',
      stringValue: `${this.zbid}`,
    })
  },
  destroyed() {
    // 移除监听事件
    // document.removeEventListener('keydown', this.keydown, false)
    document.removeEventListener('keypress', this.keypress, false)
    document.removeEventListener('click', this.formulaBlur)
  },
  methods: {
    processReq(req) {
      // 获取查询内容
      return req
    },
    handleOk() {
      const list = this.$refs.zblist.getSelectedRows()
      if (list.length === 0) {
        message.error('请选择指标!')
      } else {
        this.listSelected([], list)
        this.$refs.zblist.clearSelection()
        this.visible = false
      }
    },
    handleCancel() {
      this.visible = false
    },
    listSelected(keys, keyinfos) {
      this.visible = false
      if (keyinfos?.length > 0) {
        const zbid = '#v_' + keyinfos[0].id
        this.selectList = keyinfos[0]
        this.addItem(zbid, 'obj')
      }
    },
    getCheckNode(checkNode) {
      this.visible = false
    },
    selectZb(event) {
      // 阻止丢失事件
      event.stopPropagation()
      this.visible = true
      this.selectZbkey += 1
    },
    checkformula() {
      // 校验所有数字是否合规，两个plain中间的是否是数字格式
      let strnum = ''
      let info = '该公式合法'
      let flag = true
      let gs = ''
      this.formulaList.forEach((v) => {
        if (v.type === 'obj') {
          gs += 'o'
        } else {
          gs += v.value
        }
      })
      let tt = /([+\-*/]{2,})/ // +-*/运算符不能连着
      if (tt.test(gs)) {
        flag = false
      }
      tt = /\(\)/ // 不可含有空括号
      if (tt.test(gs)) {
        flag = false
      }
      tt = /^[+\-*/]/ // 运算符开头
      if (tt.test(gs)) {
        flag = false
      }
      tt = /[+\-*/]$/ // 运算符结尾
      if (tt.test(gs)) {
        flag = false
      }
      // 数字和 指标不能连着
      // tt = /([{0-9}{o}]{2,})/
      // if (tt.test(gs)) {
      //   flag = false
      // }
      // 错误情况，(后面是运算符
      tt = /\([+\-*/]/
      if (tt.test(gs)) {
        flag = false
      }

      // 错误情况，)前面是运算符
      if (/[+\-*/]\)/.test(gs)) {
        flag = false
      }

      // 错误情况，(前面不是运算符
      // if (/[^{+}{-}{*}{/}]\(/.test(gs)) {
      //   flag = false
      // }
      // 错误情况，使用除()+-*/之外的字符
      // if (/[^{+}{-}{*}{/}0-9.a-zA-Z\(\)]/.test(gs)) {
      //   flag = false
      // }
      // 错误情况，(后面不是运算符
      // if (/\([+\-*/]/.test(gs)) {
      //   flag = false
      // }
      if (flag) {
        // 判断数字是否标准，判断括号是否对应
        const stack = []
        const f = [...this.formulaList]
        this.formulaList.forEach((v, i) => {
          if (v.type === 'num' || v.type === 'bd') {
            strnum += v.value
          } else if (v.type === 'plain') {
            if (strnum !== '' && isNaN(strnum)) {
              flag = false
              info += ',' + strnum + '不是数字'
            } else if (v.value === '(') {
              stack.push('(')
            } else if (v.value === ')') {
              if (stack.length > 0) {
                stack.pop()
              } else {
                flag = false
                info += ',括号对应不上'
              }
            }
            strnum = ''
          } else if (v.type === 'obj') {
            if (strnum !== '') {
              flag = false
              info += ',指标前不能为数字'
              strnum += 'o'
            } else if (i !== 0 && f[i - 1].type === 'obj') {
              flag = false
            }
          }
        })
        if (strnum !== '' && isNaN(strnum)) {
          flag = false
          info += ',' + strnum + '不是数字'
        }
        if (stack.length !== 0) {
          flag = false
        }
        if (info !== '') {
          info = info.substring(1, info.length) + '，请修改'
        }
        if (flag) {
          if (f.length > 1 && f[f.length - 1].value === '-') {
            flag = false
          } else if (f.length > 1 && f[0].value === '-') {
            flag = false
          }
        }
      }
      if (!flag) {
        info = '该公式不合法'
      } else {
        if(gs.indexOf("o") === -1){
        info = '该公式至少选择一个指标'
        }else{
        info = '该公式合法'
        }
      }
      // if (!flag) {
      Modal.info({
        content: info,
      })
      return flag
      // }
    },
    isNumber(val) {
      // isNumber(val){
      const regPos = /^\d+(\.\d+)?$/
      const regNeg = /^(-(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*)))$/
      if (regPos.test(val) && regNeg.test(val)) {
        return true
      } else {
        return false
      }
    },
    openmodal() {
      this.ModalForm.num = ''
      this.currentEntryField = 'field'
      this.ModalVisible = true
    },
    ModalHandleOk() {
      this.addItem(this.ModalForm.num, 'num')
      this.ModalVisible = false
    },
    // 获取
    getFormula: function() {},

    // 点选时记录光标位置
    recordPosition(index) {
      // 只读模式，不可编辑
      if (this.readOnly) {
        return false
      }
      if (this.formulaList && this.formulaList.length > 0) {
        this.formulaList = this.formulaList.map((item, itemIndex) => {
          item.cursor = false
          if (index > -1 && index === itemIndex) {
            item.cursor = true
          } else if (index !== 0 && !index && itemIndex === this.formulaList.length - 1) {
            item.cursor = true
          }
          return item
        })
      } else {
        this.formulaList = [
          {
            cursor: true,
            type: 'placeholder',
            value: '',
          },
        ]
      }
      this.$forceUpdate()
    },

    // 失去焦点
    formulaBlur(e) {
      if (!this.visible) {
        const v = this.formulaList.findIndex((i) => i.value === '')
        if (this.formulaList.length === 1 && v > -1) {
          this.formulaList = []
        } else if (this.formulaList.length > 0 && this.formulaList[0].value !== '') {
          this.formulaList.splice(0, 0, {
            cursor: false,
            type: 'placeholder',
            value: '',
          })
        }
        this.formulaList = this.formulaList?.map((item) => {
          item.cursor = false
          return item
        })
      }
    },

    /**
     * @returns {addItem<*, void, *>}
     * 添加字段
     * type obj 字段  num 数字 plain符号
     * place 是否修改光标位置
     */
    addItem: function(val, type, place = true) {
      if (!val) return false
      const that = this
      // 插入括号
      if (type === 'plain' && val === '()') {
        val = '('
        setTimeout(function() {
          that.addItem(')', type, false)
        }, 50)
      }

      const obj = {}
      const data = {
        value: '',
        key: val,
        type: type,
      }

      if (type === 'obj') {
        // 获取数据 为 value 赋值
        // const obj = this.selectList?.find((item) => '#v_' + item.id === val)
        const obj = this.selectList
        data.value = obj.indiName
      } else {
        data.value = val
      }
      if (this.formulaList && this.formulaList.length > 0) {
        const length = this.formulaList.length
        for (let i = 0; i < length; i++) {
          // 查找光标位置 如果光标位置为空 则在最后添加
          if (this.formulaList[i].cursor) {
            this.formulaList.splice(i + 1, 0, data)
            // place && this.recordPosition(i + 1)
            if (place) this.recordPosition(i + 1)
            break
          } else if (i === this.formulaList.length - 1) {
            this.formulaList.push(data)
            this.recordPosition(this.formulaList.length - 1)
          }
        }
      } else {
        if (!this.formulaList) {
          this.formulaList = []
        }
        this.formulaList.push(data)
        this.recordPosition(this.formulaList.length - 1)
      }
    },

    // 清除全部
    clearAll() {
      this.formulaList = []
      const that = this
      setTimeout(function() {
        that.recordPosition()
      }, 100)
    },

    // 删除
    deleteItem(type) {
      const arr = JSON.parse(JSON.stringify(this.formulaList))
      var index = null
      const length = arr?.length
      var gbi = 0
      if (type === 'kh') {
        for (let i = length - 1; i > 0; i--) {
          if (arr[i].key && (arr[i].value === '(' || arr[i].value === ')')) {
            index = i
            this.formulaList.splice(index, 1)
          }
        }
        const that = this
        setTimeout(function() {
          that.recordPosition()
        }, 100)
      } else {
        for (let i = 0; i < length; i++) {
          if (arr[i].cursor && arr[i].key) {
            index = i
            if (type === 'del') {
              index = i + 1
              gbi = index
              break
            }
            if (index > -1) {
              this.formulaList.splice(index, 1)
              if (type === 'del') {
              } else {
                gbi = index - 1
                break
              }
            }
          }
        }
        const that = this
        setTimeout(function() {
          that.recordPosition(gbi)
        }, 100)
      }
    },

    // 键盘输入
    keydown(e) {
      // 禁止输入
      // 检测光标是否存在
      var index = null
      const cursorData = this.formulaList?.find((item, itemIndex) => {
        if (item.cursor) {
          index = itemIndex
        }
        return item.cursor
      })
      if (!cursorData) {
        return false
      }
      // 左右移动键控制光标位置
      if (e && [37, 39].includes(e.keyCode)) {
        if (e.keyCode === 37) {
          index = index - 1
        } else {
          index = index + 1
        }
        if (index > -1 && index < this.formulaList.length) {
          this.recordPosition(index)
        }
      } else if (e && e.keyCode === 8) {
        // Backspace 键 删除前面的值
        this.deleteItem()
      } else if (e && [107, 109, 106, 111].includes(e.keyCode)) {
        // 运算符列表
        this.addItem(e.key, 'plain')
      } else if (e && [190].includes(e.keyCode)) {
        this.addItem(e.key, 'plain')
      } else if (e && e.shiftKey && [16, 49, 57].includes(e.keyCode)) {
        if (e.keyCode === 49) e.key = ')'
      } else if (e && e.shiftKey && [48, 57].includes(e.keyCode)) {
        // 括号
        if (e.keyCode === 48) e.key = ')'
        if (e.keyCode === 57) e.key = '('
        this.addItem(e.key, 'plain')
      } else if (e && e.keyCode === 46) {
        // delete键删除光标后面的值
        this.deleteItem('del')
      } else {
        document.returnValue = false
        var tt = /^([1-9]{1}[0-9]{0,7})$/ // 能输入正数
        if (tt.test(e.key)) {
          // 输入为数字 插入数字
          // this.addItem(e.key, 'num')
          this.addItem(String.fromCharCode(e.key), 'num')
        } else {
          this.addItem(String.fromCharCode(e.key), 'plain')
        }
      }
    },
    keypress(e) {
      // 禁止输入
      // 检测光标是否存在
      var index = null
      const cursorData = this.formulaList?.find((item, itemIndex) => {
        if (item.cursor) {
          index = itemIndex
        }
        return item.cursor
      })
      if (!cursorData) {
        return false
      }
      var key = e.keyCode
      // 左右移动键控制光标位置
      if (e && [37, 39].includes(e.keyCode)) {
        if (e.keyCode === 37) {
          index = index - 1
        } else {
          index = index + 1
        }
        if (index > -1 && index < this.formulaList.length) {
          this.recordPosition(index)
        }
      } else if (e && e.keyCode === 8) {
        // Backspace 键 删除前面的值
        this.deleteItem()
        // } else if (e && [107, 109, 106, 111].includes(e.keyCode)) {
        // 运算符列表
        // this.addItem(e.key, 'plain')
      } else if (e && [190].includes(e.keyCode)) {
        this.addItem(e.key, 'plain')
      } else if (e && e.shiftKey && [16, 49, 57].includes(e.keyCode)) {
        if (e.keyCode === 49) e.key = ')'
      } else if (e && e.shiftKey && [48, 57].includes(e.keyCode)) {
        // 括号
        if (e.keyCode === 48) e.key = ')'
        if (e.keyCode === 57) e.key = '('
        this.addItem(e.key, 'plain')
        // } else if (e && e.keyCode === 46) {
        // delete键删除光标后面的值
        // this.deleteItem('del')
      } else {
        document.returnValue = false
        var tt = /^([0-9]{1}[0-9]{0,7})$/ // 能输入正数
        // var tt = /^\\d+(\\.{0,1}\\d+){0,1}$/
        if (tt.test(e.key)) {
          // 输入为数字 插入数字
          // this.addItem(e.key, 'num')
          if (tt.test(String.fromCharCode(key))) {
            this.addItem(String.fromCharCode(key), 'num')
          } else if (['+', '-', '*', '/', '.'].includes(String.fromCharCode(key))) {
            this.addItem(String.fromCharCode(key), 'plain')
          }
        } else {
          if (
            String.fromCharCode(key) === '+' ||
            String.fromCharCode(key) === '-' ||
            String.fromCharCode(key) === '*' ||
            String.fromCharCode(key) === '/' ||
            String.fromCharCode(key) === '(' ||
            String.fromCharCode(key) === ')'
          ) {
            this.addItem(String.fromCharCode(key), 'plain')
          } else if (String.fromCharCode(key) === '.') {
            this.addItem(String.fromCharCode(key), 'bd')
          }
        }
      }
    },

    /**
     * 公式转为字符串
     * 格式 [id]符号数字
     * **/
    parsingFormula: function(formulaStr) {
      let str = ''
      let arr = []
      arr = this.formulaList?.map((item) => {
        let val = item.key
        if (val) {
          if (item.type === 'obj') {
            val = '[' + val + ']'
          }
          str = str + val
        }
        return val
      })
      return str
    },
  },
}
</script>

<style module lang="scss">
@use '@/common/design' as *;
#formulaPage {
  .formulaView {
    padding: 10px 11px;
    width: 100%;
    height: 58px;
    border: 1px solid #d9d9d9;
    line-height: 1.3;
    font-size: 16px;
    overflow-y: scroll;
    color: rgba(0, 0, 0, 0.65);
    border-radius: 4px;
    .contentItem {
      position: relative;
      height: 16px;
      cursor: text;
      user-select: none;
      display: flex;
      align-items: center;
      float: left;
      .cursor {
        height: 16px;
        width: 1px;
        background: #333;
        animation: defaultCursor 1s steps(2) infinite;
        position: absolute;
        right: 0;
      }
      .obj {
        padding: 0 5px;
        margin: 0 1px;
        background: #f1f1f1;
        border-radius: 3px;
      }
      .num {
        // color: #000;
        background: #fff;
        padding: 0 1px 0 0;
      }
      .plain {
        margin: 0px 4px;
      }
      .placeholder {
        width: 4px;
      }
    }
  }
  .classStylejygs {
    border-color: #40a9ff;
  }
}

@keyframes defaultCursor {
  0% {
    opacity: 1;
  }
  100% {
    opacity: 0;
  }
}
.search {
  // width: 219px;
  margin-bottom: 10px;
  width: 50%;
}
</style>
