desktop开发手册 since : %%date(%Y-%m-%d) $Rev$ %!target:html %!postproc(tex): '\.gif' '.eps' %!preproc(html): '\.dot' '.gif' %!preproc(tex): '\.dot' '.pdf' %!encoding:utf-8 =desktop简介= desktop提供一个带有权限和工作流的操作环境,一个网站一般分为前台和后台,它提供了常用的后台操作实现机制,这大大节省了你后台开发的时间。 desktop作为ecos的一个基础app一般不单独存在,是其他app操作流程的载体。ecstore是基于ecos的开源商城系统,亦依赖desktop,它使用了绝大部分desktop的功能,建议使用desktop开发新的应用时,多参照下ecstore,为便于理解,本手册亦以ecstore为例讲解。 =此手册目标人群= 开发者:开发基于ecos的新应用或扩展已有应用功能时,需开发后台功能的会用到desktop =desktop提供了下列功能:= - 权限管理 - 回收站 - 显示app提供的菜单项或控制面板项 - finder功能 ==desktop.xml说明== 装了desktop这个app,就能识别其他app目录下的desktop.xml文件,这个文件必须列出所有后台看见或看不见的控制器,否则除非是超级管理员,任何其他非超级管理员desktop用户无法访问这些控制器。 desktop.xml的结构大概是这样的: ``` 其他 ... 会员注册项 ... 配送设置 ... 添加商品 ... ... ... ``` desktop.xml不一定包含上面的所有标签,各个标签及属性含义如下: - ``desktop `` 每个 desktop.xml 的根标签 - ``panelgroup`` 控制面板里的组 其属性含义如下: 1. ``id:``控制面板里组的唯一标识 2. ``icon:`` 控制面板里组的图标,路径默认的起点是app下的static,假如此desktop.xml是desktop这个app的,则图标的路径会自动解析成/app/desktop/static/panel-other.png 3. ``order:`` 组的显示顺序 - ``adminpanel`` 控制面板里的项 其属性含义如下: 1. ``group:`` 指属性那个控制面板组,其值是panelgroup的id属性值加app前缀,例如group="desktop_other" 2. ``permission:`` 指此控制面板里的项属性那个权限(下面讲到权限) 3. ``controller:`` controller和action(构成点此控制面板项时的去处,如果action属性未写则默认值为index) 4. ``action:`` controller和action(构成点此控制面板项时的去处,如果action属性未写则默认值为index) 5. ``display:`` 是否显示在控制面板组里,true为显示,false为不显示 - ``permissions`` 权限被包括在它里面 - ``permission`` 包含在permissions标签里,每一个都是一个权限 其属性含义如下: 1. ``id:`` 权限的唯一标识,全局唯一 2. ``display:`` 新建角色时,是否显示在角色权限列表里,true为显示,false为不显示 - ``workground`` 可以包含多个menugroup,看【图 desktop.png】 其属性有: 1.``name:`` 1区显示出来的label 2.``id:``(workground的唯一标识) 3.``controller:`` 构成点此workground tab时的去处,如果action属性未写则默认值为index 4.``action:`` 构成点此workground tab时的去处,如果action属性未写则默认值为index 5.``order:`` 此workground在tab列表中的排序 - ``menugroup`` 可以包含多个``menu``,看【图 desktop.png】 2区 - ``menu`` 看【图 desktop.png】为3区提供菜单,除了拥有跟workground一样的属性外,此标签还有另外两个属性: ``permission:`` 权限,为标签permission里的id属性的值 ``display:`` 是否显示,有些控制器里的方法是不必显示成菜单的,比如得到post数据保存商品的控制器等,这时需把display设成false的 =先来看下,一个典型的desktop的列表页包含了哪些内容= 【图 desktop.png】 [images/desktop.png] =接下来我们看各个区里的内容是如何增删及展示出来的= - 1、2、3区都是根据app下的``desktop.xml``产生,如何填充,可以参照desktop.xml的介绍试试看 - 5区顶部菜单产生是靠往服务id为desktop_menu里注册服务实现 在``service.xml``里添加 ``` b2c_service_view_menu ``` ``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[] = "浏览商店"; return $html; } } ``` 说明:``desktop_menu``的服务,必须定义名字为function_menu的方法,它的返回值即为5区的菜单项 - 4区finder,先看下细分图 【图 finder.png】 [images/finder.png] finder说明:下面对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, 'finder_aliasname'=>'xxxx', )); } ``` 后台的控制器必须继承desktop_controller,继承后才有finder方法,下面介绍下finder方法的几个参数: - 第一个参数是字符串,(上例中是b2c_mdl_goods),是model里的class名,它决定了finder列表的数据源,默认情况下是b2c_mdl_goods类里的getlist方法返回的数据 - 第二个参数是数组,这个数组内涵相当丰富,解释如下: ``title:`` 【图 finder.png】中的1区显示出来的内容 ``actions:`` 【图 finder.png】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:** 是否显示标签管理操作 下面几个控制项不是控制【图 finder.png】2区里的内容 **use_view_tab:** 是否显示finder中的tab(如果有),有无需看控制器中是否有_views方法。 **use_buildin_filter:** 是否使用高级赛选 【图 finder.png】6区 **use_buildin_refresh:** 是否显示刷新操作(高级赛选旁) **use_buildin_setcol:** 是否显示列配置 **use_buildin_selectrow:** 是否显示每条记录前的复选按钮 **allow_detail_popup:** 是否显示查看列中的弹出查看图标(【图 finder.png】4区第二个图标) **finder_aliasname:** 此finder的别名,用于保存此finder的 =下面对几个重点区域内容的填充做详细讲解= - ==增加finder列表的自定义列== finder列表的列分为以下三种: 1.查看列 (分为下列查看和弹出查看) 2.自定义列(也可称函数列),可以通过一种方法扩展 3.普通列(数据表里有的字段,也即dbschema里有的字段) 【图 finder.png】5区的两列操作和标签都不是dbschema里的字段,还能显示出来是因为他们是自定义列,通过下面的步骤实现: 1.注册一个service,其id是desktop_finder.xxx,xxx是finder方法的第一个参数,上例中是b2c_mdl_goods,最终结果在相应的应用中services.xml中如下样子: ``` b2c_finder_goods ``` b2c_finder_goods类里有两种方法,两种属性,属性和方法成对出现: 第一种 属性以detail_开头,对应的方法也以detail_开头 例如: ``` var $detail_basic = '基本信息'; function detail_basic($gid){ ... return $str; } ``` 属性detail_basic是作为列头显示的,方法detail_basic的返回值是点击查看里出现的内容[如果有多个detail_开头的方法,则显示第一个里面的内容] 第二种:属性以column_开头,对应的方法也以column_开头 ``` var $column_editbutton = '操作'; public function column_editbutton($row) { ... return $str; } ``` 属性column_editbutton是作为列头显示的,方法column_editbutton的返回值是每行此列的显示内容,方法column_editbutton的参数是当前行的数组。 补充:自定义列后来又加了一个属性,属性名规则是列变量加_order 例如 var $column_editbutton_order = **order** order 可以是COLUMN_IN_HEAD[放在普通列前面]或COLUMN_IN_TAIL[放在普通列后面] - ==高级赛选== 高级赛选中的搜索项大部分来自dbschema中,搜索类型[单选或下拉或输入关键词]也定义在dbschema 除此之外,高级赛选中的搜索项还可以通过注册service扩展,id为extend_filter_xxx,xxx为finder方法的第一个参数,例如: ``` b2c_finder_extend_orders ``` b2c_finder_extend_orders 类如下: ``` 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, ))) } } ``` class里必须包含get_extend_colums方法,它的返回值跟dbschema里的一样,如果扩展了高级搜索,一般需要在model里重定义_filter方法,以便使用上扩展过滤字段 - ==快捷搜索== 有两个地方影响快捷搜索,dbschema中定义的字段中,searchtype这一项,如果有这项则会在快捷搜索里出现,还有就是在model里定义searchOptions函数,返回值的数组就为快速搜索里的项,例如: ``` function searchOptions(){ $arr = parent::searchOptions(); return array_merge($arr,array( 'bn'=>__('货号'), 'keyword'=>__('商品关键字'), )); } ``` - ==finder上的tab== 需要在调用了finder的控制器里定义_views方法,_views方法的返回值格式如下: ``` $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注册进来,里面每一块都是一个wigets,下面是b2c的service.xml里桌面内容相关的一段 ``` b2c_desktop_widgets_workcount b2c_desktop_widgets_stats b2c_desktop_widgets_exstatistics ``` 每个class就是一个wigets,每个class里面的内容为以下格式[以b2c_desktop_widgets_workcount为例]: ``` 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显示在左侧