123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751 |
- import _ from 'lodash'
- import {grid} from '../Defaults'
- import {baseConfig} from "./base";
- import {lookupFn, lookupScope} from "../lib/lib";
- import LAY_EXCEL from "lay-excel"
- 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.Panel',
- 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({
- // 强制性属性
- }, 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.hideExport) {
- buttons.push({
- xtype: 'button',
- tooltip: '导出Excel',
- iconCls: 'x-fa fa-download',
- listeners: {
- click: this.exportExcel
- },
- })
- }
- if (!newConfig.hideAutoSize) {
- buttons.push({
- xtype: 'button',
- iconCls: 'x-fa fa-text-width',
- tooltip: '自适应宽度',
- listeners: {
- click: this.autoSizeColumns
- }
- })
- }
- if (!newConfig.hideClearFilter) {
- buttons.push({
- xtype: 'button',
- tooltip: '清空筛选',
- iconCls: 'x-fa fa-filter',
- handler: this.clearFilter
- })
- }
- if (!newConfig.hideSaveGridUIConfig) {
- buttons.push({
- xtype: 'button',
- tooltip: '保存表格自定义配置',
- iconCls: 'x-fa fa-cogs',
- handler: this.saveGridUIConfig
- })
- }
- if (!newConfig.hideClearGridUIConfig) {
- buttons.push({
- xtype: 'button',
- tooltip: '还原表格自定义配置',
- iconCls: 'x-fa fa-reply-all',
- handler: this.clearGridUIConfig
- })
- }
- if (!newConfig.hideFootbar) {
- if (newConfig.pagination) {
- newConfig.bbar = new Ext.PagingToolbar({
- // pageSize: newConfig.pageSize, 这个值是无效的
- displayInfo: true,
- store: this.store,
- emptyMsg: '没有记录',
- items: [
- {
- xtype: 'combobox',
- tooltip: '分页',
- queryMode: 'local',
- editable: false,
- allowBlank: true,
- labelAlign: 'right',
- width: 90,
- // labelWidth: 30,
- listConfig: {
- minWidth: null
- },
- value: 50,
- valueField: undefined,
- displayField: undefined,
- hideClear: true,
- store: newConfig.pageSizeOption,
- listeners: {
- change: (sender, nv, ov) => {
- this.store.pageSize = nv;
- this.store.loadPage(1);
- }
- }
- },
- ...buttons
- ]
- })
- } else {
- newConfig.bbar = {
- xtype: 'toolbar', overflowHandler: 'menu',
- items: [
- {
- xtype: 'button',
- tooltip: '刷新',
- iconCls: 'x-fa fa-refresh',
- handler: () => {
- this.reload()
- }
- },
- '-',
- ...buttons,
- ]
- }
- }
- }
- _.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 要编辑的列序号
- */
- appendEditRow(record, editRowCol) {
- const records = this.getStore().add(record)
- const recNew = records[0]
- this.setSelection(records)
- if (typeof editRowCol === 'number') {
- const ce = this.findPlugin('cellediting')
- this.editingPlugin = ce
- ce.startEdit(recNew, editRowCol)
- }
- },
- /**
- * 移除行
- * @param record 如果记录传空,就是当前选中的行
- */
- removeEditRow(record) {
- if (!record) {
- record = this.refs.grid2.selection
- }
- if (!record) {
- msg('请选中要删除的行')
- return
- }
- this.getStore().remove(record)
- },
- _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)
- }
- },
- exportCurrentExcelClick() {
- const me = this
- const {config} = me
- const scope = lookupScope(me)
- let excelFileName = config.excelFileName || scope.vjson.title || _.uniqueId("excel-")
- if (excelFileName.endsWith(".xlsx")) {
- excelFileName = excelFileName.split(".xlsx")[0]
- }
- excelFileName += ".xlsx"
- const rowsAll = this.getStore().getData().items?.map(r => r.data);
- const excelData = me.makeExcelData(rowsAll)
- LAY_EXCEL.exportExcel(excelData, excelFileName, 'xlsx')
- },
- exportExcelClick(excelExportParams) {
- const me = this
- const {config} = me
- excelExportParams.isExcelExport = true
- const scope = lookupScope(me)
- const {dataSource} = config
- let excelFileName = config.excelFileName || scope.vjson.title || _.uniqueId("excel-")
- gridInvokeBuild(scope, me, config, dataSource, excelExportParams, true, (responseData) => {
- let page = parseInt(responseData.pagination?.current) || 1
- const size = parseInt(responseData.pagination?.size) || me.exportExcelPageSize
- const total = parseInt(responseData.pagination?.total) || responseData.data?.length || 0
- me.exportExcelCurrentPage = page
- me.exportExcelPageSize = size
- me.exportExcelTotal = total
- if (excelFileName.endsWith(".xlsx")) {
- excelFileName = excelFileName.split(".xlsx")[0]
- }
- excelFileName += "(第" + me.exportExcelCurrentPage + "页,共" + Math.ceil(total / size) + "页、" + total + "条)"
- excelFileName += ".xlsx"
- const excelData = me.makeExcelData(responseData.data)
- LAY_EXCEL.exportExcel(excelData, excelFileName, 'xlsx')
- if (page < total / size) {
- page++
- }
- })
- },
- makeExcelData(jsonData) {
- if (!Array.isArray(jsonData) || jsonData.length === 0) {
- return
- }
- const me = this
- const data = [];
- // 获取表格的列定义
- const headerTextArr = []
- const headers = []
- for (let i = 0; i < me.headerCt.getGridColumns().length; i++) {
- const header = me.headerCt.getGridColumns()[i]
- if (!header.isHidden()) {
- const textStr = _.trim(header.text)
- const dataIndexStr = _.trim(header.dataIndex)
- if (dataIndexStr) {
- if (textStr === '') {
- headerTextArr.push(dataIndexStr)
- } else {
- headerTextArr.push(textStr)
- }
- headers.push(header)
- }
- }
- }
- if (headers.length === 0) {
- return
- }
- data.push(headerTextArr)
- for (let i = 0; i < jsonData.length; i++) {
- const dataRow = jsonData[i]
- const row = []
- for (let j = 0; j < headers.length; j++) {
- const key = headers[j].dataIndex
- let value = dataRow[key]
- if (typeof headers[j].renderer === 'function') {
- value = headers[j].renderer(value)
- }
- row.push(value || "")
- }
- data.push(row)
- }
- return data
- },
- initComponent() {
- const me = this
- const {config} = me
- const scope = lookupScope(this)
- if (!window["IS_DESIGN_MODE"]) {
- // 转换 dataSource 属性
- convertDataSource(me, scope, config)
- }
- this.on({
- afterrender(sender) {
- const me = this
- const {config} = this
- const {dataSource} = config
- if (config.autoLoad) {
- if (config.dataSourceCallbackFn) {
- me.reload()
- } else if (_.isPlainObject(dataSource)) {
- me.reload()
- }
- }
- if (config.contextMenu === true && _.isArray(config.tbar)) {
- const vm = this.lookupViewModel()
- this.contextMenu = this.add(new Ext.menu.Menu({
- viewModel: vm,
- items: _.map(config.tbar, item => {
- const menuItem = {
- ...item
- }
- if (menuItem.xtype === 'button') {
- delete menuItem.xtype
- }
- return menuItem
- })
- }))
- } else if (_.isPlainObject(config.contextMenu)) {
- this.contextMenu = this.add(config.contextMenu)
- }
- const $dom = $(sender.el.dom)
- $dom.on('keydown', (e) => {
- me.fireEvent('keydown', me, e,)
- }).on('keyup', (e) => {
- me.fireEvent('keyup', me, e,)
- })
- },
- itemcontextmenu(view, rec, node, index, e) {
- if (this.contextMenu) {
- e.stopEvent();
- this.contextMenu.show().setLocalXY(e.getXY());
- return false;
- }
- },
- // columnmove(sender, column, fromIndex, toIndex, eOpts) {
- // this.setColumnConfigCache()
- // },
- // columnhide(sender, column, eOpts) {
- // this.setColumnConfigCache()
- // },
- // columnshow(sender, column, eOpts) {
- // this.setColumnConfigCache()
- // },
- // columnresize(sender, column, width, eOpts) {
- // this.setColumnConfigCache()
- // },
- destory() {
- },
- })
- if (this.store?.proxy) {
- // 为 stores.proxy.buildRequest 做准备
- this.store.proxy.$owner = this
- }
- this.superclass.initComponent.call(this)
- },
- // 生成列自定义的缓存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) {
- sender.up('grid').filters.clearFilters();
- },
- saveGridUIConfig(sender) {
- const grid = sender.up('grid')
- grid.setColumnConfigCache()
- msg('保存设置成功!')
- },
- clearGridUIConfig(sender) {
- const grid = sender.up('grid')
- const key = grid.columnConfigCacheKey
- localStorage.setItem(key, "")
- msg('清空设置成功,重新打开后生效!')
- },
- setLoading(value) {
- if (value) {
- this.mask('读取中')
- } else {
- this.unmask()
- }
- },
- exportExcel(sender) {
- const rect = sender.btnEl.dom.getBoundingClientRect()
- const scope = lookupScope(this)
- const grid = sender.up('grid')
- const treeMenu = new Ext.menu.Menu(
- {
- xtype: 'menu',
- floated: false,
- width: 300,
- docked: 'left',
- items: [{
- text: '导出表格当前的数据',
- iconCls: 'x-fa fa-download',
- listeners: {
- click: (sender, value) => {
- grid.exportCurrentExcelClick()
- }
- }
- }, {
- xtype: "textfield",
- fieldLabel: '当前导出页',
- maskRe: /[0-9]/,
- value: grid.exportExcelCurrentPage,
- listeners: {
- render: (sender) => {
- grid.exportExcelCurrentPageCmp = sender
- },
- change: (sender, value) => {
- let v = parseInt(value)
- if (isNaN(v) || v === 0) {
- window['system'].msg("页码不能为0")
- v = 1
- sender.setValue(v)
- }
- const size = parseInt(grid.exportExcelPageSize)
- const total = parseInt(grid.exportExcelTotal)
- if (v > total / size) {
- v = parseInt(total / size + "")
- }
- grid.exportExcelCurrentPage = v + ""
- }
- }
- }, {
- xtype: "textfield",
- fieldLabel: '导出页大小',
- maskRe: /[0-9]/,
- value: grid.exportExcelPageSize,
- listeners: {
- render: (sender) => {
- grid.exportExcelPageSizeCmp = sender
- },
- change: (sender, value) => {
- let v = parseInt(value)
- if (isNaN(v) || v === 0) {
- window['system'].msg("导出页大小不能为0")
- v = defaultGrid.exportExcelPageSize
- sender.setValue(v);
- }
- if (v >= 10000) {
- window['system'].msg("导出页大小不能大于10000")
- v = 10000
- sender.setValue(v);
- }
- let page = parseInt(grid.exportExcelCurrentPage)
- const total = parseInt(grid.exportExcelTotal)
- if (page > total / v) {
- page = parseInt(total / v + "") + 1
- grid.exportExcelCurrentPageCmp.setValue(page)
- }
- grid.exportExcelPageSize = v + ""
- }
- }
- }, {
- xtype: "textfield",
- fieldLabel: '总条数',
- value: grid.exportExcelTotal,
- readOnly: true
- }, {
- text: '导出',
- iconCls: 'x-fa fa-download',
- listeners: {
- click: (sender, value) => {
- grid.exportExcelClick({
- exportExcelPageSize: grid.exportExcelPageSize,
- exportExcelCurrentPage: grid.exportExcelCurrentPage
- })
- }
- }
- }]
- }
- );
- treeMenu.showAt(rect.left, rect.top - 120);
- // 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);
- // }
- }
- // reload() {
- // dataSourceReload(this)
- // },
- })
- 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('无法识别的调用方法')
- }
|