import * as YvanUI from './YvanUIExtend' import CtlGridLocale from './CtlGridLocale' import { CtlGridPage } from './CtlGridPage' import agGrid from 'ag-grid' import CtlGridIdRender from './CtlGridIdRender' import { YvGridColumnEditProp, YvGridColumnProp, YvGridProp } from './CtlGridDefault' import CtlGridCellCheckbox from './CtlGridCellCheckbox' import CtlGridHeadCheckbox from './CtlGridHeadCheckbox' import { CtlBase } from './CtlBase' import { parseYvanPropChangeVJson } from './CtlUtils' import { GridDataSource } from './YvanDataSourceGrid' import { YvEvent, YvEventDispatch, YvEventDispatchArgs } from './YvanEvent' import { YvanDataSourceGrid } from './YvanDataSourceGridImp' import { CtlGridDefault } from './CtlDefaultValue' import CtlGridCellButton from './CtlGridCellButton' import CtlGridFilterSet from './CtlGridFilterSet' import CtlGridEditorText from './CtlGridEditorText' import CtlGridEditorNumber from './CtlGridEditorNumber' import CtlGridEditorCombo from './CtlGridEditorCombo' import CtlGridEditorDate from './CtlGridEditorDate' import CtlGridEditorSearch from './CtlGridEditorSearch' import CtlGridCellImage from './CtlGridCellImage' import { YvDataSource } from './YvanDataSourceImp' import webix from 'webix' /** 在CtlGridPage.ts 里面有关于点击分页按钮时候设置 GridRefreshMode **/ export enum GridRefreshMode { refreshRows, refreshWithFilter, refreshAndClearFilter } /** * 表格中的行按钮被点击后触发的事件参数 */ export interface CtlGridRowButtonClickArgs { /** * 行数据 */ data: any /** * 行序号 */ rowIndex: number /** * 列名称 */ colId: string } /** * 扩展 grid 组件 */ webix.protoUI( { name: 'grid', $init: function (config: any) { this._domid = webix.uid(); this.$view.innerHTML = `
` _.extend(this.config, config) if (config.on && typeof config.on.onMyRender === 'function') { config.on.onMyRender.call(this) } if (!config.css) { config.css = 'webix_yv_grid'; } else { config.css = config.css + ' webix_yv_grid'; } if (typeof config.height === 'number') { this._viewobj.style.height = config.height } this._viewobj.style.minHeight='133px' } }, webix.ui.view ) export class CtlGrid extends CtlBase { static create(module: any, vjson: any): CtlGrid { const that = new CtlGrid(_.cloneDeep(vjson)) that._module = module _.defaultsDeep(vjson, CtlGridDefault) if (vjson.hasOwnProperty('debugger')) { debugger } // 提取基础属性 onRender / ctlName / entityName 等等 const yvanProp = parseYvanPropChangeVJson(vjson, [ 'height', 'rowHeight', 'headerHeight' ]) // 将 yvanProp 合并至当前 CtlBase 对象 _.assign(that, yvanProp) // 删除 vjson 所有数据, 替换为 template 语法 _.forOwn(vjson, (value, key) => { delete vjson[key] }) _.merge(vjson, { view: 'grid', // template: `
`, height: yvanProp.height, on: { onMyRender: function (this: any) { _.defer(() => { that.attachHandle(this, { ...vjson, ...yvanProp }) that._resetGrid() }); }, onDestruct(this: any) { if (that.gridApi) { that.gridApi.destroy() that.gridApi = undefined } that.removeHandle() } } }) if (that.vjson.id) { vjson.id = that.vjson.id } return that } /*============================ 公共属性部分 ============================*/ allCheckedData: any[] = [] gridApi: any columnApi: any refreshMode: GridRefreshMode = GridRefreshMode.refreshRows; get webix() { return this._webix } /** * 设置数据源 */ set dataSource(nv: GridDataSource) { this.vjson.dataSource = nv // if (this._module.loadFinished) { // throw new Error('Grid 不允许动态设置数据源') // } } /** * 获取数据源 */ get dataSource(): GridDataSource { return this.vjson.dataSource } /** * 表格内换行 */ readonly wrapText: boolean = false /** * 行高 */ readonly rowHeight: number = 33 /** * 头高 */ readonly headerHeight: number = 35 /** * 是否为客户端过滤 */ readonly clientFilter: boolean = false /** * 是否为客户端排序 */ readonly clientSort: boolean = false /** * 初始化时的数据 */ readonly data?: any[] /** * 是否允许编辑 */ readonly editable!: boolean /** * 允许勾选 */ readonly checkbox!: boolean /** * 允许跨页勾选 */ readonly useCrossPageCheck!: boolean /** * 单击后立刻进入编辑 */ readonly editSingleClick!: boolean /** * 允许添加 */ readonly allowNewRow!: boolean /** * 允许过滤 */ readonly filterable!: boolean /** * 显示序号 */ readonly showRowNumber!: boolean /** * 自动调整列宽 */ readonly autoSizeColumns!: boolean /** * 单元格选中模式 */ readonly allowCellSelection!: boolean /** * 行选中模式 */ readonly allowRowSelection!: boolean /** * ID字段 */ readonly idField!: string /** * 值分隔符 */ readonly valueSep!: string /** * 保存时机(换行时/编辑完后) */ readonly saveOn!: 'editFinish' | 'rowChanged' /** * 新添加行时,初始化的数据 */ readonly newRowData!: any /** * 失去焦点后立刻结束编辑 */ readonly stopEditingWhenGridLosesFocus!: boolean /** * 是否默认选中行 */ readonly defaultUnselecteRow: boolean = false /** * 列定义 */ readonly columns!: any[] | undefined /** * 二纬表头 */ readonly columnGroup!: any[] | undefined /** * 是否自动读取数据 */ readonly autoLoad: boolean = true /** * 是否分页 */ readonly pagination: boolean = false /** * 分页大小 */ readonly pageSize: number = 100 public gridPage!: CtlGridPage /** * 行被选中后触发 */ onRowSelect?: YvEvent /** * 行被选中后触发 */ onRowCheck?: YvEvent /** * 行被双击后触发 */ onRowDblClick?: YvEvent /** * 勾选项改变后触发 */ onCheckedChange?: YvEvent /** * 数据绑定完毕后触发 */ onBindingComplete?: YvEvent /** * 焦点单元格发生变化后触发 */ onCellFocused?: YvEvent /** * 单元格被点击后触发 */ onCellClicked?: YvEvent /** * 行样式计算 */ onRowStyle?: YvEvent /** * 第一行有效数据被渲染后触发 */ onFirstDataRendered?: YvEvent /** * 按下键后触发 */ onKeyDown?: YvEvent /** * 行被删除的回调事件 * @param condition */ onRowDelete?: YvEvent /** * 获取被勾选的行ID集合 */ // checkedIds: any[] = [] /** * 选择一个指定行 * @param condition 可以是 key(主键), 也可以是 function 条件, 匹配到符合 condition 的第一条记录 */ selectRow(condition: GridSelectCondition) { const node: any = this._findNode(condition) if (node) { this.gridApi.setFocusedCell(node.rowIndex, '__ID__') node.setSelected(true) return true } return false } /** * 选择一个指定行 * @param condition 可以是 key(主键), 也可以是 function 条件, 匹配到符合 condition 的第一条记录 */ singleSelectRow(condition: GridSelectCondition) { const node: any = this._findNode(condition) if (node) { node.setSelected(true) return true } return false } /** * 选择一个指定行 * @param condition */ selectRowWithCell(condition: GridSelectCondition, cellField: string) { const node: any = this._findNode(condition) if (node) { this.gridApi.setFocusedCell(node.rowIndex, cellField) node.setSelected(true) return true } return false } /** * 闪烁指定行 * @param condition 可以是 key(主键), 也可以是 function 条件, 匹配到符合 condition 的第一条记录 */ flashRow(condition: any) { const node = this._findNode(condition) if (node) { this.gridApi.flashCells({ rowNodes: [node] }) return true } return false } /** * 闪烁指定单元格 * @param cols 列数组 * @param condition 可以是 key(主键), 也可以是 function 条件, 匹配到符合 condition 的第一条记录 */ flashCell(cols: any, condition: any) { const node = this._findNode(condition) if (node) { this.gridApi.flashCells({ columns: cols, rowNodes: [node] }) return true } return false } _validateRowChecked(data: any[]) { _.forEach(data, item => { _.forEach(this.allCheckedData, ii => { if (this._getIdByRow(item) === this._getIdByRow(ii)) { item.__grid_row_checked = true } }) }) } /** * 无感知刷新 */ _transactionUpdate(targetDataList: any[]) { if (this.useCrossPageCheck) { this._validateRowChecked(targetDataList); } if (this.editable) { const newRow = _.assign({ __grid_row_new: true }, this.vjson.defautProperties) targetDataList.push(newRow) const maxLength: any = _.max([this.pageSize, targetDataList.length]) this.paginationSetPageSize(maxLength + 1) } this._gridData = targetDataList; if (this.refreshMode === GridRefreshMode.refreshWithFilter || this.refreshMode === GridRefreshMode.refreshAndClearFilter) { /** 更改当前的刷新模式, 避免重复刷新 **/ this.refreshMode = GridRefreshMode.refreshRows this.setData(targetDataList); if (this.dataSourceBind) { this.gridApi.setFilterModel(this.dataSourceBind.lastFilterModel) } } else { this._transactionUpdateRow(targetDataList) } } /** * * @param targetDataList * @param deleteIndex */ _deleteToUpdate(targetDataList: any[], deleteIndex: number) { this._gridData.splice(deleteIndex, 1) if (this.useCrossPageCheck) { this._validateRowChecked(targetDataList) } if (targetDataList.length <= 0) { const newRow = _.assign({ __grid_row_new: true }, this.vjson.defautProperties) targetDataList.push(newRow) const maxLength: any = _.max([this.pageSize, targetDataList.length]) this.paginationSetPageSize(maxLength + 1) } this._gridData = targetDataList; if (this.refreshMode === GridRefreshMode.refreshWithFilter || this.refreshMode === GridRefreshMode.refreshAndClearFilter) { /** 更改当前的刷新模式, 避免重复刷新 **/ this.refreshMode = GridRefreshMode.refreshRows this.setData(targetDataList); if (this.dataSourceBind) { this.gridApi.setFilterModel(this.dataSourceBind.lastFilterModel) } } else { this._transactionUpdateRow(targetDataList) } if (deleteIndex < this._gridData.length) { this.selectRow(node => node.rowIndex === deleteIndex); } else { this.selectRow(node => node.rowIndex === this._gridData.length - 1) } } public updateRowData(rowData: any[]) { const transaction = { update: rowData } this.gridApi.updateRowData(transaction); } /** * 刷新行数据 */ _transactionUpdateRow(targetDataList: any[]) { /** 更改当前的刷新模式, 避免重复刷新 **/ this.refreshMode = GridRefreshMode.refreshRows const transaction: any = { add: [], remove: [], update: [] } let i = 0 this.gridApi.forEachNode((node: any) => { if (i === targetDataList.length) { //已经越位 transaction.remove.push(node.data) } else { const newData = targetDataList[i++] node.setData(newData) transaction.update.push(node.data) } }) for (; i < targetDataList.length; i++) { transaction.add.push(targetDataList[i]) } this.gridApi.updateRowData(transaction) } public addNewEditRow() { const newRow = _.assign({ __grid_row_new: true }, this.vjson.defautProperties); const transaction: any = { add: [newRow], addIndex: this.gridApi.getDisplayedRowCount(), } this.gridApi.updateRowData(transaction); } /** * 获取全部数据 */ getData(): any[] | undefined { const result: any[] = [] this.gridApi.forEachNode((node: any) => { result.push(node.data) }) return result } /** * 为表格设置数据 * 注意,调用此方法,必须在初始化时,给一个空的 data: [] 属性 * 确保表格 rowModelType:clientSide 模式 */ setData(nv: any[] | undefined) { this.gridApi.setRowData(nv) } /** * 无感刷新 * 清空缓存,从后台重新拉取数据,表格上临时修改的内容都会被清空 * * option: * clearFilter=true 是否清空筛选 */ // reload(option?: any) { // this.loading = true // // //无感刷新之前,清空所有状态 // this._clearCache() // // //需要重新请求 rowCount(总数据行) // if (this.dataSourceBind) { // this.dataSourceBind.clearRowCount() // } // // if (this.entityName) { // _.set(this.getModule(), this.entityName + '.selectedRow', undefined) // } // // /** 有clearFilter 参数的时候 一定刷新数据 **/ // if (option && option.clearFilter === true) { // this.pageAbleDataRefreshMode = "refreshAndReset" // this.gridApi.setFilterModel(null) // if (this.dataSourceBind) { // /** 表头筛选数据没有变化也要重新加载数据 **/ // if (_.isEqual(this.gridApi.getFilterModel(), this.dataSourceBind.lastFilterModel)) { // this._filterChanged(); // } // } // } else { // if (this.pagination) { // this.pageAbleDataRefreshMode = "refreshWithFilter" // this.gridPage.refreshGrid() // } else { // this.pageAbleDataRefreshMode = "refreshRows" // this.gridApi.refreshInfiniteCache() // } // } // } /** * 隐藏某列 */ hideColumnsWithColIds(...cols: any[]) { this.columnApi.setColumnsVisible(cols, false) } /** * 显示某列 */ showColumnsWithColIds(...cols: any[]) { this.columnApi.setColumnsVisible(cols, true) } /** * 无感刷新 * 清空缓存,从后台重新拉取数据,表格上临时修改的内容都会被清空 * * option: * clearFilter=true 是否清空筛选 */ reload(refreshMode: GridRefreshMode = GridRefreshMode.refreshWithFilter) { this.loading = true this.refreshMode = refreshMode //无感刷新之前,清空所有状态 this._clearCache() //需要重新请求 rowCount(总数据行) if (this.dataSourceBind) { this.dataSourceBind.clearRowCount() } if (this.entityName) { _.set(this.getModule(), this.entityName + '.selectedRow', undefined) } /** 有clearFilter 参数的时候 一定刷新数据 **/ if (refreshMode === GridRefreshMode.refreshAndClearFilter) { this.gridApi.setFilterModel(null) if (this.dataSourceBind) { /** 表头筛选数据没有变化也要重新加载数据 **/ // if (_.isEqual(this.gridApi.getFilterModel(), this.dataSourceBind.lastFilterModel)) { this._filterChanged(); // } } } else { if (this.pagination) { this.gridPage.refreshGrid() } else { this.gridApi.refreshInfiniteCache() } } } /** * 获取被选中的行主键 */ getSelectedId() { const row = this.getSelectedRow() if (row) { return this._getIdByRow(row) } } /** * 设置勾选的数据行集合 */ setCheckedIds(ids: Array) { // 清空所有元素 // this.checkedIds = ids; if (this.useCrossPageCheck) { this.allCheckedData = [] } this.gridApi.forEachNode((node: any) => { if (_.indexOf(ids, this._getIdByRow(node.data)) >= 0) { node.data.__grid_row_checked = true if (this.useCrossPageCheck) { this.allCheckedData.push(node.data); } } else { node.data.__grid_row_checked = false } }) // 刷新勾选单元格 this.gridApi.refreshCells({ columns: ['__CB__'], force: true }) } get checkedIds() { const ids: any[] = []; this.gridApi.forEachNode((node: any) => { if (node.data.__grid_row_checked) { ids.push(this._getIdByRow(node.data)) } }) return ids } /** * 获取被勾选的行 */ getCheckedRows() { const selected: any[] = [] this.gridApi.forEachNode((node: any) => { if (node.data.__grid_row_checked) { selected.push(node.data); } }) return selected } /** * 获取被勾选的所有行 */ getAllCheckedRows() { if (this.useCrossPageCheck) { return this.allCheckedData } else { return this.getCheckedRows() } } /** * 获取被选中的行数据 */ getSelectedRow() { const rows = this.getSelectedRows() return rows.length > 0 ? rows[0] : undefined } /** * 获取被选中的行数据(多选情况下回返回多行数据) */ getSelectedRows() { // 调用原生 getSelectedRows 方法有 bug // return this.gridApi.getSelectedRows(); const selected: any[] = [] this._findNode((node: any) => { if (node.selected) { selected.push(node.data) } return false }) return selected } /** * 获取被选中的行 */ getSelectedNode() { const nodes = this.getSelectedNodes() return nodes.length > 0 ? nodes[0] : undefined } /** * 获取被选中的行(多选情况下回返回多行) */ getSelectedNodes() { // 调用原生 getSelectedRows 方法有 bug // return this.gridApi.getSelectedRows(); const selected: any[] = [] this._findNode((node: any) => { if (node.selected) { selected.push(node) } return false }) return selected } validate(): Promise { const that = this return new Promise((resolver, reject) => { const result: any[] = [] const gridData = that.getGridExactlyData() _.forEach(that.columns, column => { if (column.editParams?.required === true) { _.forEach(gridData, (item, index) => { const val = _.get(item, column.field) if (!val && val != 0) { result.push({ rowIndex: index, colKey: column.field, msg: column.title + '为必填项' }) } }) } if (column.editParams?.onValidate) { _.forEach(gridData, (item, index) => { const val = _.get(item, column.field) const res = YvEventDispatch(column.editParams?.onValidate, that, val) if (res) { result.push({ rowIndex: index, colKey: column.field, msg: res }) } }) } }) if (_.size(result) > 0) { that.gridApi.stopEditing() for (let ii = result.length - 1; ii >= 0; ii--) { const element = result[ii]; that.gridApi.startEditingCell({ rowIndex: element.rowIndex, colKey: element.colKey }) } reject(result) } else { resolver(that.getGridExactlyData()); } }) } getGridData() { return this._gridData } getGridCreateData() { const dataE = this.getData() const data = _.filter(dataE, item => { return item.__grid_row_new == true && Object.keys(item).length > 1 }) return data } /** * 所有数据不包括空行 */ getGridExactlyData() { const data = this.getData() const rData: any[] = [] _.forEach(data, item => { _.forOwn(item, (value, key) => { if (key != '__ID__' && key != '__CB__' && key != '__grid_row_checked' && key != '__grid_row_new' && value != null && value != '') { rData.push(item) return false } }) }) return rData } getAllEditRows() { const dataE = this.getData() const data = _.filter(dataE, item => { return (item.__grid_row_new == true && Object.keys(item).length > 1)|| item.__ID__ }) return data } /** * 所有新增数据不包括空行 */ getGridCreateExactlyData() { const data = this.getGridCreateData() const rData: any[] = [] _.forEach(data, item => { _.forOwn(item, (value, key) => { if (key != '__ID__' && key != '__CB__' && key != '__grid_row_checked' && key != '__grid_row_new' && value != null && value != '') { rData.push(item) return false } }) }) return rData } /** * 判断数据是否为空 * @param data */ isDataVoid(data: any) { let isVoid = true _.forOwn(data, (value, key) => { if (key != '__ID__' && key != '__CB__' && key != '__grid_row_checked' && key != '__grid_row_new' && value != null && value != '') { isVoid = false return false } }) return isVoid } get hasCreateData() { const data: any = this.getGridCreateData() let isCreate = false if (!data || data.length <= 0) { return isCreate } data.forEach((element: any) => { _.forOwn(element, (value, key) => { if (key != '__ID__' && key != '__CB__' && key != '__grid_row_checked' && key != '__grid_row_new' && value != null && value != '') { isCreate = true return false } }) }); return isCreate } get hasData() { const data = this.getGridData() let isHas = false data.forEach(element => { _.forOwn(element, (value, key) => { if (key != '__ID__' && key != '__CB__' && key != '__grid_row_checked' && key != '__grid_row_new' && value != null && value != '') { isHas = true return false } }) }); return isHas } get gridEditCells() { if (!this._gridEditCells) { const vv: any[] = [] _.forEach(this.vjson.columns, item => { if (item.editable) { vv.push(item.field) } }) this._gridEditCells = vv } return this._gridEditCells } /** * 显示正在读取的状态 */ set loading(newValue: boolean) { if (!this.isGridReadReady) { return } if (newValue) { // 盖着 this.gridApi.showLoadingOverlay() $($(this._webix.$view).find('.ag-paging-panel')[0]).append(`
`); } else { // 放开 $(this._webix.$view).find('.maskBox').remove() this.gridApi.hideOverlay() } } paginationSetPageSize(size: number) { this.gridApi.paginationSetPageSize(size) } /** 设置行号, 兼容分页 **/ private setRowId(p: any) { return CtlGridIdRender(p, this) } /*============================ 私有属性部分 ============================*/ private isGridReadReady: boolean = false private dataSourceBind?: YvanDataSourceGrid = undefined private _gridData: any[] = [] private _gridEditCells: any private _gridOptions(): any { _.assign(this, { pagination: true, ..._.clone(YvGridProp), ...this.vjson, }) const resultCols: any[] = [] //显示序号列 if (this.showRowNumber) { resultCols.push({ field: '__ID__', headerName: CtlGridLocale.rownumber, width: 52, //minWidth: 52, maxWidth: 160, pinned: 'left', resizable: true, sortable: false, cellRenderer: 'CtlGridIdRender' }) } //显示勾选框 if (this.checkbox) { resultCols.push({ field: '__CB__', headerName: '', width: 40, minWidth: 40, maxWidth: 40, pinned: 'left', resizable: false, sortable: false, cellRenderer: 'CtlGridCellCheckbox', headerComponent: 'CtlGridHeadCheckbox', cellRendererParams: { isCheckedIds: true, checkboxDisabled: this.vjson.checkboxDisabled } }) } //添加自定义列 this._gridCols(resultCols) let columnDefs = resultCols if (!this.columnGroup || _.size(this.columnGroup) <= 0) { //没有多级表头 columnDefs = resultCols } else { //二级表头 columnDefs = [] let j = 0 let currentGroup: any let currentGroupSpan = -1 for (let i = 0; i < resultCols.length; i++) { const f = resultCols[i] if (!this.columnGroup[j]) { columnDefs.push(f) continue } const { from, title, span, width } = this.columnGroup[j] if (currentGroupSpan > 0) { currentGroup.children.push(f) currentGroupSpan-- if (currentGroupSpan <= 0) { j++ } } else if (f.field === from) { currentGroup = { width: width, headerName: title, children: [f] } currentGroupSpan = span - 1 columnDefs.push(currentGroup) } else { columnDefs.push(f) } } } _.forEach(columnDefs, item => { _.assign(item, { suppressKeyboardEvent: this.suppressDelete.bind(this) }) }) const gridOptions = { headerHeight: this.headerHeight, rowHeight: this.rowHeight, suppressRowHoverHighlight: true, columnDefs, animateRows: false, suppressCellSelection: !this.allowCellSelection, suppressRowClickSelection: !this.allowRowSelection, suppressColumnMoveAnimation: true, pagination: this.pagination, paginationPageSize: this.pageSize, localeText: CtlGridLocale, rowModelType: 'infinite', infiniteInitialRowCount: 200, //maxConcurrentDatasourceRequests: 2, maxBlocksInCache: 5, //cacheOverflowSize rowSelection: 'single', enableBrowserTooltips: true, //enableCellChangeFlash: true, singleClickEdit: this.editSingleClick, floatingFilter: false, stopEditingWhenGridLosesFocus: this.stopEditingWhenGridLosesFocus, getRowStyle: this._getRowStyle.bind(this), onFirstDataRendered: this._firstDataRendered.bind(this), onGridReady: this._gridReady.bind(this), // tabToNextCell: this._tabToNextCell.bind(this), // navigateToNextCell: this._navigateToNextCell.bind(this), onCellKeyDown: this._cellKeyDown.bind(this), onRowDoubleClicked: this._rowDoubleClicked.bind(this), onCellEditingStarted: this._cellEditingStarted.bind(this), onCellEditingStopped: this._cellEditingStopped.bind(this), onRowSelected: this._rowSelected.bind(this), onModelUpdated: this._modelUpdated.bind(this), onCellFocused: this._cellFocused.bind(this), onCellClicked: this._cellClicked.bind(this), onFilterChanged: this._filterChanged.bind(this), onSortChanged: this._sortChanged.bind(this), enterMovesDown: false, enterMovesDownAfterEdit: false, accentedSort: true, defaultColDef: { // flex: 1, wrapText: this.wrapText, autoHeight: true, // sortable: true, resizable: true, }, onColumnResized: (params: any) => { params.api.resetRowHeights() }, onColumnVisible: (params: any) => { params.api.resetRowHeights() }, components: { CtlGridCellButton: CtlGridCellButton, CtlGridCellCheckbox: CtlGridCellCheckbox, CtlGridHeadCheckbox: CtlGridHeadCheckbox, CtlGridEditorText: CtlGridEditorText, CtlGridEditorNumber: CtlGridEditorNumber, CtlGridEditorCombo: CtlGridEditorCombo, CtlGridEditorDate: CtlGridEditorDate, CtlGridEditorSearch: CtlGridEditorSearch, CtlGridFilterSet: CtlGridFilterSet, CtlGridCellImage: CtlGridCellImage, CtlGridIdRender: this.setRowId.bind(this) //CtlGridIdRender.bind(this) } } if (this.clientFilter) { delete gridOptions.onFilterChanged } if (this.clientSort) { delete gridOptions.onSortChanged } if (_.isArray(this.dataSource)) { //有数据,按 client 模式加载数据 _.assign(gridOptions, { rowModelType: 'clientSide', rowData: this.data, data: [] }) } if (this.pagination) { _.assign(gridOptions, { rowModelType: 'clientSide', rowData: [], data: [] }) } return gridOptions } private _filterChanged() { if (this.dataSourceBind) { if ((!_.isEqual(this.gridApi.getFilterModel(), this.dataSourceBind.lastFilterModel)) || this.refreshMode == GridRefreshMode.refreshAndClearFilter) { const reload = _.get(this.dataSourceBind, 'reload') if (typeof reload === 'function') { reload.call(this.dataSourceBind); this.reload() } } // console.log('_filterChanged', this.gridApi.getFilterModel()); } } private _sortChanged() { if (this.dataSourceBind) { if ((!_.isEqual(this.gridApi.getSortModel(), this.dataSourceBind.lastSortModel)) || this.refreshMode == GridRefreshMode.refreshAndClearFilter) { const reload = _.get(this.dataSourceBind, 'reload') if (typeof reload === 'function') { reload.call(this.dataSourceBind); this.reload() } } // console.log('_sortChanged', this.gridApi.getSortModel()); } } private _gridReady() { this.isGridReadReady = true /** 分页视图 **/ this.gridPage = new CtlGridPage(this) this._rebindDataSource() if (_.has(this.vjson, "pagination") && this.vjson.pagination === false) { this.gridPage.hidden() } } private _resetGrid() { this.isGridReadReady = false const gridOptions = this._gridOptions() const $el = $(this._webix._viewobj).find('[role="yvGrid"]')[0] const grid: any = new agGrid.Grid($el, gridOptions) grid.gridOptions.api.vue = this this.gridApi = grid.gridOptions.api this.columnApi = grid.gridOptions.columnApi //去掉 ag-unselectable 使表格允许被选定 if ($el) { $($el) .find('.ag-root.ag-unselectable') .removeClass('ag-unselectable') } if (this.vjson.collectData && !this.dataSource) { this._transactionUpdate([]) } } suppressDelete(params: any) { var KEY_DELETE = 8; var event = params.event; var key = event.which; var suppress = key === KEY_DELETE; return suppress; } _rowDoubleClicked(e: any) { YvEventDispatch(this.onRowDblClick, this, e.data) } /** * 获取下拉框的数据选项 */ _getComboFilterData(easyuiCol: any) { if (easyuiCol.editMode === 'combo') { if (typeof easyuiCol.editParams.data === 'string') { if (YvanUI.dict.hasOwnProperty(easyuiCol.editParams.data)) { return YvanUI.dict[easyuiCol.editParams.data] } else if (YvanUI.formatter.hasOwnProperty(easyuiCol.editParams.data)) { return YvanUI.formatter[easyuiCol.editParams.data] } else { console.error( '没有发现全局函数 YvanUI.formatter[dict].' + easyuiCol.editParams.data ) } } else if (easyuiCol.editParams.data.constructor === Array && easyuiCol.editParams.data.length > 0) { const editParams = easyuiCol.editParams return _.map(editParams.data, item => { return { id: item[editParams.idField], text: item[editParams.textField] } }) } else if (easyuiCol.editParams.dataSource) { const dataSourceBind = new YvDataSource(this, easyuiCol.editParams.dataSource, this._comboDataSourceProcess.bind(this, easyuiCol)) dataSourceBind.init() easyuiCol.editParams.__dataSourceBind = dataSourceBind return this._comboValidate.bind(this, easyuiCol) } } let formatter = easyuiCol.formatter if (!this.isDesignMode() && typeof easyuiCol.formatter === 'string') { // formatter 是字符串,从全局 YvanUI.formatter 找方法 if (YvanUI.dict.hasOwnProperty(easyuiCol.formatter)) { formatter = YvanUI.dict[easyuiCol.formatter] } else if (YvanUI.formatter.hasOwnProperty(easyuiCol.formatter)) { easyuiCol.formatter = YvanUI.formatter[easyuiCol.formatter] } else { console.error( '没有发现全局函数 YvanUI.formatter[dict].' + easyuiCol.editParams.data ) } } if (formatter && formatter.constructor === Array) { // formatter 是数组,就是下拉数据本身 return formatter } } _comboDataSourceProcess(easyuiCol: any, data: any) { if (easyuiCol.editParams.__dataSourceBind) { easyuiCol.editParams.__dataSourceBind.destory() delete easyuiCol.editParams.__dataSourceBind delete easyuiCol.editParams.dataSource } if ((data && data.length > 0)) { easyuiCol.editParams.options = data easyuiCol.valueValidate = (value: any) => { const optionItem = _.find(data, item => { const id = _.toString(item['id']) return id && id === _.toString(value) }) if (optionItem) { //找到text属性值 return optionItem['text'] } return value } this.gridApi.refreshCells({ columns: [easyuiCol.field], force: true }) } } _comboValidate(easyuiCol: any, value: any) { if (easyuiCol.valueValidate) { const vv = easyuiCol.valueValidate(value) return vv } return value } /** * 第一次数据被渲染之后 */ _firstDataRendered() { YvEventDispatch(this.onFirstDataRendered, this, undefined) } /** * 接受更新 * 状态位显示 OK, 删除 origin 数据, 并闪烁当前行 */ _acceptChanges(node: any) { if (node.origin) { node.cstate = 'ok' delete node.origin this.flashRow(node) node.setDataValue('__ID__', _.uniqueId()) } } /** * 接受更新 * 状态位显示 OK, 删除 origin 数据, 并闪烁当前行 */ acceptAllChanges() { this.gridApi.forEachNode((node: any) => { if (node.origin) { node.cstate = 'ok' delete node.origin this.flashRow(node) node.setDataValue('__ID__', _.uniqueId()) } }) } /** * 清空所有状态,准备获取新数据 * 当前编辑都应该清空, 勾选也应该清空 */ _clearCache() { // this.checkedIds = []; this.gridApi.forEachNode((node: any) => { if (_.has(node.data, '__grid_row_checked')) { node.data.__grid_row_checked = false } }) this.gridApi.forEachNode((node: any) => { delete node.cstate delete node.origin }) } /** * 根据行,获取主键 ID, 当主键不存在时 返回 undefined */ _getIdByRow(row: any) { if (!row) return if (this.idField) { if (this.idField.constructor === Array) { //联合组件,用valueSep分割 return _.map(this.idField, (f: any) => _.toString(row[f])).join(this.valueSep) } return row[this.idField] } console.error('表格没有设置主键!!') return undefined } /** * 重新绑定数据源 */ _rebindDataSource() { const innerMethod = () => { if (this.dataSourceBind) { this.dataSourceBind.destory() this.dataSourceBind = undefined } if (this._webix && this._module) { this.dataSourceBind = new YvanDataSourceGrid(this, this.dataSource) } } if (!this._module.loadFinished) { // onload 函数还没有执行(模块还没加载完), 延迟调用 rebind _.defer(innerMethod) } else { // 否则实时调用 rebind innerMethod() } } /** * 每次 AJAX 请求完毕之后会回调这里 */ _bindingComplete() { YvEventDispatch(this.onBindingComplete, this, undefined) if (!this.getSelectedId()) { if(this.defaultUnselecteRow){//默认不选中第一行 }else{// 默认必须选中一行 this.selectRow(() => true); } } } /** * 找到某行的 node, (一旦匹配到 condition 就停止) */ _findNode(condition: GridSelectCondition) { if (!condition) { //返回第一条被找到的数据 condition = () => true } else if (typeof condition === 'string') { //以主键查找的方式 const key = condition condition = (n: any) => { return this._getIdByRow(n.data) === key } } else if (typeof condition === 'object') { //就是 node 对象, 直接返回 return condition } const me = this let findNode = undefined try { this.gridApi.forEachNode((node: any) => { if ((condition as any).call(me, node)) { findNode = node throw Error() } }) } catch (e) { } return findNode } _cellKeyDown(param: any) { const KEY_LEFT = 37 const KEY_UP = 38 const KEY_RIGHT = 39 const KEY_DOWN = 40 const KEY_TAB = 9 const KEY_DELETE = 8 const KEY_ENTER = 13 const KEY_ESC = 27 //event.stopPropagation(); //event.preventDefault(); //通知外部 const r = YvEventDispatch(this.onKeyDown, this, param) if (r === true) { //已经被自定义函数处理掉 return } if (param.event.keyCode === KEY_ENTER) { param.event.stopPropagation() param.event.preventDefault() } else if (param.event.keyCode === KEY_DELETE) { if (this.gridApi.getEditingCells().length <= 0) { param.event.stopPropagation() param.event.preventDefault() if (this.vjson.collectData == true) { this._deleteToUpdate(this._gridData, param.rowIndex); YvEventDispatch(this.onRowDelete, this, this._gridData[param.rowIndex]) } else { if (this.dataSourceBind) { this.dataSourceBind._deleteRow(param) YvEventDispatch(this.onRowDelete, this, param.data) } } } } else if (param.event.keyCode === KEY_ESC) { //按下 ESC 还原数据到 origin 状态, 并删除所有编辑形式 if (param.node.origin) { param.event.stopPropagation() param.event.preventDefault() const data = { ...param.data, ...param.node.origin } delete param.node.cstate delete param.node.origin param.node.updateData(data) param.node.setDataValue('__ID__', _.uniqueId()) } } else if (param.event.keyCode === KEY_UP) { param.event.stopPropagation() param.event.preventDefault() const vv = param.rowIndex - 1 if (vv < 0) { return } this.selectRowWithCell(node => node.rowIndex === vv, param.colDef.field) this.gridApi.stopEditing() this.gridApi.startEditingCell({ rowIndex: vv, colKey: param.colDef.field }) } else if (param.event.keyCode === KEY_DOWN) { param.event.stopPropagation() param.event.preventDefault() const vv = param.rowIndex + 1 if (vv >= this._gridData.length) { return } this.selectRowWithCell(node => node.rowIndex === vv, param.colDef.field) this.gridApi.stopEditing() this.gridApi.startEditingCell({ rowIndex: vv, colKey: param.colDef.field }) } else if (param.event.keyCode === KEY_LEFT || (param.event.keyCode === KEY_TAB && param.event.shiftKey === true)) { param.event.stopPropagation() param.event.preventDefault() const vv = this._getPreviousEditCellFields(param.colDef.field) if (vv) { this.gridApi.setFocusedCell(param.rowIndex, vv) this.gridApi.stopEditing() this.gridApi.startEditingCell({ rowIndex: param.rowIndex, colKey: vv }) } else { const num = param.rowIndex - 1 if (num < 0) { return } this.singleSelectRow(node => node.rowIndex === num) } } else if (param.event.keyCode === KEY_RIGHT || param.event.keyCode === KEY_TAB) { param.event.stopPropagation() param.event.preventDefault() const vv = this._getNextEditCellFields(param.colDef.field) if (vv) { this.gridApi.setFocusedCell(param.rowIndex, vv) this.gridApi.stopEditing() this.gridApi.startEditingCell({ rowIndex: param.rowIndex, colKey: vv }) } else { const num = param.rowIndex + 1 if (num >= this._gridData.length) { if (this.vjson.collectData == true) { if (this._keyTabRowValidate(param.node.id, param)) { param.node.cstate = 'error' param.node.setDataValue('__ID__', _.uniqueId()) return } this._transactionUpdate(this._gridData) const firstField = this._getFirstEditCellFields(); if (firstField) { this.singleSelectRow(node => node.rowIndex === num) this.gridApi.setFocusedCell(num, firstField) this.gridApi.startEditingCell({ rowIndex: num, colKey: firstField }) } } else { this._rowEditingStopped(param.node.id, param) } return } this.singleSelectRow(node => node.rowIndex === num) } } } _getPreviousEditCellFields(field: string) { const nn = _.indexOf(this.gridEditCells, field); if (nn == -1 && nn - 1 < 0) { return null } return this.gridEditCells[nn - 1] } _getNextEditCellFields(field: string) { const nn = _.indexOf(this.gridEditCells, field); if (nn == -1 && nn + 1 >= this.gridEditCells.length) { return null } return this.gridEditCells[nn + 1] } _getFirstEditCellFields() { if (this.gridEditCells.length >= 0) { return this.gridEditCells[0] } return null } _modelUpdated() { if (this.autoSizeColumns && this.gridApi) { this.gridApi.sizeColumnsToFit() } } _cellFocused(param: any) { YvEventDispatch(this.onCellFocused, this, param) } _cellClicked(param: any) { YvEventDispatch(this.onCellClicked, this, param) if (this.onRowCheck && param.colDef.field == "__CB__") { // 触发 onRowCheck 事件 YvEventDispatch(this.onRowCheck, this, param.data) } } _getRowStyle(param: any) { return YvEventDispatch(this.onRowStyle, this, param); // 三种默认背景色:浅红色:return{background: '#ffd2d2'} 浅绿色:return{background: '#bde2c8'} 浅黄色:return{background: '#fdfbc1'} } _rowSelected(param: any) { const { node } = param const { selected, id } = node if (!selected) { //行离开事件,查看是否有数据正在编辑,提交校验 this._rowEditingStopped(id, param) return } //触发 entity 改变 if (_.size(this.entityName) > 0) { _.set(this.getModule(), this.entityName + '.selectedRow', param.data) //this.vcxt.module.$set(this.vcxt.module[this.entityName], "selectedRow", param.data); } //触发 onRowSelect 事件 YvEventDispatch(this.onRowSelect, this, param.data) } _onChecked() { } _cellEditingStarted(param: any) { let rowId if (param.node.rowPinned === 'top') { //在添加行上 rowId = -1 } else if (!param.node.rowPinned) { //在数据行上 rowId = param.node.id } this._rowEditingStarted(rowId, param) } _cellEditingStopped(param: any) { //触发单元格校验事件 if (this.saveOn !== 'editFinish') { //保存时机,是不是结束编辑后立刻保存 return } const origin = param.node.origin if (!origin) { // 这一行没有进入过编辑模式 return } const data = _.cloneDeep(param.data) delete data['__ID__'] delete data['__CB__'] _.forOwn(origin, (value, key) => { if (typeof value === 'number') { origin[key] = _.toString(value) } }) _.forOwn(data, (value, key) => { if (typeof value === 'number') { data[key] = _.toString(value) } }) if (_.isEqual(origin, data)) { //相同,改变状态位 same param.node.cstate = 'same' } else { //不相同, 提交校验 param.node.cstate = 'validate' if (this.dataSourceBind) { if (this.dataSourceBind.updateSupport()) { this.dataSourceBind._updateRow(param) } } if (this.vjson.cellEditingStopped) { YvEventDispatch(this.vjson.cellEditingStopped, this, param); } //console.log(this.dataSource, param.node) //setTimeout(() => { // this._acceptChanges(param.node) //}, 2000) } param.node.setDataValue('__ID__', _.uniqueId()) } _rowEditingStarted(rowId: any, param: any) { if (!param.node.origin) { // 以前从来没有编辑过这一行, 记录 origin const data = _.cloneDeep(param.data) delete data['__ID__'] delete data['__CB__'] param.node.origin = data } param.node.cstate = 'editing' param.node.setDataValue('__ID__', _.uniqueId()) } _keyTabRowValidate(rowId: any, param: any) { let validateFaild = false const validateFaildFileds: any[] = [] _.forEach(this.columns, column => { const currentVal = _.get(param.data, column.field) if (column.editParams?.required == true) { if (!currentVal && currentVal != 0) { validateFaildFileds.push(column.field) validateFaild = true return false } } if (column.editParams?.onValidate) { const currentResult = YvEventDispatchArgs(column.editParams?.onValidate, this, [currentVal, param.data]) if (currentResult) { validateFaildFileds.push(column.field) validateFaild = true return false } } }) if (validateFaild && validateFaildFileds.length > 0) { /** * todo validate不通过是否需要处理 */ // this.gridApi.stopEditing() // for (let ii = validateFaildFileds.length - 1; ii >= 0; ii--) { // const element = validateFaildFileds[ii] // this.gridApi.startEditingCell({ // rowIndex: parseInt(rowId), // colKey: element // }) // } } return validateFaild } _getRowValidate(rowId: any, param: any) { let validateFaild = false _.forEach(this.columns, column => { // const currentVal = _.get(this.getSelectedRow(), column.field) const val = _.get(param.data, column.field) if (column.editParams?.required == true) { // if (!currentVal) { // validateFaild = true // return false // } if (!val && val != 0) { // this.selectRowWithCell(node => node.rowIndex === parseInt(rowId), column.field) // this.gridApi.stopEditing() // this.gridApi.startEditingCell({ // rowIndex: parseInt(rowId), // colKey: column.field // }) validateFaild = true return false } } if (column.editParams?.onValidate) { // const currentResult = YvEventDispatch(column.editParams?.onValidate, this, currentVal) const result = YvEventDispatchArgs(column.editParams?.onValidate, this, [val, param.data]) // if (currentResult) { // validateFaild = true // return false // } if (result) { // this.selectRowWithCell(node => node.rowIndex === parseInt(rowId), column.field) // this.gridApi.stopEditing() // this.gridApi.startEditingCell({ // rowIndex: parseInt(rowId), // colKey: column.field // }) validateFaild = true return false } } }) return validateFaild } _rowEditingStopped(rowId: any, param: any) { if (this.isDataVoid(param.data)) { // param.node.cstate = 'same' // param.node.setDataValue('__ID__', _.uniqueId()) return } if (this._getRowValidate(rowId, param)) { param.node.cstate = 'error' param.node.setDataValue('__ID__', _.uniqueId()) return } if (this.vjson.collectData == true) { return } if (this.saveOn !== 'rowChanged') { //保存时机,是不是行更改后立刻保存 return } const origin = param.node.origin if (!origin) { // 这一行没有进入过编辑模式 return } const data = _.cloneDeep(param.data) delete data['__ID__'] delete data['__CB__'] _.forOwn(origin, (value, key) => { if (typeof value === 'number') { origin[key] = _.toString(value) } }) _.forOwn(data, (value, key) => { if (typeof value === 'number') { data[key] = _.toString(value) } }) if (_.isEqual(origin, data)) { //相同,改变状态位 same param.node.cstate = 'same' } else { //不相同, 提交校验 param.node.cstate = 'validate' if (this.dataSourceBind) { if (data.__grid_row_new) { this.dataSourceBind._addRow(param) } else { this.dataSourceBind._updateRow(param) } } //console.log(this.dataSource, param.node) //setTimeout(() => { // this._acceptChanges(param.node) //}, 2000) } param.node.setDataValue('__ID__', _.uniqueId()) } /** * Tab键导航 */ _tabToNextCell(params: any) { const previousCell = params.previousCellPosition const nextCellPosition = params.nextCellPosition //tab 永不换行 return { ...nextCellPosition, rowIndex: previousCell.rowIndex } } /** * 上下左右键导航 */ _navigateToNextCell(params: any) { console.log('_navigateToNextCell', params) const KEY_LEFT = 37 const KEY_UP = 38 const KEY_RIGHT = 39 const KEY_DOWN = 40 const previousCell = params.previousCellPosition const suggestedNextCell = params.nextCellPosition switch (params.key) { case KEY_UP: { const nextRowIndex = previousCell.rowIndex - 1 if (nextRowIndex < 0) { // returning null means don't navigate return null } this.selectRow(node => node.rowIndex === nextRowIndex) return { rowIndex: nextRowIndex, column: previousCell.column, floating: previousCell.floating } } case KEY_DOWN: { // return the cell below const rowIndex = previousCell.rowIndex + 1 const renderedRowCount = this.gridApi.getModel().getRowCount() if (rowIndex >= renderedRowCount) { // returning null means don't navigate return null } this.selectRow(node => node.rowIndex === rowIndex) return { rowIndex: rowIndex, column: previousCell.column, floating: previousCell.floating } } case KEY_LEFT: case KEY_RIGHT: return suggestedNextCell default: throw 'this will never happen, navigation is always one of the 4 keys above' } } /** * 列设置计算 */ _gridCols(resultCols: any[]): void { _.each(this.columns, column => { const easyuiCol = _.merge( { ..._.clone(YvGridColumnProp), editParams: { ..._.clone(YvGridColumnEditProp) }, wrapText: true, autoHeight: true, }, column ) //=========================== 设计模式属性 =========================== // if (this._isDesignMode) { // resultCols.push({ // suppressMovable: true, // field: easyuiCol.field, // headerName: easyuiCol.title, // resizable: true, // filter: false, // editable: false, // sortable: false, // //unSortIcon: true, // hide: false, // width: easyuiCol.width, // minWidth: easyuiCol.minwidth, // maxWidth: easyuiCol.maxwidth // }); // return; // } //=========================== 基本属性 =========================== const col: any = { suppressMovable: true, field: easyuiCol.field, headerName: easyuiCol.title, resizable: easyuiCol.resizable, filter: false, editable: false, sortable: easyuiCol.sortable, //unSortIcon: true, hide: easyuiCol.hidden } if (easyuiCol.pinned === 'left' || easyuiCol.pinned === 'right') { col.pinned = easyuiCol.pinned } if (easyuiCol.flex && easyuiCol.flex > 0 ) { col.flex = easyuiCol.flex } if (easyuiCol.suppressSizeToFit && easyuiCol.suppressSizeToFit === true) { col.suppressSizeToFit = easyuiCol.suppressSizeToFit } if (easyuiCol.sortable) { // 走服务端排序,客户端排序可以让其无效 col.comparator = () => { return 0; } } if (typeof easyuiCol.width !== 'undefined') col.width = easyuiCol.width if (typeof easyuiCol.minwidth !== 'undefined') col.minWidth = easyuiCol.minwidth if (typeof easyuiCol.maxwidth !== 'undefined') col.maxWidth = easyuiCol.maxwidth if (typeof easyuiCol.align !== 'undefined') { col.cellClass = function (params: any) { return ['yv-align-' + easyuiCol.align] } } if (_.size(easyuiCol.field) > 0) { col.tooltipField = easyuiCol.field } //=========================== buttons 属性 =========================== if (easyuiCol.buttons) { //col.cellRendererFramework = 'yvGridButton' col.cellRenderer = 'CtlGridCellButton' col.cellRendererParams = { buttons: easyuiCol.buttons } } if (easyuiCol.images) { col.cellRenderer = 'CtlGridCellImage' col.cellRendererParams = { images: easyuiCol.images } } //=========================== 编辑与formatter属性 =========================== const { editParams } = easyuiCol let formatable = false if (easyuiCol.editable && !this.isDesignMode()) { if (easyuiCol.editMode === 'checkbox') { //勾选框编辑 formatable = false col.cellRenderer = 'CtlGridCellCheckbox' col.cellRendererParams = { editParams: easyuiCol.editParams, on: editParams.on, off: editParams.off, onChange: (newValue: any) => { YvEventDispatch(editParams.onValidate, this, { value: newValue }) } } if (easyuiCol.editable) { //允许编辑 _.assign(col, { editable: true, cellEditor: 'CtlGridEditorCombo', cellEditorParams: { editParams: easyuiCol.editParams, options: [ { id: editParams.on, text: '勾选' }, { id: editParams.off, text: '不勾' } ], onChange: (newValue: any) => { YvEventDispatch(editParams.onValidate, this, { value: newValue }) } } }) } } else if (easyuiCol.editMode === 'combo') { //下拉框编辑 formatable = false const data = this._getComboFilterData(easyuiCol) _.assign(col, { editable: true, cellEditor: 'CtlGridEditorCombo', cellEditorParams: { editParams: easyuiCol.editParams, options: typeof data === 'function' ? null : data, onChange: (newValue: any) => { YvEventDispatch(editParams.onChange, this, { value: newValue }) } } }) //下拉框的 formatter 逻辑是固定的 if (typeof data === 'function') { col.valueFormatter = (params: any) => { return data(params.value) } } else { col.valueFormatter = (params: any) => { if (_.size(params.data) <= 0) return const optionItem = _.find(data, item => { const id = _.toString(item['id']) return id && id === _.toString(params.value) }) if (optionItem) { //找到text属性值 return optionItem['text'] } return params.value } } } else if (easyuiCol.editMode === 'area') { //大型富文本框编辑 formatable = true _.assign(col, { editable: true, cellEditor: 'agLargeTextCellEditor', cellEditorParams: { editParams: easyuiCol.editParams, maxLength: editParams.maxlength } }) } else if (easyuiCol.editMode === 'text') { //普通文本框编辑 formatable = true _.assign(col, { editable: true, formatter: easyuiCol.formatter, cellEditor: 'CtlGridEditorText', cellEditorParams: { type: easyuiCol.editMode, editParams: easyuiCol.editParams, onChange: (newValue: any) => { YvEventDispatch(editParams.onValidate, this, { value: newValue }) } } }) } else if (easyuiCol.editMode === 'number') { //普通文本框编辑 数字 formatable = true _.assign(col, { editable: true, cellEditor: 'CtlGridEditorNumber', cellEditorParams: { type: easyuiCol.editMode, editParams: easyuiCol.editParams, onChange: (newValue: any) => { YvEventDispatch(editParams.onValidate, this, { value: newValue }) } } }) } else if (easyuiCol.editMode === 'date' || easyuiCol.editMode === 'datetime') { formatable = true _.assign(col, { editable: true, formatter: easyuiCol.formatter, cellEditor: "CtlGridEditorDate", cellEditorParams: { type: easyuiCol.editMode, editParams: easyuiCol.editParams, onChange: (newValue: any) => { YvEventDispatch(editParams.onValidate, this, { value: newValue }) } } }); } else if (easyuiCol.editMode === 'search') { formatable = true _.assign(col, { editable: true, widget: easyuiCol.widget, cellEditor: "CtlGridEditorSearch", cellEditorParams: { type: easyuiCol.editMode, editParams: easyuiCol.editParams, onChange: (newValue: any) => { YvEventDispatch(editParams.onValidate, this, { value: newValue }) } } }); } } else { //不允许编辑的情况,全都允许格式化 formatable = true } //=========================== formatter属性 =========================== if (formatable && !this.isDesignMode()) { const data = this._getComboFilterData(easyuiCol) if (data) { //从下拉框逻辑中找到了固定映射关系 col.valueFormatter = (params: any) => { if (_.size(params.data) <= 0) return undefined const optionItem = _.find(data, item => { const id = _.toString(item['id']) return id && id === _.toString(params.value) }) if (optionItem) { //找到text属性值 return optionItem['text'] } return params.value } } else { //以 function 方式获得显示逻辑 let formatter = easyuiCol.formatter if (typeof easyuiCol.formatter === 'string') { // formatter 是字符串,从全局 YvanUI.formatter 找方法 if (!YvanUI.formatter.hasOwnProperty(easyuiCol.formatter)) { console.error( '没有发现全局函数 YvanUI.formatter.' + easyuiCol.formatter ) } else { formatter = YvanUI.formatter[easyuiCol.formatter] } } if (typeof formatter === 'function') { //formatter 是函数,调用函数来显示 col.valueFormatter = (params: any) => { if (_.size(params.data) <= 0) return undefined return formatter.call( this, params.data[easyuiCol.field], this, params.data ) } } } } //=========================== 过滤属性 =========================== if (this.filterable && easyuiCol.filterable && !easyuiCol.hidden) { const datas = this._getComboFilterData(easyuiCol) if (typeof datas === 'object') { //下拉框过滤 _.assign(col, { filter: 'CtlGridFilterSet', //suppressMenu: true, filterParams: { data: datas, }, }) } else if (easyuiCol.editMode === 'number') { //数字过滤 _.assign(col, { filter: 'agNumberColumnFilter', //NumberFilter = 26850 //suppressMenu: true, filterParams: { applyButton: true, clearButton: true, suppressAndOrCondition: true, filterOptions: [ // 服务器已经设置条件,浏览器不进行实际比对 { displayKey: 'equals', displayName: '等于', test() { return true; } }, { displayKey: 'notEqual', displayName: '不等于', test() { return true; } }, { displayKey: 'lessThan', displayName: '小于', test() { return true; } }, { displayKey: 'greaterThan', displayName: '大于', test() { return true; } }, { displayKey: 'lessThanOrEqual', displayName: '小于等于', test() { return true; } }, { displayKey: 'greaterThanOrEqual', displayName: '大于等于', test() { return true; } }, { displayKey: 'inRange', displayName: '范围', test() { return true; } }, ] } }) } else if (easyuiCol.editMode === 'date' || easyuiCol.editMode === 'datetime') { //日期筛选 _.assign(col, { filter: 'agDateColumnFilter', filterParams: { applyButton: true, clearButton: true, filterOptions: ['inRange'], suppressAndOrCondition: true, inRangeInclusive: true, comparator(v1: any, v2: any) { // 服务器已经设置条件,浏览器不进行实际比对 // 0 的情况,一定要包含 inRangeInclusive 条件 return 0 } } }) } else { //其他情况都是字符串筛选 _.assign(col, { filter: 'agTextColumnFilter', filterParams: { applyButton: true, clearButton: true, filterOptions: ['contains', 'equals', 'startsWith'], suppressAndOrCondition: true, textCustomComparator() { // 服务器已经设置条件,浏览器不进行实际比对 return true; } } }) } } //=========================== 渲染属性 =========================== if (!this.isDesignMode()) { if (typeof easyuiCol.onStyle === 'function') { _.assign(col, { cellStyle: (param: any) => { return easyuiCol.onStyle.call(this, param) } }) } if (easyuiCol.onStyle?.type && easyuiCol.onStyle?.bind) { _.assign(col, { cellStyle: (param: any) => { return YvEventDispatch(easyuiCol.onStyle, this, { "field": param.colDef.field, "value": param.value, "data": param.data }) } }) } } if (easyuiCol.editable && easyuiCol.editModeByDataField) { delete col.cellEditor col.editModeByDataField = easyuiCol.editModeByDataField _.assign(col, { cellEditorSelector: this.getColEditMode.bind(this) }) } resultCols.push(col) }) } getColEditMode(params: any) { const type = _.get(params.data, params.colDef.editModeByDataField) if (type === 'checkbox') { return { component: 'CtlGridCellCheckbox', }; } else if (type === 'combo') { return { component: 'CtlGridEditorCombo', }; } if (type === 'area') { return { component: 'agLargeTextCellEditor', }; } else if (type === 'text' || type === 'string') { return { component: 'CtlGridEditorText', }; } else if (type === 'number') { return { component: 'CtlGridEditorNumber', }; } else if (type === 'date' || type === 'datetime') { return { component: 'CtlGridEditorDate' }; } else if (type === 'search') { return { component: 'CtlGridEditorSearch' }; } else { throw new Error('unsupported edit type') } } } export type GridSelectCondition = ((row: any) => boolean) | string