mixin.js 43 KB

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