项目中要求商品有多个规格,实现的步骤如下,其中规格名修改,规格值的添加和删除代码没有贴出来
我们要实现的是如下图:
直接上代码
前端代码
{extend name="admin/public/content" /} {block name="css"}
<style>
.el-main {
padding: 0px !important;
}
.products-detail-imgwrap {
width: 300px;
}
.normal-img {
max-width: 100%;
max-height: 100%;
}
.padding15 {
padding: 10px 15px;
}
.mb10 {
margin-bottom: 10px;
}
.part{border-top: 1px solid #dddd;display: block;height: 86px;}
</style>
<style>
.goods-spec {
display: flex;
justify-content: space-between;
margin-bottom: 10px;
}
.goods-spec .goods-spec-add {
margin-right: 15px;
}
.goods-container .button-new-tag {
height: 32px;
line-height: 30px;
padding-top: 0;
padding-bottom: 0;
}
.goods-container .input-new-tag {
width: 90px;
margin-right: 10px;
vertical-align: bottom;
}
.goods-container .el-tag {
margin-right: 10px;
}
.goods-container .goods-content {
margin-bottom: 10px;
padding: 14px;
border: 1px solid #ebeef5;
border-radius: 4px;
background-color: #fcfcfc;
}
.goods-content .goods-content-box {
display: flex;
align-items: center;
}
.goods-content-box .goods-content-left {
flex: 1;
}
.el-upload--picture-card, .avatar-uploader{
width: 50px;
height: 50px;
}
</style>
{/block} {block name="body"}
<div class="ack-content" v-loading="loading">
<el-form :model="ruleForm" ref="ruleForm" label-width="150px" enctype="multipart/form-data">
<el-radio-group v-model="tabShow" style="margin-bottom: 15px;">
<el-radio-button label="1">商品基本信息</el-radio-button>
<el-radio-button label="2">商品图册</el-radio-button>
<el-radio-button label="3">商品规格设置</el-radio-button>
<el-radio-button label="4">门店价会员价设置</el-radio-button>
</el-radio-group>
<!-- 商品基本信息开始 -->
<div class="block ruleForm-width" style="margin-bottom: 15px;" v-show="tabShow == 1">
<div class="layui-card padding15">
<el-row class="mb10">
<el-col style="width:150px;">选择分类:</el-col>
<el-col style="width:400px;">
<el-cascader
@change="goodsTypeChange"
clearable
filterable
placeholder="选择商品类型"
v-model="searchCateSelectedOption"
:options="searchCateOptions"
>
</el-cascader>
</el-col>
</el-row>
<el-row class="mb10">
<el-col style="width:150px;">规格:</el-col>
<el-col style="width:400px;">
<el-input
v-model="productDetail.spec" type="text"
></el-input>
</el-col>
</el-row>
<!-- <el-row class="mb10" v-if="server_id == 1338">
<el-col style="width:150px;">品牌:</el-col>
<el-col style="width:400px;">
<el-input
v-model="productDetail.spec" type="text"
></el-input>
</el-col>
</el-row> -->
<el-row class="mb10">
<el-col style="width:150px;"> 商品品牌<font style="color: #f60;">*</font>:</el-col>
<el-col style="width:400px;">
<el-select v-model="brandSelectedOption" style="width:400px;" placeholder="商品品牌" collapse-tags size="small" filterable clearable default-first-option>
<el-option
v-for="item in brandList"
:key="item.id"
:label="item.brand_name"
:value="item.id"
@change="brandChange"
>
</el-option>
</el-select>
</el-col>
</el-row>
<el-row class="mb10">
<el-col style="width:150px;"> 商品名称:</el-col>
<el-col style="width:400px;">
<el-input
style="color: #b91616;font-size: 13px;margin-right:30px;"
v-model="productDetail.products_title"
></el-input>
</el-col>
</el-row>
<el-row class="mb10">
<el-col style="width:150px;">商品价格:</el-col>
<el-col style="width:400px;">
<el-input style="color: #b91616;font-size: 13px;margin-right:30px;" v-model="productDetail.products_price" type="number"></el-input>
</el-col>
</el-row>
<el-row class="mb10">
<el-col style="width:150px;">商品折扣价:</el-col>
<el-col style="width:400px;">
<el-input style="color: #b91616;font-size: 13px;margin-right:30px;"
v-model="productDetail.products_discount_price" type="number"
></el-input>
</el-col>
</el-row>
<el-row class="mb10">
<el-col style="width:150px;">销售价格:</el-col>
<el-col style="width:400px;">
<el-input
style="color: #b91616;font-size: 13px;margin-right:30px;"
v-model="productDetail.products_sale_price" type="number"
></el-input>
</el-col>
</el-row>
<!-- <el-row class="mb10" v-show="is_spec == true">
<el-col style="width:150px;">所属服务规格:</el-col>
<el-col style="width:400px;">
<div>
<span style="width:150px;display: inline-block;" v-show="is_part == 1">服务部位</span>
<span style="width:50px;display: inline-block;height: 1px;" v-show="is_part == 2"></span>
<span style="width:120px;display: inline-block;">车身结构</span>
<span style="width:120px;display: inline-block;">价格</span>
</div>
<div :style="width">
<div class="part" style="border-top:0;" v-for="(item,index) in part">
<el-col style="width:150px" v-show="is_part == 1" >
<el-checkbox v-model="item.checked" :label="item.server_name" :key="item.server_name" style="margin: 30px;" @change="changeServerId(index, item.server_id, $event)">{{item.server_name}}</el-checkbox>
</el-col>
<el-col style="width:50px;height: 1px;" v-show="is_part == 2" ></el-col>
<el-col style="width:120px">
<span style="width:100px" v-for="itemAttr, attrIndex in item.attr">
<el-checkbox v-model="itemAttr.checked" :label="itemAttr.name" style="margin: 10px;" @change="changeAttr(index, itemAttr.name, $event)"></el-checkbox>
</span>
</el-col>
<el-col style="width:120px" v-for="itemAttr, attrIndex in item.attr">
<span style="width:100px">
<el-input placeholder="请输入价格" v-model="itemAttr.price" size="small" style="margin: 5px;width:150px;" @change="changePrice(index, attrIndex, itemAttr.price)"><template slot="append">元</template></el-input>
</span>
</el-col>
</div>
</div>
</div>
</el-col>
</el-row> -->
<el-row class="mb10">
<el-col style="width:150px;">是否特价:</el-col>
<el-col style="width:400px;">
<el-switch v-model="productDetail.is_price"></el-switch>
</el-col>
</el-row>
<el-row class="mb10">
<el-col style="width:150px;">商品特价:</el-col>
<el-col style="width:400px;">
<el-input style="color: #b91616;font-size: 13px;margin-right:30px;" v-model="productDetail.spec_price" type="number"></el-input>
</el-col>
</el-row>
<el-row class="mb10">
<el-col style="width:150px;">净含量:</el-col>
<el-col style="width:400px;">
<el-input
v-model="productDetail.amount" type="number"
></el-input>
</el-col>
</el-row>
<el-row class="mb10">
<el-col style="width:150px;">库存:</el-col>
<el-col style="width:400px;">
<el-input
v-model="productDetail.products_quantity" type="number"
></el-input>
</el-col>
</el-row>
<el-row class="mb10">
<el-col style="width:150px;"> 价格说明:</el-col>
<el-col style="width:600px;">
<el-input
v-model="productDetail.price_desc" type="textarea"
></el-input>
</el-col>
</el-row>
<!-- <el-row class="mb10">
<el-col style="width:150px;">选择单位:</el-col>
<el-col style="width:400px;">
<el-select v-model="unitSelectedOption" placeholder="请选择" style="width: 400px;">
<el-option
v-for="item in unitOptions"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-col>
</el-row> -->
</div>
</div>
<!-- 商品基本信息结束 -->
<!-- 商品图册开始 -->
<div class="block ruleForm-width" style="margin-bottom: 15px;padding-left: 20px;" v-show="tabShow == 2">
<el-row class="mb10">
<el-col style="width:150px;">商品图片(点击上传):</el-col>
<el-upload
:action="action"
class="avatar-uploader"
list-type="picture-card"
:on-preview="handlePictureCardPreview"
:on-remove="handleRemove"
limit="10"
:on-exceed="imgExceedNum"
:multiple="true"
:show-file-list="true"
:file-list="productDetail.products_image_arr"
:on-success="successImg"
list-type="file"
data="productDetail.products_image_arr.name"
:on-preview="preview">
<i class="el-icon-plus"></i>
</el-upload>
<el-dialog :visible.sync="dialogVisible">
<img width="100%" :src="dialogImageUrl" alt="">
</el-dialog>
</el-row>
<el-row class="mb10" >
<el-col style="width:150px;"> 商品详情图(最多20张):</el-col>
<el-upload
:action="action"
class="avatar-uploader"
list-type="picture-card"
:on-preview="handlePictureCardPreview1"
:on-remove="handleRemove1"
limit="20"
:on-exceed="imgExceedNum1"
:multiple="true"
:show-file-list="true"
:file-list="productDetail.products_descs_arr"
:on-success="successImg1"
list-type="file"
data="productDetail.products_descs_arr.name"
:on-preview="preview">
<i class="el-icon-plus"></i>
</el-upload>
<el-dialog :visible.sync="dialogVisible">
<img width="100%" :src="dialogImageUrl" alt="">
</el-dialog>
</el-row>
</div>
<!-- 商品图册结束 -->
<!-- 商品规格开始 -->
<div class="block ruleForm-width" style="margin-bottom: 15px;padding-left: 20px;" v-show="tabShow == 3">
<!-- 多规格添加 -->
<!-- <el-row class="mb10" >
<el-col :span="24" v-for="cate, index in Specitem">
<h5 style="padding:20px;">{{cate.name}}:</h5>
<el-checkbox-group v-model="ruleForm.Specitem" style="margin-left: 24px;">
<el-checkbox v-for="item,itemIndex in cate.children" :id="'man' + index + itemIndex" :label="item.id" :key="item.id" v-model="item.selected">{{item.name}}</el-checkbox>
</el-checkbox-group>
</el-col>
</el-row> -->
<!-- 多规添加结束 -->
<!-- 多规格设置 -->
<el-row class="mb10">
<div id="app">
<div style="padding:14px;">
<!-- <div class="goods-spec">
<span>商品规格</span>
<el-link type="primary" @click="addPrivateSpec" class="goods-spec-add">添加规格</el-link>
</div> -->
<div class="goods-container" v-for="(attr, index) in Specitem" :key="index">
<div class="goods-content">
<div class="goods-content-box">
<div class="goods-content-left">
<el-form label-width="80px" style="width:1000px">
<el-form-item label="规格名">
<el-input v-model="attr.name" placeholder="请输入规格名" style="width:200px"></el-input>
</el-form-item>
<el-form-item label="规格值">
<!-- <el-tag v-for="tag in attr.children" :key="tag" closable :disable-transitions="false" @close="handleClose(tag, attr)">
{{ tag.name }}
</el-tag> -->
<el-checkbox-group v-model="ruleForm.Specitem" style="margin-left: 14px;" >
<el-checkbox v-for="item,itemIndex in attr.children" :id="'man' + index + itemIndex" :label="item.id" :key="item.id" v-model="item.selected" @change="handleCheckedSpecChange(attr.id, item.id)" >{{item.name}}</el-checkbox>
</el-checkbox-group>
<el-input
class="input-new-tag"
v-if="attr.inputVisible"
v-model="attr.inputValue"
:ref="`saveTagInput${index}`"
size="small"
@keyup.enter.native="handleInputConfirm(attr.inputValue, attr)"
@blur="handleInputConfirm(attr.inputValue, attr)"
>
</el-input>
<el-button v-else class="button-new-tag" size="small" @click="showInput(attr, index)">+ 添加</el-button>
</el-form-item>
</el-form>
</div>
<div class="goods-content-right">
<el-link type="danger" @click="delPrivateSpec(index)">删除规格</el-link>
</div>
</div>
</div>
</div>
<el-table ref="multipleTable" :data="tableColumnList.tableBodyList" stripe tooltip-effect="dark" style="width: 100%;margin-top:1%;">
<el-table-column :label="item.name" :property="item.name" v-for="item in tableColumnList.tableHeaderList" :key="item.name" align="center">
<template slot-scope="scope">
<span >{{ scope.row[scope.column.property] }}</span>
</template>
</el-table-column>
<el-table-column label="价格(元)">
<template slot-scope="scope">
<el-input v-model.number="scope.row.price" @change="priceChange(scope.row)"></el-input>
</template>
</el-table-column>
<el-table-column label="库存">
<template slot-scope="scope">
<el-input v-model.number="scope.row.stock" @change="priceChange(scope.row)"></el-input>
</template>
</el-table-column>
<el-table-column label="图片" >
<!-- <template slot-scope="scope">
<el-button type="text" @click="handleClick(scope.row)">上传规格图</el-button>
</template> -->
<template slot-scope="scope" class="iconImg" >
<el-upload
:key="timer"
:action="action"
class="avatar-uploader"
list-type="picture-card"
:on-preview="handlePictureCardPreview2"
:on-remove="handleRemove2"
:multiple="true"
:show-file-list="false"
:file-list="uploadFileList"
:on-success="(response, file, fileList) =>successImg2(response, file, fileList,scope)"
limit="1"
:on-exceed="imgExceedNum2"
>
<img v-if="scope.row.spec_item_image" :src="scope.row.spec_item_image" class="avatar" style="width: 50px;height: 50px;display: block;margin: auto;">
<i v-else class="el-icon-plus avatar-uploader-icon" style="width: 50px;height: 50px;display: block;margin: auto;font-size:40px;"></i>
<!-- <i class="el-icon-plus" ></i> -->
</el-upload>
<!-- <el-upload
:action="action"
class="avatar-uploader"
list-type="picture-card"
:on-preview="handlePictureCardPreview2"
:on-remove="handleRemove2"
:multiple="true"
:show-file-list="true"
:file-list="scope.row.spec_item_image"
:on-success="successImg2"
list-type="file"
data="scope.row.spec_item_image.name"
:on-preview="preview" >
<i class="el-icon-plus" ></i>
</el-upload> -->
<!-- <el-dialog :visible.sync="dialogVisible" >
<img :src="dialogImageUrl" alt="" >
</el-dialog> -->
</template>
</el-table-column>
<el-table-column prop="" label="操作" >
<template slot-scope="scope">
<el-tooltip class="item" effect="dark" content="谨慎删除,不可恢复" placement="top" >
<a href="javascript:;" @click="delProduct(scope)">
<i class="layui-icon layui-icon-delete"></i><cite>删除</cite>
</a>
</el-tooltip>
</template>
</el-table-column>
</el-table>
</div>
</div>
</el-row>
<!-- 多规格设置结束 -->
<!-- <template v-for="cate, index in Specitem">
<h5 style="padding:20px;">{{cate.name}}</h5>
<el-radio-group v-model="ruleForm.Specitem[index]" style="margin-left: 24px;">
<el-radio-button v-for="item,itemIndex in cate.children" :id="'man' + index + itemIndex" :label="item.id" :key="item.id" v-model="item.selected" >{{item.name}}</el-radio-button>
</el-radio-group>
<div style="margin: 15px 0;"></div>
</template> -->
<!-- <el-row class="mb10" >
<el-col style="width:150px;"> 商品规格图片(最多1张):</el-col>
<el-upload
:action="action"
class="avatar-uploader"
list-type="picture-card"
:on-preview="handlePictureCardPreview2"
:on-remove="handleRemove2"
limit="1"
:on-exceed="imgExceedNum2"
:multiple="true"
:show-file-list="true"
:file-list="productDetail.spec_item_image"
:on-success="successImg2"
list-type="file"
data="productDetail.spec_item_image.name"
:on-preview="preview">
<i class="el-icon-plus"></i>
</el-upload>
<el-dialog :visible.sync="dialogVisible">
<img width="100%" :src="dialogImageUrl" alt="">
</el-dialog>
</el-row> -->
</div>
<!-- 商品规格结束-->
<!-- 会员价、门店价设置开始@change="changeOriginalPriceValue(item,item.attr)" -->
<div class="block ruleForm-width" style="margin-bottom: 15px;" v-show="tabShow == 4">
<el-row class="mb10" style="width:800px;margin-left: 20px;">
<el-input v-model="productDetail.rebate" placeholder="如:0.85" style="width: 215px;" controls-position="right" ref="index1"><template slot="prepend" >会员价折扣</template></el-input>
</el-row>
<el-row class="mb10" style="margin-left: 20px;">
<span style="color:red">如下是设置的门店售价,会员价等于门店价X会员折扣自动计算</span>
</el-row>
<el-row class="mb10" v-for="item,index in productDetail.member_price" :key="index" :label="item.attr">
<el-col style="width:300px;margin-left: 20px;" >
<el-input v-model="item.price" controls-position="right" :precision="2" :step="1" :min="0" size="small" @input="changeOriginalPriceValue(item,index)"><template slot="prepend" >{{item.attr}}</template></el-input>
</el-col>
<el-col :span="6">
<el-input v-model="meprice[index]" placeholder="会员价" size="small" :disabled=true></el-input>
</el-col>
</el-row>
<el-row class="mb10" v-show="is_spec == true">
<el-col style="width:150px;">所属服务规格:</el-col>
<el-col style="width:400px;">
<div>
<span style="width:150px;display: inline-block;" v-show="is_part == 1">服务部位</span>
<span style="width:50px;display: inline-block;height: 1px;" v-show="is_part == 2"></span>
<span style="width:120px;display: inline-block;">车身结构</span>
<span style="width:120px;display: inline-block;">价格</span>
</div>
<div :style="width">
<div class="part" style="border-top:0;" v-for="(item,index) in part">
<el-col style="width:150px" v-show="is_part == 1" >
<el-checkbox v-model="item.checked" :label="item.server_name" :key="item.server_name" style="margin: 30px;" @change="changeServerId(index, item.server_id, $event)">{{item.server_name}}</el-checkbox>
</el-col>
<el-col style="width:50px;height: 1px;" v-show="is_part == 2" ></el-col>
<el-col style="width:120px">
<span style="width:100px" v-for="itemAttr, attrIndex in item.attr">
<el-checkbox v-model="itemAttr.checked" :label="itemAttr.name" style="margin: 10px;" @change="changeAttr(index, itemAttr.name, $event)"></el-checkbox>
</span>
</el-col>
<el-col style="width:120px" v-for="itemAttr, attrIndex in item.attr">
<span style="width:100px">
<el-input placeholder="请输入价格" v-model="itemAttr.price" size="small" style="margin: 5px;width:150px;" @change="changePrice(index, attrIndex, itemAttr.price)"><template slot="append">元</template></el-input>
</span>
</el-col>
</div>
</div>
</div>
</el-col>
</el-row>
</br>
<el-row style="margin-left: 20px;">
<el-button type="primary" @click="submitForm('ruleForm')">确认保存</el-button>
</el-row>
</div>
<!-- 会员价、门店价设置结束 -->
</el-form>
<!-- 规格图片上传会话框 -->
<el-dialog title="上传图片" :visible.sync="uploadQcVisible" @closed="closePic">
<el-upload
:key="timer"
:action="action"
class="avatar-uploader"
list-type="picture-card"
:on-preview="handlePictureCardPreview2"
:on-remove="handleRemove2"
:multiple="true"
:show-file-list="true"
:file-list="uploadFileList"
:on-success="successImg2"
limit="1"
:on-exceed="imgExceedNum2"
>
<i class="el-icon-plus" ></i>
</el-upload>
</el-dialog>
<!-- 规格图片上传会话框结束 -->
</div>
{/block} {block name="js"}
<script>
//引入layui
layui.config({
base: '__STATIC__/admin/static/' //静态资源所在路径
}).extend({
index: 'lib/index' //主入口模块
}).use('index');
// vue 渲染数据
var vm = new Vue({
el: '#app',
data: {
tabShow:1,
isDialogFormVisible: false,
uploadQcVisible:false,
timer:'',
uploadFileList:[],
tempObj:[],
loading: false,
orderDetail: {},
ruleForm : {
Specitem:[]
},
meprice:[],
order_id: '',
//商品信息START
storeList: [],
attr_price:'',
is_spec: false,
width: 'width: auto;',
server_id: JSON.parse('{$server_id}'),//'{$server_id}',
// 商品sku
tableColumnList:{
tableHeaderList: [],
tableBodyList: []
},
//new 选中的规格项
spec_arr:{},
// part: [
// {
// server_id: 1,
// server_name: '1111',
// attr: [
// {
// name: '轿车',
// price: '20.00'
// },
// {
// name: 'SUV',
// price: '30.00'
// },
// ]
// },
// {
// server_id: 2,
// server_name: '2222',
// attr: [
// {
// name: '轿车',
// price: '20.00'
// },
// {
// name: 'SUV',
// price: '30.00'
// },
// ]
// },
// ],
part: [],
productDetail: {
products_title: '',
products_price: 0,
products_image_arr: [],
store: [],
sps:[],
price_desc:'',
products_category: '',
products_quantity: 0,
spec: '',
amount: '',
defaultCheckedKeys: [], //服务分类选中值
products_attr: [],
products_descs_arr:[],
Specitem:[],
spec_item_image:'',
is_price:false,
member_price:[],//会员价
rebate:'',
spec_price:'',
// {
// server_id: '',
// attrSpec: '',
// price: ''
// }
//]
},
cateOptions: [], //分类列表
cateSelectedOption: [], //分类选中值
Specitem:[],//分类下的规格项
spec_disabled:true,
specOptions:[], //规格列表
specSelectedOption:'',//规格选中值
//搜索分类
searchCateSelectedOption:[],
searchCateOptions:[],
unitOptions: [{ //单位列表
value: 1,
label: '毫升'
}, {
value: 2,
label: '升'
}, {
value: 3,
label: '克'
}, {
value: 4,
label: '千克'
}, {
value: 5,
label: '个'
}],
spec_item_image:[],
unitSelectedOption: '',//单位选中值
brand_disabled:true,
brandSelectedOption:'',//品牌选中值
brandList:[],//品牌列表
storeOptions: [],
spsOptions: [],
showTree:true,
dialogImageUrl: '',
dialogVisible: false,
delImageUrl:[],
defaultImageNames:['products_image','products_image_2','products_image_3','products_image_4','products_image_5'],
store_id: '{$store_id}',
store_server_id: '{$store_server_id}',
type: '{$type}',
copy: '{$copy}',
attr: '{$attr}',
is_part: 0,
tt:'',
temp:[],
attrName: [],
attrPrice: [],
server: [
{
server_id: '',
attr: [
{
attr_name: '',
price: ''
}
]
}
],
server_id:'{$server_id}',
action: '/admin/Product/uploadDetail',
},
created() {
//引用公共js勿删 {include file='admin/public/js'/}
let cate_id = '{$cate_id}';
if(cate_id!=0){
this.getSpecItemLists(cate_id)
this.getBrandList(cate_id)
}
//获取数据
this.get();
this.getStoreList();
this.getCateList();
this.getSpsList();
this.getPart();
// console.log(this.type);
/*console.log(this.cateOptions);*/
},
methods: {
// 添加规格
addPrivateSpec(index) {
// this.privateGoodsItem.push({
// privateSpecName: '',
// dynamicTags: [],
// inputVisible: false,
// inputValue: ''
// })
},
closePic(){
this.timer = new Date().getTime()
// this.uploadFileList = []
},
//规格图上传
handleClick(row){
this.uploadQcVisible=true;
this.tempObj = row
//判断row.piclist是否已经传过数据
if(row.spec_item_image.length !== 0){
this.uploadFileList = Object.assign([],row.spec_item_image)
}
console.log(row)
},
delPrivateSpec(index) {
this.privateGoodsItem.splice(index, 1)
},
handleInputConfirm(val, attr) {
if (val) {
attr.dynamicTags.push(val)
}
attr.inputVisible = false
attr.inputValue = ''
},
handleClose(tag, item) {
item.dynamicTags.splice(item.dynamicTags.indexOf(tag), 1)
},
showInput(attr, index) {
attr.inputVisible = true
this.$nextTick((_) => {
this.$refs[`saveTagInput${index}`][0].$refs.input.focus()
})
},
// 笛卡尔积算法
cartesianProductOf(...args) {
return args.reduce(
(total, current) => {
let ret = []
total.forEach((a) => {
current.forEach((b) => {
ret.push(a.concat([b]))
})
})
return ret
},
[[]]
)
},
//移除数组中的元素返回新数组
remove(arr, item) {
let newArr = arr.slice(0);
for (let i = newArr.length; i >= 0; i--) {
if (newArr[i] === item) {
newArr.splice(i, 1)
}
}
return newArr
},
// 选择规格
handleCheckedSpecChange(spec_id,item_id){
let _this=this;
if(Object.keys(this.spec_arr)==0){
if(!this.spec_arr.hasOwnProperty(spec_id)){
this.spec_arr[spec_id] = [];
this.spec_arr[spec_id].push(item_id);
}
}else{
if(this.spec_arr.hasOwnProperty(spec_id)){
this.spec_arr[spec_id].forEach((itemarr,index)=>{
if(itemarr==item_id){
let narr=this.remove(this.spec_arr[spec_id], item_id);
this.spec_arr[spec_id] = [];
if(narr.length>0){
for (let i = 0; i < narr.length; i++) {
this.spec_arr[spec_id].push(narr[i]);
}
}else{
delete this.spec_arr[spec_id];
}
}else{
if(this.spec_arr[spec_id].indexOf(this.spec_arr[spec_id][index])==index){
this.spec_arr[spec_id].push(item_id);
}
}
});
}else{
this.spec_arr[spec_id] = [];
this.spec_arr[spec_id].push(item_id);
}
}
// console.log(this.spec_arr)
axios.post('/admin/Goodsspec/getSpecInput',{data:this.spec_arr,checkarr:this.ruleForm.Specitem}).then(res => {
this.tableColumnList=res.data;
})
},
// 移除某一列
delProduct(arr){
let key=arr.$index;
let newarr=this.tableColumnList
axios.post('/admin/Goodsspec/getDatahandle',{data:newarr,key:key}).then(res => {
this.tableColumnList=res.data;
console.log(this.tableColumnList)
})
},
priceChange(val){
console.log(val)
},
getPart() {
let products_id = '{$products_id}';
if(products_id =='') {
axios.get('/admin/product/getPart?store_id={$store_id}&store_server_id={$store_server_id}&type={$type}').then(res => {
this.is_spec = res.data.is_spec;
this.part = res.data.part;
this.is_part = res.data.is_part;
if(res.data.is_part == 0) {
this.width = 'width: 300px'
}
//console.log(this.part)
})
} else {
axios.get('/admin/product/getPart?products_id={$products_id}&store_server_id={$store_server_id}&type={$type}').then(res => {
this.is_spec = res.data.is_spec;
this.part = res.data.part;
this.is_part = res.data.is_part;
if(res.data.is_part == 0) {
this.width = 'width: 300px'
}
})
}
},
//车型原价
changeOriginalPriceValue(item,type) {
let zhekou=this.$refs.index1.value;//设置的折扣
zhekou= zhekou?zhekou:1;
let flag = true;
let _this=this.productDetail.member_price;
const option={ attr:item.attr,price:item.price,server_type:this.type-1};
if(this.productDetail.member_price.length==0){
_this.push(option);
}else{
_this.forEach((itemarr,index)=>{
if(itemarr.attr==item.attr){
_this[index].server_type=this.type;
_this[index].price=item.price;
flag=false;
}
})
if(flag){
_this.push(option);
}
}
this.meprice[type]=zhekou*item.price;
},
changeServerId(index, value, e){
if(e == true) {
this.temp.push({'server_id':value});
for(let l = 0; l < this.part[index].attr.length; l++) {
this.part[index].attr[l].checked = true
}
this.productDetail.products_attr = this.temp;
} else {
for(let l = 0; l < this.part[index].attr.length; l++) {
this.part[index].attr[l].checked = false
for(let j = 0; j < this.part[index].attr[l].length; j++) {
this.part[index].attr[l].price = 0
}
}
}
},
changeAttr(index, attrIndex, attr, e) {
let num = 0;
for(let i = 0; i < this.part[index].attr.length; i++) {
if(this.part[index].attr[i].checked == true) {
num++;
} else {
this.part[index].attr[i].price = 0
}
}
},
changePrice(index, attrIndex, attr, value) {
},
objectSpanMethod({ row, column, rowIndex, columnIndex }) {
if (columnIndex === 0) {
if (rowIndex % 2 === 0) {
return {
rowspan: 2,
colspan: 1
};
} else {
return {
rowspan: 0,
colspan: 0
};
}
}
},
get() {
this.loading = true;
let products_id = '{$products_id}';
axios
.get('/admin/Product/storeProductDetail', {
params: { products_id: products_id}
}).then(res => {
if (res.data) {
this.loading = false;
this.productDetail = res.data;
this.meprice = res.data.meprice;
this.brandSelectedOption=res.data.b_id;
if(res.data.key){
this.ruleForm.Specitem=[];
this.ruleForm.Specitem = res.data.key;
}
this.$set(this.productDetail,'defaultCheckedKeys',this.formatTreeData(res.data.sps_ids));
this.searchCateSelectedOption = res.data.cate_selected;
this.formatPdDetail();
}
});
},
//编辑保存
submitForm(){
/*console.log(this.unitSelectedOption);
return false;*/
let _this = this;
//处理图片的数组
//let This = this
// if(this.productDetail.products_image_arr && this.productDetail.products_image_arr.length > 0) {
// for (let i=0; i<this.productDetail.products_image_arr.length; i++) {
// if (this.productDetail.products_image_arr[i].raw) {
// let reader = new FileReader();
// reader.readAsDataURL(this.productDetail.products_image_arr[i].raw);
// reader.onload = function(e) {
// _this.productDetail.products_image_arr[i].base64Val = this.result;
// };
// _this.productDetail.products_image_arr[i].isNewAdd = 1
// }
// }
// }
setTimeout(function(){
_this.productDetail.products_attr = _this.part;
let data = {
// store_id: _this.productDetail.store_id,
store_id: _this.store_id,
products_id:_this.productDetail.products_id ? _this.productDetail.products_id : 0,
products_title:_this.productDetail.products_title,
products_price:_this.productDetail.products_price,
products_discount_price:_this.productDetail.products_discount_price,
products_sale_price:_this.productDetail.products_sale_price,
cateSelectedOption:_this.cateSelectedOption,
products_image_arr:_this.productDetail.products_image_arr,
products_descs_arr:_this.productDetail.products_descs_arr,
delImageUrl:_this.delImageUrl,
products_quantity: _this.productDetail.products_quantity,
b_id: _this.brandSelectedOption,
Specitem: _this.ruleForm.Specitem,//商品规格
tag:_this.productDetail.tag,
product_base_id:_this.productDetail.product_base_id,
spec: _this.productDetail.spec,
amount: _this.productDetail.amount,
is_price: _this.productDetail.is_price,
store_server_id: _this.store_server_id,
type: _this.type,
copy: _this.copy,
attr:_this.attr,
products_attr: _this.productDetail.products_attr,
add_server_id:_this.server_id,
spec_item_image:_this.productDetail.spec_item_image,
price_desc:_this.productDetail.price_desc,
member_price:_this.productDetail.member_price,
rebate:_this.productDetail.rebate,
spec_price:_this.productDetail.spec_price,
//products_unit:_this.unitSelectedOption,
tableColumnList:_this.tableColumnList
}
_this.loading = true;
console.log(_this.tableColumnList)
// console.log(_this.tempObj)
console.log(data)
return
axios.post('/admin/Product/saveProductDetail', data).then(res => {
// console.log(res); return;
_this.loading = false;
if (res.code == 200) {
_this.$message({
type: 'success',
message: res.message
});
setTimeout(function(){
var index = parent.layer.getFrameIndex(window.name);
parent.layer.close(index);
parent.location.reload();
},10)
}else {
_this.$message({
type: 'error',
message: res.message
});
}
});
},10)
},
changeBookingTime(order_id) {
this.isDialogFormVisible = !this.isDialogFormVisible;
this.order_id = order_id;
},
formatPdDetail() {
this.$nextTick(() => {
this.cateSelectedOption = [
this.productDetail.category_pid,
this.productDetail.products_category
];
});
},
formatCateList(arr) {
arr.forEach(item => {
item.label = item.name;
item.value = item.id;
if (item.children) {
this.formatCateList(item.children);
}
});
return arr;
},
getCateList() {
this.loading = true;
let type = this.type;
let server_id = this.server_id
axios.get('/admin/Product/cateList', { params: {'type':type,'server_id':server_id} }).then(res => {
if (res.data) {
this.loading = false;
this.cateOptions = this.formatCateList(res.data);
this.searchCateOptions = this.formatCateList(res.data);
}
});
},
brandChange(arr) {
},
getSpecItemLists(cate_id){
axios.get('/admin/Product/getSpecItem', { params: {'cate_id':cate_id}}).then(res => {
this.Specitem = res.data.lists;
this.ruleForm.Specitem=res.data.keys;
})
},
// handleCheckedManServerChange(value) {
// let checkedCount = value.length;
// this.checkAll = checkedCount === this.Specitem.length;
// this.isIndeterminate = checkedCount > 0 && checkedCount < this.Specitem.length;
// },
getBrandList(cate_id){
this.loading = true;
let cate_arr = this.cateSelectedOption;
end = cate_arr[cate_arr.length-1];
if(cate_id){
end=cate_id
}
//console.log(cate_arr);
//console.log(end);
axios.get('/admin/Index/getSelectOption', { params: {'act':'goods_brand','cate_id':end}}).then(res => {
this.loading = false;
if(res.data.rows.length == 0){
this.brand_disabled = true;
}
this.brandList = res.data.rows
//console.log(res.data.rows)
});
},
goodsTypeChange(val){
if(val){
let cate_id=val[1]
session_arr = [];
for(let i = 0; i < val.length; i++){
session_arr[i] = val[i];
}
this.loading = true;
axios.get('/admin/Index/getSelectOption', { params: {'act':'goods_brand','cate_id':val.pop()}}).then(res => {
this.loading = false;
this.brandList = res.data.rows
this.searchCateOptions = Object.assign([], this.searchCateOptions, []);
this.searchCateSelectedOption= Object.assign([],this.searchCateSelectedOption, []);
this.searchCateSelectedOption = session_arr;
this.cateSelectedOption=session_arr;
this.brandSelectedOption = ''
this.getSpecItemLists(cate_id)
})
}
},
cateChange(arr) {
this.productDetail.products_category = arr.length
? arr[arr.length - 1]
: '';
let cate_id=arr[1]
//console.log(this.searchCateSelectedOption);
session_arr = [];
for(let i = 0; i < arr.length; i++){
session_arr[i] = arr[i];
}
// this.loading = true;
axios.get('/admin/Index/getSelectOption', { params: {'act':'goods_brand','cate_id':arr.pop()}}).then(res => {
// this.loading = false;
this.brandList = res.data.rows
this.searchCateOptions = Object.assign([], this.searchCateOptions, []);
this.searchCateSelectedOption= Object.assign([],this.searchCateSelectedOption, []);
this.searchCateSelectedOption = session_arr;
this.cateSelectedOption = session_arr;
this.brandSelectedOption = ''
})
},
getStoreList(){
this.loading = true;
axios.get('/admin/Index/getSelectOption', { params: {'act':'store'}}).then(res => {
this.storeOptions = res.data.rows
});
},
getSpsList() {
this.loading = true;
axios.get('/admin/Index/getSelectOption', { params: {'act':'sps'}}).then(res => {
this.spsOptions = res.data.rows
});
},
//服务类目切换
treeChange(nowNode, allNode){
/**
* allNode:{
* checkedKeys:Array[id,id,...,id],
* checkedNodes:Array[obj,obj,...,obj],
* halfCheckedKeys:Array[id,id,...,id],
* halfCheckedNodes:Array[obj,obj,...,obj]
* }
*
*/
this.$set(this.productDetail,'defaultCheckedKeys',allNode.checkedKeys);
//console.log(this.productDetail.defaultCheckedKeys)
},
//服务类目数据格式化
formatTreeData(arr){
let newArr = [];
if(arr && arr.length > 0) {
arr.forEach(item => {
if(Array.isArray(item)){
newArr.push(...item);
}else{
newArr.push(item);
}
});
}
return newArr;
},
handlePictureCardPreview(file) {
this.dialogImageUrl = file.url;
this.dialogVisible = true;
},
handlePictureCardPreview1(file) {
this.dialogImageUrl1 = file.url;
this.dialogVisible1 = true;
},
handlePictureCardPreview2(file) {
this.dialogImageUrl1 = file.url;
this.dialogVisible1 = true;
},
imgExceedNum(){
this.$message({
type: 'error',
message: '最多只能上传10张图片'
});
},
imgExceedNum1(){
this.$message({
type: 'error',
message: '最多只能上传20张图片'
});
},
imgExceedNum2(){
this.$message({
type: 'error',
message: '最多只能上传1张图片'
});
},
// 从fileList 中移除 file
removeFileFromFileList(file,fileList){
// 移除图片
const index = fileList.findIndex((currentValue)=>{
return currentValue.uid == file.uid
})
fileList.splice(index,1)
},
removeFileFromFileList1(file,fileList){
// 移除图片
const index = fileList.findIndex((currentValue)=>{
return currentValue.uid == file.uid
})
fileList.splice(index,1)
},
removeFileFromFileList2(file,fileList){
// 移除图片
const index = fileList.findIndex((currentValue)=>{
return currentValue.uid == file.uid
})
fileList.splice(index,1)
},
// 修改fileList URL 值
updateFileListUrl(file,fileList,response){
fileList.forEach(item => {
if(item.uid == file.uid){
item.url = response.data.filePath
}
});
},
updateFileListUrl1(file,fileList,response){
fileList.forEach(item => {
if(item.uid == file.uid){
item.url = response.data.filePath
}
});
},
updateFileListUrl2(file,fileList,response){
fileList.forEach(item => {
if(item.uid == file.uid){
item.url = response.data.filePath
}
});
},
// 更新submit 图片数组
updateProductsImageArr(fileList){
console.log(fileList)
// 初始化变量
this.productDetail.products_image_arr = []
fileList.forEach(item => {
console.log(item)
this.productDetail.products_image_arr.push(item)
});
console.log(this.productDetail.products_image_arr)
},
// 更新submit 详情图片数组
updateProductsImageArr1(fileList){
console.log(fileList)
// 初始化变量
this.productDetail.products_descs_arr = []
fileList.forEach(item => {
console.log(item)
this.productDetail.products_descs_arr.push(item)
});
console.log(this.productDetail.products_descs_arr)
},
// 更新submit 详情图片数组
updateProductsImageArr2(fileList){
console.log(fileList)
// 初始化变量
this.productDetail.spec_item_image = []
fileList.forEach(item => {
console.log(item)
this.productDetail.spec_item_image.push(item)
});
console.log(this.productDetail.spec_item_image)
},
//检查是否是商品库图片
checkIsProductsBaseUrl(file){
if(file.is_products_base_url===true){
return true;
}
return false;
},
// 远程删除 服务器图片接口
async checkRemoteDeleteImage(url){
let data = {
url:url
}
const res = await axios.post('/admin/Product/deleteImageFromDisk',data)
if(res.code!=200){
return false
}
return true
},
successImg(response,file,fileList){
// this.productDetail.products_image_arr = fileList
console.log(fileList)
// 上传失败
if(response.code!=200){
// 移除图片
this.removeFileFromFileList(file,fileList)
// 错误提示信息
return this.$message.error(response.message)
}
// 上传成功
// 修改fileList url (删除使用)
this.updateFileListUrl(file,fileList,response)
// 更新图片数组
console.log(fileList)
this.updateProductsImageArr(fileList)
// return
this.$message.success('上传成功')
console.log(this.productDetail.products_image_arr)
},
successImg1(response,file,fileList){
console.log(fileList)
// 上传失败
if(response.code!=200){
// 移除图片
this.removeFileFromFileList1(file,fileList)
// 错误提示信息
return this.$message.error(response.message)
}
// 上传成功
// 修改fileList url (删除使用)
this.updateFileListUrl1(file,fileList,response)
// 更新图片数组
console.log(fileList)
this.updateProductsImageArr1(fileList)
// return
this.$message.success('上传成功')
console.log(this.productDetail.products_descs_arr)
},
//规格图片上传成功
successImg2(response,file,fileList,row){
console.log(fileList)
console.log(row)
// this.tempObj.spec_item_image.push({ name: file.name, url: response.data, status: file.status, uid: file.uid })
// 上传失败
if(response.code!=200){
// 移除图片
this.removeFileFromFileList2(file,fileList)
// 错误提示信息
return this.$message.error(response.message)
}
this.tableColumnList.tableBodyList[row.$index].spec_item_image=response.data.fullPath
// 上传成功
// 修改fileList url (删除使用)
// this.updateFileListUrl2(file,fileList,response)
// 更新图片数组
// console.log(fileList)
// this.updateProductsImageArr2(fileList)
// return
this.$message.success('上传成功')
this.timer = new Date().getTime()
// console.log(this.productDetail.products_descs_arr)
},
// 文件删除回调
handleRemove(file, fileList) {
// 不是商品库图片 请求接口删除
if(false === this.checkIsProductsBaseUrl(file)){
// 请求删除图片
const url = file.url
const res = this.checkRemoteDeleteImage(url)
// 失败
if(false===res){
this.fileList.push(file)
return this.$message.error('删除失败')
}
}
// 是商品库图片只更新前端数据
// 成功
this.updateProductsImageArr(fileList)
this.$message.success('删除成功')
},
handleRemove1(file, fileList) {
// console.log(this.checkIsProductsBaseUrl(file))
// return
// 不是商品库图片 请求接口删除
if(false === this.checkIsProductsBaseUrl(file)){
// 请求删除图片
const url = file.url
const res = this.checkRemoteDeleteImage(url)
// 失败
if(false===res){
this.fileList.push(file)
return this.$message.error('删除失败')
}
}
// 是商品库图片只更新前端数据
// 成功
this.updateProductsImageArr1(fileList)
this.$message.success('删除成功')
},
handleRemove2(file, fileList) {
// console.log(this.checkIsProductsBaseUrl(file))
// return
// 不是商品库图片 请求接口删除
if(false === this.checkIsProductsBaseUrl(file)){
// 请求删除图片
const url = file.url
const res = this.checkRemoteDeleteImage(url)
// 失败
if(false===res){
this.fileList.push(file)
return this.$message.error('删除失败')
}
}
// 是商品库图片只更新前端数据
// 成功
this.updateProductsImageArr2(fileList)
this.$message.success('删除成功')
},
imageChange(file,fileList) {
//console.log(file)
//console.log(fileList)
},
handleAvatarSuccess(res, file) {
this.imageUrl = URL.createObjectURL(file.raw);
},
beforeAvatarUpload(file) {
const isJPG = file.type === 'image/jpeg';
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isJPG) {
this.$message.error('上传头像图片只能是 JPG 格式!');
}
if (!isLt2M) {
this.$message.error('上传头像图片大小不能超过 2MB!');
}
return isJPG && isLt2M;
},
preview(file) {
//console.log(file)
},
},
});
</script>
{/block}
php部分代码(主要是处理规格部分的)
<?php
namespace app\admin\controller;
use Symfony\Component\HttpFoundation\Session\Session;
use think\Request;
use think\Cache;
use think\Db;
use File\ExtraUpload;
use think\Exception;
use app\admin\Model\Product as ProductModel;
/**
* @desc 商品规格操作类
* Class Store
* @package app\admin\controller
*/
class Goodsspec extends Base
{
public function getSpecInput(){
$spec_arr=post('data/a');
$checkarr=post('checkarr/a');//选中的
$products_id=post('products_id');
$keys_tmp=[];
if($products_id){
$goods=db('seller_products_tmp')->field('products_sale_price,products_quantity,products_image,key')->where('products_id',$products_id)->whereOr('pid',$products_id)->select();
$keys=array_column($goods,'key');
$keys_tmp=implode('_',$keys);
$keys_tmp=array_unique(explode('_',$keys_tmp));
$spec_item=db('spec_item')->whereIn('id',$keys_tmp)->field('id,spec_id')->select();
$spec_arr_tmp=[];
foreach($spec_item as $k=>$v){
$spec_arr_tmp[$v['spec_id']][]=$v['id'];
}
$spec_arr=$spec_arr_tmp;
}
if(empty($spec_arr)){
$tableColumnList['tableBodyList']=[];
$tableColumnList['tableHeaderList']=[];
response($tableColumnList);
}
foreach($spec_arr as $k=>$v){
$spec_arr[$k]=array_unique($v);
}
// 排序
foreach ($spec_arr as $k => $v)
{
$spec_arr_sort[$k] = count($v);
}
asort($spec_arr_sort);
foreach ($spec_arr_sort as $key =>$val)
{
$spec_arr2[$key] = $spec_arr[$key];
}
$clo_name = array_keys($spec_arr2);
$spec_arr2 = combineDika($spec_arr2); // 获取 规格的 笛卡尔积
$spec = db('spec')->column('name','id'); // 规格表
$specItem =db('spec_item')->column('id,item,spec_id','id');//规格项
$tableHeaderList=[];
$tableBodyList=[];
foreach ($clo_name as $k => $v) {
$tableHeaderList[$k]['name']=$spec[$v];
}
foreach ($spec_arr2 as $k => $v) {
$str=implode('_',$v);
$item_key_name = array();
foreach ($v as $k2 => $v2) {
$key_data=$this->get_array_seach($products_id,$str);
$tableBodyList[$k][$spec[$specItem[$v2]['spec_id']]]= $specItem[$v2]['item'];
$tableBodyList[$k]['price']=$key_data?$key_data['products_sale_price']:0;
$tableBodyList[$k]['stock']= $key_data?$key_data['products_quantity']:0;
$tableBodyList[$k]['products_id']=$key_data?$key_data['products_id']:'';
$tableBodyList[$k]['keys']=$str;
$tableBodyList[$k]['spec_item_image']= $key_data?config('image_path').$key_data['products_image']:'';
}
}
// halt($tableBodyList);
// $tableBodyList['column']=$spec_arr2;
$columnLists['tableBodyList']=$tableBodyList;
$columnLists['tableHeaderList']=$tableHeaderList;
$tableColumnList['lists']=$columnLists;
if($keys_tmp){
$keys_tmp=array_merge($keys_tmp);
foreach($keys_tmp as $k=>$v){
$keys_tmp[$k]=intval($v);
}
}
$tableColumnList['valuekeys']=$keys_tmp;
response($tableColumnList);
}
public function get_array_seach($products_id,$keys){
$goods=db('seller_products_tmp')->field('products_sale_price,products_quantity,products_image,key,products_id')->where('products_id',$products_id)->whereOr('pid',$products_id)->select();
$data=[];
foreach($goods as $k=>$v){
if($v['key']==$keys){
$data=$v;
continue;
}
}
return $data;
}
/**
* 移除某一列数据 function
*
* @Author YJ
* @DateTime 2021-03-08
* @return void
*/
public function getDatahandle(){
$data=post('data/a');
$spec=post('spec/a');
$key=post('key');//移除的key
$arr=$data['tableBodyList'][$key];
foreach($data['tableBodyList'] as $k=>$v){
if($key==$k){
unset($data['tableBodyList'][$k]);
}
}
sort($data['tableBodyList']);
$news_key=[];
$tmp_keys='';
foreach($data['tableBodyList'] as $k=>$v){
$tmp_keys.=$v['keys']."_";
}
if($tmp_keys){
$aaa=array_unique(array_filter(explode('_',$tmp_keys)));
foreach ($aaa as $value) {
array_push($news_key,intval($value));
}
}
$cc=array_intersect($news_key,$spec);
$lists['lists']=$data;
$lists['keys']=$cc;
response($lists);
}
}
获取当前分类下的规格
/**
* 分类下的规格 function
*
* @Author YJ
* @DateTime 2021-01-21
* @return void
*/
public function getSpecItem(){
$cate_id=get('cate_id','number');
$manServer = db('spec')->where('cate_id',$cate_id)->order('id asc')->select();
foreach ($manServer as $v) {
$children=$this->_getSpecItem($v['id']);
if(!empty($children)){
$data[] = [
'id' => $v['id'],
'name' => $v['name'],
'children' =>$children ,
'selected' => false,
'indeterminate' => false,
'manCheckAll' => false
];
}
}
$keys=[];
// if($data){
// foreach ($data as $k => $v) {
// if($v['children']){
// foreach ($v['children'] as $kk => $vv) {
// array_push($keys,$vv['id']);break;
// }
// }
// }
// }
$res['lists']=$data;
$res['keys']=$keys;
response($res);
}
/**
* 规格下的属性 function
*
* @Author YJ
* @DateTime 2021-01-21
* @param [type] $spec_id
* @return void
*/
public function _getSpecItem($spec_id){
$manServer = db('spec_item')->where('spec_id',$spec_id)->select();
foreach ($manServer as $v) {
$data[] = [
'name' => $v['item'],
'id' => $v['id'],
'selected' => false,
'indeterminate' => false
];
}
return $data;
}
有待完善,不喜勿喷。