• 夺命雷公狗ThinkPHP项目之----商城9商品后台无限极分类


    无限极分类,几乎在每个网站上都会用到的,因此而重要。

    先来对数据表进行分析

    parent_id:表示当前分类的父id,他是实现无限级分类的关键

    无限级分类,主要从两个方面进行考虑的。

    1.数据库的设计,表中的parent_id字段。

    2.在程序的层面上,来完成,使用递归。

    我们只要理解下面这张图即可了解无限极分类的大部份了

    上面的这三表是否可以变成下面这一张表呢?

    这样的话关联起来是不是更加方便呢?

    说白了也就是PID就是他的老爸的ID一直到PID为0这就到了顶级分类

    添加分类,首先是要载入添加的表单,确保表单的name和字段一致,首先在view里面创建一个category文件夹在里面将模版放进去,我们先来写add.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>
    <title>SHOP 管理中心 - 添加分类 </title>
    <meta name="robots" content="noindex, nofollow">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <link href="__ADMIN__/styles/general.css" rel="stylesheet" type="text/css" />
    <link href="__ADMIN__/styles/main.css" rel="stylesheet" type="text/css" />
    </head>
    <body>
    
    <h1>
    <span class="action-span"><a href="index.php?p=admin&c=category&a=index">商品分类</a></span>
    <span class="action-span1"><a href="index.php?act=main">SHOP 管理中心</a> </span><span id="search_id" class="action-span1"> - 添加分类 </span>
    <div style="clear:both"></div>
    </h1>
    <!-- start add new category form -->
    <div class="main-div">
      <form action="" method="post" name="theForm" enctype="multipart/form-data" onsubmit="return validate()">
         <table width="100%" id="general-table">
            <tbody>
                <tr>
                    <td class="label">分类名称:</td>
                    <td><input type="text" name="cat_name" maxlength="20" value="" size="27"> <font color="red">*</font></td>
                </tr>
                <tr>
                    <td class="label">上级分类:</td>
                    <td>
                        <select name="parent_id">
                            <option value="0">顶级分类</option>
                            <volist name="cats" id='vo'>
                                <option value="{$vo['cat_id']}">{$vo['cat_name']}</option>
                            </volist>
                        </select>
                    </td>
                </tr>
    
                <tr id="measure_unit">
                    <td class="label">数量单位:</td>
                    <td><input type="text" name="unit" value="" size="12"></td>
                </tr>
                <tr>
                    <td class="label">排序:</td>
                    <td><input type="text" name="sort_order" value="50" size="15"></td>
                </tr>
    
                <tr>
                    <td class="label">是否显示:</td>
                    <td><input type="radio" name="is_show" value="1" checked="true"><input type="radio" name="is_show" value="0"></td>
                </tr>
          <tr>
            <td class="label">分类描述:</td>
            <td>
              <textarea name="cat_desc" rows="6" cols="48"></textarea>
            </td>
          </tr>
          </tbody></table>
          <div class="button-div">
            <input type="submit" value=" 确定 ">
            <input type="reset" value=" 重置 ">
          </div>
      </form>
    </div>
    
    
    
    <div id="footer">
        版权所有 &copy; 2014-2016 夺命雷公狗 - 技术总结 - 
    </div>
    
    </div>
    
    </body>
    </html>

    这里完成了后,下一步就是开始写CategoryController.class.php控制器里面的add方法了

    public function add(){
                if(IS_POST){
                    //分类信息入库
                    $data['cat_name'] = I('cat_name');
                    $data['parent_id'] = I('parent_id',0,'int');//parent_id通常是整型,所以做个小处理
                    $data['cat_desc'] = I('cat_desc');
                    $data['unit'] = I('unit');//数量
                    $data['is_show'] = I('is_show');
                    $data['sort_order'] = I('sort_order');
    
                    $categoryModel = D('category');
                    if($categoryModel->create($data)){
                        //验证通过
                        if($categoryModel->add()){
                            //插入成功
                            $this -> success('分类信息添加成功',U('index'),1);
                        }else{
                            //插入失败
                            $this -> error('分类信息添加失败');
                        }
                    }else{
                        //验证失败
                        $this -> error($categoryModel->getError());
                    }
                    return;
                }
                //载入添加分类页面
                //获取所有的分类
                $cats = M('category')->select();
                $this -> assign('cats',$cats);
                $this -> display();
            }

    在这的验证是通过model层里面进行验证的,那么我们下一步就是在model文件夹里创建一个CategoryModel.class.php的文件,代码如下所示

    <?php
        //商品分类模型
        namespace AdminModel;
        use ThinkModel;
        class CategoryModel extends Model{
            //自动验证
            protected $_validate = array(
                array('cat_name','require','商品名称不能为空'),
            );
        }

    好像是完成了噢,不过一测试,发现里面的无限极分类效果是出来了,但是实在不好看,什么都逼在同个水平线下,那么我们的解决方案是通过树状方式来进行解决问题

    我们做目录树的时候要玩到递归,递归说白了就是让他重复干事情的,给定一个pid,找他的后代节点,找到保存起来。

    条件pid等于给定的id。

    最终目的要成为这样:

    先在model层里面开干,

    <?php
        //商品分类模型
        namespace AdminModel;
        use ThinkModel;
        class CategoryModel extends Model{
            //自动验证
            protected $_validate = array(
                array('cat_name','require','商品名称不能为空'),
            );
    
            //定义一个方法,获取树状的分类信息
            public function catTree(){
                $cats = $this->select();
                return $this->tree($cats);
            }
    
            //定义一个方法,对给定的数组,递归形成树
            public function tree($arr,$pid=0,$level=0){
                static $tree = array();
                foreach($arr as $v){
                    if($v['parent_id']==$pid){
                        //说明找到,保存
                        $v['level'] = $level;
                        $tree[] = $v;
                        //继续找
                        $this -> tree($arr,$v['cat_id'],$level+1);
                    }
                }
                return $tree;
            }
        }

    然后在控制器下改下他的查询方式,代码如下:

    public function add(){
                if(IS_POST){
                    //分类信息入库
                    $data['cat_name'] = I('cat_name');
                    $data['parent_id'] = I('parent_id',0,'int');//parent_id通常是整型,所以做个小处理
                    $data['cat_desc'] = I('cat_desc');
                    $data['unit'] = I('unit');//数量
                    $data['is_show'] = I('is_show');
                    $data['sort_order'] = I('sort_order');
    
                    $categoryModel = D('category');
                    if($categoryModel->create($data)){
                        //验证通过
                        if($categoryModel->add()){
                            //插入成功
                            $this -> success('分类信息添加成功',U('index'),1);
                        }else{
                            //插入失败
                            $this -> error('分类信息添加失败');
                        }
                    }else{
                        //验证失败
                        $this -> error($categoryModel->getError());
                    }
                    return;
                }
                //载入添加分类页面
                //获取所有的分类
                $cats = D('category')->catTree();
                $this -> assign('cats',$cats);
                $this -> display();
            }

    最后在add.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>
    <title>SHOP 管理中心 - 添加分类 </title>
    <meta name="robots" content="noindex, nofollow">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <link href="__ADMIN__/styles/general.css" rel="stylesheet" type="text/css" />
    <link href="__ADMIN__/styles/main.css" rel="stylesheet" type="text/css" />
    </head>
    <body>
    
    <h1>
    <span class="action-span"><a href="index.php?p=admin&c=category&a=index">商品分类</a></span>
    <span class="action-span1"><a href="index.php?act=main">SHOP 管理中心</a> </span><span id="search_id" class="action-span1"> - 添加分类 </span>
    <div style="clear:both"></div>
    </h1>
    <!-- start add new category form -->
    <div class="main-div">
      <form action="" method="post" name="theForm" enctype="multipart/form-data" onsubmit="return validate()">
         <table width="100%" id="general-table">
            <tbody>
                <tr>
                    <td class="label">分类名称:</td>
                    <td><input type="text" name="cat_name" maxlength="20" value="" size="27"> <font color="red">*</font></td>
                </tr>
                <tr>
                    <td class="label">上级分类:</td>
                    <td>
                        <select name="parent_id">
                            <option value="0">顶级分类</option>
                            <volist name="cats" id='vo'>
                                <option value="{$vo['cat_id']}">{$vo['level']|str_repeat="&nbsp;&nbsp;&nbsp;",###}{$vo['cat_name']}</option>
                            </volist>
                        </select>
                    </td>
                </tr>
    
                <tr id="measure_unit">
                    <td class="label">数量单位:</td>
                    <td><input type="text" name="unit" value="" size="12"></td>
                </tr>
                <tr>
                    <td class="label">排序:</td>
                    <td><input type="text" name="sort_order" value="50" size="15"></td>
                </tr>
    
                <tr>
                    <td class="label">是否显示:</td>
                    <td><input type="radio" name="is_show" value="1" checked="true"><input type="radio" name="is_show" value="0"></td>
                </tr>
          <tr>
            <td class="label">分类描述:</td>
            <td>
              <textarea name="cat_desc" rows="6" cols="48"></textarea>
            </td>
          </tr>
          </tbody></table>
          <div class="button-div">
            <input type="submit" value=" 确定 ">
            <input type="reset" value=" 重置 ">
          </div>
      </form>
    </div>
    
    
    
    <div id="footer">
        版权所有 &copy; 2014-2016 夺命雷公狗 - 技术总结 - 
    </div>
    
    </div>
    
    </body>
    </html>

    添加页完事,那么下一步就是列表显示页了,先写index方法因为直接赋值刚才那个过来即可

    //显示分类
            public function index(){
                $cats = D('category')->catTree();
                $this -> assign('cats',$cats);
                $this -> display();
            }

    然后在view下的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>
    <title>SHOP 管理中心 - 商品分类 </title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <link href="__ADMIN__/styles/general.css" rel="stylesheet" type="text/css" />
    <link href="__ADMIN__/styles/main.css" rel="stylesheet" type="text/css" />
    </head>
    <body>
    
    <h1>
    <span class="action-span"><a href="__MODULE__/category/add">添加分类</a></span>
    <span class="action-span1"><a href="index.php?p=admin&c=index&a=index">SHOP 管理中心</a> </span><span id="search_id" class="action-span1"> - 商品分类 </span>
    <div style="clear:both"></div>
    </h1>
    
    <form method="post" action="" name="listForm">
    <!-- start ad position list -->
        <div class="list-div" id="listDiv">
            <table width="100%" cellspacing="1" cellpadding="2" id="list-table">
                <tbody>
                    <tr>
                        <th>分类名称</th>
                        <th>商品数量</th>
                        <th>数量单位</th>
                        <th>导航栏</th>
                        <th>是否显示</th>
                        <th>价格分级</th>
                        <th>排序</th>
                        <th>操作</th>
                    </tr>
            <volist name="cats" id="vo">
                    <tr align="center" class="0" id="0_1">
              <td align="left" class="first-cell">
              {$vo['level']|str_repeat="&nbsp;&nbsp;&nbsp;&nbsp;",###}
                            <img src="__ADMIN__/images/menu_minus.gif" id="icon_0_1" width="9" height="9" border="0" style="margin-left:0em" onclick="rowClicked(this)">
                            <span><a href="goods.php?act=list&amp;cat_id=1">{$vo['cat_name']}</a></span>
                         </td>
                        
              <td width="10%">0</td>
                        
              <td width="10%"><span onclick="listTable.edit(this, 'edit_measure_unit', 1)" title="点击修改内容" style="">{$vo['unit']}</span></td>
                        
              <td width="10%"><img src="__ADMIN__/images/no.gif" onclick="listTable.toggle(this, 'toggle_show_in_nav', 1)"></td>
                        
              <td width="10%"><img src="
                <if condition="$vo['is_show'] eq 1">
                __ADMIN__/images/yes.gif"
                <else />
                __ADMIN__/images/no.gif"
                </if>
                 onclick="listTable.toggle(this, 'toggle_is_show', 1)"></td>
                        
              <td><span onclick="listTable.edit(this, 'edit_grade', 1)" title="点击修改内容" style="">5</span></td>
                        
              <td width="10%" align="right"><span onclick="listTable.edit(this, 'edit_sort_order', 1)" title="点击修改内容" style="">{$vo['sort_order']}</span></td>
                        <td width="24%" align="center">
                            <a href="category.php?act=move&amp;cat_id=1">转移商品</a> |
                            <a href="__CONTROLLER__/edit/id/{$vo['cat_id']}">编辑</a> |
                            <a href="__CONTROLLER__/del/id/{$vo['cat_id']}" onclick="return confirm('您是否真的删除这个品牌呢?')" title="移除">移除</a>
                        </td>
                    </tr>
            </volist>
        </tbody>
      </table>
    </div>
    </form>
    
      </table>
    </div>
    </form>
    
    
    <div id="footer">
        版权所有 &copy; 2014-2016 夺命雷公狗 - 技术总结 - </div>
    </div>
     <script>
        /**
     * 折叠分类列表
     */
    var imgPlus = new Image();
    imgPlus.src = "application/views/admin/images/menu_plus.gif";
    
    function rowClicked(obj)
    {
      // 当前图像
      img = obj;
      // 取得上二级tr>td>img对象
      obj = obj.parentNode.parentNode;
      // 整个分类列表表格
      var tbl = document.getElementById("list-table");
      // 当前分类级别
      var lvl = parseInt(obj.className);
      // 是否找到元素
      var fnd = false;
      var sub_display = img.src.indexOf('menu_minus.gif') > 0 ? 'none' : 'table-row' ;
      // 遍历所有的分类
      for (i = 0; i < tbl.rows.length; i++)
      {
          var row = tbl.rows[i];
          if (row == obj)
          {
              // 找到当前行
              fnd = true;
              //document.getElementById('result').innerHTML += 'Find row at ' + i +"<br/>";
          }
          else
          {
              if (fnd == true)
              {
                  var cur = parseInt(row.className);
                  var icon = 'icon_' + row.id;
                  if (cur > lvl)
                  {
                      row.style.display = sub_display;
                      if (sub_display != 'none')
                      {
                          var iconimg = document.getElementById(icon);
                          iconimg.src = iconimg.src.replace('plus.gif', 'minus.gif');
                      }
                  }
                  else
                  {
                      fnd = false;
                      break;
                  }
              }
          }
      }
    
      for (i = 0; i < obj.cells[0].childNodes.length; i++)
      {
          var imgObj = obj.cells[0].childNodes[i];
          if (imgObj.tagName == "IMG" && imgObj.src != 'application/views/admin/images/menu_arrow.gif')
          {
              imgObj.src = (imgObj.src == imgPlus.src) ? 'application/views/admin/images/menu_minus.gif' : imgPlus.src;
          }
      }
    }
    </script>
    </body>
    </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>
    <title>SHOP 管理中心 - 添加分类 </title>
    <meta name="robots" content="noindex, nofollow">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <link href="__ADMIN__/styles/general.css" rel="stylesheet" type="text/css" />
    <link href="__ADMIN__/styles/main.css" rel="stylesheet" type="text/css" />
    </head>
    <body>
    
    <h1>
    <span class="action-span"><a href="index.php?p=admin&c=category&a=index">商品分类</a></span>
    <span class="action-span1"><a href="index.php?act=main">SHOP 管理中心</a> </span><span id="search_id" class="action-span1"> - 添加分类 </span>
    <div style="clear:both"></div>
    </h1>
    <!-- start add new category form -->
    <div class="main-div">
      <form action="category.php" method="post" name="theForm" enctype="multipart/form-data" onsubmit="return validate()">
         <table width="100%" id="general-table">
            <tbody>
                <tr>
                    <td class="label">分类名称:</td>
                    <td><input type="text" name="cat_name" maxlength="20" value="{$cat['cat_name']}" size="27"> <font color="red">*</font></td>
                </tr>
                <tr>
                    <td class="label">上级分类:</td>
                    <td>
                        <select name="parent_id">
                            <option value="0">顶级分类</option>
                            <volist name="cats" id='vo'>
                                <option value="{$vo['cat_id']}"
                                <if condition="$vo['cat_id'] eq $cat['parent_id']" >selected="selected"</if>
                                >{$vo['level']|str_repeat="&nbsp;&nbsp;&nbsp;",###}{$vo['cat_name']}</option>
                            </volist>     
                        </select>
                    </td>
                </tr>
    
                <tr id="measure_unit">
                    <td class="label">数量单位:</td>
                    <td><input type="text" name="unit" value="{$cat['unit']}" size="12"></td>
                </tr>
                <tr>
                    <td class="label">排序:</td>
                    <td><input type="text" name="sort_order" value="{$cat['sort_order']}" size="15"></td>
                </tr>
    
                <tr>
                    <td class="label">是否显示:</td>
                    <td><input type="radio" name="is_show" value="1" checked="true"
                    <if condition="$cat['is_show'] eq 1">checked="checked"</if>
                    > 是<input type="radio" name="is_show" value="0"
                    <if condition="$cat['is_show'] eq 0">checked="checked"</if>
                    > 否  </td>
                </tr>
                <tr>
                    <td class="label">是否显示在导航栏:</td>
                    <td><input type="radio" name="show_in_nav" value="1"><input type="radio" name="show_in_nav" value="0" checked="true"></td>
                </tr>
                <tr>
                    <td class="label">设置为首页推荐:</td>
                    <td>
                        <input type="checkbox" name="cat_recommend[]" value="1"> 精品          
                        <input type="checkbox" name="cat_recommend[]" value="2"> 最新          
                        <input type="checkbox" name="cat_recommend[]" value="3"> 热门       
                    </td>
                </tr>
          <tr>
            <td class="label">分类描述:</td>
            <td>
              <textarea name="cat_desc" rows="6" cols="48">{$cat['cat_desc']}</textarea>
            </td>
          </tr>
          </tbody></table>
          <div class="button-div">
            <input type="submit" value=" 确定 ">
            <input type="reset" value=" 重置 ">
          </div>
          <input type="hidden" name="cat_id" value="{$cat['cat_id']}" />
      </form>
    </div>
    
    
    
    <div id="footer">
        版权所有 &copy; 2014-2016 夺命雷公狗 - 技术总结 - 
    </div>
    
    </div>
    
    </body>
    </html>

    要注意,在编辑的表单中一定要传cat_id,否则更新会失败

     <input type="hidden" name="cat_id" value="{$cat['cat_id']}" />

    注意:在更新的时候,如果把当前分类或则其子分类作为上级分类,就会出现逻辑错误..

    所以我们要先到model里面定义一个方法,让他不能随便让他的当前分类或者子分类作为上级分类,否则就会出现逻辑上的错误。。

    在CategoryModel.class.php里面定义一个方法,代码如下所示:

    //给定一个分类,找其后代分类的cat_id,包括他自己
            public function getSubIds($cat_id){
                $cats = $this -> select();
                $list = $this -> tree($cats,$cat_id);
                $res = array();
                foreach($list as $v){
                    $res[] = $v['cat_id'];
                }
                //把cat_id追加到数组
                $res[] = $cat_id;
                return $res;
            }

    让后会控制器下定义edit方法,代码如下所示:

    //修改分类
            public function edit(){
                $cat_id = I('id');
                if(IS_POST){
                    //更新分类
                    $data['cat_name'] = I('cat_name');
                    $data['parent_id'] = I('parent_id',0,'int');//parent_id通常是整型,所以做个小处理
                    $data['cat_desc'] = I('cat_desc');
                    $data['unit'] = I('unit');//数量
                    $data['is_show'] = I('is_show');
                    $data['sort_order'] = I('sort_order');
                    $data['cat_id'] = I('cat_id');
                    $categoryModel = D('category');
    
                    $ids = $categoryModel->getSubIds($data['cat_id']);
                    if(in_array($data['parent_id'],$ids)){
                        $this -> error('抱歉,不能把当前分类及其子分类作为其上级分类');
                    }
    
                    if($categoryModel->create($data)){
                        //验证通过
                        if($categoryModel->save()){
                            //插入成功
                            $this -> success('分类信息修改成功',U('index'),1);
                        }else{
                            //插入失败
                            $this -> error('分类信息修改失败');
                        }
                    }else{
                        //验证失败
                        $this -> error($categoryModel->getError());
                    }
                    return;
                }
                $cat = M('category')->find($cat_id);
                $cats = D('category')->catTree();
                $this -> assign('cats',$cats);
                $this -> assign('cat',$cat);
                $this -> display();
            }

    修改也好了,那么就差最后一步了,还差删除分类的了,代码如下所示:

    //删除分类
            public function del(){
                $cat_id = I('id',0,'int');
                $categoryModel = D('category');
                $ids = $categoryModel->getSubIds($cat_id);//这里的目的就是查下有没有子类
                if(count($ids)>1){
                    $this ->error("该分类下面还存在子分类,请处理好了再来");
                }
                if(M('category')->delete($cat_id)){
                    $this -> success('删除成功',U('index'),1);
                }else{
                    $this ->error('删除失败');
                }
            }
  • 相关阅读:
    html5 input type=search
    深入理解html5系列-文本标签
    HTML5里autofocus属性
    sessionStorage和localStorage中 存储
    knockoutjs foreach array绑定 表格 下拉框绑定
    redis’五种格式的存储与展示
    redis与memcache的区别2
    mysql分区及实例演示
    windows下安装redis以及测试
    mysql导入导出sql文件
  • 原文地址:https://www.cnblogs.com/leigood/p/4946324.html
Copyright © 2020-2023  润新知