|
@@ -0,0 +1,460 @@
|
|
|
+import _ from 'lodash'
|
|
|
+import {grid} from '../Defaults'
|
|
|
+import {baseConfig} from "./base";
|
|
|
+import {lookupFn, lookupScope} from "../lib/lib";
|
|
|
+import {
|
|
|
+ disabled,
|
|
|
+ fieldLabel,
|
|
|
+ gravity,
|
|
|
+ height,
|
|
|
+ metaId,
|
|
|
+ PropertyDescriptionTable,
|
|
|
+ tooltip,
|
|
|
+ value,
|
|
|
+ width,
|
|
|
+ YvBase
|
|
|
+} from "../PropertyDescriptionTable";
|
|
|
+import {PropertyDescription} from "../PropertyDescription";
|
|
|
+import {gridInvokeBuild} from "./stores";
|
|
|
+import {msg} from 'src/message';
|
|
|
+
|
|
|
+
|
|
|
+const defaultGrid = grid
|
|
|
+export default function () {
|
|
|
+
|
|
|
+ Ext.define('Yvan.Grid', {
|
|
|
+ extend: 'Ext.grid.Grid',
|
|
|
+ xtype: 'yvgrid',
|
|
|
+
|
|
|
+ constructor(config) {
|
|
|
+ const me = this
|
|
|
+ const {dataSource} = config
|
|
|
+ if (!window["IS_DESIGN_MODE"]) {
|
|
|
+ this.columnConfigCacheKey = this.makeColumnConfigCacheKey(config)
|
|
|
+ if (Array.isArray(config.columns) && config.columns.length > 0) {
|
|
|
+ const cacheData = this.getColumnConfigCache()
|
|
|
+ if (Array.isArray(cacheData) && cacheData.length > 0) {
|
|
|
+ const newColumns = []
|
|
|
+
|
|
|
+ for (let j = 0; j < cacheData.length; j++) {
|
|
|
+ const itData = cacheData[j]
|
|
|
+ for (let i = 0; i < config.columns.length; i++) {
|
|
|
+ const column = config.columns[i]
|
|
|
+ if (itData.dataIndex === column.dataIndex) {
|
|
|
+ if (itData.width) {
|
|
|
+ column.width = itData.width
|
|
|
+ }
|
|
|
+ column.hidden = itData.hidden
|
|
|
+ column.locked = itData.locked
|
|
|
+ newColumns.push(column)
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ config.columns = newColumns
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ const newConfig = _.defaultsDeep({
|
|
|
+ // 强制性属性 bug.
|
|
|
+ // lock 属性会造成 Cannot read properties of undefined (reading 'els')
|
|
|
+ // enableLocking: false,
|
|
|
+ // syncRowHeight: false,
|
|
|
+
|
|
|
+ }, baseConfig(config, 'row-item'), config, grid)
|
|
|
+
|
|
|
+ // 在面板上的组件
|
|
|
+ const scope = newConfig.$initParent.yvanScope || newConfig.$initParent.lookupReferenceHolder().yvanScope;
|
|
|
+
|
|
|
+ const buttons = []
|
|
|
+
|
|
|
+ const {getRowClass} = newConfig
|
|
|
+ if (typeof getRowClass === 'string' && (
|
|
|
+ _.startsWith(getRowClass, "scope.") ||
|
|
|
+ _.startsWith(getRowClass, "system."))
|
|
|
+ ) {
|
|
|
+ const fn = lookupFn(scope, getRowClass)
|
|
|
+ _.set(newConfig, 'viewConfig.getRowClass', fn)
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!newConfig.hideAutoSize) {
|
|
|
+ buttons.push({
|
|
|
+ xtype: 'button',
|
|
|
+ iconCls: 'x-fa fa-text-width',
|
|
|
+ tooltip: '自适应宽度',
|
|
|
+ listeners: {
|
|
|
+ click: this.autoSizeColumns
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ _.each(newConfig.columns, c => {
|
|
|
+ const {renderer} = c
|
|
|
+ if (typeof renderer === 'string' && (
|
|
|
+ _.startsWith(renderer, "scope.") ||
|
|
|
+ _.startsWith(renderer, "system."))
|
|
|
+ ) {
|
|
|
+ if (newConfig.$initParent) {
|
|
|
+ if (scope) {
|
|
|
+ const rendererFn = lookupFn(scope, renderer)
|
|
|
+ c.renderer = rendererFn
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ this.superclass.constructor.call(this, newConfig)
|
|
|
+ // this.store.pageSize = newConfig.pageSize
|
|
|
+ },
|
|
|
+
|
|
|
+ setData(value) {
|
|
|
+ const me = this
|
|
|
+ me._setDataReal(value)
|
|
|
+ },
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 添加行,并进入编辑状态
|
|
|
+ * @param record 新行的属性集
|
|
|
+ * @param editRowCol 要编辑的列序号,或 dataIndex 的名称
|
|
|
+ */
|
|
|
+ appendEditRow(record, editRowCol) {
|
|
|
+ const records = this.getStore().add(record)
|
|
|
+ const recNew = records[0]
|
|
|
+ this.setSelection(records)
|
|
|
+
|
|
|
+ if (typeof editRowCol === 'string' && editRowCol) {
|
|
|
+ editRowCol = this.columns.findIndex((c) => c.dataIndex === editRowCol)
|
|
|
+ }
|
|
|
+
|
|
|
+ if (typeof editRowCol === 'number') {
|
|
|
+ const ce = this.findPlugin('cellediting')
|
|
|
+ this.editingPlugin = ce
|
|
|
+ ce.startEdit(recNew, editRowCol)
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 移除行
|
|
|
+ * @param record 如果记录传空,就是当前选中的行
|
|
|
+ */
|
|
|
+ removeEditRow(record) {
|
|
|
+ if (!record) {
|
|
|
+ record = this.selection
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!record) {
|
|
|
+ msg('请选中要删除的行')
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ this.getStore().remove(record)
|
|
|
+ },
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取全部原始数据
|
|
|
+ */
|
|
|
+ getDataRows() {
|
|
|
+ return this.getStore().data.items.map(r => r.data)
|
|
|
+ },
|
|
|
+
|
|
|
+ getEditRecord() {
|
|
|
+ const me = this
|
|
|
+ const editingPlugin = me.editingPlugin || me.ownerGrid.editingPlugin
|
|
|
+ const rowIdx = editingPlugin?.activeEditor?.context?.rowIdx
|
|
|
+
|
|
|
+ let record;
|
|
|
+ if (!rowIdx) {
|
|
|
+ record = me.getSelectionModel().getLastSelected()
|
|
|
+ } else {
|
|
|
+ record = me.store.getAt(rowIdx)
|
|
|
+ }
|
|
|
+
|
|
|
+ return record
|
|
|
+ },
|
|
|
+
|
|
|
+ getEditRow() {
|
|
|
+ const me = this
|
|
|
+ return me.getEditRecord()?.data
|
|
|
+ },
|
|
|
+
|
|
|
+ setEditRow(rowValues) {
|
|
|
+ const me = this
|
|
|
+ const record = me.getEditRecord()
|
|
|
+ if (record) {
|
|
|
+ _.forOwn(rowValues, (v, k) => {
|
|
|
+ record.set(k, v)
|
|
|
+ })
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ _transform(data) {
|
|
|
+ // 无论是 grid._setDataReal 还是 stores.gridInvokeBuild 都会走这个函数,设值前都可以改变表格值
|
|
|
+ _.forEach(data, row => {
|
|
|
+ row._origin = _.clone(row)
|
|
|
+ })
|
|
|
+ },
|
|
|
+
|
|
|
+ _setDataReal(value) {
|
|
|
+ const me = this
|
|
|
+ this._transform(value)
|
|
|
+ me.setStore(new Ext.data.Store({
|
|
|
+ fields: getFileds(this),
|
|
|
+ data: value
|
|
|
+ }))
|
|
|
+ },
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 轻量级刷新
|
|
|
+ */
|
|
|
+ refreshData() {
|
|
|
+ const store = this.getStore()
|
|
|
+ if (store) {
|
|
|
+ store.reload()
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 为表格强制设置焦点
|
|
|
+ * @param seq 顺序号
|
|
|
+ */
|
|
|
+ focusRow(seq) {
|
|
|
+ this.setSelection(this.store.getAt(seq))
|
|
|
+ this.getView().focusRow(seq)
|
|
|
+ },
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 重新载入数据(重新计算参数)
|
|
|
+ */
|
|
|
+ reload(reloadParams = {}) {
|
|
|
+ const me = this
|
|
|
+ const {config} = me
|
|
|
+
|
|
|
+ if (config.dataSourceCallbackFn) {
|
|
|
+ // 函数请求刷新
|
|
|
+ const scope = lookupScope(this)
|
|
|
+ _.defer(() => {
|
|
|
+ me.setLoading(true)
|
|
|
+ })
|
|
|
+ config.dataSourceCallbackFn.call(scope, me, {
|
|
|
+ successCallback(value) {
|
|
|
+ me._setDataReal(value)
|
|
|
+ _.defer(() => {
|
|
|
+ me.setLoading(false)
|
|
|
+ })
|
|
|
+ me.fireEvent('dataLoadComplete', me, true, value);
|
|
|
+ },
|
|
|
+ failCallback(error) {
|
|
|
+ _.defer(() => {
|
|
|
+ me.setLoading(false)
|
|
|
+ })
|
|
|
+ me.fireEvent('dataLoadComplete', me, false, error);
|
|
|
+ }
|
|
|
+ })
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ // if (this.store) {
|
|
|
+ // this.store.reload({aaaa: 1, bbbb: 2})
|
|
|
+ // }
|
|
|
+ const {dataSource} = config
|
|
|
+ if (_.isPlainObject(dataSource) && !window["IS_DESIGN_MODE"]) {
|
|
|
+ const scope = lookupScope(me)
|
|
|
+ gridInvokeBuild(scope, me, config, dataSource, reloadParams)
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ initialize() {
|
|
|
+ const me = this
|
|
|
+ const {config} = me
|
|
|
+ const scope = lookupScope(this)
|
|
|
+
|
|
|
+ if (!window["IS_DESIGN_MODE"]) {
|
|
|
+ // 转换 dataSource 属性
|
|
|
+ convertDataSource(me, scope, config)
|
|
|
+ }
|
|
|
+
|
|
|
+ // this.on({
|
|
|
+ //
|
|
|
+ //
|
|
|
+ //
|
|
|
+ // destory() {
|
|
|
+ // },
|
|
|
+ // })
|
|
|
+
|
|
|
+
|
|
|
+ if (this.store?.proxy) {
|
|
|
+ // 为 stores.proxy.buildRequest 做准备
|
|
|
+ this.store.proxy.$owner = this
|
|
|
+ }
|
|
|
+
|
|
|
+ this.superclass.initialize.call(this)
|
|
|
+ },
|
|
|
+
|
|
|
+ afterRender() {
|
|
|
+ const me = this
|
|
|
+ const {config} = this
|
|
|
+ const {dataSource} = config
|
|
|
+
|
|
|
+ if (config.autoLoad) {
|
|
|
+ if (config.dataSourceCallbackFn) {
|
|
|
+ me.reload()
|
|
|
+
|
|
|
+ } else if (_.isPlainObject(dataSource)) {
|
|
|
+ me.reload()
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 生成列自定义的缓存key
|
|
|
+ makeColumnConfigCacheKey(config) {
|
|
|
+ const me = this
|
|
|
+ const scope = config.$initParent.yvanScope || config.$initParent.lookupReferenceHolder().yvanScope;
|
|
|
+ let key = "gridColumnCache-" + scope.scopeKey + "-"
|
|
|
+ if (config.reference) {
|
|
|
+ key += config.reference
|
|
|
+ } else {
|
|
|
+ let subKey = ""
|
|
|
+ for (let i = 0; i < config.columns.length; i++) {
|
|
|
+ const column = config.columns[i]
|
|
|
+ if (column.dataIndex) {
|
|
|
+ subKey += column.dataIndex
|
|
|
+ }
|
|
|
+ }
|
|
|
+ key += subKey
|
|
|
+ }
|
|
|
+ return key
|
|
|
+ },
|
|
|
+
|
|
|
+ getColumnConfigCache() {
|
|
|
+ const key = this.columnConfigCacheKey
|
|
|
+ const dataStr = localStorage.getItem(key)
|
|
|
+ if (dataStr) {
|
|
|
+ return JSON.parse(dataStr)
|
|
|
+ }
|
|
|
+ return ""
|
|
|
+ },
|
|
|
+
|
|
|
+ setColumnConfigCache() {
|
|
|
+ const key = this.columnConfigCacheKey
|
|
|
+ const cacheData = []
|
|
|
+ const columns = this.headerCt.getGridColumns()
|
|
|
+ let index = 0
|
|
|
+ for (let i = 0; i < columns.length; i++) {
|
|
|
+ const column = columns[i]
|
|
|
+ if (column.dataIndex) {
|
|
|
+ cacheData.push({
|
|
|
+ dataIndex: column.dataIndex,
|
|
|
+ width: column.width,
|
|
|
+ hidden: column.hidden,
|
|
|
+ locked: column.locked,
|
|
|
+ index
|
|
|
+ })
|
|
|
+ index++
|
|
|
+ }
|
|
|
+ }
|
|
|
+ localStorage.setItem(key, JSON.stringify(cacheData))
|
|
|
+ },
|
|
|
+
|
|
|
+ autoSizeColumns(sender) {
|
|
|
+ const grid = sender.up('grid')
|
|
|
+ // const columns = grid.columns;
|
|
|
+ // for (let i = 0; i < columns.length; i++) {
|
|
|
+ // const column = columns[i];
|
|
|
+ // grid.getView().autoSizeColumn(column);
|
|
|
+ // column.setWidth(column.getWidth() + 5);
|
|
|
+ // }
|
|
|
+ for (let i = 1; i < grid.headerCt.getColumnCount(); i++) {
|
|
|
+ grid.headerCt.getGridColumns()[i].autoSize(i);
|
|
|
+ grid.headerCt.getGridColumns()[i].setWidth(grid.headerCt.getGridColumns()[i].getWidth() + 15);
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ clearFilter(sender) {
|
|
|
+ const grid = sender.up('grid')
|
|
|
+ grid.filters.clearFilters()
|
|
|
+ grid.getStore().sorters.removeAll()
|
|
|
+ // grid.getStore().reload()
|
|
|
+ },
|
|
|
+
|
|
|
+ setLoading(value) {
|
|
|
+ if (value) {
|
|
|
+ this.mask('读取中')
|
|
|
+ } else {
|
|
|
+ this.unmask()
|
|
|
+ }
|
|
|
+ },
|
|
|
+ })
|
|
|
+
|
|
|
+ PropertyDescriptionTable.set(
|
|
|
+ 'yvgrid',
|
|
|
+ new PropertyDescription(YvBase, {
|
|
|
+ props: [
|
|
|
+ fieldLabel, value, disabled,
|
|
|
+ gravity, tooltip, metaId, width, height
|
|
|
+ ],
|
|
|
+ })
|
|
|
+ )
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 获取 columns 中所有的 dataIndex
|
|
|
+ */
|
|
|
+function getFileds(newConfig) {
|
|
|
+ const fields = []
|
|
|
+ _.forEach(newConfig.columns, c => {
|
|
|
+ if (c.dataIndex) {
|
|
|
+ fields.push(c.dataIndex)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ return fields
|
|
|
+}
|
|
|
+
|
|
|
+function convertDataSource(sender, scope, newConfig) {
|
|
|
+ if (typeof newConfig.store !== 'undefined') {
|
|
|
+ // 有 store 属性的情况下,不做任何事
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ if (typeof newConfig.dataSource === 'undefined') {
|
|
|
+ // 没有定义 dataSource 的情况下,不做任何事
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ if (_.isArray(newConfig.data)) {
|
|
|
+ // 有 data 属性赋值的情况下
|
|
|
+ newConfig.store = {
|
|
|
+ fields: getFileds(newConfig),
|
|
|
+ data: newConfig.data
|
|
|
+ }
|
|
|
+ delete newConfig.data
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ let {dataSource} = newConfig
|
|
|
+ if (typeof dataSource === 'string') {
|
|
|
+ // dataSource 是字符串的情况下,找到成员函数
|
|
|
+ dataSource = lookupFn(scope, dataSource)
|
|
|
+ }
|
|
|
+
|
|
|
+ if (typeof dataSource === 'function') {
|
|
|
+ // dataSource 是函数的情况下,在 afterrender 之后进行回调
|
|
|
+ newConfig.store = new Ext.data.Store({
|
|
|
+ fields: getFileds(newConfig),
|
|
|
+ // data: [],
|
|
|
+ autoLoad: true,
|
|
|
+ proxy: {
|
|
|
+ type: 'memory',
|
|
|
+ data: [],
|
|
|
+ // reader: {
|
|
|
+ // type: 'json',
|
|
|
+ // rootProperty: 'users'
|
|
|
+ // }
|
|
|
+ }
|
|
|
+ })
|
|
|
+ newConfig.dataSourceCallbackFn = dataSource
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ // throw new TypeError('无法识别的调用方法')
|
|
|
+}
|