1,规格名称表
CREATE TABLE `fa_item_attr_key` ( `attr_key_id` int(10) unsigned NOT NULL AUTO_INCREMENT, `item_id` int(10) unsigned DEFAULT '0', `attr_name` varchar(50) NOT NULL, PRIMARY KEY (`attr_key_id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8
2,规格属性表
CREATE TABLE `fa_item_attr_val` ( `symbol` int(10) NOT NULL AUTO_INCREMENT, `attr_key_id` int(10) unsigned DEFAULT NULL, `item_id` int(10) unsigned DEFAULT '0', `attr_value` varchar(255) DEFAULT NULL, PRIMARY KEY (`symbol`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8
3,商品sku表
CREATE TABLE `fa_item_sku` ( `sku_id` int(10) unsigned NOT NULL AUTO_INCREMENT, `item_id` int(10) unsigned DEFAULT '0', `attr_symbol_path` varchar(255) NOT NULL, `price` double(15,2) NOT NULL DEFAULT '0.00' COMMENT '价格', `freight` double(15,2) DEFAULT '0.00' COMMENT '运费', `stock` int(10) unsigned NOT NULL DEFAULT '0', `original_price` double(15,2) DEFAULT NULL COMMENT '原始价格', PRIMARY KEY (`sku_id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8
1,前端样式(参考资料:https://www.cnblogs.com/moumou0213/p/7233357.html https://wenku.baidu.com/view/12fc20e10740be1e640e9ae5.html)
2,添加页代码
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <link rel="stylesheet" href="http://cdn.bootcss.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css"> </head> <body> <div> <label> </label> <div > <button id="add_lv1" class="btn btn-primary" type="button">添加规格项</button> <button id="update_table" class="btn btn-success" type="button">生成规格项目表</button> </div> </div> <div> <button id="save_product" style="display: none;">保存商品</button> </div> <div id="lv_table_con" style="display: none;"> <label>规格项目表</label> <div> <div id="lv_table"> </div> </div> </div> <script src="http://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script> <script> var lv1HTML = '<div class="control-group lv1 item-attr">' + '<label>规格名称</label>' + '<div>' + '<input type="text" name="lv1" placeholder="规格名称">' + '<button class="btn btn-primary add_lv2" type="button">添加参数</button>' + '<button class="btn btn-danger remove_lv1" type="button">删除规格</button>' + '</div>' + '<div class="controls lv2s"></div>' + '</div>'; var lv2HTML = '<div style="margin-top: 5px;">' + '<input type="text" name="lv2" placeholder="参数名称">' + '<button class="btn btn-danger remove_lv2" type="button">删除参数</button>' + '</div>'; $(document).ready(function() { $('#add_lv1').on('click', function() { var last = $('.control-group.lv1:last'); if (!last || last.length == 0) { $(this).parents('.control-group').eq(0).after(lv1HTML); } else { last.after(lv1HTML); } }); $(document).on('click', '.remove_lv1', function() { $(this).parents('.lv1').remove(); }); $(document).on('click', '.add_lv2', function() { $(this).parents('.lv1').find('.lv2s').append(lv2HTML); }); $(document).on('click', '.remove_lv2', function() { $(this).parent().remove(); }); $(document).on('click', '#save_product', function () { var obj = {}; var i = 0; var first = ''; var tmp = {}; $('#lv_table input').each(function (index, e) { var name = $(e).attr('name'); var value = $(e).val(); symbol = name.split('|')[0]; key = name.split('|')[1]; if (index == 0) { first = symbol; tmp = {symbol: symbol, item_id: 1}; } else if (first != symbol) { first = symbol; i++; tmp = {symbol: symbol, item_id: 1}; } tmp[key] = value; obj[i] = tmp; }); $.ajax({ 'url': '/api/test/test/save_sku', 'method': 'post', 'data': obj, 'success': function (e) { } }); console.log(obj); }); $(document).on('click', '#save_attr', function() { save_attr(); }); $('#update_table').on('click', function() { save_attr(); // update_table(); }); function update_table() { var lv1Arr = $('input[name="lv1"]'); if (!lv1Arr || lv1Arr.length == 0) { $('#lv_table_con').hide(); $('#lv_table').html(''); return; } for (var i = 0; i < lv1Arr.length; i++) { var lv2Arr = $(lv1Arr[i]).parents('.lv1').find('input[name="lv2"]'); if (!lv2Arr || lv2Arr.length == 0) { alert('请先删除无参数的规格项!'); return; } } var tableHTML = ''; tableHTML += '<table class="table table-bordered">'; tableHTML += ' <thead>'; tableHTML += ' <tr>'; for (var i = 0; i < lv1Arr.length; i++) { tableHTML += '<th width="50">' + $(lv1Arr[i]).val() + '</th>'; } tableHTML += ' <th width="20">现价</th>'; tableHTML += ' <th width="20">原价</th>'; tableHTML += ' <th width="20">库存</th>'; tableHTML += ' </tr>'; tableHTML += ' </thead>'; tableHTML += ' <tbody>'; var numsArr = new Array(); var idxArr = new Array(); for (var i = 0; i < lv1Arr.length; i++) { numsArr.push($(lv1Arr[i]).parents('.lv1').find('input[name="lv2"]').length); idxArr[i] = 0; } var len = 1; var rowsArr = new Array(); for (var i = 0; i < numsArr.length; i++) { len = len * numsArr[i]; var tmpnum = 1; for (var j = numsArr.length - 1; j > i; j--) { tmpnum = tmpnum * numsArr[j]; } rowsArr.push(tmpnum); } key='test'; for (var i = 0; i < len; i++) { tableHTML += ' <tr data-row="' + (i+1) + '">'; var name = ''; var value = ''; for (var j = 0; j < lv1Arr.length; j++) { var n = parseInt(i / rowsArr[j]); if (j == 0) { } else if (j == lv1Arr.length - 1) { n = idxArr[j]; if (idxArr[j] + 1 >= numsArr[j]) { idxArr[j] = 0; } else { idxArr[j]++; } } else { var m = parseInt(i / rowsArr[j]); n = m % numsArr[j]; } var text = $(lv1Arr[j]).parents('.lv1').find('input[name="lv2"]').eq(n).val(); var id = $(lv1Arr[j]).parents('.lv1').find('input[name="lv2"]').eq(n).attr('data-id'); if (j != lv1Arr.length - 1) { value += id + ','; name += text + ','; } else { name += text; value += id; } if (i % rowsArr[j] == 0) { tableHTML += '<td width="50" rowspan="' + rowsArr[j] + '" data-rc="' + (i+1) + ',' + (j+1) + '">' + text + '</td>'; } // key=$(lv1Arr[j]).val(); // key=$(lv1Arr[j]).attr('data-id'); } tableHTML += '<td width="20"><input type="text" name="'+ value + '|price" value="'+ '"/></td>'; tableHTML += '<td width="20"><input type="text" name="' + value + '|original_price" value="'+ '" /></td>'; tableHTML += '<td width="20"><input type="text" name="' + value + '|stock" value="'+ '" /></td>'; tableHTML += '</tr>'; } tableHTML += '</tbody>'; tableHTML += '</table>'; $('#lv_table_con').show(); $('#lv_table').html(tableHTML); } function save_attr() { //生成key var key=[]; $('.item-attr input[name=lv1]').each(function (index,ele) { key.push($(ele).val()); }); //生成值 var need=[]; for ( j=0;j<key.length;j++){ need[j]=[]; } i=0; $('.item-attr input').each(function (index,ele) { if($(ele).attr('name')=='lv1' && index!=0){ i++; }else if(index!=0){ need[i].push($(ele).val()); } }); $.ajax({ 'url':'/api/test/test/save_attr', 'method':'post', 'data':{key:JSON.stringify(key),'value':JSON.stringify(need)}, 'sync':0, 'success':function (e) { key=e.data.key; value=e.data.value; create_attr_id(key,value); } }); } function create_attr_id(key,value) { console.log(key,value); $('.item-attr input[name=lv1]').each(function (index,ele) { $(ele).attr('data-id',key[index]); }); $('.item-attr input[name=lv2]').each(function (index,ele) { $(ele).attr('data-id',value[index]); }); update_table(); $('#save_product').show(); } }); </script> </body> </html>
3,编辑页代码
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <link rel="stylesheet" href="http://cdn.bootcss.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css"> </head> <body> <div> <label> </label> <div> <button id="add_lv1" class="btn btn-primary" type="button">添加规格项</button> <button id="update_table" class="btn btn-success" type="button">生成规格项目表</button> </div> </div> {foreach $itemAttr as $key=> $item} <div class="control-group lv1 item-attr"><label>规格名称</label> <div><input type="text" name="lv1" data-id="{$item.attr_key_id}" value="{$item.attr_name}" placeholder="规格名称"> <button class="btn btn-primary add_lv2" type="button">添加参数</button> <button class="btn btn-danger remove_lv1" type="button">删除规格</button> </div> <div class="controls lv2s"> {foreach $item.itemattrval as $value} <div style="margin-top: 5px;"><input type="text" name="lv2" data-id="{$value.symbol}" value="{$value.attr_value}" placeholder="参数名称"> <button class="btn btn-danger remove_lv2" type="button">删除参数</button> </div> {/foreach} </div> </div> {/foreach} <div> <button id="save_product" style="display: none;">保存商品</button> </div> <div id="lv_table_con" style="display: none;"> <label>规格项目表</label> <div> <div id="lv_table"> </div> </div> </div> <script src="http://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script> <script> var lv1HTML = '<div class="control-group lv1 item-attr">' + '<label>规格名称</label>' + '<div>' + '<input type="text" name="lv1" placeholder="规格名称">' + '<button class="btn btn-primary add_lv2" type="button">添加参数</button>' + '<button class="btn btn-danger remove_lv1" type="button">删除规格</button>' + '</div>' + '<div class="controls lv2s"></div>' + '</div>'; var lv2HTML = '<div style="margin-top: 5px;">' + '<input type="text" name="lv2" placeholder="参数名称">' + '<button class="btn btn-danger remove_lv2" type="button">删除参数</button>' + '</div>'; $(document).ready(function () { $('#add_lv1').on('click', function () { var last = $('.control-group.lv1:last'); if (!last || last.length == 0) { $(this).parents('.control-group').eq(0).after(lv1HTML); } else { last.after(lv1HTML); } }); $(document).on('click', '.remove_lv1', function () { $(this).parents('.lv1').remove(); }); $(document).on('click', '.add_lv2', function () { $(this).parents('.lv1').find('.lv2s').append(lv2HTML); }); $(document).on('click', '.remove_lv2', function () { $(this).parent().remove(); }); $(document).on('click', '#save_product', function () { var obj = {}; var i = 0; var first = ''; var tmp = {}; $('#lv_table input').each(function (index, e) { var name = $(e).attr('name'); var value = $(e).val(); symbol = name.split('|')[0]; key = name.split('|')[1]; if (index == 0) { first = symbol; tmp = {symbol: symbol, item_id: 1}; } else if (first != symbol) { first = symbol; i++; tmp = {symbol: symbol, item_id: 1}; } tmp[key] = value; obj[i] = tmp; }); $.ajax({ 'url': '/api/test/test/save_sku', 'method': 'post', 'data': obj, 'success': function (e) { } }); console.log(obj); }); $('#update_table').on('click', function () { save_attr(); }); function save_attr() { //生成key var key = []; $('.item-attr input[name=lv1]').each(function (index, ele) { key.push($(ele).val()); }); //生成值 var need = []; for (j = 0; j < key.length; j++) { need[j] = []; } i = 0; $('.item-attr input').each(function (index, ele) { if ($(ele).attr('name') == 'lv1' && index != 0) { i++; } else if (index != 0) { need[i].push($(ele).val()); } }); $.ajax({ 'url': '/api/test/test/save_attr', 'method': 'post', 'data': {key: JSON.stringify(key), 'value': JSON.stringify(need)}, 'sync': 0, 'success': function (e) { key = e.data.key; value = e.data.value; create_attr_id(key, value); } }); } function create_attr_id(key,value) { console.log(key,value); $('.item-attr input[name=lv1]').each(function (index,ele) { $(ele).attr('data-id',key[index]); }); $('.item-attr input[name=lv2]').each(function (index,ele) { $(ele).attr('data-id',value[index]); }); update_table(); $('#save_product').show(); } function update_table() { var lv1Arr = $('input[name="lv1"]'); if (!lv1Arr || lv1Arr.length == 0) { $('#lv_table_con').hide(); $('#lv_table').html(''); return; } for (var i = 0; i < lv1Arr.length; i++) { var lv2Arr = $(lv1Arr[i]).parents('.lv1').find('input[name="lv2"]'); if (!lv2Arr || lv2Arr.length == 0) { alert('请先删除无参数的规格项!'); return; } } var tableHTML = ''; tableHTML += '<table class="table table-bordered">'; tableHTML += ' <thead>'; tableHTML += ' <tr>'; for (var i = 0; i < lv1Arr.length; i++) { tableHTML += '<th width="50">' + $(lv1Arr[i]).val() + '</th>'; } tableHTML += ' <th width="20">现价</th>'; tableHTML += ' <th width="20">原价</th>'; tableHTML += ' <th width="20">库存</th>'; tableHTML += ' </tr>'; tableHTML += ' </thead>'; tableHTML += ' <tbody>'; var numsArr = new Array(); var idxArr = new Array(); for (var i = 0; i < lv1Arr.length; i++) { numsArr.push($(lv1Arr[i]).parents('.lv1').find('input[name="lv2"]').length); idxArr[i] = 0; } var len = 1; var rowsArr = new Array(); for (var i = 0; i < numsArr.length; i++) { len = len * numsArr[i]; var tmpnum = 1; for (var j = numsArr.length - 1; j > i; j--) { tmpnum = tmpnum * numsArr[j]; } rowsArr.push(tmpnum); } key='test'; for (var i = 0; i < len; i++) { tableHTML += ' <tr data-row="' + (i+1) + '">'; var name = ''; var value = ''; for (var j = 0; j < lv1Arr.length; j++) { var n = parseInt(i / rowsArr[j]); if (j == 0) { } else if (j == lv1Arr.length - 1) { n = idxArr[j]; if (idxArr[j] + 1 >= numsArr[j]) { idxArr[j] = 0; } else { idxArr[j]++; } } else { var m = parseInt(i / rowsArr[j]); n = m % numsArr[j]; } var text = $(lv1Arr[j]).parents('.lv1').find('input[name="lv2"]').eq(n).val(); var id = $(lv1Arr[j]).parents('.lv1').find('input[name="lv2"]').eq(n).attr('data-id'); if (j != lv1Arr.length - 1) { value += id + ','; name += text + ','; } else { name += text; value += id; } if (i % rowsArr[j] == 0) { tableHTML += '<td width="50" rowspan="' + rowsArr[j] + '" data-rc="' + (i+1) + ',' + (j+1) + '">' + text + '</td>'; } // key=$(lv1Arr[j]).val(); // key=$(lv1Arr[j]).attr('data-id'); } tableHTML += '<td width="20"><input type="text" name="'+ value + '|price" value="'+ '"/></td>'; tableHTML += '<td width="20"><input type="text" name="' + value + '|original_price" value="'+ '" /></td>'; tableHTML += '<td width="20"><input type="text" name="' + value + '|stock" value="'+ '" /></td>'; tableHTML += '</tr>'; } tableHTML += '</tbody>'; tableHTML += '</table>'; $('#lv_table_con').show(); $('#lv_table').html(tableHTML); } function edit() { var attr=JSON.parse('{$itemSku}'); // $('#update_table').trigger('click'); update_table(); $('#lv_table tbody tr').each(function (index,ele) { for (i=0;i<attr.length;i++){ if(index==i){ attr_symbol_path=attr[i].attr_symbol_path; $(ele).find('input[name="'+attr_symbol_path+'|price"]').val(attr[i].price); $(ele).find('input[name="'+attr_symbol_path+'|original_price"]').val(attr[i].original_price); $(ele).find('input[name="'+attr_symbol_path+'|stock"]').val(attr[i].stock); } } }); } edit(); }); </script> </body> </html>
4,后台代码 首页 ,编辑页
public function index(){ return $this->view->fetch(); } public function edit(){ $item_id=1; $data=ItemAttrKey::where(['item_id'=>$item_id])->with(['itemattrval'])->select(); $need=[]; foreach ($data as $item) { $need[]=$item->toArray(); } $sku=ItemSku::where(['item_id'=>$item_id])->select(); $skus=[]; foreach ($sku as $item) { $skus[]=$item->toarray(); } $this->view->assign('itemAttr',$need); $this->view->assign('itemSku',json_encode($skus,320)); return $this->view->fetch(); }
5,api接口
public function save_sku(){ if(request()->isPost()){ $data=request()->post(); $bool=ItemSku::where(['item_id'=>$data[0]['item_id']])->delete(); console($bool); foreach ($data as $item) { $sku=new ItemSku(); $sku->item_id=$item['item_id']; $sku->original_price=$item['original_price']; $sku->price=$item['price']; $sku->stock=$item['stock']; $sku->attr_symbol_path=$item['symbol']; $sku->save(); } } } public function save_attr() { if(request()->isPost()){ $data=request()->post(); $key=json_decode($data['key'],true); $value=json_decode($data['value'],true); $item_id=1; $key_id=[]; ItemAttrKey::where(['item_id'=>$item_id])->delete(); foreach ($key as $k) { $attr_key=ItemAttrKey::where(['attr_name'=>$k,'item_id'=>$item_id])->find(); if(!$attr_key){ $attr_key=new ItemAttrKey(); $attr_key->attr_name=$k; $attr_key->item_id=$item_id; $attr_key->save(); } $key_id[]=$attr_key->attr_key_id; } $tm_v_in=[]; $tm_v=[]; ItemAttrVal::where(['item_id'=>$item_id])->delete(); foreach ($value as $key=>$v){ $attr_key_id=$key_id[$key]; foreach ($v as $v1){ $attr_value=ItemAttrVal::where(['attr_value'=>$v1,'attr_key_id'=>$attr_key_id])->find(); if(!$attr_value){ $attr_value=new ItemAttrVal(); $attr_value->attr_key_id=$attr_key_id; $attr_value->attr_value=$v1; $attr_value->item_id=$item_id; $attr_value->save(); } $tm_v[]=$attr_value->symbol; } // $tm_v[]=$tm_v_in; } $this->success('请求成功',['key'=>$key_id,'value'=>$tm_v]); } $this->success('请求成功'); }
6,使用方法: 1,点击生成规格选项,首先调用后台,保存规格属性接口 2,点击保存商品,会将sku信息插入数据库