030开发日志(创建ManyToMany的column5)
现在对于这个字段来说,还剩最后一个功能了,那就是可以修改ManyToMany的值了。在grid的inline操作里面,是可以直接删除已有值,但是如果要新增的话,就必须要有一个新的界面了。下面来看看开发修改ManyToMany字段所需要的步骤。
1、创建一个修改窗口,在里面创建一个可check的树;
2、到后台请求数据,读取当前记录的所有的ManyToMany的可选项,并把已经选中的打勾;
3、根据读取到的数据更新树;
4、用户操作check 和 uncheck;
5、保存修改,使用ajax 将修改过后的ManyToMany中打勾的选项发送到后台,执行保存功能;
6、刷新当前记录,显示正确的ManyToMany值。
在以上的步骤中可以看出,对于所有的ManyToMany字段的修改都是用这一个办法。上面步骤中比较难的就是如何根据前台的请求生成模块该记录的ManyToMany的所有选项并把已经选中的打勾,以及保存修改过后的值。对于本系统而言,所有的方法尽量都是通用的,因此有些功能的开发比较困难。
在进行第2步操作时,前台应传给后台的参数应该有:当前模块名称,当前记录id,ManyToMany的模块名称,中间模块的名称。
同样在进行第5步操作的时候,也要传给后台第2步的参数,并加上当前所有选中ManyToMany的值。
接着前一节的ManyToManyColumn.js,来修改一下当用户单击修改按钮的时候要进行的操作。
processEvent : function(type, view, cell, recordIndex, cellIndex, e,
record, row) {
var me = this;
if (type === 'click') {
var module = this.up('modulegrid').module;
if (e.getTarget().className === 'manyToManyContext') {
app.modules.showModuleRecord(this.manyToManyModuleName, e
.getTarget().getAttribute('_id'));
} else if (Ext.String.startsWith(e.getTarget().className,
'manyToManyContextClose')) {
// 点击了删除按钮,先找到前面一个节点,里面包含了要删除的信息
var target = e.getTarget().previousElementSibling;
var text = module.tf_title + ' ' + record.getTitleTpl() + ' 的 '
+ this.manyToManyModuleTitle + '【' + target.innerHTML + '】';
Ext.MessageBox.confirm('确定删除', '确定要删除' + text + '吗?', function(
btn) {
if (btn == 'yes') {
// 使用module里面批量删除的ajax
Ext.Ajax.request({
url : 'rest/module/removerecords.do',
params : {
moduleName : me.fieldDefine.tf_joinTable,
ids : target.getAttribute('_joinid'),
titles : target.innerHTML
},
success : function(response) {
var info = Ext.decode(response.responseText, true);
if (info.resultCode == 0) {
Ext.toastInfo(text + ' 已成功被删除。');
// 删除记录后,刷新当前记录
me.up('modulegrid').refreshSelectedRecord();
} else {
Ext.MessageBox.show({
title : '删除结果',
msg : text + '删除失败:<br/><br/>'
+ info.errorMessageList,
buttons : Ext.MessageBox.OK,
icon : Ext.MessageBox.ERROR
});
}
},
failure : function() {
window.alert('删除时,服务器返回返回错误');
}
})
}
});
} else if (Ext.String.startsWith(e.getTarget().className,
'manyToManyEdit')) {
//编辑当前记录的manyToMany字段;
Ext.widget(
'manytomanyeditwindow',
{
grid : me.up('modulegrid'),
title : module.tf_title + '【' + record.getTitleTpl()
+ '】的' + this.manyToManyModuleTitle,
moduleName : module.tf_moduleName,
idvalue : record.getIdValue(),
manyToManyModuleName : me.manyToManyModuleName,
linkModuleName : me.fieldDefine.tf_joinTable
}).show();
}
}
}
在上面的代码中可以看出,如果单击了修改按钮,会去创建一个manytomanyeditwindow。在这个window中完成上面的6步操作。
/**
* 修改记录的manyToMany字段的窗口,在窗口中完成选择操作,并可保存。
*/
Ext.define('app.module.widget.window.ManyToManyEditWindow', {
extend : 'Ext.window.Window',
alias : 'widget.manytomanyeditwindow',
requires : [ 'app.lib.CheckTreePanel' ],
width : 450,
height : 600,
modal : true,
maximizable : true,
layout : 'fit',
buttons : [ '->', {
text : '保存',
iconCls : 'fa fa-save',
handler : function(button) {
var window = button.up('window');
var tree = window.down('treepanel');
var selected = []
tree.getRootNode().cascadeBy(function(node) {
// 所有选中的 ManyToMany 的值
if (node.data.checked == true && node.data.leaf == true) {
selected.push(node.data.fieldvalue);
}
});
// 提交ajax请求后台修改
Ext.Ajax.request({
url : 'modulemanytomany/setmanytomanydetail.do',
params : {
moduleName : window.moduleName,
id : window.idvalue,
manyToManyModuleName : window.manyToManyModuleName,
linkModuleName : window.linkModuleName,
selected : selected.join(',')
},
success : function(response) {
var info = Ext.decode(response.responseText, true);
if (info.success) {
Ext.toastInfo(window.titlemess + ' 已保存。');
window.grid.refreshSelectedRecord();
window.close();
} else
Ext.toastError(window.titlemess + ' 保存失败。<br>' + '原因:' + info.msg);
}
})
}
}, {
text : '关闭',
iconCls : 'fa fa-close',
handler : function(button) {
button.up('window').close();
}
}, '->' ],
initComponent : function() {
var me = this;
this.titlemess = this.title;
this.title = '设置 ' + this.titlemess;
this.items = [ {
xtype : 'checktreepanel',
autoLoad : false,
rootVisible : false,
root : {},
store : Ext.create('Ext.data.TreeStore', {
proxy : {
type : 'ajax',
url : 'modulemanytomany/getmanytomanydetail.do',
extraParams : {
moduleName : me.moduleName,
id : me.idvalue,
manyToManyModuleName : me.manyToManyModuleName,
linkModuleName : me.linkModuleName
}
}
})
} ];
this.callParent(arguments);
}
})
这是前台的界面操作的代码,那么后台要处理上面所述的第2,第5步。需要新增一个Controller类来接收ajax请求。下面这个是控制类:
package com.jfok.cfcmms.controller;
import java.util.List;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.jfok.cfcmms.service.ModuleManyToManyService;
import com.jfok.cfcmms.share.TreeNodeRecordChecked;
import com.jfok.cfcmms.util.ActionResult;
/**
* 用来管理模块的ManyToMany数据的读取和修改的保存
*
* @author jiangfeng
*
* 2016-01-11
*
*/
@Controller
@RequestMapping("/modulemanytomany")
public class ModuleManyToManyController {
@Resource
private ModuleManyToManyService moduleManyToManyService;
/**
*
* @param request
* @param moduleName
* 当前模块名称
* @param id
* 当前记录id
* @param manyToManyModuleName
* manyToMany的模块名称
* @param linkModuleName
* 中间模块名称
* @return 返回所有manyToManyModuleName的记录数据,并把当前记录已有的manyToMany值的checked置为true
*/
@RequestMapping("/getmanytomanydetail.do")
public @ResponseBody List<TreeNodeRecordChecked> genManyToManyDetail(HttpServletRequest request,
String moduleName, String id, String manyToManyModuleName, String linkModuleName) {
return moduleManyToManyService.getManyToManyDetail(request, moduleName, id,
manyToManyModuleName, linkModuleName);
}
/**
*
* @param request
* @param moduleName
* 当前模块名称
* @param id
* 当前记录id
* @param manyToManyModuleName
* manyToMany的模块名称
* @param linkModuleName
* 中间模块名称
* @param selected
* 所有选中的值,以逗号分隔
* @return 返回所有manyToManyModuleName的记录数据,并把当前记录已有的manyToMany值的checked置为true
*/
@RequestMapping("/setmanytomanydetail.do")
public @ResponseBody ActionResult setManyToManyDetail(HttpServletRequest request,
String moduleName, String id, String manyToManyModuleName, String linkModuleName,
String selected) {
return moduleManyToManyService.setManyToManyDetail(request, moduleName, id,
manyToManyModuleName, linkModuleName, selected.split(","));
}
}
最后一个就是用来处理请求的Service类了,这个类也是这个功能的关键。由他来完成系统中所有的类似的ManyToMany字段读取和修改的操作。
package com.jfok.cfcmms.service;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import com.jfok.cfcmms.DAO.ModuleDAO;
import com.jfok.cfcmms.DAO.SystemBaseDAO;
import com.jfok.cfcmms.core.module.SqlGenerator;
import com.jfok.cfcmms.core.module.SqlModuleFilter;
import com.jfok.cfcmms.hibernate.system.module._Module;
import com.jfok.cfcmms.share.TreeNodeRecord;
import com.jfok.cfcmms.share.TreeNodeRecordChecked;
import com.jfok.cfcmms.share.ValueText;
import com.jfok.cfcmms.util.ActionResult;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
@Service
public class ModuleManyToManyService {
@Resource
private SystemBaseDAO systemBaseDAO;
@Resource
private ModuleDAO moduleDAO;
@Resource
private ModuleService moduleService;
/**
*
* @param request
* @param moduleName
* 当前模块名称
* @param id
* 当前记录id
* @param manyToManyModuleName
* manyToMany的模块名称
* @param linkModuleName
* 中间模块名称
* @return 返回所有manyToManyModuleName的记录数据,并把当前记录已有的manyToMany值的checked置为true
*/
@Transactional(propagation = Propagation.REQUIRED, readOnly = true)
public List<TreeNodeRecordChecked> getManyToManyDetail(HttpServletRequest request,
String moduleName, String id, String manyToManyModuleName, String linkModuleName) {
_Module module = SystemAndLoginInfoService.getModuleWithName(moduleName);
_Module manyToManyModule = SystemAndLoginInfoService.getModuleWithName(manyToManyModuleName);
List<TreeNodeRecord> result = new ArrayList<TreeNodeRecord>();
// 首先读取manyToManyModuleName中的所有权限可视范围之内的数据
List<ValueText> allTreeItems = moduleDAO.getModuleWithComboDataWithQuery(manyToManyModuleName,
null, request);
for (ValueText vt : allTreeItems) {
TreeNodeRecordChecked record = new TreeNodeRecordChecked();
record.setFieldvalue(vt.getValue());
record.setText(vt.getText());
record.setLeaf(true);
result.add(record);
}
// 在linkModuleName中读取当前id的manyToMany的值,在数据可视涠之内
List<SqlModuleFilter> filters = new ArrayList<SqlModuleFilter>();
SqlModuleFilter moduleIdFilter = new SqlModuleFilter();
moduleIdFilter.setModuleName(module.getTf_moduleName());
moduleIdFilter.setTableAsName(module.getTableAsName());
moduleIdFilter.setPrimarykey(module.getTf_primaryKey());
moduleIdFilter.setEqualsValue(id);
filters.add(moduleIdFilter);
SqlGenerator generator = new SqlGenerator(linkModuleName, request);
generator.setModuleFilters(filters);
JSONArray dataArray = moduleDAO.getData(generator, -1, 0);
// 生成TreeNodeRecordChecked,并加入checked标志
for (int i = 0; i < dataArray.size(); i++) {
String manytomanyid = dataArray.getJSONObject(i).getString(
manyToManyModule.getTableAsName() + "___" + manyToManyModule.getTf_primaryKey());
for (TreeNodeRecord record : result) {
if (record.getFieldvalue().equals(manytomanyid))
((TreeNodeRecordChecked) record).setChecked(true);
}
}
// 返回结果
List<TreeNodeRecordChecked> root = new ArrayList<TreeNodeRecordChecked>();
TreeNodeRecordChecked rootrecord = new TreeNodeRecordChecked();
rootrecord.setText(manyToManyModule.getTf_title());
rootrecord.setChildren(result);
rootrecord.setExpanded(true);
root.add(rootrecord);
return root;
}
public ActionResult setManyToManyDetail(HttpServletRequest request, String moduleName, String id,
String manyToManyModuleName, String linkModuleName, String[] selected) {
_Module module = SystemAndLoginInfoService.getModuleWithName(moduleName);
_Module manyToManyModule = SystemAndLoginInfoService.getModuleWithName(manyToManyModuleName);
_Module linkedModule = SystemAndLoginInfoService.getModuleWithName(linkModuleName);
// 在linkModuleName中读取当前id的manyToMany的值,在数据可视涠之内
List<SqlModuleFilter> filters = new ArrayList<SqlModuleFilter>();
SqlModuleFilter moduleIdFilter = new SqlModuleFilter();
moduleIdFilter.setModuleName(module.getTf_moduleName());
moduleIdFilter.setTableAsName(module.getTableAsName());
moduleIdFilter.setPrimarykey(module.getTf_primaryKey());
moduleIdFilter.setEqualsValue(id);
filters.add(moduleIdFilter);
SqlGenerator generator = new SqlGenerator(linkModuleName, request);
generator.setModuleFilters(filters);
JSONArray dataArray = moduleDAO.getData(generator, -1, 0);
// 如果原来有,现在selected里面没有了,那么就要删除了
for (int i = 0; i < dataArray.size(); i++) {
String manytomanyid = dataArray.getJSONObject(i).getString(
manyToManyModule.getTableAsName() + "___" + manyToManyModule.getTf_primaryKey());
boolean isfound = false;
for (String selectedid : selected) {
if (manytomanyid.equals(selectedid)) {
isfound = true;
break;
}
}
if (!isfound) {
// 需要删除这个manyTomany,调用系统Service的remove,会判断能否删除的逻辑,会记入日志
// 尚未做出错处理
moduleService.remove(linkModuleName,
dataArray.getJSONObject(i).getString(linkedModule.getTf_primaryKey()), request);
}
}
// 如果原来没有,现在selected里面有了,那么就要增加进去
for (String selectedid : selected) {
if (selectedid.length() > 0) {
boolean isfound = false;
for (int i = 0; i < dataArray.size(); i++) {
String manytomanyid = dataArray.getJSONObject(i).getString(
manyToManyModule.getTableAsName() + "___" + manyToManyModule.getTf_primaryKey());
if (manytomanyid.equals(selectedid)) {
isfound = true;
break;
}
}
if (!isfound) {
JSONObject object = new JSONObject();
object.put(
manyToManyModule.getTableAsName() + "___" + manyToManyModule.getTf_primaryKey(),
selectedid);
object.put(module.getTableAsName() + "___" + module.getTf_primaryKey(), id);
// 需要新增这个manyTomany,调用系统Service的add ,会判断是否能新增等逻辑,会记入日志
// 尚未做出错处理
moduleService.add(linkModuleName, object.toString(), request);
}
}
}
ActionResult result = new ActionResult();
return result;
}
}
经过以上代码的协同工作,我们可以打开人员的设置权限的窗口来进行权限设置了。
修改一些用户操作角色,然后保存。
至此用户的ManyToMany字段操作角色的修改即可完成。
对于操作角色来说,用户也是一个ManyToMany字段,同样也适用于这样操作。
至此ManyToMany字段的定义、显示、操作都基本完成。
进阶设想:
对于选择tree的改进。在我现在的系统里,在用户模块中,有一个设置权限的按钮,其实就是完成了ManyToMany字段的选择与保存,有了这个字段功能之后,这个设置权限的按钮就可以不要了。但是有一点是不一样的,看看下面的截图:
在上图的选择角色的窗口的tree中,角色是按照角色分组来进行分类的,这样在选择的时候可以更直观。以后的ManyToMany字段的选择树也要做成可以配置成这样的结构。这里我大体先写一下思路:
1、在模块配置中新增一个配置字段:ManyToMany选择时候的树形模块路径;
2、在某个模块被当作ManyToMany字段来选择的时候,读取其模块路径,然后把当前模块的值都加在相应的节点之下。
比如对于角色来选择人员来说,可以把部门作为人员的模块路径,这样在选择树中,先是部门的值,然后人员会挂在相应的部门之下来进行选择。
(这个功能以后有时间再做了)