Dorado 5 : 7.4.产品目录树维护 (T22)

概述

本示例是一个常见的产品目录树的演示。本示例链接如下:

 

准备工作

新建一工程producttree,并且配置好数据库,具体步骤参考3.1.2节。

开发步骤

添加Dataset

步骤1:添加一Common ViewModel,文件名为ProductTree。
步骤2:添加该ViewModel的实现,代码如下:

import java.util.List;
import com.bstek.dorado.data.Dataset;
import com.bstek.dorado.data.ParameterSet;
import com.bstek.dorado.data.Record;
import com.bstek.dorado.data.RecordIterator;
import com.bstek.dorado.data.db.DBStatement;
import com.bstek.dorado.utils.variant.VariantSet;
import com.bstek.dorado.view.DefaultViewModel;
/**
 * ProductTreeViewModel
 */
public class ProductTreeViewModel extends DefaultViewModel {
    protected void doUpdateData(ParameterSet parameters,
            ParameterSet outParameters) throws Exception {
        DBStatement stCategory = new DBStatement();
        stCategory.setSql(DBStatement.SELECT, "category");
        DBStatement stDelCategory = new DBStatement();
        stDelCategory.setSql(DBStatement.DELETE, "category");
        DBStatement stDelProduct = new DBStatement();
        stDelProduct.setSql(DBStatement.DELETE, "product");
        try {
            Dataset datasetCategory = getDataset("datasetCategory");
            RecordIterator iter = datasetCategory.recordIterator();
            iter.setVisibility(Dataset.FILTER_DELETED);
            while (iter.hasNext()) {
                Record record = iter.nextRecord();
                deleteChildCategory(record.getString("category_id"),
                        stCategory, stDelCategory, stDelProduct);
            }
        } finally {
            stCategory.close();
            stDelCategory.close();
            stDelProduct.close();
        }
        super.doUpdateData(parameters, outParameters);
    }
    private void deleteChildCategory(String categoryId, DBStatement stCategory,
            DBStatement stDelCategory, DBStatement stDelProduct)
            throws Exception {
        stCategory.parameters().setString("parent_id", categoryId);
        List list = stCategory.queryForList();
        int size = list.size();
        for (int i = 0; i < size; i++) {
            VariantSet category = (VariantSet) list.get(i);
            deleteChildCategory(category.getString("category_id"), stCategory,
                    stDelCategory, stDelProduct);
        }
        stDelCategory.parameters().setString("category_id", categoryId);
        stDelCategory.execute();
        stDelProduct.parameters().setString("category_id", categoryId);
        stDelProduct.execute();
    }
}

步骤3:添加一CustomDataset,id设置为datasetRoot,添加两个字段,分别为category_id,category_name。
步骤4:为datasetRoot添加一Dataset Listener,代码如下:

import com.bstek.dorado.data.AbstractDatasetListener;
import com.bstek.dorado.data.Dataset;
/**
 * ProductTree_datasetRootListener
 */
public class ProductTree_datasetRootListener extends AbstractDatasetListener {
    public void afterLoadData(Dataset dataset) throws Exception {
        dataset.insertRecord();
        dataset.setString("category_id", "$null");
        dataset.setString("category_name", "<产品目录>");
    }
}

步骤5:添加一AutoSqlDataset,选择Category表,选择所有列,属性设置如下:

属性

id

datasetCategory

originTable

category

keyFields

category_id

为AutoSqlDataset的Field的category_id和category_name添加"Vlidator-Required",添加位置如下图所示:

为AutoSqlDataset添加一BaseMatchRule,属性设置如下:

属性

level

1

dataType

string

value

:parent_id

escapeEnabled

true

table

category

originField

parent_id

operator

=

为AutoSqlDataset添加一Parameter,属性设置如下:

属性

name

parent_id

value

$null

为datasetCategory的beforeDelete事件添加如下代码:

var category_id = parseInt(record.getValue("category_id"));
if (record.getString("parent_id") == "" && (category_id == 1 || category_id == 2 || category_id == 3)) {
	  return "处于演示数据的安全考虑,本例不允许您删除顶层的分类!";}

步骤6:添加一AutoSqlDataset,选择Product表,选择所有字段,属性设置如下:

属性

id

datasetProduct

originTable

product

keyFields

product_id

为AutoSqlDataset的Field的product_id、category_id和product_name添加"Vlidator-Required"
为AutoSqlDataset添加三个BaseMatchRule,属性设置分别如下:

属性

level

1

dataType

string

value

:category_id

escapeEnabled

true

table

product

originField

category_id

operator

=

属性

level

1

dataType

string

value

:product_id

escapeEnabled

true

table

product

originField

product_id

operator

=

属性

level

1

dataType

string

value

:product_name

escapeEnabled

true

table

product

originField

product_name

operator

like

 

添加DataTree

步骤1:添加一DataTree,属性设置如下:

属性

id

treeProduct

height

100%

width

100%

draggable

true

步骤2:为treeProduct添加一Simple Tree Level,属性设置如下:

属性

name

root

dataset

datasetRoot

labelField

category_name

expanded

true

步骤3:为root添加一Recursive Tree Level,属性设置如下:

属性

name

category

dataset

datasetCategory

recursiveKeyFields

category_id

recursiveKeyParameters

parent_id

labelField

category_name

detailKeyParameters

parent_id

masterKeyFields

category_id

步骤4:为product添加一Simple Tree Level,属性设置如下:

属性

name

product

dataset

datasetProduct

masterKeyFields

category_id

detailKeyParameters

category_id

labelField

product_name

hasChild

false

步骤5:为treeProduct的beforeCurrentChange事件添加如下代码:

if (node.getLevel() == 1) { 
	return new AbortException(); 
}

为treeProduct的afterCurrentChange事件添加如下代码:

if (node == null) return; 
 
if (node.getTreeLevel().getName() == "category") { 
	 tabsetDetail.setCurrentTab("category"); 
} 
else { 
	 tabsetDetail.setCurrentTab("product"); 
}

为treeProduct的onDragOver事件添加如下代码:

var draggingLevel = draggingObject.getTreeLevel().getName();
var targetLevel = targetObject.getTreeLevel().getName();
if (draggingLevel == "category") {
  return (targetLevel == "root" || targetLevel == "category");
}
else if (draggingLevel == "product") {
  return (targetLevel == "category");
}

为treeProduct的onDragEnd事件添加如下代码:

var draggingLevel = draggingObject.getTreeLevel().getName();
var targetLevel = targetObject.getTreeLevel().getName();
var draggingRecord = draggingObject.getRecord();
var targetRecord = targetObject.getRecord();
if (draggingLevel == "category") {
  if (targetLevel == "root") {
    draggingRecord.setValue("parent_id", null);
  }
  else {
    draggingRecord.setValue("parent_id", targetRecord.getValue("category_id"));
  }
}
else if (draggingLevel == "product") {
  draggingRecord.setValue("category_id", targetRecord.getValue("category_id"));
}
return true;

添加AutoForm和Button

步骤1:添加一AutoForm,属性设置如下:

属性

id

formCategory

dataset

datasetCategory

选中formCategory,点击字段生成按钮。
步骤2:添加一Button,属性设置如下:

属性

id

buttonAddCategory

value

添加分类

为buttonAddCategory的onClick事件添加如下代码:

if (!validateCurrentRecord()) return;
var record = datasetCategory.insertRecord();
var currentNode = treeProduct.getCurrentNode();
var parentNode = currentNode.getParent();
if (parentNode.getLevel() > 0) {
  var parentRecord = parentNode.getRecord();
  var parent_id = parentRecord.getValue("category_id");
  if (parent_id == "$null") parent_id = null;
  record.setValue("parent_id", parent_id);
}
var node = new RecordTreeNode(record, currentNode.getTreeLevel());
parentNode.addNode(node);
treeProduct.setCurrentNode(node);


步骤3:添加一Button,属性设置如下:

属性

id

buttonAddChildCategory

value

添加子分类

为buttonAddChildCategory的onClick事件添加如下代码:

if (!validateCurrentRecord()) return;

var currentNode = treeProduct.getCurrentNode();
treeProduct.expandNode(currentNode);

var record = datasetCategory.insertRecord();
var parentRecord = currentNode.getRecord();
record.setValue("parent_id", parentRecord.getValue("category_id"));
var node = new RecordTreeNode(record, currentNode.getTreeLevel());
currentNode.addNode(node);
treeProduct.setCurrentNode(node);


步骤4:添加一Button,属性设置如下:

属性

id

buttonDelCategory

value

删除分类

为buttonDelCategory的onClick事件添加如下代码:

if (confirm("确定要删除此产品分类以及其中的所有子分类和产品吗?")) { 
	 datasetCategory.deleteRecord(); 
}

步骤5:添加一Button,属性设置如下:

属性

id

buttonAddChildProduct

value

添加子产品

为buttonAddChildProduct的onClick事件添加如下代码:

if (!validateCurrentRecord()) return;

var currentNode = treeProduct.getCurrentNode();
treeProduct.expandNode(currentNode);

var record = datasetProduct.insertRecord();
var parentRecord = currentNode.getRecord();
record.setValue("category_id", parentRecord.getValue("category_id"));
var node = new RecordTreeNode(record, currentNode.getTreeLevel().getTreeLevel("product"));
currentNode.addNode(node);
treeProduct.setCurrentNode(node);


步骤6:添加一AutoForm,属性设置如下:

属性

id

formProduct

dataset

datasetProduct

选中formProduct,点击字段生成按钮。
步骤7:添加一Button,属性设置如下:

属性

id

buttonAddProduct

value

添加产品

为buttonAddProduct的onClick事件添加如下代码:

 if (!validateCurrentRecord()) return;

var record = datasetProduct.insertRecord();
var currentNode = treeProduct.getCurrentNode();
var parentNode = currentNode.getParent();
var parentRecord = parentNode.getRecord();
record.setValue("category_id", parentRecord.getValue("category_id"));
var node = new RecordTreeNode(record, currentNode.getTreeLevel());
parentNode.addNode(node);
treeProduct.setCurrentNode(node);

步骤8:添加一Button,属性设置如下:

属性

id

buttonDelProduct

value

删除产品

为buttonDelProduct的onClick事件添加如下代码:

if (confirm("确定要删除此产品吗?")) { 
	 datasetProduct.deleteRecord(); 
}

步骤9:为View的function添加如下代码:

 function validateCurrentRecord() {
  if (tabsetDetail.getCurrentTab().getName() == "category") {
    return datasetCategory.postRecord();
  }
  else {
    return datasetProduct.postRecord();
  }
}

为View的onLoad事件添加如下代码:

var current = datasetCategory.getCurrent();
if (current != null) {
  var node = treeProduct.findNodeByRecord(current);
  if (node != null) treeProduct.setCurrentNode(node);
}

为View的onUnLoad事件添加如下代码:

if (commandSave.isDirty()) {
  if (confirm("本页面中有未保存的数据.\n您希望在离开之前对这些数据进行保存吗?")) {
    commandSave.execute();
  }
}

添加Command和Button

步骤1:添加一UpdateCommand,id设置为commandSave。
选中commandSave,为其添加两个DatasetInfo,分别为datasetCategory、datasetProduct。
步骤2:添加一Button,属性设置如下:

属性

id

buttonSave

command

commandSave

value

保存所有修改

 

创建Jsp页面

生成Jsp页面以后再编辑一下布局,最后结果如下:

<%@ page contentType="text/html; charset=UTF-8" %> 
<%@ taglib uri="http://www.bstek.com/dorado" prefix="d" %> 
 <html> 
 <head> 
 </head> 
 <body style="margin: 0; overflow: hidden"> 
 <d:View config="ProductTree"> 
 <d:Layout type="border"> 
 <d:Pane position="center"> 
 <d:SplitPanel id="splitpanel1" orientation="horizontal" width="100%" height="100%" showButtons="true"> 
 <d:DataTree id="treeProduct" /> 
 <d:Splitter /> 
 <d:TabSet id="tabsetDetail" showFrame="false"> 
 <d:Tab name="category" visible="false" padding="12"> 
 <d:Layout type="Hflow" height="30"> 
 <d:Pane> 
 <d:Button id="buttonAddCategory" /> 
 </d:Pane> 
 <d:Pane> 
 <d:Button id="buttonAddChildCategory" /> 
 </d:Pane> 
 <d:Pane> 
 <d:Button id="buttonDelCategory" /> 
 </d:Pane> 
 <d:Pane> 
 <d:Button id="buttonAddChildProduct" /> 
 </d:Pane> 
 </d:Layout> 
 <d:AutoForm id="formCategory" /> 
 </d:Tab> 
 <d:Tab name="product" visible="false" padding="12"> 
 <d:Layout type="Hflow" height="30"> 
 <d:Pane> 
 <d:Button id="buttonAddProduct" /> 
 </d:Pane> 
 <d:Pane> 
 <d:Button id="buttonDelProduct" /> 
 </d:Pane> 
 </d:Layout> 
 <d:AutoForm id="formProduct" /> 
 </d:Tab> 
 </d:TabSet> 
 </d:SplitPanel> 
 </d:Pane> 
 <d:Pane position="bottom" align ="right" padding="6" style="background-color: #f0f0f0"> 
 <d:Button id="buttonSave" /> 
 </d:Pane> 
 </d:Layout> 
 </d:View> 
 </body> 
 </html>

查看运行效果

启动服务器后,浏览效果如下:

点击左边不同的节点,可以在右侧对该节点进行操作。

知识点

本示例的知识点为DataTree部分。关于DataTree可以参考《dorado 5 组件详解 1.1》第二部分的B部分的第2部分。