近在寫項目,發現很多情況下遇到無限極分類的情況,這里寫一下,幫助還對這塊不太熟悉的同學的同時自己也做一下總結
首先無限極分類函數:
function get_attr($list, $pid){ $tree=array(); //每次都聲明一個新數組用來放子元素 foreach($list as $v){ if($v['pid']==$pid){ //匹配子記錄 $v['children']=get_attr($list,$v['id']); //遞歸獲取子記錄 if($v['children']==null){ unset($v['children']); //如果子元素為空則unset()進行刪除,說明已經到該分支的最后一個元素了(可選) } $tree[]=$v; //將記錄存入新數組 } } return $tree; //返回新數組 }
分頁函數
public function pageS($table,$num,$order='',$field='*',$where='',$join=''){ $User=M($table); // 實例化User對象 $count=$User->join($join)->where($where)->count();// 查詢滿足要求的總記錄數 $Page=new \Think\Page($count,$num);// 實例化分頁類 傳入總記錄數和每頁顯示的記錄數 $show=$Page->show();// 分頁顯示輸出// 進行分頁數據查詢 注意limit方法的參數要使用Page類的屬性 $list=$User->join($join)->order($order)->field($field)->where($where)->limit($Page->firstRow.','.$Page->listRows)->select(); $list=get_attr($list,0); $this->assign('page',$show);// 賦值分頁輸出 $this->assign('list',$list);// 賦值分頁輸出 return $list; }
控制器調用
public function index(){ $this-> pageS('district',10,'id asc','*','disabled=0'); $this -> display(); }
打印出的數據格式
模板頁面輸出
<volist name="list" id="v"> <tr> <td><input type="checkbox" class="js_check" name="id[]" value="{$v['id']}"></td> <td>{$v['id']}</td> <td>{$v.name}</td> <td> <a class="btn btn-xs btn-warning" data-id='94' href="__URL__/edit/id/{$v['id']}">修改</a> <a class="btn btn-xs btn-danger ajax-get" data-id='93' href="{:U('dele?id='.$v['id'])}">刪除</a> </td> </tr> <volist name="v.children" id="vs"> <tr> <td><input type="checkbox" class="js_check" name="id[]" value="{$vs['id']}"></td> <td>{$vs['id']}</td> <td>?┗?{$vs.name}</td> <td> <a class="btn btn-xs btn-warning" data-id='94' href="__URL__/edit/id/{$vs['id']}">修改</a> <a class="btn btn-xs btn-danger ajax-get" data-id='93' href="{:U('dele?id='.$vs['id'])}">刪除</a> </td> </tr> </volist>
頁面展示效果
認真寫代碼,認真享受生活。我是兔子不叫,我為自己代言!
————— 這是華麗的分割線 (`?ω?′) —————
ps:希望喜歡我的朋友點贊,關注,轉發一下。
網站開發,程序設計,UI等相關問題,編程技巧以及其他你想向我問的問題,來者不拒。
分層數據(Hierarchical Data),比如無限級分類菜單、省市區分級等,類似于樹型數據結構,在 MySQL 等關系型數據庫中不能很自然的展示這種父-子關系,常見的實現模型有兩種,一種是鄰接表模型 (The Adjacency List Model),另一種是嵌套集合模型 (Nested Set Model)。
分層結構數據示例:省市區分級
鄰接表模型,至少有 id 和 parent_id 兩個字段,通過父級 ID(parent_id)字段值,遞歸算法,將存儲的數據構建為樹。
嵌套集合模型是一種新的分層數據模型,通過集合的包含關系表示分層結構,每一個分層可以用一個集合(圖中的一個圈)來表示。在 MySQL 中定義兩個字段 lft 和 rgt ,即集合的左值和右值來表示一個集合的范圍。
圖片來源:wikipedia
如圖所示,處于層級結構頂端的 Clothing 分類包含所有的子類,因此它的左值和右值分別為 1 和 22,右值是其包含的所有節點總數的兩倍。下一層級 Men's 和 Women's 兩個子類的左值和右值分別為(2,9)和(10,21),每一層節點的左值和右值都根據它們包含的子層級來賦值。如果這時在 Suits 中再增加一個分類到 jackets 之后,那么新增加的分類左值和右值分別是(8,9),原 Suits、Men's、Clothing 的右值及 Women's 集合內的所有的集合的左值和右值都加 2 。
MySql 中以嵌套集合模型存儲的省市區分層數據
如圖所示,在 Laravel 框架的Nestedset 擴展模塊中,默認定義了字段 _lft 和 _rgt 分別保存左值和右值,表示集合的范圍(因為 left 和 right 在MySQL當中是保留字,所以不能用于字段名),還定義了字段 parent_id 用來表示父級節點。
增加節點時,新節點的所有右邊節點的值都加 2。查詢時按節點的邊緣走,子節點的 _lft 值總是在其父節點的 _lft值 和 _rgt值 之間。
總之在實現無限級分類時,鄰接表模型增加節點相對容易,但查詢因為要用遞歸,雖然容易理解但嚴重影響效率。嵌套集合模型增加和修改節點比較復雜,但查詢時比較簡單。不過對于分層數據,一般在創建好之后就很少修改,而查詢卻要頻繁的調用。我想在大多數情況下嵌套集合模型應該更適用一些吧。
在 Laravel 框架中,嵌套集合模型已經有了一個很好的“輪子”,就是 Nestedset 擴展模塊,讓我們可以不用去管實現的細節,簡單好用,簡直不要太爽啊。
1、安裝 nestedset 擴展
安裝時要注意版本,查看laravel 版本命令: php artisan -v,Laravel 5.7+ 之后支持 nestedset v5 版本。
composer require kalnoy/nestedset
2、創建一個 district 模型及其數據庫遷移文件。
php artisan make:model district -m
編輯生成的模型文件 district.php ,增加一行,use NodeTrait; 引入嵌套集合模型 Nestedset 擴展的 Trait ,然后 district 模型就可以直接使用 Nestedset 擴展定義的方法了,是的,就是這么簡單。
use Kalnoy\Nestedset\NodeTrait;
class District extends Model
{
use NodeTrait; // 引入嵌套集合模型 Nestedset 擴展的 Trait
編輯生成的數據庫遷移文件,位于database/migrations目錄下,文件名形如 2020_05_20_094506_create_districts_table.php ,在 up 方法的 schema 構建器中增加一行:$table->nestedSet(); 這是 nestedset 擴展用來生成 _lft _rgt parent_id 三個字段,用嵌套集模型實現無限級分類。
public function up()
{
Schema::table('districts', function (Blueprint $table) {
$table->increments('id');
$table->string('name',64)->comment('名稱');
// 嵌套集模型,無限級分類,nestedset擴展,增加了三個字段:_lft _rgt parent_id ,類型 int 長度10
$table->nestedSet();
$table->unsignedSmallInteger('type')->nullable()->comment('機構類別_省市縣鄉學區_12345_五類,允許值為NULL');
$table->boolean('status')->default(1)->comment('啟用或禁用狀態,默認值為1(啟用)');
});
}
運行遷移,將字段添加到 districts 表中。
php artisan migrate
3、配置路由,編輯 routes/api.php 文件,創建 restfull 風格的路由。
Route::middleware('auth:api')->prefix('v1')->group(function() {
// 區域
Route::apiResource('districts', 'DistrictController');
// ......
});
4、生成 Rest 風格的資源控制器文件。
php artisan make:controller DistrictController --resource
編輯控制器文件,為了簡單,對代碼做了簡化,沒有做數據校驗及權限驗證,并且已經對返回的 json 格式數據做了全局處理,測試客戶端是 Postman,最后的前端展示是 Element。
5、查詢操作:編輯 index 方法
public function index(Request $request)
{
// 從當前認證用戶信息中獲取用戶所在區域、用戶角色
$user=$request->user('api');
$userDistrictID=55;
$isSuperAdmin=true;
if ($isSuperAdmin) {
$result=District::get()->toTree(); // 獲取全部節點的集合,將它轉化為樹
} else {
$result=District::descendantsAndSelf($userDistrictID)->toTree(); // 按節點 id 獲取包含自身在內的所有子節點
}
return $this->success($result);
}
這里用了兩個方法,District::get()->toTree(); // 獲取全部節點的集合,將它轉化為樹。
District::descendantsAndSelf($userDistrictID)->toTree(); // 按節點 id 做為父節點,獲取包含自身在內的所有子節點,并轉化為樹。
get 請求路徑 /api/v1/districts ,返回結果示例:
{
"status": "success",
"code": 200,
"data": {
"name": "北京市",
"parent_id": null,
"_lft": 11,
"_rgt": 16,
"id": 37,
"children": [
{
"name": "東城區",
"parent_id": 37,
"_lft": 12,
"_rgt": 13,
"id": 38,
"children": []
},
{
"name": "西城區",
"parent_id": 37,
"_lft": 14,
"_rgt": 15,
"id": 39,
"children": []
}
]
}
}
編輯 show 方法:
public function show($id)
{
//
$result=District::find($id);
return $this->success($result);
}
get 請求,路徑 /api/v1/districts/55 (其中55是區域的 ID)
6、修改 update 方法,實現修改節點名稱的功能。
public function update(Request $request, $id)
{
// put 請求,修改名稱
$node=District::find($id); // 要修改的節點
$node->name=$request->name;
$node->save();
return $this->success($node);
}
put 請求,路徑 /api/v1/districts/55 (其中55是區域的 ID)
7、編輯 store 方法,實現增加節點的功能。前面說過,增加節點相對復雜一些。先給出三個示例數組,用來展示增加節點時的數據結構。在每次增加操作中,只能有一個根節點,可以有多個后代節點。nestArrA 用來展示添加多個后代節點,其中第一個 name 鍵就是根節點的名稱。nestArrC 用來展示添加子節點,只能一次添加一個子節點,其中 'parent_id'=> 55,表示要添加子節點所在的父節點。
// 數據示例,創建節點,第一個 name 是root節點
$nestArrA=[
'name'=> '甘肅省',
'children'=> [
[
'name'=> '蘭州市',
'children'=> [
[
'name'=> '城關區',
],
],
],
[
'name'=> '隴南市',
'children'=> [
[
'name'=> '武都區',
],
[
'name'=> '文縣',
],
],
],
],
];
// 數據示例,創建節點,多個子節點
$nestArrB=[
'name'=> '北京市',
'children'=> [
[
'name'=> '東城區',
],
[
'name'=> '西城區',
],
],
];
// 添加子節點示例數據,一次只能添加一條node
$nestArrC=[
'parent_id'=> 55,
'node'=> [
'name'=> '柏林學區',
'type'=> '5'
],
];
這里當存在 parent_id 時,要創建子節點,在 nestedset 擴展中有多種方法可用。如果以子節點自身做為對象來創建時,就要對子節點實例化,再賦值,有點麻煩。所以這里先查找到這個 id 的節點對象作為父節點,再借助父節點的 children 關系,添加子節點到父節點末端。
public function store(Request $request)
{
// 創建節點
$inputData=$request->all();
if ($inputData['parent_id'] ) {
// 如示例數據$nestArrC,則創建子節點,一次只能添加一條
$parent=District::find($inputData['parent_id'] ); // 已存在的節點,做為新添加節點的父節點
$result=$parent->children()->create($inputData['node']); //借助父節點的children關系,添加子節點到指定的父節點末端
}else {
// 請求數據結構如示例數據$nestArrA或$nestArrB,將數組構建為樹,只能有一個root節點 ,但可以有許多個子孫節點。
$result=District::create($inputData); // 將數組構建為樹
}
return $this->success($result);
}
post 請求,路徑 /api/v1/districts ,發送的 json 格式數據示例:
{
"parent_id":"35",
"node":
{
"name":"武都區"
}
}
前端使用 Element 框架實現,代碼太多,只用圖片展示一下完成的效果。總之在 Laravel 中利用 nestedset 擴展以 restfull 方法提供 api ,前端配合 Element 框架,可以非常簡單的實現無限級分類。
前端展示分層結構
(自動篩選,添加子節點)
參考資料:
laravel-nestedset擴展: https://github.com/lazychaser/laravel-nestedset
laravel-nestedset:多級無限分類正確姿勢 https://segmentfault.com/a/1190000012986277
在 MySql 中管理分層數據(譯文:Yimin): https://www.cnblogs.com/phaibin/archive/2009/06/09/1499687.html
維基百科_嵌套集合模型 https://en.wikipedia.org/wiki/Nested_set_model
分層數據 Hierarchical Data 探索 (3.嵌套集合模型) 無限極分類 https://segmentfault.com/a/1190000021727382
---end---
月8日起,國家13部門開展了聯合整治“保健”市場亂象的“百日行動”。作為保健品行業、直銷行業的一員,無限極積極擁護、主動配合,全面開展自省自查自糾。
本著正視問題、承擔責任,狠抓重點、堅決落實,集中整治與長效監管相結合的指導原則,1月28日,無限極以更高標準、更嚴要求制定了專項整改“十項措施”,快速落實整改,目前已取得初步成效。
日前,無限極(中國)有限公司媒體事務總監張前在接受南方日報、南方+記者獨家專訪時,詳細介紹了無限極深化落實整改措施的最新情況。其中,張前還特別提到,為了將專項整改“十項措施”貫徹到底,無限極成立了28個由行政總監擔任組長的工作組,分赴全國30家分公司,在全國范圍內開展“承擔主體責任,落實專項整改——規范萬里行”工作,協助并配合分公司落實專項整改工作。
繼續妥善處理消費者投訴和退換貨
為了更好地傾聽消費者的建議,快速、妥善處理消費者投訴,1月18日,無限極成立了由高級副總裁牽頭的消費者投訴處理專職小組,對所有投訴實行一案一檔、專人負責、責任到人的跟進處理方式。截至3月28日,消費者投訴處理完成率為63%,其余仍在溝通處理中。
根據專項整改“十項措施”的要求,無限極嚴格執行退換貨制度,妥善處理退換貨。數據顯示,1月9日至3月27日的退換貨申請,耐用品退換貨完成率達97%,快消品退換貨完成率達99.8%,平均處理時間約1.31天。
切實采取措施保護消費者的合法權益
據張前介紹,實施專項整改“十項措施”以來,無限極在官方網站、APP、微信公眾號、微博、服務熱線、銷售小票和銷售系統界面等消費者能夠接觸到的環節,統一發布了“保健食品不是藥物,保健食品不能治病”的警示語。2月1日,分公司服務中心已全部完成警示語的擺放和張貼;截至3月13日,所有專賣店均已完成警示語的擺放和張貼。
2019年4月1日起,無限極實施對產品大額消費進行主動提醒服務。此外,無限極運用大數據智能監測單筆額度較大的保健食品消費,將主動通過人工電話外呼,告知消費者“保健食品不是藥物,保健食品不能治病”,建議消費者理性消費,并提醒消費者享有退換貨權利。
全面整治夸大虛假宣傳
張前還透露,針對部分自媒體上關于無限極的夸大虛假宣傳、內容侵權等違法行為,無限極采取了一系列整治舉措,包括:建立監控預警系統,有效監控并成功鎖定大批山寨號發布者,刪除違規文章44033篇,通過申訴等方式注銷發布違規信息的賬號191個;通過立案訴訟,重點打擊了26個冒充無限極名義發布不實或違規信息的賬號等。
持續深化經銷商管理和教育
實施專項整改“十項措施”以來,無限極暫停審批專賣店三個月,截至3月15日,所有專賣店已完成《規范經營承諾書》的簽署。
近期,無限極對經銷商管理工作進行全面梳理、重新規劃。3月19日,無限極公布了《經銷商管理辦法》,構建了從準入、經營到退出的經銷商全流程管理體系,以更高標準、更嚴要求,規范經銷商的經營行為,切實保護消費者的合法權益,承擔企業對經銷商管理的主體責任;并將“規范經營責任”列入相關職能的考核指標,責任到人,定期對經銷商規范管理辦法的落實情況進行總結、檢討、整改,對執行不力并造成嚴重后果的人員予以追責。
開展“規范萬里行”工作
日前,為了將專項整改“十項措施”貫徹到底,無限極成立了28個由行政總監擔任組長的工作組,從3月20日至31日,奔赴全國各地30家分公司,在全國范圍內開展“承擔主體責任,落實專項整改——規范萬里行”工作,協助并配合分公司落實專項整改工作。截至3月30日19:00,工作組足跡經90座城市,26.6萬公里,已累計舉辦198場經銷商座談會,覆蓋人數6886人。
工作組主要以座談會的形式,對各地經銷商代表進行規范經營宣導,引導市場轉變觀念及業務行為,誠信自律,規范經營。具體包括:
1.進一步解讀國家“百日行動”精神,幫助經銷商和行政員工深刻認識到保健品行業關系到社會民生,消費者合法權益的保護至關重要;
2.重申專項整改“十項措施”,并要求持續深化落實;
3.幫助并推動經銷商轉變觀念,深刻認識到以更高標準、更嚴要求進行規范經營不僅是對消費者權益的保障,也是對自身利益的保護,必須堅決執行;
4.引導與會人員制定行動計劃并進行分享,確保下一步的行動落實。
為保障“規范萬里行”工作順利開展,在工作組奔赴各地分公司前夕,無限極組織開展了“規范萬里行”啟動會,對工作組成員進行動員和集訓。
無限極總部還特別設立“規范萬里行”辦公室,全力支持、服務28個工作組,收集每天的進度與反饋,及時迭代、補充信息資料,并制作每日簡報,持續推進相關工作。
通過座談會,經銷商們深刻領會了國家“百日行動”精神,進一步認識到規范經營的重要性和必要性,紛紛表示將以實際行動,將專項整改“十項措施”貫徹到底,維護消費者的合法權益。
最后,張前表示,健康、規范和有序的市場環境,是企業生存發展的土壤。無限極堅決擁護“百日行動”,堅決整改。
隨著專項整改“十項措施”的深化推進,無限極將進一步推動規范教育,在全員中落實規范經營,切實維護消費者的合法權益,為企業的持續穩健發展營造良好環境,實現企業、行業和社會的和諧共贏。
【作者】 趙兵輝
【來源】 南方報業傳媒集團南方+客戶端
*請認真填寫需求信息,我們會在24小時內與您取得聯系。