<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;
}
...