Blogger Information
Blog 81
fans 1
comment 0
visits 124126
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
商品sku,笛卡尔积实现商品多规格。
有什么是忘不了的的博客
Original
2553 people have browsed it

在做商品添加的时候,最常见的多规格产品数据。如何来实现呢?

分享一个我自己学习做出来的小栗子(tp5.1&layui)。如图:

sku.png

代码写的比较啰嗦,但是清楚逻辑就可以。

思路:

    但选择分类时,去生成对应的规格table,这里的数据写在spec.html 页面了。所以就是发送请求返回一个页面,放到指定位置。

    当添加规格值时,加载生成规格数据表。需要把规格排序,值最少排在前面。获取每一个规格值ID(我是在添加的时候直接入库,并判断是否存在改值,返回这条规格值的id),获取去所有的规格值id生成数组,规格项id为下标,规格值id为数组值的二维数组。然后在通过笛卡尔积得到所有的规格在进行循环拼接table 字符串返回。

思路写的可能不大好:不过可以看我下面粘的代码。

笛卡尔积php实现代码:

//多个数组的笛卡尔积 调用这个
function combineDika() {
    $data = func_get_args();//获取参数
    $data = current($data);
    $cnt = count($data);
    $result = array();
    $arr1 = array_shift($data);
    foreach($arr1 as $key=>$item){
        $result[] = array($item);
    }

    foreach($data as $key=>$item){
        $result = combineArray($result,$item);
    }
    return $result;
}

//两个数组的笛卡尔积
function combineArray($arr1,$arr2) {
    $result = array();
    foreach ($arr1 as $item1){
        foreach ($arr2 as $item2){
            $temp = $item1;
            $temp[] = $item2;
            $result[] = $temp;
        }
    }
    return $result;
}

js合并单元格,同一个列连续相同的两个值合并在一起

// 合并单元格
function merge() {
    //要合并的table的ID
    var tab = document.getElementById("spec_input_table");//这里的ID是关键,一定要相互对应
    //maxCol:合并单元格作用到多少列
    var maxCol = 2, val, count, start;
    if (tab != null) {
        for (var col = maxCol - 1; col >= 0; col--) {
            count = 1;
            val = "";
            for (var i = 0; i < tab.rows.length; i++) {
                if (val == tab.rows[i].cells[col].innerHTML) {
                    count++;
                } else {
                    if (count > 1) { //合并
                        start = i - count;
                        tab.rows[start].cells[col].rowSpan = count;
                        for (var j = start + 1; j < i; j++) {
                            tab.rows[j].cells[col].style.display = "none";
                        }
                        count = 1;
                    }
                    val = tab.rows[i].cells[col].innerHTML;
                }
            }
            if (count > 1) {
                //合并,最后几行相同的情况下
                start = i - count;
                tab.rows[start].cells[col].rowSpan = count;
                for (var j = start + 1; j < i; j++) {
                    tab.rows[j].cells[col].style.display = "none";
                }
            }
        }
    }
}

//获取选中商品规格和规格值的ID来生成商品sku
    public function getSpecItem(){
        //获取到的数组
        //[2=>[10,11],3=>[12,13,14],5=>[15]] 下标是规格项id=>值为该规格项规格值id
        $specArr = Request::post('spec_arr');
        //获取数组中每个子数组的元素个数,主要是用来排序的判断那个规则项在前
        //循环后[2=>2,3=>3,5=>1]
        foreach ($specArr as $k => $v){
            $specArrSort[$k] = count($specArr[$k]);
        }
        //保存键名的升序排序,这个时候[5=>1,2=>2,3=>3]
        //这里排序的意义:在输出表头的时候规格值少的在前
        asort($specArrSort);
        //根据排序的下标进行数组的排序
        //排序后[[15],[10,11],[12,13,14]] //这时候数组的下标丢失不过没有关系
        foreach ($specArrSort as $k=>$v){
            $specArr1[] = $specArr[$k];
        }
        //获取规格id
        //[2,3,5]
        $clo_name = array_keys($specArr);
//        var_dump($specArr1);
        //笛卡尔积
        //
        $specSort = combineDika($specArr1);
        //规格表 获取所有数据
        $specCatsList = SpecCats::where('dataFlag',1)->field('catName,catId')->select()->toArray();
        //对获取的数据进行重构,以catId为键catName为值。这里主要是为了配合我们排序好的$specArrSort数据来获取规格名称
        $specCatsList = array_column($specCatsList,'catName','catId');
        //规格项值表  获取所有固定规格的规格值
        $specItemList = SpecItem::where('spec_id','IN',$clo_name)->select()->toArray();
        //数组重构,获取数组的id值,在以id数组为键规格值数组为值重构数组。
        $specItemListKey = array_column($specItemList,'id');
        $specItemList = array_combine($specItemListKey,$specItemList);
        //生成table表格字符串
        $str = '<table id="spec_input_table" lay-filter="demo" class="layui-table">';
        $str .='<tr>';
        //表头开始 根据排序好的$specArrSort的数组[5=>1,2=>2,3=>3]根据他的下标循环输出规格项的名称。
        foreach ($specArrSort as $k=>$v){
            $str .='<td><b>'.$specCatsList[$k].'</b></td>';
        }
         $str .='<td><b>价格</b></td><td><b>库存</b></td><td><b>预警值</b></td></tr>';
        //表头结束
//        var_dump($clo_name);
//        halt($specItemList);

        //循环笛卡尔积后的数组
        //表身体开始
        foreach ($specSort as $k => $v){
            $str .= '<tr>';
            $item_key_name = [];
                foreach ($v as $k1=>$v1){
                    //因为进行笛卡尔积的是规格项值的id,所以需要从重构后的规格项值数组中获取规格值名称
                    $str .='<td>'.$specItemList[$v1]['item'].'</td>';
                    //获取 规格项:规格值 的数据格式
                    $item_key_name[$v1] = $specCatsList[$specItemList[$v1]['spec_id']] .":".$specItemList[$v1]['item'];
                }
                //根据键排序[45=>'内存:222',46 =>'颜色:333',50 =>'型号:666']
                ksort($item_key_name);
                $item_key = implode('_',array_keys($item_key_name));//45_16_50
                $item_name = implode(' ',$item_key_name);//内存:222 颜色:333 型号:666
                $str .= '<td><input type="text" value="0" name="item['.$item_key.'][shopPrice]" lay-verify="required|number" autocomplete="off" class="layui-input" ></td>';
                $str .= '<td><input type="text" value="0" name="item['.$item_key.'][goodsStock]" lay-verify="required|number" autocomplete="off" class="layui-input"></td>';
                $str .= '<td><input type="text" value="0" name="item['.$item_key.'][warnStock]" lay-verify="required|number" autocomplete="off" class="layui-input" >
                             <input type="hidden" name="item['.$item_key.'][key_value]" value="'.$item_name.'"></td>';
                $str .= '</tr>';
//                var_dump($item_key_name);
        }
        //表身体结束
        $str .='</table>';
        exit($str);
    }
    //获取该分类下的规格
    public function specCats()
{
    if (Request::isAjax()){
        $id = Request::param('id');
        //因为我传过去的是一个1_2这样的数据,2是1的儿子
        $goodscatarr = explode('_',$id );
        $data['goodsCatId'] = $goodscatarr[0];
        $data['goodsCatIdTwo'] = $goodscatarr[1];
          //SpecCats 我的商品规格表
        $specList = SpecCats::where('goodsCatId',$data['goodsCatIdTwo'])->where('dataFlag',1)->field('catId,catName')->order('order','desc')->select();
        $this->view->assign('specList',$specList);
        //把一个页面返回回去
        return  view('spec');
    }
}

我的spec.html页面

{__NOLAYOUT__}//取消模板布局
<link rel="stylesheet" href="/static/layuimini/css/public.css" media="all">
<style>
    #spec_cat_item th ,#spec_cat_item{
        text-align: center;
    }
</style>
<body>
<div class="layui-form-item">
    <label class="layui-form-label">规格</label>
    <div class="layui-input-block">
        <table lay-filter="demo"   class="layui-table">
            <tbody>
            //展示规格项值添加的那一块
            {volist name="specList" id="vo"}
            <tr>
                <td style="width:100px">选择{$vo.catName}:</td>
                <td>
                    <div class="layui-input-inline" style="width: 100%">
                        <input type="text" id="specItem"  name="specItem"  autocomplete="off" class="layui-input" style=" width: 100px;display:inline-block">&nbsp;&nbsp;
                        <a href="javascript:;" style="color: #1E9FFF" onclick="addSpecItem(this,{$vo.catId})">添加</a>&nbsp;&nbsp;
                
                    </div>
                </td>
            </tr>
            {/volist}
            </tbody>
        </table>
        //这里用来添加商品的笛卡尔积后的数据
        <div id="spec_cat_item">

        </div>
    </div>
</div>
let specItem = {};
//添加规格项值
function addSpecItem(obj,specId) {
    let val = $(obj).siblings('input[name="specItem"]').val()
    //指出一个对象是否具有指定名称的属性。
    if (!specItem.hasOwnProperty(specId)){
        specItem[specId]=[]
    }
    //判断该数组中是否已存在该值
    if  (val.length == 0 ){
        layer.msg('规格值不能为空')
    }else if (specItem[specId].indexOf(val)==-1){
        specItem[specId].push(val)
        $.ajax({
            url:'/admin/goods/addSpecItem',
            data:{'item':val,specId},
            type:'get',
            success:function (e) {
                //吧值插入到页面中
                if  (e.code == 0){
                    layer.alert(e.msg)
                    return
                }
                let dom = "<div style='display: inline-block;' class='specAdd'>" +
                    "<button class='layui-btn'  spec_id='"+specId+"' data_id='"+e.id+"'  style='background-color: #d4d4d4'>"+val+"</button>" +
                    "<i onclick='specDelete(this,"+specId+",\""+val+"\")' class='layui-icon layui-icon-close-fill specDel'></i></div>"
                $(obj).siblings('#specItem').before(dom)
                //插入成功清空input里的值
                $(obj).siblings('#specItem').val('')
                //获取添加的规格值的id
                getSpecArr()
            }
        })
    }else{
        layer.msg('该规格值已存在')
    }
    // console.log(specItem)
}
//获取添加的规格值的id
function getSpecArr(){
    var spec_arr = {}
    $(".specAdd button").each(function () {
        let spec_id = $(this).attr('spec_id')
        let item_id = $(this).attr('data_id')
        if (!spec_arr.hasOwnProperty(spec_id)){
            spec_arr[spec_id]=[]
        }
        spec_arr[spec_id].push(item_id)
    })
    getSpecItem(spec_arr)
}
function getSpecItem(spec_arr){
    $.ajax({
        url:'/admin/goods/getSpecItem',
        data:{spec_arr},
        type:'post',
        success:function (e) {
        //插入到页面
            $("#spec_cat_item").html('')
            $("#spec_cat_item").append(e)
            //合并单元格
            merge()
        }
    })
}
//删除规格项值
function specDelete(obj,specId,val) {
    let key = specItem[specId].indexOf(val)
    specItem[specId].splice(key,1)
    $(obj).parent().remove();
    console.log(specItem)
    //获取添加的规格值的id重新加载一次
    getSpecArr()
}

就这些了。理解怎么做最重要, 站在巨人的肩膀上干什么都很舒服。

Statement of this Website
The copyright of this blog article belongs to the blogger. Please specify the address when reprinting! If there is any infringement or violation of the law, please contact admin@php.cn Report processing!
All comments Speak rationally on civilized internet, please comply with News Comment Service Agreement
1 comments
phpcn_u23835 2020-05-07 00:02:45
js合并单元格就开始有点看不懂了
1 floor
Author's latest blog post