§ 后台视图
后台视图有两个页面完成
1、列表页视图
文件:./apps/book/view/index.php
<?php $this->display('header', 'system');?>
<link rel="stylesheet" type="text/css" href="<?php echo IMG_URL?>js/lib/tablesorter/style.css"/>
<link rel="stylesheet" type="text/css" href="<?php echo IMG_URL?>js/lib/pagination/style.css"/>
<link rel="stylesheet" type="text/css" href="<?php echo IMG_URL?>js/lib/contextMenu/style.css"/>
<script type="text/javascript" src="<?=IMG_URL?>js/lib/cmstop.table.js"></script>
<script type="text/javascript" src="<?=IMG_URL?>js/lib/jquery.tablesorter.js"></script>
<script type="text/javascript" src="<?=IMG_URL?>js/lib/cmstop.contextMenu.js"></script>
<script type="text/javascript" src="<?=IMG_URL?>js/lib/jquery.pagination.js"></script>
<script type="text/javascript" src="apps/book/js/book.js"></script>
<div class="bk_10"></div>
<div class="tag_1 mar_l_8">
<ul class="tag_list" id="bystate_list">
<li><a href="javascript:book.reload('state=all');" class="s_3" >全部</a></li>
<li><a href="javascript:book.reload('state=0');" >未审核</a></li>
<li><a href="javascript:book.reload('state=1');" >未回复</a></li>
<li><a href="javascript:book.reload('state=2');" >已回复</a></li>
</ul>
</div>
<div class="bk_8"></div>
<table width="98%" cellpadding="0" cellspacing="0" id="item_list" class="tablesorter table_list mar_l_8">
<thead><tr>
<th width="35" class="t_l bdr_3"><input type="checkbox" id="check_all" /></th>
<th >留言内容</th>
<th width="12%">留言人</th>
<th width="15%" class="ajaxer"><div name="addtime">发布时间</div></th>
<th width="9%">状态</th>
<th width="80">操作管理</th>
</tr></thead>
<tbody id="list_body"></tbody>
</table>
<div class="clear"></div>
<ul id="right_menu" class="contextMenu">
<li class="edit"><a href="#book.view">详情(回复)</a></li>
<li class="check"><a href="#book.check">审核</a></li>
<li class="delete"><a href="#book.del">删除</a></li>
</ul>
<div class="table_foot">
<div id="pagination" class="pagination f_r"></div>
<p class="f_l">
<button type="button" onclick="book.check()" class="button_style_1">审核</button>
<button type="button" onclick="book.del()" class="button_style_1">删除</button>
</p>
</div>
<script type="text/javascript">
book.init();
</script>
<?php $this->display('footer', 'system');?>
2、详细信息(回复)页视图
文件:./apps/book/view/view.php
<form id="<?=$app?>_<?=$controller?>_view" id="<?=$app?>_<?=$controller?>_view" method="POST" class="validator" action="?app=<?=$app?>&controller=<?=$controller?>&action=reply">
<input type="hidden" name="id" id="id" value="<?=$id?>" />
<table width="98%" border="0" cellspacing="0" cellpadding="0" class="table_form">
<tr>
<td colspan="2"><span id="pic"></span></td>
</tr>
<tr>
<th width="60">留言者:</th>
<td><?php echo $username; ?></td>
</tr>
<tr>
<th>Email:</th>
<td><?php echo $email; ?> </td>
</tr>
<tr>
<th>留言时间:</th>
<td><?php echo $addtime; ?> </td>
</tr>
<tr>
<th>留言IP:</th>
<td><?php echo $ip; ?> </td>
</tr>
<tr>
<th>留言内容:</th>
<td><textarea><?php echo $content; ?></textarea></td>
</tr>
<tr>
<th>回复内容:</th>
<td><textarea id="reply" name="reply"><?php echo $reply; ?></textarea></td>
</tr>
<?php if(!empty($replytime)){ ?>
<tr>
<th>回复时间:</th>
<td><?php echo $replytime; ?></td>
</tr>
<?php } ?>
</table>
</form>
后台使用了独立的JS文件和表单验证配置文件,存储在 ./public/admin/apps/book/后台公共目录下。
文件:./public/admin/apps/book/js/book.js
(function($){
var tableApp = null;
var book = {
init: function(){
var manage_td = '<img src="images/delete.gif" title="删除" alt="删除" width="16" height="16" class="manage" onclick="book.del(\'{id}\');"/>';
var row_template = '<tr id="row_{id}">';
row_template +=' <td><input type="checkbox" class="checkbox_style" name="chk_row" id="chk_row_{id}" value="{id}" /></td>';
row_template +=' <td><a href="#book.view({id})"">{content}</a></td>';
row_template +=' <td>{username}</td>';
row_template +=' <td class="t_c">{addtime}</td>';
row_template += ' <td class="t_c">{state}</td>';
row_template +=' <td class="t_c" id="manage_{id}" name="manage" value="manage">'+manage_td+'</td>';
row_template +='</tr>';
tableApp = new ct.table('#item_list', {
rowIdPrefix : 'row_',
pageSize : 15,
rowCallback: 'init_row_event',
dblclickHandler : 'book.view',
jsonLoaded : 'json_loaded',
template : row_template,
baseUrl : '?app=book&controller=index&action=page'
});
tableApp.load();
},
reload: function(where){
tableApp.load(where);
},
view:function(id){
ct.formDialog({title:'查看留言信息',height:330,width:400},'?app=book&controller=index&action=view&id='+id,function(json){
if(json.state){
ct.ok(json.info);
return true;
}else{
return false;
}
}
);
},
del: function(id){
var msg = '';
if(id === undefined){
id = tableApp.checkedIds();
if (!id.length) {
ct.warn('请选中要删除项');
return;
}
msg = '确定删除选中的<b style="color:red">'+id.length+'</b>条记录吗?';
}else{
msg = '确定删除编号为<b style="color:red">'+id+'</b>的记录吗?';
}
ct.confirm(msg,function(){
var data = 'id='+id;
$.getJSON('?app=book&controller=index&action=delete', data, function(json){
json.state
? (ct.warn(json.info), tableApp.deleteRow(id))
: ct.warn(json.error);
});
});
},
check: function(id){
var msg = '';
if(id === undefined){
id = tableApp.checkedIds();
if (!id.length) {
ct.warn('请选中要审核的项');
return;
}
}
var data = 'id='+id;
$.getJSON('?app=book&controller=index&action=check', data, function(json){
json.state
? ct.ok(json.info)
: ct.warn(json.error);
});
}
}
window.book = book;
function init_row_event(id, tr) { }
function json_loaded(json) { }
})(jQuery);
§ 前台模版
由于该应用要求使用ajx在同一页面完成所有操作,所以模版只有一个页面。
文件:./templates/default/book/index.html
内容如下:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset={$CONFIG[charset]}" />
<title>{$SETTING['bookname']}</title>
<script type="text/javascript" src="{IMG_URL}js/config.js"></script>
<script type="text/javascript" src="{IMG_URL}js/lib/jquery.js"></script>
<script type="text/javascript" src="{IMG_URL}apps/book/js/book.js"></script>
<link href="{IMG_URL}apps/book/css/book.css" type="text/css" rel="stylesheet" rev="stylesheet" media="screen" />
</head>
<body>
<div id="header">
<h1>{$SETTING['bookname']}</h1>
<p>关于cmstop,你想说些什么?</p>
</div>
<div id="main">
<div id="m_right">
<h2>留言须知</h2>
<p>一、不得发表违反中华人民共和国宪法和法律、违反改革开放和四项基本原则的言论。<br/>
二、不得发表造谣、诽谤他人的言论。<br/>
三、不得发表未经证实的消息,亲身经历请注明。<br/>
四、请勿发表任何形式的广告。<br/>
五、请勿发表与国家工商行政管理总局工作无关的言论。<br/>
六、请留真实联系方式以便核对,联系方式不实者,留言将予以删除。<br/>
七、本栏目非论坛性质,只用于国家工商行政管理总局机关和公众之间的交流,不用于公众之间的交流。<br/>
</p>
</div>
<div id="m_left">
<div id="add">
<form name="book_add" id="book_add">
<label for="username">留言者:</label><br/>
<input type="text" name="username" id="username" size="20" class="inputnew" /><br/>
<label for="email">Email:</label><br/>
<input type="text" name="email" id="email" size="50" class="inputnew" /><br/>
<label for="content">留言内容:</label><br/>
<textarea name="content" id="content" rows="5" cols="73" class="textarea" /></textarea><br/>
<span style="float:right;"><input type="submit" id="submit" class="button" value="提 交" /></span>
<span><!--{if $SETTING['iscode'] }-->
<label for="seccode">验证码:</label>
<input name="seccode" id="seccode" size="4" type="text" value="" maxlength="4" class="inputnew" />
<img src="{url('system/seccode/image')}" id="seccodeimg" onclick="this.src='{url('system/seccode/image')}&id='+Math.random()*5;" style="cursor:pointer;" width="48" height="20" align="absmiddle" class="img_mar"/>
<a href="javascript:;" onclick="$('#seccodeimg').click()" class="ch-yzm">换一张</a>
<span class="warn" style="display:none;"></span>
</li>
<!--{else}-->
如果你有任何问题,请联系CmsTop!
<!--{/if}--></span>
</form>
</div>
<div id="list"></div>
<div id="more" class="more">正在加载更多内容...</div>
</div>
</div>
<div id="footer">© CmsTop 2011</div>
<script language="JavaScript">
$(init);
</script>
</body>
</html>
该模版使用了单独的JS和CSS文件(JS、CSS和图片文件均属于资源型文件,前台应用资源文件存储在 ./public/img/apps/)
文件:./public/img/apps/book/js/book.js
内容如下:
(function($){
var types = ['DOMMouseScroll', 'mousewheel'];
$.fn.mousewheel = function(fn) {
return fn ? this.bind("mousewheel", fn) : this.trigger("mousewheel");
};
$.event.special.mousewheel = {
setup: function() {
if ( this.addEventListener )
for ( var i=types.length; i; )
this.addEventListener( types[--i], handler, false );
else
this.onmousewheel = handler;
},
teardown: function() {
if ( this.removeEventListener )
for ( var i=types.length; i; )
this.removeEventListener( types[--i], handler, false );
else
this.onmousewheel = null;
}
};
function handler(event) {
var args = [].slice.call( arguments, 1 ), delta = 0, returnValue = true;
event = $.event.fix(event || window.event);
event.type = "mousewheel";
if ( event.wheelDelta ) delta = event.wheelDelta/120;
if ( event.detail ) delta = -event.detail/3;
// Add events and delta to the front of the arguments
args.unshift(event, delta);
return $.event.handle.apply(this, args);
}
})(jQuery);
(function($){
var frm = null,
btn = null,
ul = null,
more = null,
lock = false,
page = 0,
win = $(window),
isunbind = false;
function add(e){
var f = this;
e.preventDefault();
e.stopPropagation();
var data = frm.serialize();
btn.attr('disabled', true);
$.ajax({
url:'?app=book&controller=index&action=add',
dataType:'json',
data:data,
type:'POST',
success:function(json){
if (json.state) {
var li = createRow(json.data);
ul.prepend(li.hide());
li.slideDown();
} else {
if(json.error){
alert(json.error);
}else{
alert('添加失败');
}
}
},
error:function(){
alert('请求异常');
},
complete:function(){
btn.attr('disabled', false).removeAttr('disabled');
}
});
}
function createRow(row) {
var li = '<li>'+
'<strong>'+(row.username||'网友')+'</strong>'+
'<em>('+row.email+')</em>'+
'<span>'+row.addtime+'</span>'+
'<p>'+row.content+'</p>';
if(row.reply){
li = li + '<p class="reply"><b>回复:</b>' + row.reply + '</p>';
}
li = li + '</li>';
return $(li);
}
function spage(e, data){
if (data < 0 && document.documentElement.scrollTop + win.height() > document.documentElement.scrollHeight - 50)
{
query(page+1);
}
}
function query(p){
if (lock) {
return;
}
lock = true;
more.addClass('loading');
$.ajax({
url:'?app=book&controller=index&action=page&page='+p,
dataType:'json',
type:'GET',
success: function(json){
for (var i=0, t; t = json[i++];) {
ul.append(createRow(t));
}
if (p <= 1) {
win.mousewheel(spage);
}
if (!isunbind && p > 4) {
win.unbind('mousewheel', spage);
isunbind = true;
}
if (json.length) {
page = p;
} else if (!isunbind) {
win.unbind('mousewheel', spage);
isunbind = true;
}
},
complete:function(){
lock = false;
more.removeClass('loading');
}
});
}
window.init = function(){
frm = $('#book_add').bind('submit', add);
btn = $('#submit');
ul = $('#list');
more = $('#more');
query(1);
};
})(jQuery);
文件:./public/img/apps/book/css/book.css
内容如下:
div,form,ul,ol,li,span,input,h1,h2,h3,p,b,strong{margin:0;padding:0;margin:0;}
ul,ol,li{
list-style:none;
}
.inputnew{
padding:2px;
border:1px solid #ACD6F6;
height:23px;
line-height:23px;
border-radius: 5px;
}
.textarea{
padding:2px;
border:1px solid #ACD6F6;
line-height:23px;
border-radius: 5px;
}
body{
text-align:center;
font-size:14px;
}
#header{
width:960px;
margin:0 auto;
text-align:left;
margin-top:20px;
margin-bottom:10px;
}
#header h1{font-size:30px;}
#header p{color:#666;}
#main{
width:960px;
margin:0 auto;
text-align:left;
overflow:auto;
zoom:1;
}
#m_left{
width:660px;
}
#m_right{
float:right;
width:280px;
background:#FFF7D2;
border:1px solid #FFCC01;
}
#m_right h2{
font-size:16px;
padding:10px;
}
#m_right p{
line-height:150%;
padding:10px 20px;
}
#add{
padding:20px;
background:#EEF7FF;
color:#666;
border:1px solid #D0E7FA;
}
#add label{
color:#666;
font-size:14px;
font-weight:bold;
line-height:30px;
}
#add span{
display:block;
padding-top:5px;
}
#footer{
width:960px;
margin:0 auto;
text-align:center;
margin-top:20px;
}
.button{
border:1px solid #389407;
background:#47AD0D;
color:#fff;
height:25px;
line-height:20px;
padding:2px 5px;
cursor:pointer;
}
#list{
padding:10px 0;
}
#list li{
padding:5px;
border-bottom: 1px solid #ACD6F6;
}
#list strong{
font-size:14px;
font-weight:bold;
color:#0066CC;
}
#list em{
font-size:12px;
color:#FF9933;
}
#list span{
float:right;
}
#list p{
padding:10px;
}
#list .reply{
background:#EEF7FF;
}
.more {
display:none;
}
.loading{
border:1px solid #ACD6F6;
background:#EEF7FF;
text-align:center;
height:50px;
line-height:50px;
display:block;
}
注:本示例模版全部使用HTML+JS+CSS完成,没有使用图片文件,如果有图片也应放在和CSS文件夹同级目录,以方便使用IMG_URL调用资源。
§ 总注
在视图中通常会使用到三个公共位置
前台apps动态调用数据文件目录 ./public/app/apps/应用名称
前台静态调用资源文件目录 ./public/img/apps/应用名称
后台控制器调用的资源文件目录 ./public/admin/apps/应用名称