
<desktop>
    <panelgroup id="other" icon="panel-other.png" order="100">其他</panelgroup>
    ...
    <adminpanel group="desktop_other" permission="other" controller='admin_member_attr' action='index' display='true'>会员注册项</adminpanel>
    ...
    <permissions>
        <permission id="shipment" display='true'>配送设置</permission>
        ...
    </permissions>
    <workground name="商品" id="b2c.wrokground.goods" controller="admin_goods" action="index" order="20">
        <menugroup name="商品管理">
            <menu controller='admin_goods_editor' action='add' permission='goods' display='false' order='10'>添加商品</menu>
            ...
        </menugroup>
        ...
    </workground>
    ...
</desktop>
每个 desktop.xml 的根标签
控制面板里的组其属性含义如下:
控制面板里的项其属性含义如下:
权限被包括在它里面
包含在permissions标签里,每一个都是一个权限其属性含义如下:
可以包含多个menugroup,看下【desktop图例】其属性有:
可以包含多个menu,看【desktop图例】 【2区】
看【desktop图例】为【3区】提供菜单,除了拥有跟workground一样的属性外,此标签还有另外三个属性:
permission: 权限,为标签permission里的id属性的值
display: 是否显示,有些控制器里的方法是不必显示成菜单的,比如得到post数据保存商品的控制器等,这时需把display设成false的
params: 在url中传值,菜单上的访问链接将加上params的参数例如:
<menu controller="admin_notebook" action="index" params="view:1|schema:2">留言编辑列表</menu> 点击留言编辑列表 得到的URL地址为: http://localhost/book/index.php/shopadmin/#app=notebook&ctl=admin_notebook&act=index&view=1&schema=2

在service.xml里添加
     <service id="desktop_menu">
        <class>b2c_service_view_menu</class>
    </service>
b2c_service_view_menu内容如下
class b2c_service_view_menu{
    function function_menu(){
        $shop_base = app::get('site')->router()->gen_url(array('app'=>'site', 'ctl'=>'default'));
        $html[] = "<a href='$shop_base' target='_blank'>浏览商店</a>";
        return $html;
    }
}
说明:desktop_menu的服务,必须定义名字为function_menu的方法,它的返回值即为【5区】的菜单项

finder说明:
    我们平时做任何web应用大概都少不了后台管理功能,
    这之中最常看到的大概就是:数据列表,对数据进行单条查看,删除,搜索列表数据。
    finder就是做这样工作的,要做到这些事情只需简单的给一个方法传几个参数而已。
例如:    function index(){
        $this->finder('b2c_mdl_goods',array(
        'title'=>app::get('b2c')->_('商品列表'),
        'actions'=>array(array('label'=>app::get('b2c')->_('添加商品'),
	            'href'=>'index.php?app=b2c&ctl=admin_goods_editor&act=add','target'=>'_blank'),),
        'use_buildin_set_tag'=>true,
        'use_buildin_filter'=>true,
        'use_buildin_export'=>true,
        'allow_detail_popup'=>true,
        'use_view_tab'=>true,
        'base_filter'=>array('order_refer'=>'local','disabled'=>'false'), //对tab数据进行过滤筛选
        'finder_aliasname'=>'xxxx',
            ));
    }
后台的控制器必须继承desktop_controller,继承后才有finder方法,下面介绍下finder方法的几个参数:title: 【图 finder】中的【1区】显示出来的内容
actions: 【图 finder】【2区】里的内容除了显示内置的操作以外(use_buildin_set_tag,use_buildin_filter这些是控制项),还可以自定义添加新操作,参照上面格式。
allow_detail_popup: allow_detail_popup和其下面的其他项,是上面所说的内置的操作的控制项,其值为true时,显示此内置项。完整的内置操作及含义如下(可到desktop_finder_builder_view类里查看):
use_buildin_new_dialog: 是否显示新建操作
use_buildin_set_tag: 是否显示设置标签操作
use_buildin_recycle: 是否显示删除操作
use_buildin_export: 是否显示导出操作
use_buildin_import: 是否显示导入操作
use_buildin_tagedit: 是否显示标签管理操作
base_filter: 对tab数据进行过滤筛选,参照上面格式
top_extra_view 在finder列表头部增加其他自定义html显示,如top_extra_view=>array('app名称'=>'页面路径');
use_view_tab: 是否显示finder中的tab(如果有),有无需看控制器中是否有_views方法。
use_buildin_filter: 是否使用高级筛选 【图 finder】【6区】
use_buildin_refresh: 是否显示刷新操作(高级筛选旁)
use_buildin_setcol: 是否显示列配置
use_buildin_selectrow: 是否显示每条记录前的复选按钮
allow_detail_popup: 是否显示查看列中的弹出查看图标(【图 finder.png】4区第二个图标)
finder_aliasname: 此finder的别名,用于保存此finder的
    <service id="desktop_finder.b2c_mdl_goods">
        <class>b2c_finder_goods</class>
    </service>
b2c_finder_goods类里有两种方法,两种属性,属性和方法成对出现:
    var $detail_basic = '基本信息';
    function detail_basic($gid){
        ...
        return $str;
    }
属性detail_basic是作为列头显示的, 方法detail_basic的返回值是点击查看里出现的内容 [如果有多个detail_开头的方法,则显示第一个里面的内容]
    var $column_editbutton = '操作';
    public function column_editbutton($row)
    {
        ...
        return $str;
    }
属性column_editbutton是作为列头显示的, 方法column_editbutton的返回值是每行此列的显示内容, 方法column_editbutton的参数是当前行的数组。
 ...
   	var $column_try = '测试';
   	var $column_try_width = 100;
	public function column_try($row)
	{
		return '====';
	}
 ...
效果如图:
     ...........
      'item_subject' =>
          array (
             'type' => 'varchar(100)',
             'in_list'=>true,
             'is_title'=>true,
             'default_in_list'=>true,
             'label'=>'第一列',
             'order'=>10,   //注意这里
             ),
      'item_content' =>
           array (
             'label' => '第三列',
             'in_list'=>true,
             'default_in_list' => true,
             'order'=>30,
             'type' => 'text',
             ),
      'item_posttime' =>
          array (
             'in_list'=>true,
             'default_in_list' => true,
             'label' => '第二列',
          	 'order'=>20,
             'type' => 'archar',
             ),
      ...........
效果如图:
属性名规则是列变量加_order 例如 var $column_editbutton_order = order
 ...
   	var $column_editbutton = '操作';
   	var $column_editbutton_order = COLUMN_IN_TAIL;
	public function column_editbutton($row)
	{
		return '====';
	}
...
效果如下:
注意:此列表排序只能为初始化排序,如果做了如下保存操作则只能手动排序咯

高级筛选中的搜索项大部分来自dbschema中, 搜索类型[单选或下拉或输入关键词]也定义在dbschema
    <service id="extend_filter_b2c_mdl_orders">
        <class>b2c_finder_extend_orders</class>
    </service>
class b2c_finder_extend_members{
    function get_extend_colums(){
            $db['members']=array (
              'columns' =>
              array (
                'refer_id' =>
                array (
                  'type' => 'varchar(200)',
                  'required' => true,
                  'default' => 0,
                  'label' => '首次来源ID',
                  'width' => 75,
                  'editable' => true,
                  'filtertype' => 'yes',
                  'filterdefault' => true,
                  'in_list' => true,
                  'default_in_list' => true,
                ),
        ...
                 'refer_url' =>
                array (
                  'type' => 'varchar(200)',
                  'required' => true,
                  'default' => 0,
                  'label' => '首次来源URL',
                  'width' => 75,
                  'editable' => true,
                  'filtertype' => 'yes',
                  'filterdefault' => true,
                  'in_list' => true,
                  'default_in_list' => true,
                )));
			return $db;
    }
}
class里必须包含get_extend_colums方法, 它的返回值跟dbschema里的一样,如果扩展了高级搜索, 一般需要在model里重定义_filter方法,以便使用上扩展过滤字段
    function searchOptions(){
        $arr = parent::searchOptions();
        return array_merge($arr,array(
                'bn'=>__('货号'),
                'keyword'=>__('商品关键字'),
            ));
    }
$sub_menu = array(
            0=>array('label'=>app::get('b2c')->_('全部'),'optional'=>false,'filter'=>"",'addon'=>1,'href'=>'xxx.xxx','finder'=>'xxxx'),
        ...
            7=>array('label'=>app::get('b2c')->_('已作废'),'optional'=>false,'filter'=>array('status'=>'dead'),'addon'=>1,'href'=>'xxx.xxx'),
        );
label: tab的标题文字
optional: 此tab是否可选
filter: 此tab的过滤条件
addon: 此过滤条件下有多少条记录
href: 此tab的链接地址
如果finder方法第二个参数中使用了use_buildin_recycle, 则此finder列表的actions区就有了内置的删除按钮, 有时需要在删除前和删除后做一些检测工作, 比方记录不准删除,或删除记录时需删除资源文件等。 实现这一功能机制是在model里定义pre_recycle[删除前执行]和suf_recycle[删除后执行]方法
登录后台首先看到的界面,其内容由各个app通过service注册进来, 里面每一块都是一个widgets,下面是b2c的service.xml里桌面内容相关的一段
    <service id="desktop.widgets">
        <class>b2c_desktop_widgets_workcount</class>
        <class>b2c_desktop_widgets_stats</class>
        <class>b2c_desktop_widgets_exstatistics</class>
    </service>
class b2c_desktop_widgets_workcount implements desktop_interface_widget{
    function __construct($app){
        $this->app = $app;
        $this->render =  new base_render(app::get('b2c'));
    }
    function get_title(){
        return app::get('b2c')->_("统计分析");
    }
    function get_html(){
    ...
        return $render->fetch('desktop/widgets/workcount.html');
    }
    function get_className(){
          return " valigntop";
    }
    function get_width(){
          return "l-1";
    }
}
function get_title(): desktop widgets标题
function get_title(): desktop widgets 内容
function get_className(): 给desktop widgets 区块添加class name
function get_width(): 返回值为l-1显示在左侧,值为l-2显示在左侧
 
 。
。
<?php
...
  var $detail_edit2 = '详细列表2';
    function detail_edit2($id){
        $render = app::get('notebook')->render();
        $oItem = kernel::single("notebook_mdl_item");
        $items = $oItem->getList('item_subject, item_posttime, item_email',
                     array('item_id' => $id), 0, 1);
        $render->pagedata['item'] = $items[0];
        $render->display('admin/itemdetail.html');
    }
...
以上代码仅仅是为了实例需要,没有什么实际的意义。在function中我们可以根据自己的需求进行处理。
 
<?php
...
     public function modifier_item_email($row){
         $row = "<span style='color:red'>".$row."</span>";
         return $row;
     }
...
重要提示:modifier的命名规则是modifier_ColumnName(ColumnName是表对应dbshema中的字段名字)。
 
<?php
...
    public function modifier_item_email($row){
        //修改后代码
        if (strstr($row,'tntppa')){
            return "<span style='color:red'>".$row."</span>";
        }else{
            return $row;
        }
        //修改后代码
    }
...

 
...
    <service id="desktop_controller_content.desktop.default.index">
        <class>notebook_ctl_admin_out</class>
    </service>
...
<?php
    class notebook_ctl_admin_out extends base_controller implements desktop_interface_controller_content{
        public function modify(&$html, &$obj){
           $arr = "<a href=\"index.php?ctl=dashboard&act=index\">ECstore</a>";
           $html = str_replace($arr, "",$html);
           //替换logo
           $logoimg = "<img src=\"http://service.shopex.cn/images/fail.gif\"  alt=\"ShopEx CERT INFO\" />";
           $logoimgM = "<img src=\"https://blog.wanxiaohong.cn/images/alllogo/alllogo_19.gif\" height=\"40px\"/>";
           $html = str_replace($logoimg, $logoimgM, $html);
        }
    }
 

注:我们也可以通过modify这个方法来修改其他后台页面信息。
注:【方法三】只有在系统安装前可以使用。
 
<services>
    <service id="desktop_finder.notebook_mdl_item">
        <class>notebook_finder_item</class>
    </service>
</services>
<?php
...
    //增加一个虚拟列
    var $column_edit2 = '测试列';
    public function column_edit2($row){
        return $row['item_subject'];
    }
...
 
...
    <service id="desktop_view_helper">
        <class>notebook_view_helper</class>
    </service>
...
<?php
class notebook_view_helper extends desktop_controller{
    function function_desktop_header($params, &$smarty){
        return app::get("notebook")->render()->fetch("header.html");
    }
}
<style>
/*按需求增加的列表另外三种颜色状态*/
.finder-list .list-row {background:#FFCC33}
.finder-list .list-warn{background:#FF0000}
.finder-list .list-even{background:#66CC00}
</style>
<?php
...
    public function row_style($row){
            if($row['item_subject']=='t'){
                return 'list-even';
            }elseif($row['item_subject']=='rt'){
                return 'list-row';
            }else{
                return 'list-warn';
            }
    }
...
 
实际上这个字段数据是通过dbschema多表链接来完成的。
<?php
...
      'user_id' =>
    array(
      'type' => 'table:account@pam',
      'required' => true,
      'label' => '用户ID',//finder里显示的列名称
      'in_list' => true,//是否显示在列配置中,默认为false
      'default_in_list' => true//默认在desktop列表中是否显示
    ),
...
在这里我们有必要解释一下:'type' => 'table:account@pam', 这句代码的意思是: 在本表中的user_id这个字段的类型与pam_account这个表中的主键的字段一致。
<?php
...
        'login_name'=>array('type'=>'varchar(100)','is_title'=>true,'required' => true, ),
...
D:\wamp\www\twitter\app\base>cmd update Scanning local Applications... ok. Updating base_application_cache_expires@pam. Installing Cache_Expires DB:PAM_ACCOUNT UPDATE CACHE EXPIRES KV DATA Installing Cache_Expires DB:PAM_AUTH UPDATE CACHE EXPIRES KV DATA Installing Cache_Expires DB:PAM_LOG UPDATE CACHE EXPIRES KV DATA
注:如果被链接的表(本例中的pam_accout表)没有字段被设置属性为'is_title'=>true,那么系统默认 将主键的下一个字段为输出数据。
中也说到,用通过modify这个函数来实现对后台logo的操作,但是这样无法覆盖全部的需求(比如后台登陆logo)。这个时候,就可以用下面修改数据库然后进行cmd kvrecovery 操作,来完成我们的需求。

注意:"s:18:这是一个测试"是序列化后的结果,修改时不仅要修改后面的文本,还要修改与之对应的字符个数"s:18"。 在utf8字符集下,每个汉字=3个字符。于是上例中“这是一个测试”=3*6个字符。


 
<?php
...
    //自定义快速搜索字段名称
    function searchOptions(){
        $arr = parent::searchOptions();//得到dbschema里定义searchtype的字段
        $columns = array();
        $columns['item_subject']='自定义1';//将搜索字段自定义名称
        $columns['item_posttime']='自定义2';
        $columns['item_email']='自定义3';
        $return = array_merge($arr,$columns);//保证所有属性为searchtype的字段都显示
        return $return;
    }
...
