一、程式 admin_kind.php
<?php
/* 引入檔頭,每支程都會引入 */
require_once 'head.php';
#權限檢查
if(!$_SESSION['isAdmin'])redirect_header("index.php", 3000, "您沒有管理員權限!");
#引入類別物件
include_once WEB_PATH . "/class/ugmKind.php";
#取得主要資料庫
$tbl = "ugm_p_kind";
/* 過濾變數,設定預設值 */
$op = system_CleanVars($_REQUEST, 'op', 'opList', 'string');
$sn = system_CleanVars($_REQUEST, 'sn', '', 'int');
$kind = system_CleanVars($_REQUEST, 'kind', 'prod', 'string');
#foreign key
$foreign = array(
"prod" => array("title" => "商品類別","stopLevel"=>1)
);
#實體化 類別物件
#stopLevel
$stopLevel = $foreign[$kind]['stopLevel']; //ugm_tools
$ofsn = 0;
//(資料表,分類,層數,父層)
$ugmKind = new ugmKind($tbl, $kind, $stopLevel, $ofsn);
#---------------------------------
#程式流程
switch ($op) {
//新增資料
case "opAllInsert":
$msg = opAllInsert();
redirect_header($_SESSION['returnUrl'], 3000, $msg);
exit;
case "opUpdateSort": //更新排序
echo opUpdateSort();
exit;
case "opSaveDrag": //移動類別儲存
echo opSaveDrag();
exit;
#類別刪除
case "opDelete" :
$msg = opDelete($sn);
redirect_header($_SESSION['returnUrl'], 3000, $msg);
exit;
//更新啟用狀態
case "opUpdateEnable":
$msg = opUpdateEnable();
redirect_header($_SESSION['returnUrl'], 3, $msg);
break;
#ajax拖曳排序
case "op_ajax_update_sort":
echo op_ajax_update_sort();
exit;
break;
#新增(Create)
case "opInsert":
$msg = opInsert();
redirect_header($_SESSION['returnUrl'], 3000, $msg);
exit;
#更新(Update)
case "opUpdate":
$msg = opUpdate($sn);
redirect_header($_SESSION['returnUrl'], 3000, $msg);
exit;
break;
#顯示單筆(Read)
case "op_show":
op_show($sn);
break;
#表單
case "opForm":
opForm($sn);
break;
#讀取(Read)
default:
$op = "opList";
$_SESSION['returnUrl'] = getCurrentUrl();
opList($kind);
break;
}
/*---- 將變數送至樣版----*/
$smarty->assign("WEB", $WEB);
$smarty->assign("op", $op);
/*---- 程式結尾-----*/
$smarty->display('theme_admin.tpl');
/*---- 程式結尾-----*/
###########################################################
# 批次編輯資料
###########################################################
function opAllInsert() {
global $db, $ugmKind;
foreach ($_POST['title'] as $sn => $title) {
$title = db_CleanVars($title, "類別名稱");//類別名稱
$sn = db_CleanVars($sn, "sn");//sn
$sql = "update `".$ugmKind->get_tbl()."` set
`title` = '{$title}'
where sn='{$sn}'";
$db->query($sql) or redirect_header("", 3000, $db->error."\n".$sql,true);
}
return "更新所有類別完成!";
}
###########################################
# 自動更新排序
###########################################
function opUpdateSort() {
global $db, $ugmKind;
$sort = 1;
foreach ($_POST['tr'] as $sn) {
if (!$sn) {
continue;
}
$sql = "update `{$ugmKind->get_tbl()}` set
`sort`='{$sort}'
where `sn`='{$sn}'";
$db->query($sql) or redirect_header("", 3000, $db->error."\n".$sql,true);
$sort++;
}
return "排序完成!!";
}
###########################################
# 移動類別儲存
###########################################
function opSaveDrag() {
global $db,$ugmKind;
$ofsn = intval($_POST['ofsn']); //目的
$sn = intval($_POST['sn']); //來源
$kind = $ugmKind->get_kind(); //關鍵字
$tbl = $ugmKind->get_tbl(); //資料表
$stopLevel = $ugmKind->get_stopLevel(); //層次
//$ofsn = $ugmKind->get_ofsn(); //父層
//return $ugmKind->chk_kind_level_down($sn);
#檢查類別層次
$thisLevel = $ugmKind->get_thisLevel($sn);
$downLevel = $ugmKind->get_downLevel($sn);
$ofsnLevel = $ugmKind->get_thisLevel($ofsn);
if (!$sn) {
#根目錄不可移動
die("根目錄不可移動 (" . date("Y-m-d H:i:s") . ")");
} elseif ($ofsn == $sn) {
#自己移至自己
die("不能自己移至自己(" . date("Y-m-d H:i:s") . ")");
} elseif ($ofsnLevel + $downLevel >= $stopLevel) {
#自己往底層移動或自己底下層數+目的所在層數 > 類別層數
die("子類別太多,請先將子類別移動!(" . date("Y-m-d H:i:s") . ")");
}
$sql = "update `{$tbl}`
set
`ofsn`='{$ofsn}'
where `sn`='{$sn}'";
$db->query($sql) or redirect_header("", 3000, $db->error."\n".$sql,true);
return "移動類別完成!";
}
###############################
# 刪除類別
###############################
function opDelete($sn){
global $db,$ugmKind;
$kind = $ugmKind->get_kind(); //關鍵字
$tbl = $ugmKind->get_tbl(); //資料表
$stopLevel = $ugmKind->get_stopLevel(); //層次
$ofsn = $ugmKind->get_ofsn(); //父層
#檢查類別層次
$downLevel = $ugmKind->get_downLevel($sn);
if($downLevel)redirect_header($_SESSION['returnUrl'], 3000, "尚有子類別,無法刪除!");
#刪除商品資料
$sql = "delete
from `{$tbl}`
where `sn`='{$sn}'
";
$db->query($sql) or redirect_header("", 3000, $db->error."\n".$sql,true);
return "刪除成功!";
}
###############################################################################
# 更新啟用
###############################################################################
function opUpdateEnable() {
global $db,$ugmKind;
#過瀘資料
$_GET['sn'] = db_CleanVars($_GET['sn'], "sn");
$_GET['enable'] = db_CleanVars($_GET['enable'], "啟用");
/****************************************************************/
//更新
$sql = "update " . $ugmKind->get_tbl() . " set
`enable` = '{$_GET['enable']}'
where `sn`='{$_GET['sn']}'";
$db->query($sql) or redirect_header("", 3000, $db->error."\n".$sql,true);
return "更新啟用狀態成功!";
}
###########################################################
# 新增資料
###########################################################
function opInsert() {
global $db, $ugmKind;
#驗證token
verifyToken($_POST['token']);
$kind = $ugmKind->get_kind(); //關鍵字
$tbl = $ugmKind->get_tbl(); //資料表
$stopLevel = $ugmKind->get_stopLevel(); //層次
$ofsn = $ugmKind->get_ofsn(); //父層
$_POST['title'] = db_CleanVars($_POST['title'], "類別名稱");//類別名稱
$_POST['kind'] = db_CleanVars($_POST['kind'], "kind");//分類
$_POST['enable'] = db_CleanVars($_POST['enable'], "啟用");//狀態
$_POST['sn'] = db_CleanVars($_POST['sn'], "");//sn
$_POST['ofsn'] = db_CleanVars($_POST['ofsn'], "ofsn");//ofsn
//-------------------------------------------------------*/
#取得排序-----------------------------#
$sql = "select max(sort) as max_sort
from `{$tbl}`
where ofsn='{$_POST['ofsn']}' and kind='{$_POST['kind']}'";
$result = $db->query($sql) or redirect_header("", 3000, $db->error."\n".$sql,true);
list($sort) = $row = $result->fetch_row();
$sort++;
#---------寫入-------------------------
$sql = "insert into `{$tbl}`
(`ofsn` ,`title` , `enable` , `sort`,`kind`)
values
('{$_POST['ofsn']}' , '{$_POST['title']}' ,'{$_POST['enable']}' , '{$sort}' , '{$_POST['kind']}')";
$db->query($sql) or redirect_header("", 3000, $db->error."\n".$sql,true);
//取得最後新增資料的流水編號
//$_POST['sn'] = $db->insert_id;
return "新增類別->{$_POST['title']} 成功!";
}
#################################
# 更新資料
#################################
function opUpdate($sn) {
global $db,$ugmKind;
#驗證token
verifyToken($_POST['token']);
$kind = $ugmKind->get_kind(); //關鍵字
$tbl = $ugmKind->get_tbl(); //資料表
$stopLevel = $ugmKind->get_stopLevel(); //層次
$ofsn = $ugmKind->get_ofsn(); //父層
#過濾
$_POST['title'] = db_CleanVars($_POST['title'], "類別名稱");//類別名稱
$_POST['kind'] = db_CleanVars($_POST['kind'], "kind");//分類
$_POST['enable'] = db_CleanVars($_POST['enable'], "啟用");//狀態
$_POST['sn'] = db_CleanVars($_POST['sn'], "sn");//sn
$_POST['ofsn'] = db_CleanVars($_POST['ofsn'], "ofsn");//ofsn
#檢查類別層次
$thisLevel = $ugmKind->get_thisLevel($sn);
$downLevel = $ugmKind->get_downLevel($sn);
$ofsnLevel = $ugmKind->get_thisLevel($_POST['ofsn']);
if($_POST['ofsn'] == $_POST['sn'])redirect_header($_SESSION['returnUrl'], 3000, "不能設定自己為父類別");
if($ofsnLevel + $downLevel >= $stopLevel)redirect_header($_SESSION['returnUrl'], 3000, "子類別太多,請先將子類別移動,再更新!");
$sql = "update `{$tbl}` set
`ofsn` = '{$_POST['ofsn']}',
`title` = '{$_POST['title']}',
`kind` = '{$_POST['kind']}',
`enable` = '{$_POST['enable']}'
where sn='{$_POST['sn']}'";
$db->query($sql) or redirect_header("", 3000, $db->error."\n".$sql,true);
return "編輯類別->{$_POST['title']} 成功!";
}
###############################################################################
# 編輯表單
###############################################################################
function opForm($sn = "") {
global $db,$smarty,$ugmKind;
$kind = $ugmKind->get_kind(); //關鍵字
$tbl = $ugmKind->get_tbl(); //資料表
$stopLevel = $ugmKind->get_stopLevel(); //層次
$ofsn = $ugmKind->get_ofsn(); //父層
//----------------------------------*/
$_GET['ofsn'] = !isset($_GET['ofsn']) ? 0 : intval($_GET['ofsn']);
//抓取預設值
if (!empty($sn)) {
$row = $ugmKind->get_rowBYsn($sn);
$pre = "編輯";
$row['op'] = "opUpdate";
//print_r($row);die();
} else {
$row = array();
$pre = "新增";
$row['op'] = "opInsert";
}
$row['formTitle'] = $pre . "類別";
$row['stopLevel'] = $stopLevel;
//預設值設定
//設定「kind_sn」欄位預設值
$row['sn'] = (!isset($row['sn'])) ? "" : $row['sn'];
//設定「ofsn」欄位預設值
$row['ofsn'] = (!isset($row['ofsn'])) ? $_GET['ofsn'] : $row['ofsn'];
if ($stopLevel > 1) {
$row['ofsnOption'] = $ugmKind->get_ofsnOption($row['ofsn']);
}
//設定「title」欄位預設值
$row['title'] = (!isset($row['title'])) ? "" : $row['title'];
//設定「enable」欄位預設值
$row['enable'] = (!isset($row['enable'])) ? "1" : $row['enable'];
//設定「kind」欄位預設值
$row['kind'] = (!isset($row['kind'])) ? $ugmKind->get_kind() : $row['kind'];
$smarty->assign('row', $row);
#防止偽造表單
$token = getTokenHTML();
$smarty->assign("token", $token);
}
#################################
# 列表程式
#################################
function opList($kind) {
global $db,$smarty,$foreign,$ugmKind;
# 預設Foreign key=> system
#---- 防呆
if (!in_array($kind, array_keys($foreign))) {
$kind = "prod";
}
# ----得到foreign key選單
$foreignOption = $ugmKind->get_foreignOption($foreign,$kind);
$foreignForm = "
<div class='row' style='margin-bottom:10px;'>
<div class='col-sm-3'>
<select name='kind' id='kind' class='form-control' onchange=\"location.href='?kind='+this.value\">
$foreignOption
</select>
</div>
</div>
";
$smarty->assign('foreignForm', $foreignForm);
$smarty->assign('kind', $kind);
# ----得到陣列 ----------------------------
$list = $ugmKind->get_listArr();
$listTitles = array(
"title" => array("content" => "標題", "width" => 9, "align" => "center"),
"enable" => array("content" =>"啟用", "width" => 1, "align" => "center"),
"function" => array("content" => "功能", "width" => 2, "align" => "center"),
);
$smarty->assign("listTitles", $listTitles);
#內容---------------------------------------------------------#
$listBodys = array(
"title" => array("valuetype" => "text", "align" => "left"),
"enable" => array("valuetype" => "yesNo", "align" => "center"),
"function" => array("valuetype" => "btn", "align" => "center", "btn" => array("edit", "del")), //瀏覽、編輯、刪除
);
$listHtml = $ugmKind->get_listHtml($list, $listBodys);
$smarty->assign("listHtml", $listHtml);
return;
}
二、樣板 admin_kind.tpl
<{if $op=="opList"}>
<link href="<{$xoAppUrl}>class/treeTable/stylesheets/jquery.treetable.css" rel="stylesheet">
<link href="<{$xoAppUrl}>class/treeTable/stylesheets/jquery.treetable.theme.default.css" rel="stylesheet">
<script
src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"
integrity="sha256-VazP97ZCwtekAsvgPBSUwPFKdrwD3unUfSGVYrahUqU="
crossorigin="anonymous"></script>
<script type="text/javascript" src="<{$xoAppUrl}>class/treeTable/javascripts/src/jquery.treetable.js"></script>
<script type="text/javascript">
$(function() {
//可以展開,預設展開
$('#form_table').treetable({ expandable: true ,initialState: 'expanded' });
// 配置拖動節點
$('#form_table .folder').draggable({
helper: 'clone',
opacity: .75,
refreshPositions: true, // Performance?
revert: 'invalid',
revertDuration: 300,
scroll: true
});
// Configure droppable rows
$('#form_table .folder').each(function() {
$(this).parents('#form_table tr').droppable({
accept: '.folder',
drop: function(e, ui) {
var droppedEl = ui.draggable.parents('tr');
console.log(droppedEl[0]);
$('#form_table').treetable('move', droppedEl.data('ttId'), $(this).data('ttId'));
//alert( droppedEl.data('ttId'));
//目地的sn :$(this).data('ttId')
//自己的sn:droppedEl.data('ttId')
$.ajax({
type: 'POST',
url: '?op=opSaveDrag',
data: { ofsn: $(this).data('ttId'), sn: droppedEl.data('ttId'),kind :"<{$kind}>" },
success: function(theResponse) {
//$('#save_msg').html(theResponse);
//警告視窗
swal({
title: theResponse,
text: '自動刷新畫面',
type: 'success',
showCancelButton: false,
confirmButtonColor: '#3085d6',
confirmButtonText: '確定'
}).then(function () {
location.href="<{$smarty.session.returnUrl}>";
});
}
});
},
hoverClass: 'accept',
over: function(e, ui) {
var droppedEl = ui.draggable.parents('tr');
if(this != droppedEl[0] && !$(this).is('.expanded')) {
$('#form_table').treetable('expandNode', $(this).data('ttId'));
}
}
});
});
//排序
$('#sort').sortable({ opacity: 0.6, cursor: 'move', update: function() {
var order = $(this).sortable('serialize') + '&op=opUpdateSort';
$.post('<{$WEB.file_name}>', order, function(theResponse){
//$('#save_msg').html(theResponse);//傳回訊息
//警告視窗
swal({
title: theResponse,
text: '自動刷新畫面',
type: 'success',
showCancelButton: false,
confirmButtonColor: '#3085d6',
confirmButtonText: '確定'
}).then(function () {
location.href="<{$smarty.session.returnUrl}>";
});
});
}
});
//每行的删除操作注册脚本事件
$(".btnDel").bind("click", function(){
var vbtnDel=$(this);//得到点击的按钮对象
var vTr=vbtnDel.parents("tr");//得到父tr对象;
var sn=vTr.attr("sn");//取得 sn
var title=$("#title_"+sn).val();//取得 title
//警告視窗
swal({
title: '確定要刪除此資料?',
text: title,
type: 'warning',
showCancelButton: true,
confirmButtonColor: '#3085d6',
cancelButtonColor: '#d33',
confirmButtonText: '確定刪除!',
cancelButtonText: '取消!'
}).then(function () {
location.href="admin_kind.php?op=opDelete&sn=" + sn;
})
});
});
</script>
<div class="panel panel-primary">
<div class="panel-heading"><h3 class="panel-title">類別管理</h3></div>
<div class="panel-body">
<div id="save_msg"></div>
<form action='<{$WEB.file_name}>' method='post' id='myForm'>
<{$foreignForm}>
<table id="form_table" class="table table-bordered table-striped table-hover">
<thead>
<tr class="active">
<{foreach from=$listTitles item=row key=k}>
<th class="col-sm-<{$row.width}> text-<{$row.align}>"><{$row.content}></th>
<{/foreach}>
</tr>
</thead>
<!-- 根目錄開始 -->
<tr id='tr_0' data-tt-id="0">
<td class="text-left" colspan=<{$listTitles|@count}>>
<span class='folder'></span>
<i class="fa fa-home" aria-hidden="true"></i>根目錄
<a href="#" class="btn btn-success btn-xs" onclick="jQuery('#form_table').treetable('expandAll'); return false;">展開<i class="fa fa-expand" aria-hidden="true"></i></a>
<a href="#" class="btn btn-danger btn-xs" onclick="jQuery('#form_table').treetable('collapseAll'); return false;">闔起<i class="fa fa-compress" aria-hidden="true"></i></a>
<a href="#" class="btn btn-warning btn-xs">重整畫面<i class="fa fa-refresh" aria-hidden="true"></i></a>
<a href="?op=opForm&kind=<{$kind}>&ofsn=0" class="btn btn-primary btn-xs" ait="在根目錄建立子類別">新增<i class="fa fa-plus" aria-hidden="true"></i></a>
</td>
</tr>
<!-- 根目錄結束 -->
<tbody id='sort'>
<{$listHtml}>
</tbody>
<tfoot>
<tr>
<td colspan=3 class="text-center">
<input type='hidden' name='op' value="opAllInsert">
<input type='hidden' name='kind' value="<{$kind}>">
<button type="submit" class="btn btn-primary">送出</button>
</td>
</tr>
</tfoot>
</table>
</form>
</div>
</div>
<{/if}>
<{if $op=="opForm"}>
<div class="panel panel-primary">
<div class="panel-heading"><h3 class="panel-title"><{$row.formTitle}></h3></div>
<div class="panel-body">
<form role="form" action="<{$WEB.file_name}>" method="post" id="myForm" enctype="multipart/form-data">
<div class="row">
<div class="col-sm-6">
<div class="form-group">
<label>標題</label>
<input type='text' name='title' value='<{$row.title}>' id='title' class="form-control">
</div>
</div>
<div class="col-sm-2">
<div class="form-group">
<label style="display:block;" >啟用</label>
<input type='radio' name='enable' id='enable_1' value='1' <{if $row.enable==1}>checked<{/if}>>
<label for='enable_1'>啟用</label>
<input type='radio' name='enable' id='enable_0' value='0' <{if $row.enable==0}>checked<{/if}>>
<label for='enable_0'>停用</label>
</div>
</div>
<{if $row.stopLevel > 1}>
<div class="col-sm-2">
<div class="form-group">
<label>父類別</label>
<select name="ofsn" id="ofsn" class="form-control" size="1" >
<option value="0">/</option>
<{$row.ofsnOption}>
</select>
</div>
</div>
<{else}>
<input type='hidden' name='ofsn' value='0'>
<{/if}>
</div>
<hr>
<div class="form-group text-center">
<button type="submit" class="btn btn-primary">送出</button>
<{if !$row.sn}>
<button type="reset" class="btn btn-danger">重設</button>
<{/if}>
<button type="button" class="btn btn-warning" onclick="location.href='<{$smarty.session.returnUrl}>'">返回</button>
<input type='hidden' name='op' value='<{$row.op}>'>
<input type='hidden' name='sn' value='<{$row.sn}>'>
<input type='hidden' name='kind' value='<{$row.kind}>'>
<{$token}>
</div>
</form>
</div>
</div>
<{/if}>
三、使用