常规功能和模块自定义系统 (cfcmms)—019自定义grid方案(3)
这一节开始进入自定义的内部,来看看第一个自定义的功能是如何实现的。
1、在系统登录的时候,将所有的登录用户有权限的模块定义信息全部发送到前端。这段代码在app/view/main/MainModel.js中。在MainModel创建的时候,通过会发送一个同步的ajax请求来获取数据。取得数据后将所有的module信息放到MainView的data中。
Ext.Ajax
.request({
url : 'applicationinfo.do',
async : false, // 同步
success : function(response) {
var text = response.responseText;
var applicationInfo = Ext.decode(text, true);
applicationInfo.tf_previewExts = applicationInfo.tf_previewExts
.split(',');
for (i in applicationInfo.modules) {
var moduleinfo = applicationInfo.modules[i];
for (j in applicationInfo.roleInfo.tf_userRoleDetails) {
if (applicationInfo.roleInfo.tf_userRoleDetails[j].tf_moduleId == moduleinfo.tf_moduleId) {
//加入每个模块的权限信息
moduleinfo.tf_userRole = applicationInfo.roleInfo.tf_userRoleDetails[j];
break;
}
}
if (!moduleinfo.tf_userRole)
moduleinfo.tf_userRole = {};
// 给每个模块创建一个ModuleInfo的模块信息类
me.data.modules.add(moduleinfo.tf_moduleName,
new Ext.create('app.module.ModuleInfo', moduleinfo));
}
delete applicationInfo.modules;
delete applicationInfo.roleInfo.tf_userRoleDetails;
Ext.apply(me.data, applicationInfo);
}
});
“省份”模块的所有从后台加载过来的数据如下图所示:
2、在创建模块显示的时候,会根据tf_gridSchemes中的定义来生成grid的columns。在app/module/factory/中建立了一个columnsFactory.js用来根据模块的grid的定义来生成columns。其主要的一段代码如下:
/**
* module是模块的字义,schemeOrderId 为要生成的columns的 顺序号,不指定顺序号,则默认第一个方案
*/
getColumns : function(module, schemeOrderId) {
var scheme = module.getGridScheme(schemeOrderId);
var columns = [];
// 是否有附件,有附件则加入附件按钮
if (module.tf_hasAttachment
&& module.tf_userRole.tf_attachmentBrowse)
columns.push({
locked : true,
xtype : 'attachmentnumbercolumn'
});
// 是否模块具有审核功能
if (module.tf_hasAuditing) {
columns.push({
locked : true,
xtype : 'auditingactioncolumn'
});
}
// 是否模块具有审批功能
if (module.tf_hasApprove) {
columns.push({
locked : true,
xtype : 'approveactioncolumn'
});
}
// 是否模块具有支付功能
if (module.tf_hasPayment) {
columns.push({
locked : true,
xtype : 'payoutactioncolumn'
});
}
// 如果是附件模块,加一个可以预览的列
if (module.tf_moduleName == '_Attachment') {
columns
.push({
dataIndex : 'tf_attachmentId',
text : '预览',
align : 'center',
menuDisabled : true,
sortable : true,
width : 56,
resizable : false,
renderer : function(val, rd, model) {
if (model.get('tf_filename'))
return '<img height="16" width="16" src="attachment/preview.do?id='
+ model.get('tf_attachmentId') + '" />';
else
return '<img height="16" width="16" src="" />';
}
});
}
// 如果模块有记录icon,则加入记录字段icon列
if (module.tf_hasRecordIcon){
columns.push({
xtype : 'recordiconcolumn'
})
}
for ( var i in scheme.tf_schemeGroups) {
var sg = scheme.tf_schemeGroups[i];
// 是否需要分组
var isgroup = sg.tf_isShowHeaderSpans;
var group = {
gridGroupId : sg.tf_gridGroupId,
text : sg.tf_gridGroupName,
locked : sg.tf_isLocked,
columns : []
};
for ( var j in sg.tf_groupFields) {
var gf = sg.tf_groupFields[j];
var fd = module.getFieldDefine(gf.tf_fieldId);
var field;
if (fd) {
if (fd.tf_isHidden)
continue;
field = this.getColumn(gf, fd, module);
} else { // 如果不是本模块的基本字段,那么在附加字段中找(可能是父模块,祖父模块的字段,或者子模块的聚合字段)
var fd = module.getAdditionFieldDefine(gf.tf_fieldId);
field = this.getColumn(gf, fd, module);
if (field.dataIndex.search('C_') == 0) {
field.moduleName = field.dataIndex.slice(2);
field.renderer = this.childCountFieldRenderer;
}
}
field.locked = sg.tf_isLocked || gf.tf_isLocked;
// 如果列显示字段有附加的属性,如renderer 可以放在这里加入进去
if (gf.tf_otherSetting) {
try {
eval('Ext.apply(field,' + gf.tf_otherSetting + ')');
} catch (err) {
}
}
if (isgroup) {
this.canReduceTitle(group, field);
group.columns.push(field);
} else
columns.push(field);
}
if (isgroup) {
this.canReduceTitle(group, field);
columns.push(group);
}
}
console.log(columns);
return columns;
}
上面这段代码首先根据模块的设置,判断是否有一些独立的信息显示字段,例如附件、图标、预览列等。然后将gridScheme中的分组定义依次加入到columns中。在加入的时候还要判断是否显示分组。
这里处理了一个title显示的问题,例如有个分组的名称叫:“本年”,而分组下的字段名叫 “本年新增金额”,那么字段名中的“本年”将是可以被省掉的,下面的函数用来处理这个操作。
// 看看分组名称是不是 下面column 的开头,如果是开头的话,并且columntitle 后面有内容,就把
// 相同的部分截掉
canReduceTitle : function(group, field) {
if (field.text.indexOf(group.text) == 0) {
field.text = field.text.slice(group.text.length).replace('(',
'').replace(')', '').replace('(', '').replace(')', '');
if (field.text.indexOf("<br/>") == 0)
field.text = field.text.slice(5);
}
},
如果一个字段有计量单位,那么需要在表头里显示一下。
getTextAndUnit : function(fd) {
var result = fd.tf_title.replace(new RegExp('--', 'gm'), '<br/>');// title中间有--表示换行
var unitText = Ext.monetary.unitText === '个' ? ''
: Ext.monetary.unitText;
if (fd.tf_isMonetary && Ext.monetaryPosition === 'columntitle') {// 可能选择金额单位千,万,百万,亿
if (fd.tf_unitText || unitText)
result += '<br/><span style="color:green;">(' + unitText
+ (fd.tf_unitText ? fd.tf_unitText : '') + ')</span>';
} else {
if (fd.tf_unitText)
result += '<br/><span style="color:green;">('
+ fd.tf_unitText + ')</span>';
}
return result;
},
其中还有一个 getColumn函数是用来生成每一列的定义的。
/**
* 根据groupField,fieldDefine的定义,生成一个column的定义
*/
getColumn : function(gf, fd, module) {
var field = {
filter : {},
maxWidth : 800,
fieldDefine : fd,
gridFieldId : gf.tf_gridFieldId, // 加上这个属性,用于在列改变了宽度过后,传到后台
sortable : true,
text : this.getTextAndUnit(fd),
dataIndex : (fd.baseField || fd.tf_aggregate) ? fd.tf_fieldName
: fd.manytoone_TitleName
};
if (fd.tf_tooltipTpl) {
field.tooltipTpl = fd.tf_tooltipTpl; // 显示在字段值上的tooltip的tpl值
field.tooltipXTemplate = new Ext.XTemplate(fd.tf_tooltipTpl);
}
if (gf.tf_ishidden)
field.hidden = true;
// 如果是此人可以审批的字段,那么加上一个可以审批的标记
if (module.tf_hasApprove
&& module.tf_userRole.tf_approveOrder >= 1) {
if (field.dataIndex.indexOf('tf_sh') == 0
&& field.dataIndex.substr(field.dataIndex.length - 1, 1) == module.tf_userRole.tf_approveOrder)
field.text = '<span class="approvethisgridheadicon" >'
+ '<img src="images/approve/approve_edit.png" />'
+ fd.tf_title + '</span>';
}
switch (fd.tf_fieldType) {
case 'Image':
Ext.apply(field, {
xtype : 'imagecolumn',
align : 'center',
width : 100,
});
break;
case 'Date':
Ext.apply(field, {
xtype : 'datecolumn',
align : 'center',
width : 100,
renderer : Ext.util.Format.dateRenderer
});
break;
case 'Datetime':
Ext.apply(field, {
xtype : 'datecolumn',
align : 'center',
width : 130,
renderer : Ext.util.Format.dateRenderer
});
break;
case 'Boolean':
field.xtype = 'checkcolumn';
field.stopSelection = false;
field.processEvent = function(type) {
if (type == 'click')
return false;
};
break;
case 'Integer':
Ext.apply(field, {
align : 'right',
xtype : 'numbercolumn',
tdCls : 'intcolor',
format : '#',
renderer : Ext.util.Format.intRenderer
});
break;
case 'Double':
Ext.apply(field, {
align : 'right',
xtype : 'numbercolumn',
width : 110,
renderer : Ext.util.Format.floatRenderer
});
break;
case 'Float':
Ext.apply(field, {
align : 'right',
xtype : 'numbercolumn',
width : 110,
renderer : Ext.util.Format.floatRenderer
});
break;
case 'Percent':
Ext.apply(field, {
align : 'center',
xtype : 'widgetcolumn',
width : 110,
// renderer : Ext.util.Format.percentRenderer
widget : {
xtype : 'progressbarwidget',
animate : true,
textTpl : [ '{percent:number("0")}%' ]
}
});
break;
case 'String':
if (module.tf_nameFields == fd.tf_fieldName)
Ext.apply(field, {
text : '<span class="fa fa-key"> ' + fd.tf_title
+ '</span>',
renderer : Ext.util.Format.nameFieldRenderer,
summaryType : 'count',
summaryRenderer : function(value) {
return Ext.String.format('小计 ( {0} 条记录)', value);
}
});
else
Ext.apply(field, {
renderer : Ext.util.Format.defaultRenderer
});
break;
default:
Ext.apply(field, {
renderer : Ext.util.Format.defaultRenderer
});
break;
}
if (fd.s) { // tf_allowSummary
Ext.apply(field, {
hasSummary : true,
summaryType : 'sum'
});
}
// 如果是可以改变显示单位的数值,可以选择万,千,百万,亿
if (fd.tf_isMonetary)
field.renderer = Ext.util.Format.monetaryRenderer;
if (gf.tf_columnWidth > 0)
field.width = gf.tf_columnWidth;
else if (gf.tf_columnWidth == -1) {
field.flex = 1;
field.minWidth = 120;
}
if (fd.manytoone_TitleName) {
var pmodule = app.modules.getModuleInfo(fd.tf_fieldType);
var icon = '';
if (pmodule && pmodule.iconURL)
icon = '<img src="' + pmodule.iconURL + '" />';
Ext.apply(field, {
renderer : Ext.util.Format.manytoOneFieldRenderer,
text : '<span class="gridheadicon" >' + icon + fd.tf_title
+ '</span>',
manytooneIdName : fd.manytoone_IdName,
moduleName : fd.tf_fieldType
});
}
// 如果一个字段是一个附加字段,这个字段正好是父模块的父模块的一个namefileds字段,那么也要加成单击可以显示的功能
// P__t1020___tf_title,例如这样的
if (Ext.String.startsWith(fd.tf_fieldName, "P_")) {
var fn = fd.tf_fieldName;
var ppAsName = fn.substring(2, 10);
if (ppAsName[6] == '_')
ppAsName = ppAsName.substring(0, 6);
var pmodule = app.modules.getModuleInfo(ppAsName);
if (Ext.String.endsWith(fn, pmodule.tf_nameFields)) {
var icon = '';
if (pmodule && pmodule.iconURL)
icon = '<img src="' + pmodule.iconURL + '" />';
Ext.apply(field, {
renderer : Ext.util.Format.manytoOneFieldRenderer,
text : '<span class="gridheadicon" >' + icon
+ fd.tf_title.replace(new RegExp('--', 'gm'), '<br/>')
+ '</span>',
manytooneIdName : pmodule.tableAsName + '___'
+ pmodule.tf_primaryKey,
moduleName : pmodule.tf_moduleName
});
}
}
return field;
},
还有一些函数是用来生成父级模块记录链接字段和子模块聚合字段,详见程序。
通过以上的这些函数就可以根据配置信息动态的生成一个grid所需要的各个列了。