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