mixin.ts 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087
  1. import XEUtils from 'xe-utils'
  2. import { VxeUI } from '../../../ui'
  3. import { isEnableConf } from '../../../ui/src/utils'
  4. import { getCellValue, setCellValue, getRowid } from '../../src/util'
  5. import { removeClass, addClass } from '../../../ui/src/dom'
  6. import { warnLog, errLog } from '../../../ui/src/log'
  7. import type { VxeTableConstructor, TableInternalData, VxeTableDefines, TableReactData, VxeTablePrivateMethods } from '../../../../types'
  8. const { getConfig, renderer, getI18n } = VxeUI
  9. const browseObj = XEUtils.browse()
  10. function getEditColumnModel (row: any, column: VxeTableDefines.ColumnInfo) {
  11. const { model, editRender } = column
  12. if (editRender) {
  13. model.value = getCellValue(row, column)
  14. model.update = false
  15. }
  16. }
  17. function setEditColumnModel (row: any, column: VxeTableDefines.ColumnInfo) {
  18. const { model, editRender } = column
  19. if (editRender && model.update) {
  20. setCellValue(row, column, model.value)
  21. model.update = false
  22. model.value = null
  23. }
  24. }
  25. function removeCellSelectedClass ($xeTable: VxeTableConstructor & VxeTablePrivateMethods) {
  26. const el = $xeTable.$refs.refElem as HTMLDivElement
  27. if (el) {
  28. const cell = el.querySelector('.col--selected')
  29. if (cell) {
  30. removeClass(cell, 'col--selected')
  31. }
  32. }
  33. }
  34. function syncActivedCell ($xeTable: VxeTableConstructor & VxeTablePrivateMethods) {
  35. const reactData = $xeTable as unknown as TableReactData
  36. const { editStore, tableColumn } = reactData
  37. const editOpts = $xeTable.computeEditOpts
  38. const { actived } = editStore
  39. const { row, column } = actived
  40. if (row || column) {
  41. if (editOpts.mode === 'row') {
  42. tableColumn.forEach((column) => setEditColumnModel(row, column))
  43. } else {
  44. setEditColumnModel(row, column)
  45. }
  46. }
  47. }
  48. function insertTreeRow ($xeTable: VxeTableConstructor & VxeTablePrivateMethods, newRecords: any[], isAppend: boolean) {
  49. const internalData = $xeTable as unknown as TableInternalData
  50. const { tableFullTreeData, afterFullData, fullDataRowIdData, fullAllDataRowIdData } = internalData
  51. const treeOpts = $xeTable.computeTreeOpts
  52. const { rowField, parentField, mapChildrenField } = treeOpts
  53. const childrenField = treeOpts.children || treeOpts.childrenField
  54. const funcName = isAppend ? 'push' : 'unshift'
  55. newRecords.forEach((item) => {
  56. const parentRowId = item[parentField]
  57. const rowid = getRowid($xeTable, item)
  58. const matchObj = parentRowId ? XEUtils.findTree(tableFullTreeData, (item) => parentRowId === item[rowField], { children: mapChildrenField }) : null
  59. if (matchObj) {
  60. const { item: parentRow } = matchObj
  61. const parentRest = fullAllDataRowIdData[getRowid($xeTable, parentRow)]
  62. const parentLevel = parentRest ? parentRest.level : 0
  63. let parentChilds = parentRow[childrenField]
  64. let mapChilds = parentRow[mapChildrenField]
  65. if (!XEUtils.isArray(parentChilds)) {
  66. parentChilds = parentRow[childrenField] = []
  67. }
  68. if (!XEUtils.isArray(mapChilds)) {
  69. mapChilds = parentRow[childrenField] = []
  70. }
  71. parentChilds[funcName](item)
  72. mapChilds[funcName](item)
  73. const rest = { row: item, rowid, seq: -1, index: -1, _index: -1, $index: -1, treeIndex: -1, _tIndex: -1, items: parentChilds, parent: parentRow, level: parentLevel + 1, height: 0, resizeHeight: 0, oTop: 0, expandHeight: 0 }
  74. fullDataRowIdData[rowid] = rest
  75. fullAllDataRowIdData[rowid] = rest
  76. } else {
  77. if (parentRowId) {
  78. warnLog('vxe.error.unableInsert')
  79. }
  80. afterFullData[funcName](item)
  81. tableFullTreeData[funcName](item)
  82. const rest = { row: item, rowid, seq: -1, index: -1, _index: -1, $index: -1, treeIndex: -1, _tIndex: -1, items: tableFullTreeData, parent: null, level: 0, height: 0, resizeHeight: 0, oTop: 0, expandHeight: 0 }
  83. fullDataRowIdData[rowid] = rest
  84. fullAllDataRowIdData[rowid] = rest
  85. }
  86. })
  87. }
  88. // function insertGroupRow ($xeTable: VxeTableConstructor & VxeTablePrivateMethods, newRecords: any[], isAppend: boolean) {
  89. // }
  90. function handleInsertRowAt ($xeTable: VxeTableConstructor & VxeTablePrivateMethods, records: any[], targetRow: any, isInsertNextRow?: any) {
  91. const props = $xeTable
  92. const reactData = $xeTable as unknown as TableReactData
  93. const internalData = $xeTable as unknown as TableInternalData
  94. const { treeConfig } = props
  95. const { isRowGroupStatus } = reactData
  96. const { tableFullTreeData, afterFullData, mergeBodyList, tableFullData, fullDataRowIdData, fullAllDataRowIdData, insertRowMaps, removeRowMaps } = internalData
  97. const treeOpts = $xeTable.computeTreeOpts
  98. const { transform, parentField, rowField, mapChildrenField } = treeOpts
  99. const childrenField = treeOpts.children || treeOpts.childrenField
  100. if (!XEUtils.isArray(records)) {
  101. records = [records]
  102. }
  103. const newRecords: any[] = $xeTable.defineField(records.map(record => Object.assign(treeConfig && transform ? { [mapChildrenField]: [], [childrenField]: [] } : {}, record)))
  104. let treeRecords: any[] = []
  105. if (treeConfig && transform) {
  106. treeRecords = XEUtils.toArrayTree(newRecords, { key: rowField, parentKey: parentField, children: childrenField })
  107. }
  108. if (XEUtils.eqNull(targetRow)) {
  109. // 如果为虚拟树
  110. if (treeConfig && transform) {
  111. insertTreeRow($xeTable, newRecords, false)
  112. } else if (isRowGroupStatus) {
  113. // 如果分组
  114. if (treeConfig) {
  115. throw new Error(getI18n('vxe.error.noTree', ['insert']))
  116. }
  117. warnLog(getI18n('vxe.error.noGroup', ['remove']))
  118. // insertGroupRow($xeTable, newRecords, false)
  119. } else {
  120. newRecords.forEach(item => {
  121. const rowid = getRowid($xeTable, item)
  122. const rest = { row: item, rowid, seq: -1, index: -1, _index: -1, $index: -1, treeIndex: -1, _tIndex: -1, items: afterFullData, parent: null, level: 0, height: 0, resizeHeight: 0, oTop: 0, expandHeight: 0 }
  123. fullDataRowIdData[rowid] = rest
  124. fullAllDataRowIdData[rowid] = rest
  125. afterFullData.unshift(item)
  126. tableFullData.unshift(item)
  127. })
  128. // 刷新单元格合并
  129. mergeBodyList.forEach((mergeItem: any) => {
  130. const { row: mergeRowIndex } = mergeItem
  131. if (mergeRowIndex >= 0) {
  132. mergeItem.row = mergeRowIndex + newRecords.length
  133. }
  134. })
  135. }
  136. } else {
  137. if (targetRow === -1) {
  138. // 如果为虚拟树
  139. if (treeConfig && transform) {
  140. insertTreeRow($xeTable, newRecords, true)
  141. } else if (isRowGroupStatus) {
  142. // 如果分组
  143. if (treeConfig) {
  144. throw new Error(getI18n('vxe.error.noTree', ['insert']))
  145. }
  146. warnLog(getI18n('vxe.error.noGroup', ['remove']))
  147. // insertGroupRow($xeTable, newRecords, true)
  148. } else {
  149. newRecords.forEach(item => {
  150. const rowid = getRowid($xeTable, item)
  151. const rest = { row: item, rowid, seq: -1, index: -1, _index: -1, $index: -1, treeIndex: -1, _tIndex: -1, items: afterFullData, parent: null, level: 0, height: 0, resizeHeight: 0, oTop: 0, expandHeight: 0 }
  152. fullDataRowIdData[rowid] = rest
  153. fullAllDataRowIdData[rowid] = rest
  154. afterFullData.push(item)
  155. tableFullData.push(item)
  156. })
  157. }
  158. } else {
  159. // 如果为虚拟树
  160. if (treeConfig && transform) {
  161. const matchMapObj = XEUtils.findTree(tableFullTreeData, item => targetRow[rowField] === item[rowField], { children: mapChildrenField })
  162. if (matchMapObj) {
  163. const { parent: parentRow } = matchMapObj
  164. const parentMapChilds = parentRow ? parentRow[mapChildrenField] : tableFullTreeData
  165. const parentRest = fullAllDataRowIdData[getRowid($xeTable, parentRow)]
  166. const parentLevel = parentRest ? parentRest.level : 0
  167. treeRecords.forEach((row, i) => {
  168. if (parentRow) {
  169. if (row[parentField] !== parentRow[rowField]) {
  170. row[parentField] = parentRow[rowField]
  171. errLog('vxe.error.errProp', [`${parentField}=${row[parentField]}`, `${parentField}=${parentRow[rowField]}`])
  172. }
  173. } else {
  174. if (row[parentField] !== null) {
  175. row[parentField] = null
  176. errLog('vxe.error.errProp', [`${parentField}=${row[parentField]}`, 'null'])
  177. }
  178. }
  179. let targetIndex = matchMapObj.index + i
  180. if (isInsertNextRow) {
  181. targetIndex = targetIndex + 1
  182. }
  183. parentMapChilds.splice(targetIndex, 0, row)
  184. })
  185. XEUtils.eachTree(treeRecords, (item) => {
  186. const rowid = getRowid($xeTable, item)
  187. const rest = { row: item, rowid, seq: -1, index: -1, _index: -1, $index: -1, treeIndex: -1, _tIndex: -1, items: parentMapChilds, parent: parentRow, level: parentLevel + 1, height: 0, resizeHeight: 0, oTop: 0, expandHeight: 0 }
  188. if (item[childrenField]) {
  189. item[mapChildrenField] = item[childrenField]
  190. }
  191. fullDataRowIdData[rowid] = rest
  192. fullAllDataRowIdData[rowid] = rest
  193. }, { children: childrenField })
  194. // 源
  195. if (parentRow) {
  196. const matchObj = XEUtils.findTree(tableFullTreeData, item => targetRow[rowField] === item[rowField], { children: childrenField })
  197. if (matchObj) {
  198. const parentChilds = matchObj.items
  199. let targetIndex = matchObj.index
  200. if (isInsertNextRow) {
  201. targetIndex = targetIndex + 1
  202. }
  203. parentChilds.splice(targetIndex, 0, ...treeRecords)
  204. }
  205. }
  206. } else {
  207. warnLog('vxe.error.unableInsert')
  208. insertTreeRow($xeTable, newRecords, true)
  209. }
  210. } else if (isRowGroupStatus) {
  211. // 如果分组
  212. if (treeConfig) {
  213. throw new Error(getI18n('vxe.error.noTree', ['insert']))
  214. }
  215. warnLog(getI18n('vxe.error.noGroup', ['remove']))
  216. } else {
  217. if (treeConfig) {
  218. throw new Error(getI18n('vxe.error.noTree', ['insert']))
  219. }
  220. let afIndex = -1
  221. // 如果是可视索引
  222. if (XEUtils.isNumber(targetRow)) {
  223. if (targetRow < afterFullData.length) {
  224. afIndex = targetRow
  225. }
  226. } else {
  227. afIndex = $xeTable.findRowIndexOf(afterFullData, targetRow)
  228. }
  229. // 如果是插入指定行的下一行
  230. if (isInsertNextRow) {
  231. afIndex = Math.min(afterFullData.length, afIndex + 1)
  232. }
  233. if (afIndex === -1) {
  234. throw new Error(getI18n('vxe.error.unableInsert'))
  235. }
  236. afterFullData.splice(afIndex, 0, ...newRecords)
  237. const tfIndex = $xeTable.findRowIndexOf(tableFullData, targetRow)
  238. if (tfIndex > -1) {
  239. tableFullData.splice(tfIndex + (isInsertNextRow ? 1 : 0), 0, ...newRecords)
  240. } else {
  241. tableFullData.push(...newRecords)
  242. }
  243. // 刷新单元格合并
  244. mergeBodyList.forEach((mergeItem: any) => {
  245. const { row: mergeRowIndex, rowspan: mergeRowspan } = mergeItem
  246. if (mergeRowIndex >= afIndex) {
  247. mergeItem.row = mergeRowIndex + newRecords.length
  248. } else if (isInsertNextRow ? (mergeRowIndex + mergeRowspan >= afIndex) : (mergeRowIndex + mergeRowspan > afIndex)) {
  249. mergeItem.rowspan = mergeRowspan + newRecords.length
  250. }
  251. })
  252. }
  253. }
  254. }
  255. const handleStatus = (newRow: any) => {
  256. const rowid = getRowid($xeTable, newRow)
  257. // 如果是被删除的数据,则还原状态
  258. if (removeRowMaps[rowid]) {
  259. delete removeRowMaps[rowid]
  260. if (insertRowMaps[rowid]) {
  261. delete insertRowMaps[rowid]
  262. }
  263. } else {
  264. insertRowMaps[rowid] = newRow
  265. }
  266. }
  267. // 如果为虚拟树
  268. if (treeConfig && transform) {
  269. XEUtils.eachTree(treeRecords, handleStatus, { children: mapChildrenField })
  270. } else {
  271. newRecords.forEach(handleStatus)
  272. }
  273. reactData.removeRowFlag++
  274. reactData.insertRowFlag++
  275. $xeTable.cacheRowMap(false)
  276. $xeTable.updateScrollYStatus()
  277. $xeTable.handleTableData(treeConfig && transform)
  278. if (!(treeConfig && transform)) {
  279. $xeTable.updateAfterDataIndex()
  280. }
  281. $xeTable.updateFooter()
  282. $xeTable.handleUpdateBodyMerge()
  283. $xeTable.checkSelectionStatus()
  284. if (reactData.scrollYLoad) {
  285. $xeTable.updateScrollYSpace()
  286. }
  287. return $xeTable.$nextTick().then(() => {
  288. $xeTable.updateCellAreas()
  289. return $xeTable.recalculate(true)
  290. }).then(() => {
  291. return {
  292. row: newRecords.length ? newRecords[newRecords.length - 1] : null,
  293. rows: newRecords
  294. }
  295. })
  296. }
  297. function handleInsertChildRowAt ($xeTable: VxeTableConstructor & VxeTablePrivateMethods, records: any, parentRow: any, targetRow: any, isInsertNextRow?: boolean) {
  298. const props = $xeTable
  299. const { treeConfig } = props
  300. const treeOpts = $xeTable.computeTreeOpts
  301. const { transform, rowField, parentField } = treeOpts
  302. if (treeConfig && transform) {
  303. if (!XEUtils.isArray(records)) {
  304. records = [records]
  305. }
  306. return handleInsertRowAt($xeTable, records.map((item: any) => Object.assign({}, item, { [parentField]: parentRow[rowField] })), targetRow, isInsertNextRow)
  307. } else {
  308. errLog('vxe.error.errProp', ['tree-config.transform=false', 'tree-config.transform=true'])
  309. }
  310. return Promise.resolve({ row: null, rows: [] })
  311. }
  312. function handleClearEdit ($xeTable: VxeTableConstructor & VxeTablePrivateMethods, evnt: Event | null, targetRow?: any) {
  313. const reactData = $xeTable as unknown as TableReactData
  314. const { editStore } = reactData
  315. const { actived, focused } = editStore
  316. const { row, column } = actived
  317. const validOpts = $xeTable.computeValidOpts
  318. if (row || column) {
  319. if (targetRow && getRowid($xeTable, targetRow) !== getRowid($xeTable, row)) {
  320. return $xeTable.$nextTick()
  321. }
  322. syncActivedCell($xeTable)
  323. actived.args = null
  324. actived.row = null
  325. actived.column = null
  326. $xeTable.updateFooter()
  327. $xeTable.dispatchEvent('edit-closed', {
  328. row,
  329. rowIndex: $xeTable.getRowIndex(row),
  330. $rowIndex: $xeTable.getVMRowIndex(row),
  331. column,
  332. columnIndex: $xeTable.getColumnIndex(column),
  333. $columnIndex: $xeTable.getVMColumnIndex(column)
  334. }, evnt || null)
  335. }
  336. focused.row = null
  337. focused.column = null
  338. if (validOpts.autoClear) {
  339. if (validOpts.msgMode !== 'full' || getConfig().cellVaildMode === 'obsolete') {
  340. if ($xeTable.clearValidate) {
  341. return $xeTable.clearValidate()
  342. }
  343. }
  344. }
  345. return $xeTable.$nextTick().then(() => $xeTable.updateCellAreas())
  346. }
  347. function handleEditActive ($xeTable: VxeTableConstructor & VxeTablePrivateMethods, params: any, evnt: Event | null, isFocus: boolean, isPos: boolean) {
  348. const props = $xeTable
  349. const reactData = $xeTable as unknown as TableReactData
  350. const $xeGrid = $xeTable.$xeGrid
  351. const { editConfig, mouseConfig } = props
  352. const { editStore, tableColumn } = reactData
  353. const editOpts = $xeTable.computeEditOpts
  354. const { mode } = editOpts
  355. const { actived, focused } = editStore
  356. const { row, column } = params
  357. const { editRender } = column
  358. const cell = (params.cell || $xeTable.getCellElement(row, column))
  359. const beforeEditMethod = editOpts.beforeEditMethod || editOpts.activeMethod
  360. params.cell = cell
  361. if (cell && isEnableConf(editConfig) && isEnableConf(editRender)) {
  362. // 激活编辑
  363. if (!$xeTable.isPendingByRow(row) && !$xeTable.isAggregateRecord(row)) {
  364. if (actived.row !== row || (mode === 'cell' ? actived.column !== column : false)) {
  365. // 判断是否禁用编辑
  366. let type: 'edit-disabled' | 'edit-activated' = 'edit-disabled'
  367. if (!beforeEditMethod || beforeEditMethod({ ...params, $table: $xeTable, $grid: $xeGrid })) {
  368. if (mouseConfig) {
  369. $xeTable.clearSelected()
  370. if ($xeTable.clearCellAreas) {
  371. $xeTable.clearCellAreas()
  372. $xeTable.clearCopyCellArea()
  373. }
  374. }
  375. $xeTable.closeTooltip()
  376. if (actived.column) {
  377. handleClearEdit($xeTable, evnt)
  378. }
  379. type = 'edit-activated'
  380. column.renderHeight = cell.offsetHeight
  381. actived.args = params
  382. actived.row = row
  383. actived.column = column
  384. if (mode === 'row') {
  385. tableColumn.forEach((column: any) => getEditColumnModel(row, column))
  386. } else {
  387. getEditColumnModel(row, column)
  388. }
  389. const afterEditMethod = editOpts.afterEditMethod
  390. $xeTable.$nextTick(() => {
  391. if (isFocus) {
  392. $xeTable.handleFocus(params, evnt)
  393. }
  394. if (afterEditMethod) {
  395. afterEditMethod({ ...params, $table: $xeTable, $grid: $xeGrid })
  396. }
  397. })
  398. }
  399. $xeTable.dispatchEvent(type, {
  400. row,
  401. rowIndex: $xeTable.getRowIndex(row),
  402. $rowIndex: $xeTable.getVMRowIndex(row),
  403. column,
  404. columnIndex: $xeTable.getColumnIndex(column),
  405. $columnIndex: $xeTable.getVMColumnIndex(column)
  406. }, evnt)
  407. // v4已废弃
  408. if (type === 'edit-activated') {
  409. $xeTable.dispatchEvent('edit-actived', {
  410. row,
  411. rowIndex: $xeTable.getRowIndex(row),
  412. $rowIndex: $xeTable.getVMRowIndex(row),
  413. column,
  414. columnIndex: $xeTable.getColumnIndex(column),
  415. $columnIndex: $xeTable.getVMColumnIndex(column)
  416. }, evnt)
  417. }
  418. } else {
  419. const { column: oldColumn } = actived
  420. if (mouseConfig) {
  421. $xeTable.clearSelected()
  422. if ($xeTable.clearCellAreas) {
  423. $xeTable.clearCellAreas()
  424. $xeTable.clearCopyCellArea()
  425. }
  426. }
  427. if (oldColumn !== column) {
  428. const { model: oldModel } = oldColumn
  429. if (oldModel.update) {
  430. setCellValue(row, oldColumn, oldModel.value)
  431. }
  432. if ($xeTable.clearValidate) {
  433. $xeTable.clearValidate(row, column)
  434. }
  435. }
  436. column.renderHeight = cell.offsetHeight
  437. actived.args = params
  438. actived.column = column
  439. if (isPos) {
  440. setTimeout(() => {
  441. $xeTable.handleFocus(params, evnt)
  442. })
  443. }
  444. }
  445. focused.column = null
  446. focused.row = null
  447. $xeTable.focus()
  448. }
  449. }
  450. return $xeTable.$nextTick()
  451. }
  452. function handleEditCell ($xeTable: VxeTableConstructor & VxeTablePrivateMethods, row: any, fieldOrColumn: string | VxeTableDefines.ColumnInfo, isPos: boolean) {
  453. const props = $xeTable
  454. const internalData = $xeTable as unknown as TableInternalData
  455. const { editConfig } = props
  456. const column = XEUtils.isString(fieldOrColumn) ? $xeTable.getColumnByField(fieldOrColumn) : fieldOrColumn
  457. if (row && column && isEnableConf(editConfig) && isEnableConf(column.editRender) && !$xeTable.isAggregateRecord(row)) {
  458. return Promise.resolve(isPos ? $xeTable.scrollToRow(row, column) : null).then(() => {
  459. const cell = $xeTable.getCellElement(row, column)
  460. if (cell) {
  461. handleEditActive($xeTable, {
  462. row,
  463. rowIndex: $xeTable.getRowIndex(row),
  464. column,
  465. columnIndex: $xeTable.getColumnIndex(column),
  466. cell,
  467. $table: $xeTable
  468. }, null, isPos, isPos)
  469. internalData._lastCallTime = Date.now()
  470. }
  471. return $xeTable.$nextTick()
  472. })
  473. }
  474. return $xeTable.$nextTick()
  475. }
  476. export default {
  477. methods: {
  478. /**
  479. * 往表格中插入临时数据
  480. *
  481. * @param {*} records
  482. */
  483. _insert (records: any) {
  484. return handleInsertRowAt(this, records, null)
  485. },
  486. /**
  487. * 往表格指定行中插入临时数据
  488. * 如果 row 为空则从插入到顶部
  489. * 如果 row 为 -1 则从插入到底部
  490. * 如果 row 为有效行则插入到该行的位置
  491. * @param {Object/Array} records 新的数据
  492. * @param {Row} targetRow 指定行
  493. * @returns
  494. */
  495. _insertAt (records: any, targetRow: any) {
  496. return handleInsertRowAt(this, records, targetRow)
  497. },
  498. _insertNextAt (records: any, targetRow: any) {
  499. return handleInsertRowAt(this, records, targetRow, true)
  500. },
  501. _insertChild (records: any, parentRow: any) {
  502. return handleInsertChildRowAt(this, records, parentRow, null)
  503. },
  504. _insertChildAt (records: any, parentRow: any, targetRow: any) {
  505. return handleInsertChildRowAt(this, records, parentRow, targetRow)
  506. },
  507. _insertChildNextAt (records: any, parentRow: any, targetRow: any) {
  508. return handleInsertChildRowAt(this, records, parentRow, targetRow, true)
  509. },
  510. /**
  511. * 删除指定行数据
  512. * 如果传 row 则删除一行
  513. * 如果传 rows 则删除多行
  514. * 如果为空则删除所有
  515. */
  516. _remove (rows: any[]) {
  517. const $xeTable = this as VxeTableConstructor & VxeTablePrivateMethods
  518. const props = $xeTable
  519. const reactData = $xeTable as unknown as TableReactData
  520. const internalData = $xeTable as unknown as TableInternalData
  521. const { treeConfig } = props
  522. const { editStore, isRowGroupStatus } = reactData
  523. const { tableFullTreeData, selectCheckboxMaps, afterFullData, mergeBodyList, tableFullData, pendingRowMaps, insertRowMaps, removeRowMaps } = internalData
  524. const checkboxOpts = $xeTable.computeCheckboxOpts
  525. const treeOpts = $xeTable.computeTreeOpts
  526. const { transform, mapChildrenField } = treeOpts
  527. const childrenField = treeOpts.children || treeOpts.childrenField
  528. const { actived } = editStore
  529. const { checkField } = checkboxOpts
  530. let delList: any[] = []
  531. if (!rows) {
  532. rows = tableFullData
  533. } else if (!XEUtils.isArray(rows)) {
  534. rows = [rows]
  535. }
  536. // 如果是新增,则保存记录
  537. rows.forEach(row => {
  538. if (!$xeTable.isInsertByRow(row)) {
  539. const rowid = getRowid($xeTable, row)
  540. removeRowMaps[rowid] = row
  541. }
  542. })
  543. // 如果绑定了多选属性,则更新状态
  544. if (!checkField) {
  545. rows.forEach((row) => {
  546. const rowid = getRowid(this, row)
  547. if (selectCheckboxMaps[rowid]) {
  548. delete selectCheckboxMaps[rowid]
  549. }
  550. })
  551. reactData.updateCheckboxFlag++
  552. }
  553. // 从数据源中移除
  554. if (tableFullData === rows) {
  555. rows = delList = tableFullData.slice(0)
  556. this.tableFullData = []
  557. this.afterFullData = []
  558. this.clearMergeCells()
  559. } else {
  560. // 如果为虚拟树
  561. if (treeConfig && transform) {
  562. rows.forEach((row) => {
  563. const rowid = getRowid(this, row)
  564. const matchMapObj = XEUtils.findTree(tableFullTreeData, item => rowid === getRowid(this, item), { children: mapChildrenField })
  565. if (matchMapObj) {
  566. const rItems = matchMapObj.items.splice(matchMapObj.index, 1)
  567. delList.push(rItems[0])
  568. }
  569. const matchObj = XEUtils.findTree(tableFullTreeData, item => rowid === getRowid(this, item), { children: childrenField })
  570. if (matchObj) {
  571. matchObj.items.splice(matchObj.index, 1)
  572. }
  573. const afIndex = this.findRowIndexOf(afterFullData, row)
  574. if (afIndex > -1) {
  575. afterFullData.splice(afIndex, 1)
  576. }
  577. })
  578. } else if (isRowGroupStatus) {
  579. // 如果分组
  580. warnLog(getI18n('vxe.error.noGroup', ['remove']))
  581. } else {
  582. rows.forEach((row: any) => {
  583. const tfIndex = this.findRowIndexOf(tableFullData, row)
  584. if (tfIndex > -1) {
  585. const rItems = tableFullData.splice(tfIndex, 1)
  586. delList.push(rItems[0])
  587. }
  588. const afIndex = this.findRowIndexOf(afterFullData, row)
  589. if (afIndex > -1) {
  590. // 刷新单元格合并
  591. mergeBodyList.forEach((mergeItem: any) => {
  592. const { row: mergeRowIndex, rowspan: mergeRowspan } = mergeItem
  593. if (mergeRowIndex > afIndex) {
  594. mergeItem.row = mergeRowIndex - 1
  595. } else if (mergeRowIndex + mergeRowspan > afIndex) {
  596. mergeItem.rowspan = mergeRowspan - 1
  597. }
  598. })
  599. afterFullData.splice(afIndex, 1)
  600. }
  601. })
  602. }
  603. }
  604. // 如果当前行被激活编辑,则清除激活状态
  605. if (actived.row && $xeTable.findRowIndexOf(rows, actived.row) > -1) {
  606. $xeTable.clearEdit()
  607. }
  608. // 从新增中移除已删除的数据
  609. rows.forEach((row: any) => {
  610. const rowid = getRowid($xeTable, row)
  611. if (insertRowMaps[rowid]) {
  612. delete insertRowMaps[rowid]
  613. }
  614. if (pendingRowMaps[rowid]) {
  615. delete pendingRowMaps[rowid]
  616. }
  617. })
  618. reactData.removeRowFlag++
  619. reactData.insertRowFlag++
  620. reactData.pendingRowFlag++
  621. $xeTable.cacheRowMap(false)
  622. $xeTable.handleTableData(treeConfig && transform)
  623. $xeTable.updateFooter()
  624. $xeTable.handleUpdateBodyMerge()
  625. if (!(treeConfig && transform)) {
  626. $xeTable.updateAfterDataIndex()
  627. }
  628. $xeTable.checkSelectionStatus()
  629. if (reactData.scrollYLoad) {
  630. $xeTable.updateScrollYSpace()
  631. }
  632. return this.$nextTick().then(() => {
  633. this.updateCellAreas()
  634. return this.recalculate(true)
  635. }).then(() => {
  636. return { row: delList.length ? delList[delList.length - 1] : null, rows: delList }
  637. })
  638. },
  639. /**
  640. * 删除复选框选中的数据
  641. */
  642. _removeCheckboxRow () {
  643. return this.remove(this.getCheckboxRecords()).then((params: any) => {
  644. this.clearCheckboxRow()
  645. return params
  646. })
  647. },
  648. /**
  649. * 删除单选框选中的数据
  650. */
  651. _removeRadioRow () {
  652. const radioRecord = this.getRadioRecord()
  653. return this.remove(radioRecord || []).then((params: any) => {
  654. this.clearRadioRow()
  655. return params
  656. })
  657. },
  658. /**
  659. * 删除当前行选中的数据
  660. */
  661. _removeCurrentRow () {
  662. const currentRecord = this.getCurrentRecord()
  663. return this.remove(currentRecord || []).then((params: any) => {
  664. this.clearCurrentRow()
  665. return params
  666. })
  667. },
  668. /**
  669. * 获取表格数据集,包含新增、删除、修改
  670. */
  671. _getRecordset () {
  672. const removeRecords = this.getRemoveRecords()
  673. const pendingRecords = this.getPendingRecords()
  674. const delRecords = removeRecords.concat(pendingRecords)
  675. // 如果已经被删除,则无需放到更新数组
  676. const updateRecords = this.getUpdateRecords().filter((row: any) => {
  677. return !delRecords.some((item: any) => this.eqRow(item, row))
  678. })
  679. return {
  680. insertRecords: this.getInsertRecords(),
  681. removeRecords,
  682. updateRecords,
  683. pendingRecords
  684. }
  685. },
  686. /**
  687. * 获取新增的临时数据
  688. */
  689. _getInsertRecords () {
  690. const $xeTable = this as VxeTableConstructor & VxeTablePrivateMethods
  691. const internalData = $xeTable as unknown as TableInternalData
  692. const { fullAllDataRowIdData, insertRowMaps } = internalData
  693. const insertRecords: any[] = []
  694. XEUtils.each(insertRowMaps, (row, rowid) => {
  695. if (fullAllDataRowIdData[rowid]) {
  696. insertRecords.push(row)
  697. }
  698. })
  699. return insertRecords
  700. },
  701. /**
  702. * 获取已删除的数据
  703. */
  704. _getRemoveRecords () {
  705. const $xeTable = this as VxeTableConstructor & VxeTablePrivateMethods
  706. const internalData = $xeTable as unknown as TableInternalData
  707. const { removeRowMaps } = internalData
  708. const removeRecords: any[] = []
  709. XEUtils.each(removeRowMaps, (row) => {
  710. removeRecords.push(row)
  711. })
  712. return removeRecords
  713. },
  714. /**
  715. * 获取更新数据
  716. * 只精准匹配 row 的更改
  717. * 如果是树表格,子节点更改状态不会影响父节点的更新状态
  718. */
  719. _getUpdateRecords () {
  720. const $xeTable = this as VxeTableConstructor & VxeTablePrivateMethods
  721. const props = $xeTable
  722. const internalData = $xeTable as unknown as TableInternalData
  723. const { keepSource, treeConfig } = props
  724. const { tableFullData } = internalData
  725. const treeOpts = $xeTable.computeTreeOpts
  726. if (keepSource) {
  727. syncActivedCell($xeTable)
  728. if (treeConfig) {
  729. return XEUtils.filterTree(tableFullData, row => $xeTable.isUpdateByRow(row), treeOpts)
  730. }
  731. return tableFullData.filter((row) => $xeTable.isUpdateByRow(row))
  732. }
  733. return []
  734. },
  735. /**
  736. * 处理激活编辑
  737. */
  738. handleEdit (params: any, evnt: any) {
  739. const $xeTable = this as VxeTableConstructor & VxeTablePrivateMethods
  740. return handleEditActive($xeTable, params, evnt, true, true)
  741. },
  742. /**
  743. * @deprecated
  744. */
  745. handleActived (params: any, evnt: any) {
  746. return this.handleEdit(params, evnt)
  747. },
  748. _getColumnModel (row: any, column: VxeTableDefines.ColumnInfo) {
  749. getEditColumnModel(row, column)
  750. },
  751. _setColumnModel (row: any, column: VxeTableDefines.ColumnInfo) {
  752. setEditColumnModel(row, column)
  753. },
  754. _syncActivedCell () {
  755. const $xeTable = this
  756. syncActivedCell($xeTable)
  757. },
  758. _clearActived (row: any) {
  759. warnLog('vxe.error.delFunc', ['clearActived', 'clearEdit'])
  760. // 即将废弃
  761. return this.clearEdit(row)
  762. },
  763. /**
  764. * 清除激活的编辑
  765. */
  766. _clearEdit (row: any) {
  767. const $xeTable = this as VxeTableConstructor & VxeTablePrivateMethods
  768. return handleClearEdit($xeTable, null, row)
  769. },
  770. /**
  771. * 取消编辑
  772. */
  773. handleClearEdit (evnt: Event | null, targetRow?: any) {
  774. const $xeTable = this
  775. return handleClearEdit($xeTable, evnt, targetRow)
  776. },
  777. _getActiveRecord () {
  778. const $xeTable = this as VxeTableConstructor & VxeTablePrivateMethods
  779. const reactData = $xeTable as unknown as TableReactData
  780. const internalData = $xeTable as unknown as TableInternalData
  781. warnLog('vxe.error.delFunc', ['getActiveRecord', 'getEditCell'])
  782. const { editStore } = reactData
  783. const { fullAllDataRowIdData } = internalData
  784. const { args, row } = editStore.actived
  785. if (args && row && fullAllDataRowIdData[getRowid($xeTable, row)]) {
  786. return Object.assign({}, args, { row })
  787. }
  788. return null
  789. },
  790. _getEditRecord () {
  791. const $xeTable = this as VxeTableConstructor & VxeTablePrivateMethods
  792. const reactData = $xeTable as unknown as TableReactData
  793. const internalData = $xeTable as unknown as TableInternalData
  794. warnLog('vxe.error.delFunc', ['getEditRecord', 'getEditCell'])
  795. const { editStore } = reactData
  796. const { fullAllDataRowIdData } = internalData
  797. const { args, row } = editStore.actived
  798. if (args && row && fullAllDataRowIdData[getRowid($xeTable, row)]) {
  799. return Object.assign({}, args, { row })
  800. }
  801. return null
  802. },
  803. _getEditCell () {
  804. const $xeTable = this as VxeTableConstructor & VxeTablePrivateMethods
  805. const reactData = $xeTable as unknown as TableReactData
  806. const { editStore } = reactData
  807. const { row, column } = editStore.actived
  808. if (column && row) {
  809. return {
  810. row,
  811. rowIndex: $xeTable.getRowIndex(row),
  812. column,
  813. columnIndex: $xeTable.getColumnIndex(column)
  814. }
  815. }
  816. return null
  817. },
  818. _isActiveByRow (row: any) {
  819. const $xeTable = this as VxeTableConstructor & VxeTablePrivateMethods
  820. warnLog('vxe.error.delFunc', ['isActiveByRow', 'isEditByRow'])
  821. // 即将废弃
  822. return $xeTable.isEditByRow(row)
  823. },
  824. /**
  825. * 判断行是否为激活编辑状态
  826. * @param {Row} row 行对象
  827. */
  828. _isEditByRow (row: any) {
  829. const $xeTable = this as VxeTableConstructor & VxeTablePrivateMethods
  830. const reactData = $xeTable as unknown as TableReactData
  831. const { editStore } = reactData
  832. return editStore.actived.row === row
  833. },
  834. /**
  835. * 处理聚焦
  836. */
  837. handleFocus (params: any) {
  838. const $xeTable = this as VxeTableConstructor & VxeTablePrivateMethods
  839. const { row, column, cell } = params
  840. const { editRender } = column
  841. const editOpts = $xeTable.computeEditOpts
  842. if (isEnableConf(editRender)) {
  843. const compRender = renderer.get(editRender.name)
  844. let autoFocus = editRender.autofocus || editRender.autoFocus
  845. let autoSelect = editRender.autoSelect || editRender.autoselect
  846. let inputElem
  847. // 是否启用聚焦
  848. if (editOpts.autoFocus) {
  849. if (!autoFocus && compRender) {
  850. autoFocus = compRender.tableAutoFocus || compRender.tableAutofocus || (compRender as any).autoFocus || compRender.autofocus
  851. }
  852. if (!autoSelect && compRender) {
  853. autoSelect = compRender.tableAutoSelect || (compRender as any).autoSelect || compRender.autoselect
  854. }
  855. // 如果指定了聚焦 class
  856. if (XEUtils.isFunction(autoFocus)) {
  857. inputElem = autoFocus.call($xeTable, params)
  858. } else if (autoFocus) {
  859. if (autoFocus === true) {
  860. // 自动匹配模式,会自动匹配第一个可输入元素
  861. inputElem = cell.querySelector('input,textarea')
  862. } else {
  863. inputElem = cell.querySelector(autoFocus)
  864. }
  865. if (inputElem) {
  866. inputElem.focus()
  867. }
  868. }
  869. }
  870. if (inputElem) {
  871. if (autoSelect) {
  872. inputElem.select()
  873. } else {
  874. // 保持一致行为,光标移到末端
  875. if (browseObj.msie) {
  876. const textRange = inputElem.createTextRange()
  877. textRange.collapse(false)
  878. textRange.select()
  879. }
  880. }
  881. } else {
  882. // 是否自动定位
  883. if (editOpts.autoPos) {
  884. if (!column.fixed) {
  885. // 显示到可视区中
  886. $xeTable.scrollToRow(row, column)
  887. }
  888. }
  889. }
  890. }
  891. },
  892. _setActiveRow (row: any) {
  893. const $xeTable = this as VxeTableConstructor & VxeTablePrivateMethods
  894. warnLog('vxe.error.delFunc', ['setActiveRow', 'setEditRow'])
  895. // 即将废弃
  896. return $xeTable.setEditRow(row)
  897. },
  898. /**
  899. * 激活行编辑
  900. */
  901. _setEditRow (row: any, fieldOrColumn: any) {
  902. const $xeTable = this as VxeTableConstructor & VxeTablePrivateMethods
  903. let column = XEUtils.find(this.visibleColumn, column => isEnableConf(column.editRender))
  904. let isPos = false
  905. if (fieldOrColumn) {
  906. isPos = true
  907. if (fieldOrColumn !== true) {
  908. column = XEUtils.isString(fieldOrColumn) ? $xeTable.getColumnByField(fieldOrColumn) : fieldOrColumn
  909. }
  910. }
  911. return handleEditCell($xeTable, row, column, isPos)
  912. },
  913. _setActiveCell (row: any, fieldOrColumn: any) {
  914. warnLog('vxe.error.delFunc', ['setActiveCell', 'setEditCell'])
  915. // 即将废弃
  916. return this.setEditCell(row, fieldOrColumn)
  917. },
  918. /**
  919. * 激活单元格编辑
  920. */
  921. _setEditCell (row: any, fieldOrColumn: any) {
  922. const $xeTable = this as VxeTableConstructor & VxeTablePrivateMethods
  923. return handleEditCell($xeTable, row, fieldOrColumn, true)
  924. },
  925. /**
  926. * 只对 trigger=dblclick 有效,选中单元格
  927. */
  928. _setSelectCell (row: any, fieldOrColumn: string | VxeTableDefines.ColumnInfo) {
  929. const $xeTable = this as VxeTableConstructor & VxeTablePrivateMethods
  930. const reactData = $xeTable as unknown as TableReactData
  931. const { tableData } = reactData
  932. const editOpts = $xeTable.computeEditOpts
  933. const column = XEUtils.isString(fieldOrColumn) ? $xeTable.getColumnByField(fieldOrColumn) : fieldOrColumn
  934. if (row && column && editOpts.trigger !== 'manual') {
  935. const rowIndex = $xeTable.findRowIndexOf(tableData, row)
  936. if (rowIndex > -1) {
  937. const cell = $xeTable.getCellElement(row, column)
  938. const params = {
  939. row,
  940. rowIndex,
  941. column,
  942. columnIndex: $xeTable.getColumnIndex(column),
  943. cell
  944. }
  945. $xeTable.handleSelected(params, {})
  946. }
  947. }
  948. return $xeTable.$nextTick()
  949. },
  950. /**
  951. * 处理选中源
  952. */
  953. handleSelected (params: any, evnt: any) {
  954. const $xeTable = this as VxeTableConstructor & VxeTablePrivateMethods
  955. const props = $xeTable
  956. const reactData = $xeTable as unknown as TableReactData
  957. const { mouseConfig } = props
  958. const { editStore } = reactData
  959. const mouseOpts = $xeTable.computeMouseOpts
  960. const editOpts = $xeTable.computeEditOpts
  961. const { actived, selected } = editStore
  962. const { row, column } = params
  963. const isMouseSelected = mouseConfig && mouseOpts.selected
  964. const selectMethod = () => {
  965. if (isMouseSelected && (selected.row !== row || selected.column !== column)) {
  966. if (actived.row !== row || (editOpts.mode === 'cell' ? actived.column !== column : false)) {
  967. handleClearEdit($xeTable, evnt)
  968. $xeTable.clearSelected()
  969. if ($xeTable.clearCellAreas) {
  970. $xeTable.clearCellAreas()
  971. $xeTable.clearCopyCellArea()
  972. }
  973. selected.args = params
  974. selected.row = row
  975. selected.column = column
  976. if (isMouseSelected) {
  977. this.addCellSelectedClass()
  978. }
  979. $xeTable.focus()
  980. if (evnt) {
  981. $xeTable.dispatchEvent('cell-selected', params, evnt)
  982. }
  983. }
  984. }
  985. return $xeTable.$nextTick()
  986. }
  987. return selectMethod()
  988. },
  989. /**
  990. * 获取选中的单元格
  991. */
  992. _getSelectedCell () {
  993. const $xeTable = this as VxeTableConstructor & VxeTablePrivateMethods
  994. const reactData = $xeTable as unknown as TableReactData
  995. const { editStore } = reactData
  996. const { row, column } = editStore.selected
  997. if (row && column) {
  998. return {
  999. row,
  1000. column
  1001. }
  1002. }
  1003. return null
  1004. },
  1005. /**
  1006. * 清除所选中源状态
  1007. */
  1008. _clearSelected () {
  1009. const $xeTable = this as VxeTableConstructor & VxeTablePrivateMethods
  1010. const reactData = $xeTable as unknown as TableReactData
  1011. const { editStore } = reactData
  1012. const { selected } = editStore
  1013. selected.row = null
  1014. selected.column = null
  1015. removeCellSelectedClass($xeTable)
  1016. return $xeTable.$nextTick()
  1017. },
  1018. reColTitleSdCls () {
  1019. const headerElem = this.elemStore['main-header-list']
  1020. if (headerElem) {
  1021. XEUtils.arrayEach(headerElem.querySelectorAll('.col--title-selected'), elem => removeClass(elem, 'col--title-selected'))
  1022. }
  1023. },
  1024. addCellSelectedClass () {
  1025. const $xeTable = this as VxeTableConstructor & VxeTablePrivateMethods
  1026. const reactData = $xeTable as unknown as TableReactData
  1027. const { editStore } = reactData
  1028. const { selected } = editStore
  1029. const { row, column } = selected
  1030. removeCellSelectedClass($xeTable)
  1031. if (row && column) {
  1032. const cell = $xeTable.getCellElement(row, column)
  1033. if (cell) {
  1034. addClass(cell, 'col--selected')
  1035. }
  1036. }
  1037. }
  1038. } as any
  1039. } as any