动态可配置的SKU表(skuTable)

概述

基于 Layui 的 SkuTable 组件。根据配置动态生成 sku 表。

 

最新版本下载地址:

GitHub

Gitee

在线演示

 

spu 和 sku


这里拿 iphone6s 举例,它身上有很多的属性和值, 比如

毛重: 420.00 g

产地:中国大陆

容量: 16G, 64G, 128G

颜色:银,白,玫瑰金

spu 指的是商品(iphone6s),spu 属性就是不会影响到库存和价格的属性,又叫关键属性,与商品是一对一的关系,比如

毛重: 420.00 g

产地:中国大陆

sku 指的是具体规格单品(玫瑰金 16G),sku 属性就是会影响到库存和价格的属性,又叫销售属性,与商品是多对一的关系,比如

容量: 16G, 64G, 128G

颜色:银,白,玫瑰金

所以 iphone6s 则会生成 3 * 3 = 9 个 sku

 

业务逻辑


1. 同一商品不同 SKU 库存和售价不同.

2. 不同类型的商品具有不同的属性名和属性值 (如汽车和服饰), 所以属性需要支持后期添加和维护.

3. 在某个商品分类下通过属性筛选商品.

4. 商家某件商品的销量统计,该件商品内几个不同 SKU 的销量统计.

5. 更多…

 

效果图:

 新代码:

<!doctype html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>动态SKU表</title>
    <!-- 引入 layui.css -->
    <link rel="stylesheet" type="text/css" href="./layui/css/layui.css"/>
</head>
<body>

<div class="layui-container">
    <form action="" class="layui-form fairy-form">
        <!-- sku参数表 -->
        <div class="layui-form-item">
            <label class="layui-form-label">规格:</label>
            <div class="layui-input-block">
                <div class="fairy-spec-table"></div>
            </div>
        </div>

        <!-- 动态sku表 -->
        <div class="layui-form-item">
            <label class="layui-form-label">SKU表:</label>
            <div class="layui-input-block">
                <div class="fairy-sku-table"></div>
            </div>
        </div>

        <div class="layui-form-item">
            <div class="layui-input-block">
                <button class="layui-btn" lay-submit lay-filter="submit">立即提交</button>
                <button type="reset" class="layui-btn layui-btn-primary">重置</button>
            </div>
        </div>
    </form>
</div>
<!-- 引入 layui.js -->
<script src="./layui/layui.js"></script>
<!-- 引入 skuTable.js -->
<script src="./skuTable.js"></script>
<script>
    layui.config({
        base: './'
    }).use(['form', 'skuTable'], function () {
        var form = layui.form, skuTable = layui.skuTable;

        //注意!!! 注意!!! 注意!!!
        //如果配置了相关接口请求的参数,请置本示例于服务器中预览,不然会有浏览器跨域问题
        //示例中的json文件仅做格式返回参考,若多次执行添加规格后再为新增后的规格添加规格值,会发现所有新增的规格都增加了该规格值。注意!此处并非是bug,原因是因为示例中返回的新增规格值id是重复的,而在正常接口请求每次返回的新增规则id是不一样的
        var obj = skuTable.render({
            //sku表相同属性值是否合并行
            rowspan: true,
            //上传接口地址
            //接口要求返回格式为 {"code": 200, "data": {"url": "xxx"}, "msg": ""}
            uploadUrl: './json/upload.json',
            //添加规格接口地址,如果为空则表示不允许增加规格
            //接口要求返回格式为 {"code": 200, "data": {"id": "xxx"}, "msg": ""}
            specCreateUrl: './json/specCreate.json',
            //添加规格值接口地址,如果为空则表示不允许增加规格值
            //接口要求返回格式为 {"code": 200, "data": {"id": "xxx"}, "msg": ""}
            specValueCreateUrl: './json/specValueCreate.json',
            //sku表格配置参数
            skuTableConfig: {
                thead: [
                    {title: '图片', icon: ''},
                    {title: '销售价(元)', icon: 'layui-icon-cols'},
                    {title: '市场价(元)', icon: 'layui-icon-cols'},
                    {title: '成本价(元)', icon: 'layui-icon-cols'},
                    {title: '库存', icon: 'layui-icon-cols'},
                    {title: '状态', icon: ''},
                ],
                tbody: [
                    {type: 'image', field: 'picture', value: '', verify: '', reqtext: ''},
                    {type: 'input', field: 'price', value: '0', verify: 'required|number', reqtext: '销售价不能为空'},
                    {type: 'input', field: 'market_price', value: '0', verify: 'required|number', reqtext: '市场价不能为空'},
                    {type: 'input', field: 'cost_price', value: '0', verify: 'required|number', reqtext: '成本价不能为空'},
                    {type: 'input', field: 'stock', value: '0', verify: 'required|number', reqtext: '库存不能为空'},
                    {type: 'select', field: 'status', option: [{key: '启用', value: '1'}, {key: '禁用', value: '0'}], verify: 'required', reqtext: '状态不能为空'},
                ]
            },
            //规格数据, 一般从接口获取
            specData: [
                {
                    id: "1",
                    title: "颜色",
                    child: [
                        {id: "1", title: "红", checked: true},
                        {id: "2", title: "黄", checked: false},
                        {id: "3", title: "蓝", checked: false}
                    ]
                }, {
                    id: "2",
                    title: "尺码",
                    child: [
                        {id: "4", title: "S", checked: true},
                        {id: "5", title: "M", checked: true},
                        {id: "6", title: "L", checked: false},
                        {id: "7", title: "XL", checked: false}
                    ]
                }, {
                    id: "3",
                    title: "款式",
                    child: [
                        {id: "8", title: "男款", checked: true},
                        {id: "9", title: "女款", checked: true}
                    ]
                }
            ],
            //sku数据
            //新增的时候为空对象
            //编辑的时候可以从后台接收,会自动填充sku表,可以去掉注释看效果
            // skuData: {
            //     "skus[1-4-8][picture]": "https://cdn.layui.com/upload/2019_5/168_1559291577683_9348.png",
            //     "skus[1-4-8][price]": "100",
            //     "skus[1-4-8][market_price]": "200",
            //     "skus[1-4-8][cost_price]": "50",
            //     "skus[1-4-8][stock]": "18",
            //     "skus[1-4-8][status]": "0",
            //     "skus[1-4-9][picture]": "",
            //     "skus[1-4-9][price]": "0",
            //     "skus[1-4-9][market_price]": "0",
            //     "skus[1-4-9][cost_price]": "0",
            //     "skus[1-4-9][stock]": "0",
            //     "skus[1-4-9][status]": "1",
            //     "skus[1-5-8][picture]": "",
            //     "skus[1-5-8][price]": "0",
            //     "skus[1-5-8][market_price]": "0",
            //     "skus[1-5-8][cost_price]": "0",
            //     "skus[1-5-8][stock]": "0",
            //     "skus[1-5-8][status]": "1",
            //     "skus[1-5-9][picture]": "",
            //     "skus[1-5-9][price]": "0",
            //     "skus[1-5-9][market_price]": "0",
            //     "skus[1-5-9][cost_price]": "0",
            //     "skus[1-5-9][stock]": "0",
            //     "skus[1-5-9][status]": "1"
            // }
        });

        form.on('submit(submit)', function (data) {
            //获取规格数据
            console.log(obj.getSpecData());
            //获取表单数据
            console.log(data.field);

            var state = Object.keys(data.field).some(function (item, index, array) {
                return item.startsWith('skus');
            });
            state ? layer.alert(JSON.stringify(data.field), {title: '提交的数据'}) : layer.msg('sku表数据不能为空', {icon: 5, anim: 6});
            return false;
        });
    });
</script>
</body>
</html>

 老代码(弃用):

<!doctype html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>动态SKU表-白開水</title>
    <link rel="stylesheet" type="text/css" href="https://www.layuicdn.com/layui/css/layui.css"/>
    <style>
        #sku-table thead tr th i,
        #sku-table tbody tr td img {
            cursor: pointer;
        }
    </style>
</head>
<body>
<div class="layui-container">
    <form action="" class="layui-form">
        <div class="layui-form-item">
            <label class="layui-form-label">规格:</label>
            <div class="layui-input-block">
                <table class="layui-table" id="spec-table">
                    <thead>
                    <tr>
                        <th>规格名</th>
                        <th>规格值</th>
                    </tr>
                    </thead>
                    <tbody>
                    <tr>
                        <td data-id="1">颜色</td>
                        <td>
                            <input type="checkbox" title="红" lay-filter="filter" value="1" checked>
                            <input type="checkbox" title="黄" lay-filter="filter" value="2">
                            <input type="checkbox" title="蓝" lay-filter="filter" value="3">
                        </td>
                    </tr>
                    <tr>
                        <td data-id="2">尺码</td>
                        <td>
                            <input type="checkbox" title="S" lay-filter="filter" value="4" checked>
                            <input type="checkbox" title="M" lay-filter="filter" value="5" checked>
                            <input type="checkbox" title="L" lay-filter="filter" value="6">
                            <input type="checkbox" title="XL" lay-filter="filter" value="7">
                        </td>
                    </tr>
                    <tr>
                        <td data-id="2">款式</td>
                        <td>
                            <input type="checkbox" title="男款" lay-filter="filter" value="8" checked>
                            <input type="checkbox" title="女款" lay-filter="filter" value="9" checked>
                        </td>
                    </tr>
                    </tbody>
                </table>
            </div>
        </div>
        <div class="layui-form-item layui-hide">
            <label class="layui-form-label">SKU表:</label>
            <div class="layui-input-block">
                <table class="layui-table" id="sku-table">
                    <thead></thead>
                    <tbody></tbody>
                </table>
            </div>
        </div>
        <div class="layui-form-item">
            <div class="layui-input-block">
                <button class="layui-btn" lay-submit lay-filter="submit">立即提交</button>
                <button type="reset" class="layui-btn layui-btn-primary">重置</button>
                <input type="hidden" name="spec" value="">
            </div>
        </div>
    </form>
</div>

<script src="https://www.layuicdn.com/layui/layui.js"></script>
<script>
    layui.use(['form', 'upload', 'jquery'], function () {
        var form = layui.form, upload = layui.upload, $ = layui.jquery;

        function createSkuTable(url = '') {
            var specData = [];
            $.each($('#spec-table tbody tr'), function () {
                var child = [];
                $.each($(this).find('input[type=checkbox]'), function () {
                    child.push({id: $(this).val(), title: $(this).attr('title'), checked: $(this).is(':checked')});
                });
                var specItem = {id: $(this).find('td').eq(0).attr('data-id'), title: $(this).find('td').eq(0).text(), show: $(this).find('input[type=checkbox]:checked').length > 0, child: child};
                specData.push(specItem);
            });

            if ($('#spec-table tbody input[type=checkbox]:checked').length) {
                $('#sku-table').parent().parent().removeClass('layui-hide');

                var prependThead = [], prependTbody = [];
                $.each(specData, function () {
                    if (this.show) {
                        prependThead.push(this.title);
                        var prependTbodyItem = [];
                        $.each(this.child, function () {
                            if (this.checked) {
                                prependTbodyItem.push({id: this.id, title: this.title});
                            }
                        });
                        prependTbody.push(prependTbodyItem);
                    }
                });
                if (prependThead.length > 0) {
                    $('#sku-table thead').html('<tr>' +
                        prependThead.map(function (t, i, a) {
                            return '<th>' + t + '</th>'
                        }) +
                        '<th>图片</th>' +
                        '<th>销售价(元) <i class="layui-icon layui-icon-cols"></i></th>' +
                        '<th>市场价(元) <i class="layui-icon layui-icon-cols"></i></th>' +
                        '<th>成本价(元) <i class="layui-icon layui-icon-cols"></i></th>' +
                        '<th>库存 <i class="layui-icon layui-icon-cols"></i></th>' +
                        '<th>状态 </th>' +
                        '</tr>');
                }

                var prependTbodyTrs = [];
                prependTbody.reduce(function (prev, cur, index, array) {
                    var tmp = [];
                    prev.forEach(function (a) {
                        cur.forEach(function (b) {
                            tmp.push({id: a.id + '-' + b.id, title: a.title + '-' + b.title});
                        })
                    });
                    return tmp;
                }).forEach(function (item, index, array) {
                    prependTbodyTrs.push('<tr>' +
                        item.title.split('-').map(function (t, i, a) {
                            return '<td>' + t + '</td>';
                        }) +
                        '<td><input type="hidden" name="skus[' + item.id + '][picture]" value=""><img src="https://shop.yyhjx.net/backend/assets/abec325a/img/sku-add.png" alt="sku图片"></td>' +
                        '<td><input type="text" name="skus[' + item.id + '][price]" value="0" class="layui-input" lay-verify="required|number" lay-reqtext="销售价不能为空"></td>' +
                        '<td><input type="text" name="skus[' + item.id + '][market_price]" value="0" class="layui-input" lay-verify="required|number" lay-reqtext="市场价不能为空"></td>' +
                        '<td><input type="text" name="skus[' + item.id + '][cost_price]" value="0" class="layui-input" lay-verify="required|number" lay-reqtext="成本价不能为空"></td>' +
                        '<td><input type="text" name="skus[' + item.id + '][stock]" value="0" class="layui-input" lay-verify="required|number" lay-reqtext="库存不能为空"></td>' +
                        '<td><select name="skus[' + item.id + '][status]"><option value="1">启用</option><option value="0">禁用</option></select></td>' +
                        '</tr>');
                });
                if (prependTbodyTrs.length > 0) {
                    $('#sku-table tbody').html(prependTbodyTrs.join(''));
                    $('input[name=spec]').val(JSON.stringify(specData));
                    form.render('select');
                    upload.render({
                        elem: '#sku-table td img',
                        url: url,
                        exts: 'png|jpg|ico|jpeg|gif',
                        accept: 'images',
                        acceptMime: 'image/*',
                        multiple: false,
                        done: function (res) {
                            if (res.code === 200) {
                                var url = res.data.url;
                                $(this.item).attr('src', url).prev().val(url);
                                layer.msg(res.msg);
                            } else {
                                layer.msg(res.msg);
                            }
                            return false;
                        }
                    });
                }
            } else {
                $('#sku-table').parent().parent().addClass('layui-hide');
                $('#sku-table thead').html('');
                $('#sku-table tbody').html('');
                $('input[name=spec]').val('');
            }
        }

        /**
         * 初始化sku表
         */
        createSkuTable();

        /**
         * 监听sku表变化
         */
        form.on('checkbox(filter)', function (data) {
            createSkuTable();
        });

        /**
         * 监听批量赋值
         */
        $(document).on('click', '#sku-table thead tr th i', function () {
            var that = this;
            layer.prompt(function (value, index, elem) {
                $.each($('#sku-table tbody tr'), function () {
                    $(this).find('td').eq($(that).parent().index()).children('input').val(value);
                });
                layer.close(index);
            });
        });

        /**
         * 监听表单提交
         */
        form.on('submit(submit)', function (data) {
            var state = Object.keys(data.field).some(function (item, index, array) {
                return item.startsWith('skus');
            });
            state ? layer.alert(JSON.stringify(data.field), {title: '提交的数据'}) : layer.msg('sku表数据不能为空', {icon: 5, anim: 6});
            return false;
        });
    });
</script>
</body>
</html>

 

友情链接:

https://www.copylian.com/technology/230.html

https://learnku.com/articles/48792

 

posted @ 2021-01-22 16:03  白開水  阅读(2496)  评论(1编辑  收藏  举报