477 lines
15 KiB
Java
477 lines
15 KiB
Java
import XEUtils from 'xe-utils/methods/xe-utils'
|
|
import VXETable from '../../v-x-e-table'
|
|
import { UtilTools, DomTools } from '../../tools'
|
|
|
|
export default {
|
|
methods: {
|
|
/**
|
|
* 往表格中插入临时数据
|
|
*
|
|
* @param {*} records
|
|
*/
|
|
_insert (records) {
|
|
return this.insertAt(records)
|
|
},
|
|
/**
|
|
* 往表格指定行中插入临时数据
|
|
* 如果 row 为空则从插入到顶部
|
|
* 如果 row 为 -1 则从插入到底部
|
|
* 如果 row 为有效行则插入到该行的位置
|
|
* @param {Object/Array} records 新的数据
|
|
* @param {Row} row 指定行
|
|
*/
|
|
_insertAt (records, row) {
|
|
const { afterFullData, editStore, scrollYLoad, tableFullData, treeConfig } = this
|
|
if (treeConfig) {
|
|
throw new Error(UtilTools.getLog('vxe.error.noTree', ['insert']))
|
|
}
|
|
if (!XEUtils.isArray(records)) {
|
|
records = [records]
|
|
}
|
|
const nowData = afterFullData
|
|
const newRecords = records.map(record => this.defineField(Object.assign({}, record)))
|
|
if (!row) {
|
|
nowData.unshift(...newRecords)
|
|
tableFullData.unshift(...newRecords)
|
|
} else {
|
|
if (row === -1) {
|
|
nowData.push(...newRecords)
|
|
tableFullData.push(...newRecords)
|
|
} else {
|
|
const targetIndex = nowData.indexOf(row)
|
|
if (targetIndex === -1) {
|
|
throw new Error(UtilTools.error('vxe.error.unableInsert'))
|
|
}
|
|
nowData.splice(...([targetIndex, 0].concat(newRecords)))
|
|
tableFullData.splice(...([tableFullData.indexOf(row), 0].concat(newRecords)))
|
|
}
|
|
}
|
|
editStore.insertList.unshift(...newRecords)
|
|
this.handleTableData()
|
|
this.updateFooter()
|
|
this.updateCache()
|
|
this.checkSelectionStatus()
|
|
if (scrollYLoad) {
|
|
this.updateScrollYSpace()
|
|
}
|
|
return this.$nextTick().then(() => {
|
|
this.recalculate()
|
|
return {
|
|
row: newRecords.length ? newRecords[newRecords.length - 1] : null,
|
|
rows: newRecords
|
|
}
|
|
})
|
|
},
|
|
/**
|
|
* 删除指定行数据
|
|
* 如果传 row 则删除一行
|
|
* 如果传 rows 则删除多行
|
|
* 如果为空则删除所有
|
|
*/
|
|
_remove (rows) {
|
|
const { afterFullData, tableFullData, editStore, treeConfig, checkboxOpts, selection, isInsertByRow, scrollYLoad } = this
|
|
const { actived, removeList, insertList } = editStore
|
|
const { checkField: property } = checkboxOpts
|
|
let rest = []
|
|
const nowData = afterFullData
|
|
if (treeConfig) {
|
|
throw new Error(UtilTools.getLog('vxe.error.noTree', ['remove']))
|
|
}
|
|
if (!rows) {
|
|
rows = tableFullData
|
|
} else if (!XEUtils.isArray(rows)) {
|
|
rows = [rows]
|
|
}
|
|
// 如果是新增,则保存记录
|
|
rows.forEach(row => {
|
|
if (!isInsertByRow(row)) {
|
|
removeList.push(row)
|
|
}
|
|
})
|
|
// 如果绑定了多选属性,则更新状态
|
|
if (!property) {
|
|
XEUtils.remove(selection, row => rows.indexOf(row) > -1)
|
|
}
|
|
// 从数据源中移除
|
|
if (tableFullData === rows) {
|
|
rows = rest = tableFullData.slice(0)
|
|
tableFullData.length = 0
|
|
nowData.length = 0
|
|
} else {
|
|
rest = XEUtils.remove(tableFullData, row => rows.indexOf(row) > -1)
|
|
XEUtils.remove(nowData, row => rows.indexOf(row) > -1)
|
|
}
|
|
// 如果当前行被激活编辑,则清除激活状态
|
|
if (actived.row && rows.indexOf(actived.row) > -1) {
|
|
this.clearActived()
|
|
}
|
|
// 从新增中移除已删除的数据
|
|
XEUtils.remove(insertList, row => rows.indexOf(row) > -1)
|
|
this.handleTableData()
|
|
this.updateFooter()
|
|
this.updateCache()
|
|
this.checkSelectionStatus()
|
|
if (scrollYLoad) {
|
|
this.updateScrollYSpace()
|
|
}
|
|
return this.$nextTick().then(() => {
|
|
this.recalculate()
|
|
return { row: rest.length ? rest[rest.length - 1] : null, rows: rest }
|
|
})
|
|
},
|
|
_removeSelecteds () {
|
|
// 在 v3 中废弃 removeSelecteds
|
|
UtilTools.warn('vxe.error.delFunc', ['removeSelecteds', 'removeCheckboxRow'])
|
|
return this.removeCheckboxRow()
|
|
},
|
|
/**
|
|
* 删除复选框选中的数据
|
|
*/
|
|
_removeCheckboxRow () {
|
|
return this.remove(this.getCheckboxRecords()).then(params => {
|
|
this.clearCheckboxRow()
|
|
return params
|
|
})
|
|
},
|
|
/**
|
|
* 删除单选框选中的数据
|
|
*/
|
|
_removeRadioRow () {
|
|
const radioRecord = this.getRadioRecord()
|
|
return this.remove(radioRecord || []).then(params => {
|
|
this.clearRadioRow()
|
|
return params
|
|
})
|
|
},
|
|
/**
|
|
* 删除当前行选中的数据
|
|
*/
|
|
_removeCurrentRow () {
|
|
const currentRecord = this.getCurrentRecord()
|
|
return this.remove(currentRecord || []).then(params => {
|
|
this.clearCurrentRow()
|
|
return params
|
|
})
|
|
},
|
|
/**
|
|
* 获取表格数据集,包含新增、删除、修改
|
|
*/
|
|
_getRecordset () {
|
|
return {
|
|
insertRecords: this.getInsertRecords(),
|
|
removeRecords: this.getRemoveRecords(),
|
|
updateRecords: this.getUpdateRecords()
|
|
}
|
|
},
|
|
/**
|
|
* 获取新增的临时数据
|
|
*/
|
|
_getInsertRecords () {
|
|
const insertList = this.editStore.insertList
|
|
const insertRecords = []
|
|
if (insertList.length) {
|
|
this.tableFullData.forEach(row => {
|
|
if (insertList.indexOf(row) > -1) {
|
|
insertRecords.push(row)
|
|
}
|
|
})
|
|
}
|
|
return insertRecords
|
|
},
|
|
/**
|
|
* 获取已删除的数据
|
|
*/
|
|
_getRemoveRecords () {
|
|
return this.editStore.removeList
|
|
},
|
|
/**
|
|
* 获取更新数据
|
|
* 只精准匹配 row 的更改
|
|
* 如果是树表格,子节点更改状态不会影响父节点的更新状态
|
|
*/
|
|
_getUpdateRecords () {
|
|
const { keepSource, tableFullData, isUpdateByRow, treeConfig, treeOpts } = this
|
|
// 在 v3 中必须要开启 keep-source
|
|
if (!keepSource) {
|
|
UtilTools.warn('vxe.error.reqProp', ['keep-source'])
|
|
}
|
|
if (keepSource) {
|
|
if (treeConfig) {
|
|
return XEUtils.filterTree(tableFullData, row => isUpdateByRow(row), treeOpts)
|
|
}
|
|
return tableFullData.filter(row => isUpdateByRow(row))
|
|
}
|
|
return []
|
|
},
|
|
/**
|
|
* 处理激活编辑
|
|
*/
|
|
handleActived (params, evnt) {
|
|
const { editStore, editOpts, tableColumn } = this
|
|
const { mode, activeMethod } = editOpts
|
|
const { actived } = editStore
|
|
const { row, column, cell } = params
|
|
const { editRender } = column
|
|
if (editRender && cell) {
|
|
if (actived.row !== row || (mode === 'cell' ? actived.column !== column : false)) {
|
|
// 判断是否禁用编辑
|
|
let type = 'edit-disabled'
|
|
if (!activeMethod || activeMethod(params)) {
|
|
if (this.keyboardConfig || this.mouseConfig) {
|
|
this.clearCopyed(evnt)
|
|
this.clearChecked()
|
|
this.clearSelected(evnt)
|
|
}
|
|
this.clostTooltip()
|
|
this.clearActived(evnt)
|
|
type = 'edit-actived'
|
|
column.renderHeight = cell.offsetHeight
|
|
actived.args = params
|
|
actived.row = row
|
|
actived.column = column
|
|
if (mode === 'row') {
|
|
tableColumn.forEach(column => this._getColumnModel(row, column))
|
|
} else {
|
|
this._getColumnModel(row, column)
|
|
}
|
|
this.$nextTick(() => {
|
|
this.handleFocus(params, evnt)
|
|
})
|
|
}
|
|
this.emitEvent(type, params, evnt)
|
|
} else {
|
|
const { column: oldColumn } = actived
|
|
if (oldColumn !== column) {
|
|
const { model: oldModel } = oldColumn
|
|
if (oldModel.update) {
|
|
UtilTools.setCellValue(row, oldColumn, oldModel.value)
|
|
}
|
|
this.clearValidate()
|
|
}
|
|
column.renderHeight = cell.offsetHeight
|
|
actived.args = params
|
|
actived.column = column
|
|
setTimeout(() => {
|
|
this.handleFocus(params, evnt)
|
|
})
|
|
}
|
|
this.focus()
|
|
}
|
|
return this.$nextTick()
|
|
},
|
|
_getColumnModel (row, column) {
|
|
const { model, editRender } = column
|
|
if (editRender) {
|
|
model.value = UtilTools.getCellValue(row, column)
|
|
model.update = false
|
|
}
|
|
},
|
|
_setColumnModel (row, column) {
|
|
const { model, editRender } = column
|
|
if (editRender && model.update) {
|
|
UtilTools.setCellValue(row, column, model.value)
|
|
model.update = false
|
|
model.value = null
|
|
}
|
|
},
|
|
/**
|
|
* 清除激活的编辑
|
|
*/
|
|
_clearActived (evnt) {
|
|
const { tableColumn, editStore, editOpts } = this
|
|
const { actived } = editStore
|
|
const { args, row, column } = actived
|
|
if (row || column) {
|
|
if (editOpts.mode === 'row') {
|
|
tableColumn.forEach(column => this._setColumnModel(row, column))
|
|
} else {
|
|
this._setColumnModel(row, column)
|
|
}
|
|
this.updateFooter()
|
|
this.emitEvent('edit-closed', args, evnt)
|
|
}
|
|
actived.args = null
|
|
actived.row = null
|
|
actived.column = null
|
|
return (VXETable._valid ? this.clearValidate() : this.$nextTick()).then(this.recalculate)
|
|
},
|
|
// 在 v3.0 中废弃 getActiveRow
|
|
_getActiveRow () {
|
|
UtilTools.warn('vxe.error.delFunc', ['getActiveRow', 'getActiveRecord'])
|
|
return this.getActiveRecord()
|
|
},
|
|
_getActiveRecord () {
|
|
const { $el, editStore, afterFullData } = this
|
|
const { args, row } = editStore.actived
|
|
if (args && afterFullData.indexOf(row) > -1 && $el.querySelectorAll('.vxe-body--column.col--actived').length) {
|
|
return Object.assign({}, args)
|
|
}
|
|
return null
|
|
},
|
|
// 在 v3.0 中废弃 hasActiveRow
|
|
_hasActiveRow (row) {
|
|
UtilTools.warn('vxe.error.delFunc', ['hasActiveRow', 'isActiveByRow'])
|
|
return this.isActiveByRow(row)
|
|
},
|
|
/**
|
|
* 判断行是否为激活编辑状态
|
|
* @param {Row} row 行对象
|
|
*/
|
|
_isActiveByRow (row) {
|
|
return this.editStore.actived.row === row
|
|
},
|
|
/**
|
|
* 处理聚焦
|
|
*/
|
|
handleFocus (params) {
|
|
const { row, column, cell } = params
|
|
const { editRender } = column
|
|
if (editRender) {
|
|
const compRender = VXETable.renderer.get(editRender.name)
|
|
const { autofocus, autoselect } = editRender
|
|
let inputElem
|
|
// 如果指定了聚焦 class
|
|
if (autofocus) {
|
|
inputElem = cell.querySelector(autofocus)
|
|
}
|
|
// 渲染器的聚焦处理
|
|
if (!inputElem && compRender && compRender.autofocus) {
|
|
inputElem = cell.querySelector(compRender.autofocus)
|
|
}
|
|
if (inputElem) {
|
|
inputElem.focus()
|
|
if (autoselect) {
|
|
inputElem.select()
|
|
} else {
|
|
// 保持一致行为,光标移到末端
|
|
if (DomTools.browse.msie) {
|
|
const textRange = inputElem.createTextRange()
|
|
textRange.collapse(false)
|
|
textRange.select()
|
|
}
|
|
}
|
|
} else {
|
|
// 显示到可视区中
|
|
this.scrollToRow(row, column)
|
|
}
|
|
}
|
|
},
|
|
/**
|
|
* 激活行编辑
|
|
*/
|
|
_setActiveRow (row) {
|
|
return this.setActiveCell(row, XEUtils.find(this.visibleColumn, column => column.editRender).property)
|
|
},
|
|
/**
|
|
* 激活单元格编辑
|
|
*/
|
|
_setActiveCell (row, field) {
|
|
return this.scrollToRow(row, true).then(() => {
|
|
if (row && field) {
|
|
const column = XEUtils.find(this.visibleColumn, column => column.property === field)
|
|
if (column && column.editRender) {
|
|
const cell = DomTools.getCell(this, { row, column })
|
|
if (cell) {
|
|
this.handleActived({ row, rowIndex: this.getRowIndex(row), column, columnIndex: this.getColumnIndex(column), cell, $table: this })
|
|
this.lastCallTime = Date.now()
|
|
}
|
|
}
|
|
}
|
|
return this.$nextTick()
|
|
})
|
|
},
|
|
/**
|
|
* 只对 trigger=dblclick 有效,选中单元格
|
|
*/
|
|
_setSelectCell (row, field) {
|
|
const { tableData, editOpts, visibleColumn } = this
|
|
if (row && field && editOpts.trigger !== 'manual') {
|
|
const column = XEUtils.find(visibleColumn, column => column.property === field)
|
|
const rowIndex = tableData.indexOf(row)
|
|
if (rowIndex > -1 && column) {
|
|
const cell = DomTools.getCell(this, { row, rowIndex, column })
|
|
const params = { row, rowIndex, column, columnIndex: visibleColumn.indexOf(column), cell }
|
|
this.handleSelected(params, {})
|
|
}
|
|
}
|
|
return this.$nextTick()
|
|
},
|
|
/**
|
|
* 处理选中源
|
|
*/
|
|
handleSelected (params, evnt) {
|
|
const { mouseConfig, mouseOpts, editOpts, editStore, elemStore } = this
|
|
const { actived, selected } = editStore
|
|
const { row, column, cell } = params
|
|
const isMouseSelected = mouseConfig && mouseOpts.selected
|
|
// 在 v3.0 中废弃 mouse-config.checked
|
|
const isMouseChecked = mouseConfig && (mouseOpts.range || mouseOpts.checked)
|
|
const selectMethod = () => {
|
|
if ((isMouseSelected || isMouseChecked) && (selected.row !== row || selected.column !== column)) {
|
|
if (actived.row !== row || (editOpts.mode === 'cell' ? actived.column !== column : false)) {
|
|
if (this.keyboardConfig) {
|
|
this.clearChecked(evnt)
|
|
this.clearIndexChecked()
|
|
this.clearHeaderChecked()
|
|
this.clearSelected(evnt)
|
|
}
|
|
this.clearActived(evnt)
|
|
selected.args = params
|
|
selected.row = row
|
|
selected.column = column
|
|
if (isMouseSelected) {
|
|
this.addColSdCls()
|
|
}
|
|
// 如果配置了批量选中功能,则为批量选中状态
|
|
if (isMouseChecked) {
|
|
const headerElem = elemStore['main-header-list']
|
|
this.handleChecked([[cell]])
|
|
if (headerElem) {
|
|
this.handleHeaderChecked([[headerElem.querySelector(`.${column.id}`)]])
|
|
}
|
|
this.handleIndexChecked([[cell.parentNode.querySelector('.col--seq')]])
|
|
}
|
|
this.focus()
|
|
}
|
|
}
|
|
return this.$nextTick()
|
|
}
|
|
return selectMethod()
|
|
},
|
|
/**
|
|
* 清除所选中源状态
|
|
*/
|
|
_clearSelected () {
|
|
const { selected } = this.editStore
|
|
selected.row = null
|
|
selected.column = null
|
|
this.reColTitleSdCls()
|
|
this.reColSdCls()
|
|
return this.$nextTick()
|
|
},
|
|
reColTitleSdCls () {
|
|
const headerElem = this.elemStore['main-header-list']
|
|
if (headerElem) {
|
|
XEUtils.arrayEach(headerElem.querySelectorAll('.col--title-selected'), elem => DomTools.removeClass(elem, 'col--title-selected'))
|
|
}
|
|
},
|
|
reColSdCls () {
|
|
const cell = this.$el.querySelector('.col--selected')
|
|
if (cell) {
|
|
DomTools.removeClass(cell, 'col--selected')
|
|
}
|
|
},
|
|
addColSdCls () {
|
|
const { selected } = this.editStore
|
|
const { row, column } = selected
|
|
this.reColSdCls()
|
|
if (row && column) {
|
|
const cell = DomTools.getCell(this, { row, column })
|
|
if (cell) {
|
|
DomTools.addClass(cell, 'col--selected')
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|