<template>
  <el-input v-bind="$attrs" v-on="$listeners" :value="value" :type="type" clearable :placeholder="placeholder"
    :autosize="type == 'textarea' ? { minRows: 2, maxRows: 5 } : null" :show-word-limit="type == 'textarea'"
    @keydown="handleKeydown" @blur="handleBlur">

    <!-- 透传所有普通插槽 -->
    <template v-for="(_, slotName) in $slots" #[slotName]>
      <slot :name="slotName"></slot>
    </template>

    <!-- 透传所有作用域插槽 -->
    <template v-for="(_, slotName) in $scopedSlots" #[slotName]="scope">
      <slot :name="slotName" v-bind="scope"></slot>
    </template>
  </el-input>
</template>

<script>

/* *
 * InputPlus 是一个增强型输入框组件，用于修复原生 input/el-input 在 type="number" 时的限制问题。
 *
 * 主要功能：
 * - 修复 maxlength 失效问题，支持按字符的最大长度截取（数字类型最大支持 16 位）。
 * - 如果截取后以.结尾，那么多截取一位
 * - 支持负数输入控制（通过 acceptMinus 属性）。
 * - 支持小数位数限制（通过 decimalLimit 属性）。
 * - 自动处理特殊格式：如将 `.5` 转换为 `0.5`，将 `-0.00` 转换为 `0` 等。
 *
 * 注意事项：
 * - 不支持多个符号（如 `--` 或 `++`）或符号在中间的情况（如 '--1, 1-1'），因为此时值为空字符串，无法替换。
 *
 * 使用示例：
  <!-- kebab-case 风格 -->
  <input-plus
    v-model="form.price"
    type="number"
    maxlength="10"
    :accept-minus="false"
    :decimal-limit="2"
  ></input-plus>

  <!-- PascalCase 风格 -->
  <InputPlus
    v-model="form.age"
    type="number"
    maxlength="3"
    :acceptMinus="false"
    :decimalLimit="0"
  />
 */

export default {
  name: 'InputPlus',
  props: {
    value: {
      type: [String, Number],
      default: ''
    },
    type: {
      type: String,
      default: 'text'
    },
    // 是否允许负数（默认允许）
    acceptMinus: {
      type: Boolean,
      default: true
    },
    // 小数位数限制(默认null不限制)
    decimalLimit: {
      type: [Number, String],
      default: null
    },
    // 占位符（支持自定义，默认值为 "请输入"）
    placeholder: {
      type: String,
      default: '请输入'
    },
  },
  data() {
    return {}
  },
  computed: {
    maxlength() {
      // 将 maxlength 转换为数字类型，确保严谨性
      const attrMaxlength = Number(this.$attrs?.maxlength);
      if (!attrMaxlength) return null; // 如果未定义或无效，则返回 null
      if (this.type !== 'number') return attrMaxlength; // 非 number 类型直接返回
      // 对于 number 类型，最大长度限制为 16
      return attrMaxlength > 16 ? 16 : attrMaxlength;
    },
  },
  methods: {
    /**
     * 键盘按下时控制输入长度
     * - 当输入达到 maxlength 时，仅允许特定按键（如删除、方向键等）。
     * @param {KeyboardEvent} event 键盘事件对象
     */
    handleKeydown(event) {
      if (this.type === 'number' && this.maxlength !== null) {
        const currentValue = event.target.value || '';
        if (currentValue.length >= this.maxlength) {
          const allowedKeys = [
            'Backspace',    // 退格键（删除光标前一个字符）
            'Delete',       // 删除键（删除光标后一个字符）
            'ArrowLeft',    // 左箭头键（光标左移）
            'ArrowRight',   // 右箭头键（光标右移）
            'ArrowUp',      // 上箭头键（光标上移）
            'ArrowDown',    // 下箭头键（光标下移）
            'Tab',          // Tab键（切换到下一个表单元素）
            'Enter',        // 回车键（确认输入）
            'Escape',       // Esc键（取消输入）
            'Home',         // Home键（将光标移动到行首）
            'End',          // End键（将光标移动到行尾）
            'PageUp',       // PageUp键（将光标移到页面上）
            'PageDown',     // PageDown键（将光标移到页面下）
            'Control',      // Ctrl键（组合键）
            'Alt',          // Alt键（组合键）
            'Shift',        // Shift键（组合键）
            'Meta',         // Meta键（组合键, 右侧的Ctrl）
          ];

          // 如果不是允许的按键，则阻止输入
          if (!allowedKeys.includes(event.key)) {
            event.preventDefault();
          }
        }
      }
    },
    /**
     * 失焦时处理最终结果并触发 input 事件
     * - 根据配置处理负数、小数位数限制、特殊格式等。
     * - 最终值通过 $emit('input') 传递给父组件。
     * @param {FocusEvent} event 失焦事件对象
     */
    handleBlur(event) {
      if (this.type === 'number') {
        let currentValue = event.target.value || '';
        if (currentValue != null && currentValue != undefined && currentValue != '') {
          // 处理负数
          if (!this.acceptMinus) {
            currentValue = currentValue.replace(/-/g, '');
          }
          // 处理位数-兼容number/string————toFixed精度有问题
          if (currentValue.indexOf('.') > 0 && this.decimalLimit !== null) {
            // 不要小数点(0)需要把“.”去掉，其他保留
            let num = this.decimalLimit === 0 ? parseInt(this.decimalLimit) : parseInt(this.decimalLimit) + 1
            currentValue = currentValue.slice(0, currentValue.indexOf('.') + num)
          }
          // 处理.5成0.5  处理-.5为-0.5
          if (currentValue.startsWith('.') || currentValue.startsWith('-.')) {
            currentValue = '0' + currentValue
          }
          // 处理0.00 00为0
          if (parseFloat(currentValue) === 0) {
            currentValue = 0
          }
          // 按长度截取---设置了有小数时，刚好最后一个截取到小数时再补一位
          if (currentValue.length > this.maxlength) {
            let tmp = currentValue.substring(0, this.maxlength)
            // 如果截取后以小数点结尾，则多截取一位
            if (tmp.endsWith('.')) {
              currentValue = currentValue.substring(0, this.maxlength + 1)
            } else {
              currentValue = tmp
            }
          }
        } else {
          currentValue = ''
        }
        // console.log('handleBlur', currentValue)
        this.$emit('input', currentValue);
      }
    }
  }
}
</script>

<style lang='scss' scoped></style>