前言
公司商城业务需把原本的统一属性分割为单商品的属性值,在编写的过程中,困难度很大,借鉴了很多案例,最终实现,现分享出来,供大家参考。
实现效果图
image.png
数据格式对照图
CDD1ECB3-EDC1-4df7-B708-AE6667989B88.png
微信图片_20210520100336.png
A6F0E480-8FC0-46fb-9627-4646D8CCF79F.png
utils.js
//商品属性组合算法 笛卡尔积算法
export function calcDescartes(){
return Array.prototype.reduce.call(arguments,function(a, b) {
let ret = [];
a.forEach(function(a_item) {
b.forEach(function(b_item) {
ret.push(a_item.concat([b_item]));
});
});
return ret;
}, [[]]);
}
变量定义及注释代码
import { Modal, Input, InputNumber,Button, Upload, message, Row, Col, Icon, Radio, Switch,Tabs,Spin,Tooltip,Popconfirm,DatePicker, Popover,Checkbox,Table } from 'antd';
import {calcDescartes} from '../../../utils/utils.js';
this.state = {
attr:[{attr_name:'',attr_val:[]}],//商品属性
recordAttr:[{attr_name:'',attr_val:[]}],//商品属性 记录 用于对比
isShowCharDetail:false,//是否展示属性明细 点击添加属性值的时候才显示
charTableData:[],//属性明细数据
recordCharTableData:[],//属性明细数据 记录数据 用于对比
visibleAttrBtn:true,//属性添加按钮是否显示
sortOpt:'',//批量设置方式 price价格 stock库存
totalPrice:0,//批量价格值
totalStock:0,//批量库存值
visibleOuterAttrBtn:true,//属性外层的 添加属性按钮是否显示 是否展示属性可编辑区域
allowAddCharPic:false,//是否允许第一个属性添加属性值图片
disabledStorage:false,//库存是否可以修改 编辑时 秒杀按钮已开启状态不能修改库存
isEdit:false,//是否在编辑页面
isSeckill:false,//商品是否在秒杀中
overCharVis:false,//属性明细表超过200就提示用户
isOverChar:false,//明细是否超过200
};
js代码 基本逻辑
//处理点击事件
handleBtn(tag,params,e){
let {verifyStore,allowAddCharPic,charTableData,sortOpt,totalPrice,totalStock,isEdit,isSeckill,isOverChar} = this.state;
switch(tag){
case 'addFirstAttr':
//第一次添加商品属性
this.setState({
visibleOuterAttrBtn:false
})
break;
case 'addNewAttr':
//正常添加商品属性
if(isOverChar){
this.setState({
overCharVis:true
})
return;
}
let newAttr = this.state.attr;
if(newAttr && newAttr.length){
newAttr[newAttr.length] = {attr_name:'',attr_val:[]};
this.setState({
visibleAttrBtn:newAttr.length > 4 ? false : true,
attr:newAttr,
recordAttr:JSON.parse(JSON.stringify(this.state.attr)),//记录数据
})
}
break;
case 'allowAddCharPic':
//是否允许添加属性值图片
this.setState({
allowAddCharPic:params.target.checked
},()=>{
let allowAttr = this.state.attr;
if(allowAttr && allowAttr.length > 0){
if(allowAttr[0].attr_val && allowAttr[0].attr_val.length > 0){
allowAttr[0].attr_val.forEach(val=>{
params.target.checked ? val.img = '' : delete val.img;
})
}
this.setState({
attr:allowAttr,
recordAttr:JSON.parse(JSON.stringify(this.state.attr)),//记录数据
})
}
})
break;
case 'addCharValue':
//添加属性值 attr:[{attr_name:'',attr_val:[{txt:'',img:''}]}]
if(isOverChar){
this.setState({
overCharVis:true
})
return;
}
if(isSeckill){
return;
}
let operAttr = this.state.attr;
let addObj = {
txt:''
};//新增的属性值 根据是否选中可添加属性值图片来决定内容是什么
if(operAttr && operAttr.length > 0){
(allowAddCharPic && params == 0) ? addObj.img = '' : '';
if(operAttr[params].attr_val.length < 20){
operAttr[params].attr_val.push(addObj);
this.setState({
attr:operAttr,
recordAttr:JSON.parse(JSON.stringify(this.state.attr)),//记录数据
},()=>{
this.handleCharDetailShow(operAttr);
})
}
}
break;
case 'delCharVal':
//删除属性值
if(isSeckill){
return;
}
let delAttr = this.state.attr;//属性
if(delAttr && delAttr.length > 0){
delAttr[params.index].attr_val.splice(params.idx, 1);
this.setState({
attr:delAttr,
recordAttr:JSON.parse(JSON.stringify(this.state.attr)),//记录数据
},()=>{
this.handleCharData(delAttr);
this.handleCharDetailShow(delAttr);
})
}
break;
case 'uploadCharPic':
//上传属性值照片
let uploadAttr = this.state.attr;
uploadOss(e,{option:'uploadGoodsCharPic'}).then((value)=>{
if(uploadAttr && uploadAttr.length > 0){
uploadAttr[params.index].attr_val[params.idx].img = value;
this.setState({
attr:uploadAttr,
recordAttr:JSON.parse(JSON.stringify(this.state.attr)),//记录数据
})
}
}).catch(res=>{
message.error(res);
return;
})
break;
case 'setTotalPrice':
//批量设置 属性价格
this.setState({
sortOpt:'price'
})
break;
case 'setTotalStock':
//批量设置 属性库存
this.setState({
sortOpt:'stock'
})
break;
case 'saveTotalSet':
//保存批量设置属性
if(charTableData && charTableData.length > 0){
let stockArr = [];//storage
let axios_url = '';//请求地址
let obj_data = {};//请求需要传递的参数
let ids = [];//传递参数需要的ids
switch(sortOpt){
case 'price':
//价格
charTableData.forEach(item=>{
item.price = totalPrice;
ids.push(item.id);
})
axios_url = 'xxx';
obj_data.price = totalPrice;
break;
case 'stock':
//库存
charTableData.forEach(item=>{
item.stock = totalStock;
stockArr.push(item.stock);
ids.push(item.id);
})
axios_url = 'xxx/setSkuStock';
obj_data.stock = totalStock;
this.setState({
storage:JSON.stringify(stockArr) != '[]' ? stockArr.reduce((total,num)=>{return Number(total) + Number(num)}) : 0
})
break;
}
this.setState({
charTableData,
recordCharTableData:charTableData,//记录修改
},()=>{
obj_data.ids = ids.join(',');
request(axios_url, {
method: 'POST',
headers: config.headers,
body:config.parseJson(obj_data)
}).then((res) => {
})
this.setState({
sortOpt:'',
totalPrice:0,
totalStock:0
})
})
}else{
message.warn('请先添加属性');
return;
}
break;
case 'cancelTotalSet':
//取消批量设置属性
this.setState({
sortOpt:'',
totalPrice:0,
totalStock:0
})
break;
}
}
//输入框整合
handleInput(tag,e,opt){
const {charTableData,isEdit,recordCharTableData,recordAttr,attr,id} = this.state;
switch(tag){
case 'saveStorage':
//商品库存失去焦点 普通商品(无属性商品 需实时保存)
if(isEdit){
//编辑情况下 修改普通商品的库存 需要实时保存 避免超卖
let storageObj = {
id:id ? id : '',
stock:e.target.value
};
request(`xxx`, {
method: 'POST',
headers: config.headers,
body:config.parseJson(storageObj)
}).then((res) => {
// console.log(res)
})
}
break;
case 'changeAttrVal':
//修改属性值 attr:[{attr_name:'',attr_val:[{txt:''},{txt:''}]}],//商品属性
let changeAttr = this.state.attr;
let changeAttrLength = changeAttr.length;
if(changeAttr && changeAttrLength > 0){
// console.log('changeAttr[e.outer].attr_val[e.inner].txt: ',changeAttr[e.outer].attr_val[e.inner].txt)
changeAttr[e.outer].attr_val[e.inner].txt = opt.target.value.substring(0,20);
changeAttr[e.outer].attr_val[e.inner].id = `${changeAttr[e.outer].attr_val[e.inner].id}-c`
this.setState({
attr:changeAttr,
},()=>{
this.handleCharDetailShow(this.state.attr);//处理属性明细显示隐藏
})
}
break;
case 'changeBlurAttrVal':
//属性值不能相同
// console.log('e: ',e)
// console.log('opt: ',opt.target.value)
// console.log('judgeAttr: ',this.state.attr)
let judgeAttr = this.state.attr;//需要判断是否存在相同的属性值
let judgeAttrVal = [];//用于收集修改的属性值所属的属性名项下的所有属性值
if(judgeAttr && judgeAttr.length > 0){
for(let index = 0;index < judgeAttr.length;index++){
if((index == e.outer) && judgeAttr[index].attr_val && judgeAttr[index].attr_val.length > 0){
//在同一个属性名下面不允许出现相同的属性值
judgeAttr[index].attr_val.forEach(item=>{
judgeAttrVal.push(item.txt);
})
let sameIndex = judgeAttrVal.indexOf(opt.target.value);//找到相同属性值的位置
// console.log(sameIndex)
if(sameIndex > -1 && sameIndex != e.inner){
//已经存在相同的属性值了
judgeAttr[index].attr_val[e.inner].txt = '';
this.setState({
attr:judgeAttr
})
message.error('已经添加了相同的属性值');
return;
}
}
}
this.handleCharData(this.state.attr)
}
// this.handleCharData(this.state.attr);//处理属性明细数据
break;
case 'singleCharPrice':
//属性明细 单个价格
if(charTableData && charTableData.length > 0){
charTableData.forEach(item=>{
if(item.id == e.id){
item.price = opt;
}
})
this.setState({
charTableData,
recordCharTableData:charTableData,//记录修改
},()=>{
})
}
break;
case 'singleBlurCharPrice':
//属性明细 单个价格 失去焦点
if(charTableData && charTableData.length > 0){
charTableData.forEach(item=>{
if(item.id == e.id){
item.price = opt.target.value;
}
})
this.setState({
charTableData,
recordCharTableData:charTableData,//记录修改
},()=>{
let singleObj = {
ids:e.id,
stock:e.stock,
price:e.price
}
request(`xxxxxs/setSku`, {
method: 'POST',
headers: config.headers,
body:config.parseJson(singleObj)
}).then((res) => {
// console.log(res)
})
})
}
break;
case 'singleCharStock':
//属性明细 单个库存
if(charTableData && charTableData.length > 0){
let stockArr = [];
charTableData.forEach(item=>{
if(item.id == e.id){
item.stock = opt ? parseInt(opt) : 0;
}
stockArr.push(parseInt(item.stock));
})
this.setState({
charTableData,
recordCharTableData:charTableData,//记录修改
storage:stockArr.reduce((total,num)=>{return parseInt(total) + parseInt(num)})
},()=>{
})
}
break;
case 'singleCharBlurStock':
//属性明细 单个库存 失去焦点
if(charTableData && charTableData.length > 0){
let stockArr = [];
charTableData.forEach(item=>{
if(item.id == e.id){
item.stock = opt.target.value ? parseInt(opt.target.value) : 0;
}
stockArr.push(parseInt(item.stock));
})
this.setState({
charTableData,
recordCharTableData:charTableData,//记录修改
storage:stockArr.reduce((total,num)=>{return parseInt(total) + parseInt(num)})
},()=>{
let singleObj = {
ids:e.id,
stock:e.stock,
price:e.price
}
request(`xxx`, {
method: 'POST',
headers: config.headers,
body:config.parseJson(singleObj)
}).then((res) => {
// console.log(res)
})
})
}
break;
case 'price':
//批量设置价格值
this.setState({
totalPrice:e
})
break;
case 'stock':
//批量设置库存值
this.setState({
totalStock:parseInt(e)
})
break;
case 'charBlurName':
//属性名失去焦点 判断是否存在重复的属性名
if(attr && attr.length > 0){
for(let index = 0;index < attr.length;index++){
if(index != e){
if(attr[index].attr_name == opt.target.value){
attr[e].attr_name = '';
this.setState({
attr
})
message.error('已经添加了相同的属性名');
return;
}
}
}
this.handleCharData(this.state.attr)
}
break;
}
}
//获取属性
getAttr(tag,e){
const {isEdit} = this.state;
let attr = this.state.attr;
e.target.value = e.target.value.replace(/[^\u4E00-\u9FA5A-Za-z0-9,,]+$/g,"");
switch(tag.tag){
case 'name':
attr[tag.index].attr_name = e.target.value.substring(0,6);
attr[tag.index].attr_val = [];
break;
case 'value':
attr[tag.index].attr_val = e.target.value;
break;
}
this.setState({
attr,
recordAttr:JSON.parse(JSON.stringify(this.state.attr)),//记录数据
},()=>{
this.handleCharDetailShow(this.state.attr);
this.handleCharData(this.state.attr)
})
}
//删除属性
delAttr(params){
let delAttr = this.state.attr;
if(delAttr && delAttr.length > 0){
// delAttr.length = delAttr.length - 1;
delAttr.forEach(item=>{
delete delAttr[params];
})
}
this.setState({
visibleAttrBtn:true,
attr:delAttr.filter(d=>d),
recordAttr:JSON.parse(JSON.stringify(this.state.attr)),//记录数据
},()=>{
let attr = this.state.attr;
if(attr && JSON.stringify(attr) != '[]'){
//没有全部删除属性
this.setState({
visibleAttrBtn:true,
})
}else{
//属性全部删除
this.setState({
attr:[{attr_name:'',attr_val:[]}],
isShowCharDetail:false,//隐藏属性明细表格
visibleOuterAttrBtn:true,
charTableData:[],//清空属性明细数据
storage:0,//总库存清零
})
}
this.handleCharData(this.state.attr);
})
}
//处理属性明细展示数据 新增/重置属性
handleCharDetailData(attr){
//添加商品的数据处理情况 重新渲染表格数据
let charData = [];
let dataObj = {};//实际数据整理
const {recordCharTableData,charTableData,recordAttr,isEdit} = this.state;
// console.log('recordCharTableData: ',recordCharTableData)
// // console.log('charTableData: ',charTableData)
// console.log('recordAttr: ',this.state.recordAttr)
// console.log('attr: ',attr)
if(recordAttr.length != attr.length){
//新增了某一列 删除了某一列
// console.log('操作:新增了某一列 删除了某一列')
attr.forEach((val,idx)=>{
let arrItem = [];//单个属性拼接
let totalArr = [];//整理后的数据
let attrValLength = val.attr_val.length;
if(val.attr_val && attrValLength > 0){
val.attr_val.forEach((item,index)=>{
arrItem.push({key:index,txt:item.txt});
})
charData.push(arrItem);
}
// let t1 = + new Date();
// console.log('t1: ' + t1);
// console.log(totalArr)
totalArr = calcDescartes(...charData);
// console.log(totalArr)
// let t2 = + new Date();
// console.log('t2: ' + t2);
let itemObj = {};//组装数组中的每一项
let zbArr = [];//组装数据
let totalArrLength = totalArr.length;
if(totalArr && totalArrLength > 0){
totalArr.forEach((data,_idx)=>{
itemObj = {
id:_idx + 1
};
data.forEach((_item,idx_)=>{
itemObj[`v${idx_ + 1}_t`] = attr[`${idx_}`].attr_name;
itemObj[`v${idx_ + 1}`] = _item.txt;
itemObj[`v${idx_ + 1}_id`] = _item.key;
itemObj[`v${idx_ + 1}_tid`] = idx_;
itemObj['key'] = (itemObj['key'] ? itemObj['key'] : '') + itemObj[`v${idx_ + 1}_tid`] + '-' + itemObj[`v${idx_ + 1}_id`] + '_';
})
itemObj.price = 0.01;
itemObj.stock = 0;
itemObj.sellNum = 0;
zbArr.push(itemObj);
})
}
// let t3 = + new Date();
// console.log('t3: ' + t3);
// console.log(zbArr.length)
this.setState({
charTableData:zbArr
},()=>{
this.setState({
recordCharTableData:JSON.parse(JSON.stringify(this.state.charTableData)),//记录数据
})
let stockArr = [];//库存数组
zbArr.forEach(item=>{
stockArr.push(item.stock);
})
this.setState({
storage:stockArr.reduce((total,num)=>{return Number(total) + Number(num)})
})
if(this.state.charTableData && this.state.charTableData.length > 201){
this.setState({
overCharVis:true,
isOverChar:true
})
return;
}else{
this.setState({
isOverChar:false
})
}
})
})
}else{
//在原本的属性列上新增属性值和修改属性名
// console.log('在原本的属性列上新增属性值和修改属性名')
let charData = [];
let dataObj = {};//实际数据整理
let receiveAttr = attr;//收到的属性数据
let filterAttr = [];//过滤出来有效的属性数据
if(receiveAttr && receiveAttr.length > 0){
receiveAttr.forEach(item=>{
if(item.attr_val && item.attr_val.length > 0){
//把有属性值的属性项筛选出来
filterAttr.push(item);
}
})
}
filterAttr.forEach((val,idx)=>{
let arrItem = [];//单个属性拼接
let totalArr = [];//整理后的数据
if(val.attr_val && val.attr_val.length > 0){
val.attr_val.forEach((item,index)=>{
arrItem.push({key:index,txt:item.txt});
})
charData.push(arrItem);
}
// console.log('charData: ',charData)
totalArr = calcDescartes(...charData);
// console.log('totalArr: ',totalArr)
let itemObj = {};//组装数组中的每一项
let zbArr = [];//组装数据
let totalArrLength = totalArr.length;
if(totalArr && totalArrLength > 0){
totalArr.forEach((data,_idx)=>{
itemObj = {
id:_idx + 1
};
data.forEach((_item,idx_)=>{
itemObj[`v${idx_ + 1}_t`] = filterAttr[`${idx_}`].attr_name;
itemObj[`v${idx_ + 1}`] = _item.txt;
itemObj[`v${idx_ + 1}_id`] = _item.key;
itemObj[`v${idx_ + 1}_tid`] = idx_;
itemObj['key'] = (itemObj['key'] ? itemObj['key'] : '') + itemObj[`v${idx_ + 1}_tid`] + '-' + itemObj[`v${idx_ + 1}_id`] + '_';
})
itemObj.price = 0.01;
itemObj.stock = 0;
itemObj.sellNum = 0;
zbArr.push(itemObj);
})
if(idx == (filterAttr.length - 1)){
//数据整理完整后进行处理
// console.log(`原始数据: `,recordCharTableData)
// console.log(`重组数据: `,zbArr)
let zbKey = [];//重组数据的key集合
zbArr.forEach(item=>{
zbKey.push(item.key);
})
// console.log('recordCharTableData: ',recordCharTableData)
//循环原始数据
recordCharTableData.forEach(item=>{
//先判断key值是否与重组数据的key集合一致
if(zbKey.indexOf(item.key) > -1){
// console.log('找到了key: ',item.key);
// console.log('filterAttr: ',filterAttr)
//再把key进行数组分割
let key_arr = item.key.split('_').filter(d=>d);
let is_diff = false;//没有修改值
//需要原始数据当前项和attr里面的值是否一致 一致把当前项覆盖到重组数据的key位置处 需要把item中的每一项都对比一遍 再进行替换处理
for(let k_i = 0; k_i < key_arr.length; k_i++){
let index = k_i;
key_arr[k_i] = key_arr[k_i].split('-');
// console.log('key_arr[k_i]: ',key_arr[k_i])
// console.log('item[`v${index + 1}_t`]--item[`v${index + 1}`]: ', item[`v${index + 1}_t`],item[`v${index + 1}`])
// console.log('filterAttr[`${key_arr[k_i][0]}`].attr_name---filterAttr[`${key_arr[k_i][0]}`][`attr_val`][`${key_arr[k_i][1]}`][`txt`]: ', filterAttr[`${key_arr[k_i][0]}`].attr_name,filterAttr[`${key_arr[k_i][0]}`]['attr_val'][`${key_arr[k_i][1]}`]['txt'])
if(item[`v${index + 1}_t`] == filterAttr[`${key_arr[k_i][0]}`].attr_name){
if(item[`v${index + 1}`] == filterAttr[`${key_arr[k_i][0]}`]['attr_val'][`${key_arr[k_i][1]}`]['txt']){
// console.log('属性值没有变化 原始数据项直接覆盖重组数据项: ',item)
// zbArr[zbKey.indexOf(item.key)] = item;
}else{
//属性值有变化
is_diff = true;
// console.log('zbArr :',zbArr)
// console.log('属性值有变化 使用原本的数据: ',zbArr[zbKey.indexOf(item.key)])
// zbArr[zbKey.indexOf(item.key)] = zbArr[zbKey.indexOf(item.key)];
break;
}
}else{
//列名有变化
}
}
// console.log('is_diff: ' + is_diff);
if(is_diff){
// console.log('属性值有变化 使用原本的数据: ',zbArr[zbKey.indexOf(item.key)])
zbArr[zbKey.indexOf(item.key)] = zbArr[zbKey.indexOf(item.key)];
}else{
// console.log('属性值没有变化 原始数据项直接覆盖重组数据项: ',item)
zbArr[zbKey.indexOf(item.key)] = item;
}
}else{
// console.log('没找到key')
}
})
// console.log(`新__原始数据: `,recordCharTableData)
// console.log(`新__重组数据: `,zbArr)
// console.log(zbArr.length)
this.setState({
charTableData:zbArr
},()=>{
let stockArr = [];//库存数组
zbArr.forEach(item=>{
stockArr.push(item.stock);
})
this.setState({
storage:stockArr.reduce((total,num)=>{return Number(total) + Number(num)})
})
if(this.state.charTableData && this.state.charTableData.length > 201){
this.setState({
overCharVis:true,
isOverChar:true
})
return;
}else{
this.setState({
isOverChar:false
})
}
})
}
}
})
}
}
//处理属性明细数据条件判断 新增/编辑 属性
handleCharData(attr){
//区分编辑和添加
//新增尺码M属性值 先判断第一列有几个属性值 有几个属性值就插入几次 先插入第一条数据 用1*第二列数值的位置插入
const {isEdit,charTableData,recordCharTableData,recordAttr} = this.state;
if(isEdit){
//编辑
// console.log('recordAttr: ',recordAttr)
// console.log('attr: ',attr)
// console.log('charTableData: ',charTableData)
// console.log('recordCharTableData: ',recordCharTableData)
if(recordAttr.length != attr.length){
//新增了某一列 删除了某一列
// console.log('操作:新增了某一列 删除了某一列')
this.handleCharDetailData(attr);
}else{
//在原本的属性列上新增属性值和修改属性名
// console.log('在原本的属性列上新增属性值和修改属性名')
let charData = [];
let dataObj = {};//实际数据整理
let receiveAttr = attr;//收到的属性数据
let filterAttr = [];//过滤出来有效的属性数据
if(receiveAttr && receiveAttr.length > 0){
receiveAttr.forEach(item=>{
if(item.attr_val && item.attr_val.length > 0){
//把有属性值的属性项筛选出来
filterAttr.push(item);
}
})
}
filterAttr.forEach((val,idx)=>{
let arrItem = [];//单个属性拼接
let totalArr = [];//整理后的数据
if(val.attr_val && val.attr_val.length > 0){
val.attr_val.forEach((item,index)=>{
arrItem.push({key:index,txt:item.txt});
})
charData.push(arrItem);
}
// console.log('charData: ',charData)
totalArr = calcDescartes(...charData);
let itemObj = {};//组装数组中的每一项
let zbArr = [];//组装数据
let totalArrLength = totalArr.length;
// console.log('totalArr: ',totalArr)
if(totalArr && totalArrLength > 0){
totalArr.forEach((data,_idx)=>{
itemObj = {
id:_idx + 1
};
data.forEach((_item,idx_)=>{
itemObj[`v${idx_ + 1}_t`] = filterAttr[`${idx_}`].attr_name;
itemObj[`v${idx_ + 1}`] = _item.txt;
itemObj[`v${idx_ + 1}_id`] = _item.key;
itemObj[`v${idx_ + 1}_tid`] = idx_;
itemObj['key'] = (itemObj['key'] ? itemObj['key'] : '') + itemObj[`v${idx_ + 1}_tid`] + '-' + itemObj[`v${idx_ + 1}_id`] + '_';
})
itemObj.price = 0.01;
itemObj.stock = 0;
itemObj.sellNum = 0;
// console.log('itemObj: ',itemObj)
zbArr.push(itemObj);
// console.log('zbArr: ',zbArr)
})
// console.log('zbArr: ',zbArr)
if(idx == (filterAttr.length - 1)){
//数据整理完整后进行处理
// console.log(`原始数据: `,recordCharTableData)
// console.log(`重组数据: `,zbArr)
let zbKey = [];//重组数据的key集合
zbArr.forEach(item=>{
zbKey.push(item.key);
})
//循环原始数据
recordCharTableData.forEach(item=>{
//先判断key值是否与重组数据的key集合一致
if(zbKey.indexOf(item.key) > -1){
// console.log('找到了key: ',item.key);
// console.log('filterAttr: ',filterAttr)
//再把key进行数组分割
let key_arr = item.key.split('_').filter(d=>d);
let is_diff = false;//没有修改值
//需要原始数据当前项和attr里面的值是否一致 一致把当前项覆盖到重组数据的key位置处 需要把item中的每一项都对比一遍 再进行替换处理
for(let k_i = 0; k_i < key_arr.length; k_i++){
let index = k_i;
key_arr[k_i] = key_arr[k_i].split('-');
// console.log('key_arr[k_i]: ',key_arr[k_i])
// console.log('item[`v${index + 1}_t`]--item[`v${index + 1}`]: ', item[`v${index + 1}_t`],item[`v${index + 1}`])
// console.log('filterAttr[`${key_arr[k_i][0]}`].attr_name---filterAttr[`${key_arr[k_i][0]}`][`attr_val`][`${key_arr[k_i][1]}`][`txt`]: ', filterAttr[`${key_arr[k_i][0]}`].attr_name,filterAttr[`${key_arr[k_i][0]}`]['attr_val'][`${key_arr[k_i][1]}`]['txt'])
if(item[`v${index + 1}_t`] == filterAttr[`${key_arr[k_i][0]}`].attr_name){
if(item[`v${index + 1}`] == filterAttr[`${key_arr[k_i][0]}`]['attr_val'][`${key_arr[k_i][1]}`]['txt']){
// console.log('属性值没有变化 原始数据项直接覆盖重组数据项: ',item)
// zbArr[zbKey.indexOf(item.key)] = item;
}else{
//属性值有变化
is_diff = true;
// console.log('zbArr :',zbArr)
// console.log('属性值有变化 使用原本的数据: ',zbArr[zbKey.indexOf(item.key)])
// zbArr[zbKey.indexOf(item.key)] = zbArr[zbKey.indexOf(item.key)];
break;
}
}else{
//列名有变化
is_diff = true;
break;
}
}
// console.log('zbArr: ',zbArr)
// console.log('is_diff: ' + is_diff);
if(is_diff){
// console.log('属性值有变化 使用原本的数据: ',zbArr[zbKey.indexOf(item.key)])
zbArr[zbKey.indexOf(item.key)] = zbArr[zbKey.indexOf(item.key)];
}else{
// console.log('属性值没有变化 原始数据项直接覆盖重组数据项: ',item)
zbArr[zbKey.indexOf(item.key)] = item;
}
}
})
// console.log(`新__原始数据: `,recordCharTableData)
// console.log(`新__重组数据: `,zbArr)
// console.log(zbArr.length)
this.setState({
charTableData:zbArr
},()=>{
let stockArr = [];//库存数组
zbArr.forEach(item=>{
stockArr.push(item.stock);
})
this.setState({
storage:stockArr.reduce((total,num)=>{return Number(total) + Number(num)})
})
if(this.state.charTableData && this.state.charTableData.length > 201){
this.setState({
overCharVis:true,
isOverChar:true
})
return;
}else{
this.setState({
isOverChar:false
})
}
})
}
}
})
}
}else{
//添加
this.handleCharDetailData(attr);
}
}
//处理属性明细显示与隐藏
handleCharDetailShow(attr){
let status_de = '';//明细状态
let filterArr = [];//把没有属性名的数据过滤掉
if(attr && attr.length > 0){
//属性添加部分 必须有一个属性名 和属性值
attr.forEach((item,index)=>{
if(item.attr_name && String(item.attr_name).trim() != ''){
filterArr.push(item);
}
})
}
if(filterArr && filterArr.length > 0){
//整理数据
filterArr.forEach((item,index)=>{
if(item.attr_name && String(item.attr_name).trim() != ''){
if(item.attr_val.length > 0){
item.attr_val.forEach(val=>{
if(val.txt && String(val.txt).trim() != ''){
status_de = true;
}
})
}
}else{
status_de = false;
}
})
}
this.setState({
isShowCharDetail:status_de ? status_de : false
})
}
render 前端页面代码
let charColumns = [],charData=this.state.charTableData;//属性明细
let columsObj = {};//列数据整理
let dataObj = {};//实际数据整理
let receiveAttr = attr;//收到的属性数据
let filterAttr = [];//过滤出来有效的属性数据
if(receiveAttr && receiveAttr.length > 0){
receiveAttr.forEach(item=>{
if(item.attr_val && item.attr_val.length > 0){
//把有属性值的属性项筛选出来
filterAttr.push(item);
}
})
}
if(filterAttr && filterAttr.length > 0){
filterAttr.forEach((val,idx)=>{
columsObj = {
title: val.attr_name,
dataIndex: `v${idx + 1}`,
width:100,
render: (text, record, index) => {
const obj = {
children: text !== null ? text : '',
props: {}
}
obj.props.rowSpan = idx + 1 == 1 ? mergeCells(text, charData, `v${idx + 1}`, index) : '';
return obj
},
};
charColumns.push(columsObj);
})
const sellTitle =
销量
//固定列
let fixColumn = [
{
title: '价格(元)',
dataIndex: `price`,
align:'center',
width:120,
render: (text, record, index) => (
)
},
{
title: '库存',
align:'center',
dataIndex: `stock`,
width:120,
render: (text, record, index) => (
)
},
{
title: sellTitle,
dataIndex: `sellNum`,
align:'center',
width:100,
}
];
// console.log(fixColumn)
charColumns = charColumns.concat(fixColumn);
}
const mergeCells = (text, data, key, index) => {
// 上一行该列数据是否一样
if (index !== 0 && text === data[index - 1][key]) {
return 0;
}
let rowSpan = 1;
// 判断下一行是否相等
let dataLength = data.length;
for (let i = index + 1; i < dataLength; i++) {
if (text !== data[i][key]) {
break;
}
rowSpan++;
}
return rowSpan;
}
商品规格:
{
visibleOuterAttrBtn &&
( 最多添加5个商品属性 )
}
{
!visibleOuterAttrBtn &&
{
attr && attr.length > 0 && attr.map((item,index)=>(
-
属性名:
{
index == 0 ? 添加属性值图片 : ''
}
0 ? {}: {marginBottom: '20px'}}>属性值:
{
item.attr_val && item.attr_val.length > 0 && item.attr_val.map((val,idx)=>(
{
(allowAddCharPic && index == 0) ?
{val.img ?
: uploadButton}
: ''
}
))
}
{
(item.attr_val && item.attr_val.length < 20) ? : ''
}
{
(allowAddCharPic && item.attr_val && item.attr_val.length > 0 && index == 0) ? (仅支持为第一组属性设置规属性值图片;买家选择不同属性值会看到对应规格图片,建议尺寸:800 x 800像素,图片大小:2M以内,图片格式:jpg/png/gif)
: ''
}
{
isSeckill ?
:
}
))
}
{
visibleAttrBtn &&
( 最多添加5个商品属性 )
}
}
{
// 点击添加属性值 才显示
isShowCharDetail ?