php+ajax 实现无限树列表

首先介绍我实现的是xhprof插件的日志转为无限树状图,先看效果图:

废话不多说,直接看代码:(辛辛苦苦敲了好久才搞定,逻辑比较多,新手多揣摩)

控制器:

  1 <?php
  2 
  3 namespace Admin\Controller;
  4
  7 
  8 class XhprofController extends AdminbaseController
  9 {
 10     function _initialize()
 11     {
 12         parent::_initialize();
 13     }
 14 
 15     //获取当前文件目录
 16     public function index()
 17     {
 18         $file = scandir("./public");
 19         $str = ".xhprof";
 20         foreach ($file as $value) {
 21             if (preg_replace("/($str)/", "", $value) != $value) {
 22                 $dir[] = $value;
 23             }
 24         }
 25 //        $count = count($dir);
 26 //        $page = $this->page($count, 20);
 27 //        $this -> assign( "Page", $page->show( 'Admin' ) );
 28         $this->assign("dir", $dir);
 29         $this->display();
 30     }
 31 
 32     //获取适当的结构
 33     public function tree($file_name)
 34     {
 35         $file_path = "./public/xhprof/$file_name";
 36         $file_name = str_replace('.', '', $file_name);
 37         if (F($file_name)) {
 38             $mainTree = F($file_name);
 39         } else {
 40             if (file_exists($file_path)) {
 41                 $fp = fopen($file_path, "r");
 42                 $str = fread($fp, filesize($file_path));//指定读取大小,这里把整个文件内容读取出来
 43                 $array = json_decode($str, true);
 44                 $array_keys = array_keys($array);
 45                 //按照调用者整理数据
 46                 $calls = [];
 47                 foreach ($array_keys as $array_key) {
 48                     $caller = explode("==>", $array_key)[0];
 49                     $beCall = explode("==>", $array_key)[1];
 50                     if (!$calls[$caller]) {
 51                         $calls[$caller] = [
 52                             "caller" => $caller,
 53                             "beCalls" => []
 54                         ];
 55                     }
 56                     $status = 0;//是否有子目录
 57                     foreach ($array_keys as $keyv) {
 58                         if (strpos($keyv, $beCall . '==>') !== false && strpos($keyv, "@") === false && $beCall !== null && $beCall !== "count") {
 59                             $status = 1;
 60                         }
 61                     }
 62                     if ($beCall !== null) {
 63                         $calls[$caller]['beCalls'][] = array('name' => $beCall, "status" => $status, 'data' => $array[$array_key]);
 64                     }
 65                 }
 66                 foreach ($calls as &$v) {
 67                     $tmpAll = 0;
 68                     foreach ($v['beCalls'] as $vv) {
 69                         $tmpAll += $vv['data']['wt'];
 70                     }
 71                     foreach ($v['beCalls'] as &$vv1) {
 72                         $vv1['data']['wtp'] = round($vv1['data']['wt'] * 100 / $tmpAll, 2);
 73                         $vv1['wtp'] = $vv1['data']['wt'];
 74                     }
 75                 }
 76                 $mainTree = $calls;
 77                 //缓存$mainTree
 78                 F($file_name, $mainTree);
 79             } else {
 80                 $mainTree = "";
 81             }
 82         }
 83         array_multisort(array_column($mainTree["main()"]["beCalls"], "wtp"), SORT_DESC, array_column($mainTree["main()"]["beCalls"], "name"), SORT_DESC, $mainTree["main()"]["beCalls"]);
 84         $this->assign("main", $array["main()"]);
 85         $this->assign("mainTree", $mainTree["main()"]);
 86         $this->assign("level", 1);
 87         $this->assign("file_name", $file_name);
 88         $this->assign("file_path", $file_path);
 89         $this->display();
 90     }
 91 
 92     public function ajax()
 93     {
 94         $note = htmlspecialchars_decode(I("post.note"));
 95         $file_name = htmlspecialchars_decode(I("post.file_name"));
 96         $file_path = htmlspecialchars_decode(I("post.file_path"));
 97         //处理$mainTree
 98         if (F($file_name)) {
 99             $mainTree = F($file_name);
100         } else {
101             if (file_exists($file_path)) {
102                 $fp = fopen($file_path, "r");
103                 $str = fread($fp, filesize($file_path));//指定读取大小,这里把整个文件内容读取出来
104                 $array = json_decode($str, true);
105                 $array_keys = array_keys($array);
106                 //按照调用者整理数据
107                 $calls = [];
108                 foreach ($array_keys as $array_key) {
109                     $caller = explode("==>", $array_key)[0];
110                     $beCall = explode("==>", $array_key)[1];
111                     if (!$calls[$caller]) {
112                         $calls[$caller] = [
113                             "caller" => $caller,
114                             "beCalls" => []
115                         ];
116                     }
117                     $status = 0;//是否有子目录
118                     foreach ($array_keys as $keyv) {
119                         if (strpos($keyv, $beCall . '==>') !== false && strpos($keyv, "@") === false && $beCall !== null && $beCall !== "count") {
120                             $status = 1;
121                         }
122                     }
123                     if ($beCall !== null) {
124                         $calls[$caller]['beCalls'][] = array('name' => $beCall, "status" => $status, 'data' => $array[$array_key]);
125                     }
126                 }
127                 foreach ($calls as &$v) {
128                     $tmpAll = 0;
129                     foreach ($v['beCalls'] as $vv) {
130                         $tmpAll += $vv['data']['wt'];
131                     }
132                     foreach ($v['beCalls'] as &$vv1) {
133                         $vv1['data']['wtp'] = round($vv1['data']['wt'] * 100 / $tmpAll, 2);
134                         $vv1['wtp'] = $vv1['data']['wt'];
135                     }
136                 }
137                 $mainTree = $calls;
138                 //缓存$mainTree
139                 F($file_name, $mainTree);
140             } else {
141                 $mainTree = "";
142             }
143         }
144         array_multisort(array_column($mainTree[$note]["beCalls"], "wtp"), SORT_DESC, array_column($mainTree[$note]["beCalls"], "name"), SORT_DESC, $mainTree[$note]["beCalls"]);
145         $this->ajaxReturn($mainTree[$note]);
146     }
147 
148 
149 }

veiw界面:

 1 </head>
 2 <body>
 3 <div class="wrap">
 4     <ul class="nav nav-tabs">
 5         <li class="active"><a href="">{:L('ADMIN_XHPROF')}</a></li>
 6     </ul>
 7     <form method="post" class="js-ajax-form" action="{:U('AdminTerm/listorders')}">
 8         <table class="table table-hover table-bordered table-list">
 9             <thead>
10             <tr>
11                 <th width="2">ID</th>
12                 <th width="50">{:L('FILE_NAME')}</th>
13             </tr>
14             </thead>
15             <tbody>
16             <volist name="dir" id="vo" key="k">
17                 <tr>
18                     <th width="2">{$k}</th>
19                     <th width="50"><a href="{:U('admin/xhprof/tree',array('file_name'=>$vo))}">{$vo}</a></th>
20                 </tr>
21             </volist>
22             </tbody>
23             <tfoot>
24             <tr>
25                 <th width="2">ID</th>
26                 <th width="50">{:L('FILE_NAME')}</th>
27             </tr>
28             </tfoot>
29         </table>
30         <div class="pagination">{$Page}</div>
31     </form>
32 </div>
33 <script src="__PUBLIC__/js/common.js"></script>
34 </body>
35 </html>
View Code

 

  1 <html>
  2 <head>
  3     <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
  4     <title>Xhprof数据分析</title>
  5     <link rel="stylesheet" type="text/css" href="__TMPL__Public/assets/css/bootstrap.min.css"/>
  6     <link rel="stylesheet" type="text/css" href="__TMPL__Public/assets/css/xhprof.css"/>
  7     <script type="text/javascript" src="__PUBLIC__/js/jquery.js"></script>
  8 </head>
  9 <body>
 10 <div class="tree well">
 11     <ul>
 12         <li>
 13             <span class="main">
 14                 <i class='icon-minus'> </i>  <b class="name">main()</b>
 15                             第<b>&nbsp;1&nbsp;</b>级&emsp;&emsp;&emsp;
 16                             ct:<b class="bw">{$main.ct}</b>
 17                             wt:<b class="red" >{$main.wt} (100%)</b>
 18                             cpu:<b class="bw">{$main.cpu}</b>
 19                             mu:<b class="bw">{$main.mu}</b>
 20                             pmu:<b class="bw">{$main.pmu}</b>
 21             </span>
 22             <foreach name="mainTree['beCalls']" item="vo">
 23                 <ul>
 24                     <li class='parent_li'>
 25                         <span title='Collapse this branch' note="{$vo.name}" level="2" file_name={$file_name} file_path={$file_path}>
 26                              <if condition="$vo['status']==1">
 27                                  <i class="icon-plus"></i>
 28                                  <else/>
 29                                  <b style='width:14px;display: inline-block;'></b>
 30                              </if>
 31                             <div style="display: inline-block;">
 32                              <b class="name" title={$vo.name}>{$vo.name}</b>
 33                              第<b>&nbsp;2&nbsp;</b>级&emsp;&emsp;&emsp;
 34                              ct:<b class="ct">{$vo.data.ct}</b>
 35                              <if condition="$vo['data']['wtp'] gt 10">
 36                                  wt:<b class="red">{$vo.data.wt} ({$vo.data.wtp|round=2}%)</b>
 37                                  <else/>
 38                                  wt:<b class="wt" style="display: inline-block;min-width: 150px;">{$vo.data.wt} ({$vo.data.wtp|round=2}%)</b>
 39                              </if>
 40                             cpu:<b class="bw">{$vo.data.cpu}</b>
 41                             mu:<b class="bw">{$vo.data.mu}</b>
 42                             pmu:<b class="bw">{$vo.data.pmu}</b>
 43                             </div>
 44                         </span>
 45                     </li>
 46                 </ul>
 47             </foreach>
 48         </li>
 49     </ul>
 50 </div>
 51 </body>
 52 <script>
 53     $(function () {
 54         $('.tree li:has(ul)').addClass('parent_li').find(' > span').attr('title', 'Collapse this branch');
 55         $('body').on('click', "span", function (e) {
 56             e.stopPropagation();
 57             if ($(this).attr('is_click') === 1) {
 58                 return false;
 59             }
 60             $(this).attr('is_click', 1);
 61             var children = $(this).parent('li.parent_li').find(' > ul > li');
 62             if (children.is(":visible")) {
 63                 children.hide('fast');
 64                 $(this).attr('title', 'Expand this branch').find(' > i').addClass('icon-plus').removeClass('icon-minus');
 65                 $(this).attr('is_click', 0);
 66             } else {
 67                 children.show('fast');
 68                 $(this).attr('title', 'Collapse this branch').find(' > i').addClass('icon-minus').removeClass('icon-plus');
 69                 if ($(this).hasClass('main')) {
 70                     $(this).attr('is_click', 0);
 71                     return;
 72                 }
 73                 if (!$(this).siblings('.child').length) {
 74                     do_ajax($(this));
 75                 } else {
 76                     $(this).attr('is_click', 0);
 77                 }
 78             }
 79         });
 80 
 81         function do_ajax(e) {
 82             var note_js = e.attr('note');
 83             var level_js = e.attr('level');
 84             var file_name_js = e.attr('file_name');
 85             var file_path_js = e.attr('file_path');
 86             $.ajax({
 87                 type: "post",
 88                 cache: false,
 89                 dataType: "json",
 90                 url: "{:U('Admin/Xhprof/ajax')}",
 91                 data: {
 92                     note: note_js,
 93                     level: level_js,
 94                     file_name: file_name_js,
 95                     file_path: file_path_js
 96                 },
 97                 success: function (data) {
 98                     if (data.beCalls !== null) {
 99                         var str = "";
100                         for (var i = 0; i < data.beCalls.length; i++) {
101                             str += "<ul class='child'>";
102                             str += "<li class='parent_li'>";
103                             str += "<span title='Collapse this branch' class='load'   note=" + data.beCalls[i].name + " level= " + eval(Number(level_js) + 1) + " file_name= " + file_name_js + " file_path= " + file_path_js + ">";
104                             if (data.beCalls[i].status == 1) {
105                                 str += "<i  class='icon-plus' ></i>";
106                             } else {
107                                 str += "<b style='width:14px;display: inline-block;'> </b>";
108                             }
109                             str += "<b class='name' title="+ data.beCalls[i].name + ">" + data.beCalls[i].name + '</b>第<b>&nbsp;' + eval(Number(level_js) + 1) + "</b>&nbsp;级&emsp;&emsp;&emsp;ct:<b class='ct'>" + data.beCalls[i].data.ct + "</b>  wt:<b  class= " + (data.beCalls[i].data.wtp < 10 ? 'wt' : 'red') + " >" + data.beCalls[i].data.wt + "(" + data.beCalls[i].data.wtp + "%)</b>  cpu:<b class='bw' >" + data.beCalls[i].data.cpu + "</b>  mu:<b class='bw'>" + data.beCalls[i].data.mu + "</b>   pmu:<b class='bw'>" + data.beCalls[i].data.pmu + "</b></span>";
110                             str += '</li>';
111                             str += '</ul>';
112                         }
113                         e.siblings('.child').remove();
114                         e.after(str);
115                         e.attr('is_click', 0);
116                     }
117                 },
118                 error: function () {
119                 }
120             })
121         }
122     });
123 </script>
124 </html>
posted @ 2018-12-18 16:12  joker_one  阅读(298)  评论(0编辑  收藏  举报