
<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地址为: https://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数据进行过滤筛选,参照上面格式
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=\"https://service.shopex.cn/images/fail.gif\" alt=\"ShopEx CERT INFO\" />";
$logoimgM = "<img src=\"https://www.shopex.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;
}
...
