现在的位置: 首页 > 综合 > 正文

CMS:文章管理之视图(1)

2012年08月27日 ⁄ 综合 ⁄ 共 4998字 ⁄ 字号 评论关闭

文章管理的视图与文件管理区别不大,都是分左右两部分。文章管理的左边是树状的分类列表,右边以Grid形式显示的文章列表。基本上重复劳动比较多,使用Sencha Architect这个可视化工具来做这方面的设计,是不错的选择,如果公司收益好,强烈建议使用,一个开发包的价格是399美金,大约2800人民币,还是很划得来的,起码比请多个程序员划得来。

废话又有点多了,转回正题,在Scripts\app\view目录下,创建一个Content目录,用来存放文章管理需要用到的视图,主要的视图包括文章管理的主视图、分类编辑窗口和文章编辑窗口。

接着,在Content目录下创建一个名称为View.js的文件,用来定义主视图,基本结构代码如下:

Ext.define('SimpleCMS.view.Content.View',{

    extend: 'Ext.container.Container',

    alias: 'widget.contentview',

    layout:"border",

 

    initComponent: function () {

        var me = this;

 

        me.callParent(arguments);

    }

 

});

 

接下来就是一步步添加组件了,先完成树的定义,代码如下:

me.tree= Ext.widget("treepanel", {

    title: "文章类别", region: "west", collapsible: true, rootVisible:true, store: "CategoriesTree",

    width: 200, minWidth: 100, split: true

});

 

接着是Grid,代码如下:

me.grid= Ext.widget("grid", {

    title: "文章列表", region: "center",

    store: "Contents",

    selType: "checkboxmodel",

    selModel: { checkOnly: false, mode:"MULTI" },

    columns: [

            { text: '编号', dataIndex: 'ContentId', width: 80},

            { text: '标题', dataIndex: 'Title', flex: 1 },

        {xtype: "datecolumn", text: '创建时间', dataIndex: 'Created', format: "Y-m-d H:i:s", width: 150},

            { text: '排序序数', dataIndex: 'SortOrder', width: 80},

            { text: '点击量', dataIndex: 'Hits', width: 80 },

        { text: '标签', dataIndex: 'Tags',width:150 }

     ]

});

 

Grid使用了复选框作为选择行的方式,也是一向习惯了。其它方面,应该问题不大。

 

最后是将树和Grid放到容器里,代码如下:

me.items = [me.tree, me.grid];

 

现在,可以测试一下效果了,不过,这还有修改控制器,切换到文章管理的控制器,在init方法内创建视图,并添加到面板里,这个应该很熟悉了,在用户管理和图片管理已经做过了。忘记了就直接复制过来修改一下创建的视图就行了,具体代码如下:

var me= this,

    panel = me.getContentPanel(),

    view = Ext.widget("contentview");

panel.add(view);

 

代码的panel用到了getContentPanel方法,返回文章管理的面板,因而要添加引用,代码如下:

refs: [

     { ref: "ContentPanel", selector:"#contentPanel" },

],

 

当然了,不要忘记在views配置项内添加视图了,代码如下:

views:[

    'Content.View'

],

在浏览器打开后,屏幕居然什么都没显示出来,而在Firebug居然显示两个“Layout run failed”错误,说明布局有问题。这个在之前也碰到过了,就是主面板定义中,没定义文章管理面板的布局,现在切换到主面板的视图,在文章管理的面板定义上加回布局定义,布局使用Fitlayout。

刷新一下浏览器,就可看到如图40的效果了。

 

图40 文章管理的界面

现在来完成分类树的功能,先完成树的显示。在完成前,先要用实体框架,将数据库中的表转换为对象。在解决方案内添加一个新项,然后如图41所示,在添加新项窗口中,先选择数据模版,然后在中间选择ADO.NET实体数据模型,将名称修改为SimpleCMS.edmx后,单击添加按钮。

 

图41 添加实体框架

在弹出的如图42所示的实体数据模型向导窗口中,选择从数据库生成,然后单击下一步。

 

图42 实体数据模型向导窗口

在切换到如图43所示的选择您的数据连接窗口中,可以单击新建连接按钮新建一个连接。在不过,默认的ApplicationServices连接是在配置文件中定义好的连接,可以直接使用,就不必再创建新的了。选上“是,在连接字符串中包括敏感数据”后,单击下一步按钮。当然,如果不喜欢在Web.Config文件包含用户名和密码这些敏感数据,可以另行处理。

 

图43 选择数据连接

在如图44所示的选择数据库对象窗口中,展开树中的表,然后如图那样选择以“T_”开头的4个表格,然后单击完成按钮结束向导。

 

图44 选择数据库对象

等待生成完成后,会在解决方案中看到如图45所示的数据结构图。

 

图45 生成的数据结构图

看到图,一定会疑惑,为什么刚才选择了4个表格,怎么在这里只看到3个对象?这是因为连接表T_Content和T_Tag的关联表在对象中只是一种多对多关系,隐含在对象中了,因而,不需要像数据库那样,显式的表示成一个对象。

这里还要为T_Category添加一个关联,让父节点可以找到它的子节点。在T_Category 的图中单击鼠标右键,在右键菜单中选择添加>关联,在如图46所示的添加关联对话框中,修改右边的实体为T_Category,接着修改左边的多重性为“0...1(零或一个)”。接着修改左边的导航属性为Childs,这样,就可通过childs属性访问子节点了。然后将右边的导航属性修改为Parent,这样,通过Parent属性就可访问到父节点了。把复选框的勾去掉后,单击确定按钮完成添加关联操作。

图46 添加关联对话框

接着在右边的属性列表中,编辑引用约束,在如图47的引用约束对话框中,选择主体为T_Category,然后在表格中将CategoryId的依赖属性设置为ParentId。

图47 引用约束对话框

保存一下解决方案,然后新建一个服务器端的控制器Category,添加必要的引用后,添加一个只读的私有变量dc,用来访问SimpleCMSEntities的实例,代码如下:

private readonly SimpleCMSEntities dc = newSimpleCMSEntities();

 

分类树的Store调用的是List方法,因而将Index方法修改为List方法,并加入相应的权限、返回对象和基本结构代码,代码如下:

[AjaxAuthorize(Roles= "普通用户,系统管理员")]

publicJObject List()

{

    bool success = false;

    string msg = "";

    JArray ja = new JArray();

    int total = 0;

    try

    {

        success = true;

 

    }

    catch (Exception e)

    {

        msg = e.Message;

    }

    returnHelper.MyFunction.WriteJObjectResult(success, total, msg, ja);

}

 

树展开一个节点,都会以node作为参数将该节点的id提交,因而,在提取数据是,首先要做的是先从node提取id,代码如下:

intid=-1;

int.TryParse(Request["node"], out id);

 

因为在定义Store时,根节点的id为-1,因而这里要分两种情况处理搜索结果,代码如下:

IQueryable<T_Category>q = null;

if (id== -1)

{

    q = dc.T_Category.Where(m =>m.Hierarchylevel == 0 & m.State == 0).OrderBy(m=>m.Title);

}

else

{

    q = dc.T_Category.Where(m => m.ParentId== id & m.State == 0).OrderBy(m => m.Title);

}

代码中,当id为-1时,就搜索层数为0的记录,否则,则搜索ParentId的等于id的记录。

这里有个问题,因为记录根据标题进行了排序,因而未分类这个类别就不知道跑到那个位置去了,因而,为了保持为分类在顶部,在查询的时候最好把它排除出去,另外再添加到结果中,代码修改如下:

q =dc.T_Category.Where(m => m.Hierarchylevel == 0 & m.CategoryId!=10000& m.State == 0).OrderBy(m=>m.Title);

 

现在要写数据到ja里面了,因为要多次写相同格式的对象,因而,把写对象独立为一个方法比较好,代码如下:

privateJObject writeNode(int id, string text, int parentId, bool isLeaf)

{

    JObject jo = new JObject

    {

        new JProperty("id",id),

        new JProperty("text",text),

        newJProperty("parentId",parentId),

        new JProperty("leaf",newJValue(isLeaf))

    };

    if (!isLeaf)

    {

        jo.Add(new JProperty("children",new JArray()));

    }

    return jo;

}

 

从代码可以看到,方法带4个参数,前3个参数就是返回节点所需的id、text和parentId的字段。而isLeaf的作用就是判断节点是否有子节点,如果有,就添加一个children属性,这样在客户端就能看到一个加号,可以展开。

现在,先在id等于-1时的查询语句下添加以下两个节点:

ja.Add(writeNode(-99,"全部", -1,true));

ja.Add(writeNode(10000, "未分类", -1, true));

添加全部节点,目的是为了方便查看数据,如果不喜,可不要。未分类这个是必须的。注意两个节点的id。

接着就是在判断语句后用循环输出节点了,代码如下:

foreach(var c in q)

{

    bool leaf = c.Childs.Count() > 0 ? false: true;

    int pid = c.ParentId == null ? -1 :(int)c.ParentId;

    ja.Add(writeNode(c.CategoryId, c.Title,pid, leaf));

}

 

在代码中,使用到了刚才设置的关联,通过统计子节点的个数来判断该节点是否有子节点。

生成一下解决方案,然后刷新一下页面。喔,根节点没自动打开,而且也没隐藏。先切换到树的Store定义,为根节点添加一个expanded配置项,值为true,让它自动展开。然后切换到视图定义,将rootVisible配置项设置为false。这些事情在复制粘贴过程中经常会发生。

好了,现在刷新一下页面,就会看到如图48的效果了。

图48 文章类别树的显示结果

这样,树的显示就完成了,下文继续。

 源代码下载:http://vdisk.weibo.com/s/hL6up

抱歉!评论已关闭.