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 lang="en">
<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 class="control-group">
<label class="control-label"> </label>
<div class="controls" >
<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" class="control-group" style="display: none;">
<label class="control-label">规格项目表</label>
<div class="controls">
<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 class="control-label">规格名称</label>' +
'<div class="controls">' +
'<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 lang="en">
<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 class="control-group">
<label class="control-label"> </label>
<div class="controls">
<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 class="control-label">规格名称</label>
<div class="controls"><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" class="control-group" style="display: none;">
<label class="control-label">规格项目表</label>
<div class="controls">
<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 class="control-label">规格名称</label>' +
'<div class="controls">' +
'<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信息插入数据库