JVxeCellMixins.js 9.63 KB
import PropTypes from 'ant-design-vue/es/_util/vue-types'
import { filterDictText } from '@/components/dict/JDictSelectUtil'
import { getEnhancedMixins, JVXERenderType, replaceProps } from '@/components/jeecg/JVxeTable/utils/cellUtils'

// noinspection JSUnusedLocalSymbols
export default {
  inject: {
    getParentContainer: {default: () => ((node) => node.parentNode)},
  },
  props: {
    value: PropTypes.any,
    row: PropTypes.object,
    column: PropTypes.object,
    // 组件参数
    params: PropTypes.object,
    // 渲染选项
    renderOptions: PropTypes.object,
    // 渲染类型
    renderType: PropTypes.string.def('default'),
  },
  data() {
    return {
      innerValue: null,
    }
  },
  computed: {
    caseId() {
      return this.renderOptions.caseId
    },
    originColumn() {
      return this.column.own
    },
    $type() {
      return this.originColumn.$type
    },
    rows() {
      return this.params.data
    },
    fullDataLength() {
      return this.params.$table.tableFullData.length
    },
    rowIndex() {
      return this.params.rowIndex
    },
    columnIndex() {
      return this.params.columnIndex
    },
    cellProps() {
      let {originColumn: col, renderOptions} = this

      let props = {}

      // 输入占位符
      props['placeholder'] = replaceProps(col, col.placeholder)

      // 解析props
      if (typeof col.props === 'object') {
        Object.keys(col.props).forEach(key => {
          props[key] = replaceProps(col, col.props[key])
        })
      }

      // 判断是否是禁用的列
      props['disabled'] = (typeof col['disabled'] === 'boolean' ? col['disabled'] : props['disabled'])

      // TODO 判断是否是禁用的行
      // if (props['disabled'] !== true) {
      //   props['disabled'] = ((this.disabledRowIds || []).indexOf(row.id) !== -1)
      // }

      // 判断是否禁用所有组件
      if (renderOptions.disabled === true) {
        props['disabled'] = true
      }

      // update-begin-author:taoyan date:20211011 for: online表单,附表用户选择器{"multiSelect":false}不生效,单表可以生效 #3036
      let jsonStr = col['fieldExtendJson']
      if(jsonStr){
        let fieldExtendJson = JSON.parse(jsonStr)
        if(fieldExtendJson && fieldExtendJson['multiSelect']==false){
          props['multi'] = false
        }
      }
      // update-end-author:taoyan date:20211011 for: online表单,附表用户选择器{"multiSelect":false}不生效,单表可以生效 #3036

      return props
    },
  },
  watch: {
    $type: {
      immediate: true,
      handler($type) {
        this.enhanced = getEnhancedMixins($type)
        this.listeners = getListeners.call(this)
      },
    },
    value: {
      immediate: true,
      handler(val) {
        let value = val

        // 验证值格式
        let originValue = this.row[this.column.property]
        let getValue = this.enhanced.getValue.call(this, originValue)
        if (originValue !== getValue) {
          // 值格式不正确,重新赋值
          value = getValue
          vModel.call(this, value)
        }

        this.innerValue = this.enhanced.setValue.call(this, value)

        // 判断是否启用翻译
        if (this.renderType === JVXERenderType.spaner && this.enhanced.translate.enabled) {
          let res = this.enhanced.translate.handler.call(this, value)
          // 异步翻译,目前仅【多级联动】使用
          if (res instanceof Promise) {
            res.then(value => this.innerValue = value)
          } else {
            this.innerValue = res
          }
        }
      },
    },
  },
  created() {
  },
  methods: {

    /** 通用处理change事件 */
    handleChangeCommon(value) {
      let handle = this.enhanced.getValue.call(this, value)
      this.trigger('change', {value: handle})
      // 触发valueChange事件
      this.parentTrigger('valueChange', {
        type: this.$type,
        value: handle,
        oldValue: this.value,
        col: this.originColumn,
        rowIndex: this.params.rowIndex,
        columnIndex: this.params.columnIndex,
      })
    },
    /** 通用处理blur事件 */
    handleBlurCommon(value) {
      this.trigger('blur', {value})
    },

    /**
     *  如果事件存在的话,就触发
     * @param name 事件名
     * @param event 事件参数
     * @param args 其他附带参数
     */
    trigger(name, event, args = []) {
      let listener = this.listeners[name]
      if (typeof listener === 'function') {
        if (typeof event === 'object') {
          event = this.packageEvent(name, event)
        }
        listener(event, ...args)
      }
    },
    parentTrigger(name, event, args = []) {
      args.unshift(this.packageEvent(name, event))
      this.trigger('trigger', name, args)
    },
    packageEvent(name, event = {}) {
      event.row = this.row
      event.column = this.column
      //online增强参数兼容
      event.column['key'] = this.column['property']
      event.cellTarget = this
      if (!event.type) {
        event.type = name
      }
      if (!event.cellType) {
        event.cellType = this.$type
      }
      // 是否校验表单,默认为true
      if (typeof event.validate !== 'boolean') {
        event.validate = true
      }
      return event
    },

  },
  model: {
    prop: 'value',
    event: 'change'
  },
  /**
   * 【自定义增强】用于实现一些增强事件
   * 【注】这里只是定义接口,具体功能需要到各个组件内实现(也有部分功能实现)
   * 【注】该属性不是Vue官方属性,是JVxeTable组件自定义的
   *      所以方法内的 this 指向并不是当前组件,而是方法自身,
   *      也就是说并不能 this 打点调实例里的任何方法
   */
  enhanced: {
    // 注册参数(详见:https://xuliangzhan_admin.gitee.io/vxe-table/#/table/renderer/edit)
    installOptions: {
      // 自动聚焦的 class 类名
      autofocus: '',
    },
    // 事件拦截器(用于兼容)
    interceptor: {
      // 已实现:event.clearActived
      // 说明:比如点击了某个组件的弹出层面板之后,此时被激活单元格不应该被自动关闭,通过返回 false 可以阻止默认的行为。
      ['event.clearActived'](params, event, target) {
        return true
      },
      // 自定义:event.clearActived.className
      // 说明:比原生的多了一个参数:className,用于判断点击的元素的样式名(递归到顶层)
      ['event.clearActived.className'](params, event, target) {
        return true
      },
    },
    // 【功能开关】
    switches: {
      // 是否使用 editRender 模式(仅当前组件,并非全局)
      // 如果设为true,则表头上方会出现一个可编辑的图标
      editRender: true,
      // false = 组件触发后可视);true = 组件一直可视
      visible: false,
    },
    // 【切面增强】切面事件处理,一般在某些方法执行后同步执行
    aopEvents: {
      // 单元格被激活编辑时会触发该事件
      editActived() {
      },
      // 单元格编辑状态下被关闭时会触发该事件
      editClosed() {
      },
    },
    // 【翻译增强】可以实现例如select组件保存的value,但是span模式下需要显示成text
    translate: {
      // 是否启用翻译
      enabled: false,
      /**
       * 【翻译处理方法】如果handler留空,则使用默认的翻译方法
       * (this指向当前组件)
       *
       * @param value 需要翻译的值
       * @returns{*} 返回翻译后的数据
       */
      handler(value,) {
        // 默认翻译方法
        return filterDictText(this.column.own.options, value)
      },
    },
    /**
     * 【获取值增强】组件抛出的值
     * (this指向当前组件)
     *
     * @param value 保存到数据库里的值
     * @returns{*} 返回处理后的值
     */
    getValue(value) {
      return value
    },
    /**
     * 【设置值增强】设置给组件的值
     * (this指向当前组件)
     *
     * @param value 组件触发的值
     * @returns{*} 返回处理后的值
     */
    setValue(value) {
      return value
    },
    /**
     * 【新增行增强】在用户点击新增时触发的事件,返回新行的默认值
     *
     * @param row 行数据
     * @param column 列配置,.own 是用户配置的参数
     * @param $table vxe 实例
     * @param renderOptions 渲染选项
     * @param params 可以在这里获取 $table
     *
     * @returns 返回新值
     */
    createValue({row, column, $table, renderOptions, params}) {
      return column.own.defaultValue
    },
  }
}

function getListeners() {
  let listeners = Object.assign({}, (this.renderOptions.listeners || {}))
  if (!listeners.change) {
    listeners.change = async (event) => {
      vModel.call(this, event.value)
      await this.$nextTick()
      // 处理 change 事件相关逻辑(例如校验)
      this.params.$table.updateStatus(this.params)
    }
  }
  return listeners
}

export function vModel(value, row, property) {
  if (!row) {
    row = this.row
  }
  if (!property) {
    property = this.column.property
  }
  this.$set(row, property, value)
}

/** 模拟触发事件 */
export function dispatchEvent({cell, $event}, className, handler) {
  // alwaysEdit 下不模拟触发事件,否者会导致触发两次
  if (this && this.alwaysEdit) {
    return
  }
  window.setTimeout(() => {
    let element = cell.getElementsByClassName(className)
    if (element && element.length > 0) {
      if (typeof handler === 'function') {
        handler(element[0])
      } else {
        // 模拟触发点击事件
        if($event){
          element[0].dispatchEvent($event)
        }
      }
    }
  }, 10)
}