关于树形结构---无限层级通讯录

(1)表的设计

父级的id作为子级的parentid也就是说,父子级的关系用parentid这个字段关联

通讯录分组表:

通讯录联系人表:

联系人 存储分组id,因为需求,设计了部门字段,以最低部门选择的分组id,作为该条记录的groupid

(02)实现树形展示的方式一  jsTree树形插件

这个插件是基于jQuery的,通讯录,分组需要添加,修改,删除。可以满足需求,并有较好的体验、美观

jsTree: https://www.jstree.com/

引入css

<link rel="stylesheet" href="dist/themes/default/style.min.css" />

引入js

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.1/jquery.min.js"></script>

<script src="dist/jstree.min.js"></script>

前端html:

<!--通讯录内容 start-->
<div class="box-body">
     <div class="tab-content">
         <div class="row">
             <div class="col-md-8" id="container"></div>//树形结构容器
             <div class="col-md-4">
                 <h4 id="curr_op_title">新增</h4>
                 <hr/>
                 <form  role="form" id="objform" method="post" action="{buildurl('contacts_group_save','index','contacts')}">
                     <div class="form-group">
                         <label class="control-label">分组名称</label>
                         <input type="text" name="name" id="curr_op_name" placeholder="请输入分组名称" class="form-control"/>
                     </div>
                     <div class="form-group" style="text-align: right;">
                         <button class="btn btn-info" type="button" id="save">全部保存</button>
                     </div>
                 </form>
             </div>
         </div>
     </div>
</div>
<!--通讯录内容 end-->

编辑区的作用是,修改当前操作的节点名称。Form表单中隐藏着相应的节点操作数据,每点击了节点。就会生成,并记录。

类似:

type:是指定 节点之前的图标样式

var op_obj = '';//标记当前操作的对象

//生成结构树
$('#container').jstree({
    'core': { 'check_callback': true,'data':jstreelist,multiple:false },
    'plugins': ['types','dnd','contextmenu'],
    'types': {
        'default': { 'icon': 'fa fa-folder' },
        'show': { 'icon': 'fa fa-eye-slash text-muted' }
    },
    'contextmenu' : {
        'items' : function(o, cb) {
            var items = {
                createAfter: {"label": "插入节点","action": function (data) {createNode(data, 'after');}},
                createChildren: {"label": "插入子节点","action": function (data) {createNode(data, 'last');}},
                deleteItem: {"label": "删除节点","action": function (data) {deleteNode(data);}}
            };
            return items;
        }
    }
}).bind("select_node.jstree", function (event, node) {
    $('#objform').find('input[name=name]').focus();
    //点击已有节点。。编辑
    var currnode = node.node;
    $('#curr_op_name').val(currnode.text);
    //添加隐藏域和记录当前操作的对象
    if(currnode.id.indexOf('new')=='-1'){
        $('#curr_op_title').text('编辑');
        //添加隐藏域,用于记录修改的分组名
        if($("#update_"+currnode.id).length==0){
            $('#objform').append('<input type="hidden" name="update['+currnode.id+'][name]" id="update_'+currnode.id+'" value="'+currnode.text+'"  />');
        }
        //记录当前操作的对象
        op_obj = $("#update_"+currnode.id);
    }else{
        //新增节点编辑
        //记录当前操作的对象
        $('#curr_op_title').text('新增');
        op_obj = $("#add_"+currnode.id);
    }
});

//监听修改的分组名,写入隐藏域
$('#curr_op_name').on('input',function () {
    var value = $.trim($(this).val());
    var ref = $('#container').jstree(true);
    var sel = ref.get_selected();
    //有选中节点 才去更新数据
    if(sel.length!=0){
        //同步更新隐藏域和节点的文本值
        op_obj.val(value);
        ref.set_text(sel, value);
    }
});

//插入节点或插入子节点
var newId = 1;
function createNode(data, pos) {
    var inst = $.jstree.reference(data.reference);
    var obj = inst.get_node(data.reference);//获取当前树节点
    obj.data.type = 'default';
    var pid= pos=='after' ? obj.parent : obj.id;
    var data={};
    data.id='new'+(newId++);
    data.name='自定义分组';
    data.parentid=pid;
    //把以上数据写入表单
    $('#objform').append('<input type="hidden" name="add['+data.id+'][name]" id="add_'+data.id+'" value="'+data.name+'" /><input type="hidden" name="add['+data.id+'][parentid]" value="'+pid+'" id="add_pid_'+data.id +'"/>');
    inst.create_node(obj, {
            id:data.id,
            text: data.name,
            data: { data:data,jstree:{type: "show"}},
        }, pos, function (new_node) {
            inst.deselect_all();
            inst.select_node(new_node, true);
            inst.select_node(new_node);
        }
    );
    $('#objform').find('input[name=name]').focus();
}

//删除节点
function deleteNode(data) {
    var inst = $.jstree.reference(data.reference),
    obj = inst.get_node(data.reference);
    //当前删除节点的id
    var id = obj.id;
    //删除表单中的隐藏域
    if(id.indexOf('new')=='-1'){
        //原节点
        $('#update_'+id).remove();

    }else{
        //新增的节点
        $('#add_'+id).remove();
        $('#add_pid_'+id).remove();
    }
    //在表单中添加隐藏域,标记删除的节点
    $('#objform').append('<input type="hidden" name="del['+id+']" value="'+id+'" />');
    inst.delete_node(obj);
    //编辑框的值清除
    $('#curr_op_name').val('');
}

//表单提交验证,所有修改或新增的分组名不能为空
$('#save').click(function () {
    $flag = true;//标记是否通过验证
    $('#objform input:hidden').each(function (key,obj) {
      if(!$(obj).val()){
          alert('所有分组名称不能为空!');
          return false;
          $flag = false;
      }
    });
    if($flag){
        alert('此操作将对所有变更做保存,包括删除节点,您确认要进行此操作?')
        $('#objform').submit();
    }
});

后台就可以针对传过来的数据,变更通讯录分组

/**
 * @todo 通讯录保存,包含新增、修改、删除
 */
public function contacts_group_save(){
    $userid = param::get_cookie('_userid');     //获取当前用户编号
    $data = $_POST;
    if(!$data['update'] && !$data['add'] && !$data['del']){
        showmessage('数据没有任何修改', buildurl('contacts_group_list', 'index', 'contacts'));
    }
    //操作
    if($data['update']){
        //修改,验证数据
        foreach ($data['update'] as $key=>$value){
            if(empty($value['name'])){
                showmessage('分组名称不能为空!', buildurl('contacts_group_list', 'index', 'contacts'));
            }
            $info = $this->group_db->get_one(['id'=>$key]);
            if(!$info){
                showmessage('分组信息不存在!', buildurl('contacts_group_list', 'index', 'contacts'));
            }
            //当要修改的的分组名,和原组名一致,不进行修改
            $is_update = $this->group_db->get_one(['id'=>$key,'name'=>$value['name']]);
            if(!$is_update){
                //修改时,需要验证,同级别(parentid相同) 组名不能重复
                $is_update_again = $this->group_db->get_one(['parentid'=>$info['parentid'],'name'=>$value['name']]);
                if($is_update_again){
                    showmessage('同级部门已存在相同分组名称!', buildurl('contacts_group_list', 'index', 'contacts'));
                }
                $flag = $this->group_db->update(['name'=>$value['name'],'time'=>date('Y-m-d H:i:s',time())],['id'=>$key]);
            }else{
                $flag = true; //标记修改,实际未修改,为了显示修改成功
            }
        }
    }
    if($data['add']){
        //添加 验证数据
        foreach ($data['add'] as $key=>$value){
            if(empty($value['name'])){
                showmessage('分组名称不能为空!', buildurl('contacts_group_list', 'index', 'contacts'));
            }
            $is_add = $this->group_db->get_one(['name'=>$value['name'],'parentid'=>$value['parentid']]);
            if($is_add){
                showmessage('同级部门已存在相同分组名称!', buildurl('contacts_group_list', 'index', 'contacts'));
            }
            $data = array(
                'uid'=> $userid,
                'name'=>$value['name'],
                'time'=>date('Y-m-d H:i:s',time()),
                'parentid'=>$value['parentid'],
            );
            $flag = $this->group_db->insert($data);

        }

    }
    if($data['del']){
        //删除 软删除
        foreach ($data['del'] as $key=>$value){
            $flag = $this->group_db->update(['is_del'=>1,'time'=>date('Y-m-d H:i:s',time())],['id'=>$value]);
        }

    }
    if($flag){
        showmessage('用户分组更新成功!', buildurl('contacts_group_list', 'index', 'contacts'));
    }else{
        showmessage('用户分组更新失败!', buildurl('contacts_group_list', 'index', 'contacts'));
    }

}

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

kent-007

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值