diff --git a/yudao-ui-admin/src/views/mall/product/spu/index.vue b/yudao-ui-admin/src/views/mall/product/spu/index.vue index 5f5ca6d49..7b66f1f05 100644 --- a/yudao-ui-admin/src/views/mall/product/spu/index.vue +++ b/yudao-ui-admin/src/views/mall/product/spu/index.vue @@ -1,36 +1,81 @@ <template> <div class="app-container"> - <!-- 搜索工作栏 --> - <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px"> + <el-form + :model="queryParams" + ref="queryForm" + size="small" + :inline="true" + v-show="showSearch" + label-width="68px" + > <el-form-item label="商品名称" prop="name"> - <el-input v-model="queryParams.name" placeholder="请输入商品名称" clearable @keyup.enter.native="handleQuery"/> + <el-input + v-model="queryParams.name" + placeholder="请输入商品名称" + clearable + @keyup.enter.native="handleQuery" + /> </el-form-item> <el-form-item label="卖点" prop="sellPoint"> - <el-input v-model="queryParams.sellPoint" placeholder="请输入卖点" clearable @keyup.enter.native="handleQuery"/> + <el-input + v-model="queryParams.sellPoint" + placeholder="请输入卖点" + clearable + @keyup.enter.native="handleQuery" + /> </el-form-item> <el-form-item label="分类id" prop="categoryId"> - <el-input v-model="queryParams.categoryId" placeholder="请输入分类id" clearable @keyup.enter.native="handleQuery"/> + <el-input + v-model="queryParams.categoryId" + placeholder="请输入分类id" + clearable + @keyup.enter.native="handleQuery" + /> </el-form-item> <el-form-item label="价格(分)" prop="price"> - <el-input v-model="queryParams.price" placeholder="请输入价格 单位使用:分" clearable @keyup.enter.native="handleQuery"/> + <el-input + v-model="queryParams.price" + placeholder="请输入价格 单位使用:分" + clearable + @keyup.enter.native="handleQuery" + /> </el-form-item> <el-form-item label="库存数量" prop="quantity"> - <el-input v-model="queryParams.quantity" placeholder="请输入库存数量" clearable @keyup.enter.native="handleQuery"/> + <el-input + v-model="queryParams.quantity" + placeholder="请输入库存数量" + clearable + @keyup.enter.native="handleQuery" + /> </el-form-item> <el-form-item label="状态" prop="status"> - <el-select v-model="queryParams.status" placeholder="请选择上下架状态" clearable size="small"> - <el-option label="请选择字典生成" value=""/> - <el-option label="上架" value="0"/> - <el-option label="下架" value="1"/> + <el-select + v-model="queryParams.status" + placeholder="请选择上下架状态" + clearable + size="small" + > + <el-option label="请选择字典生成" value="" /> + <el-option label="上架" value="0" /> + <el-option label="下架" value="1" /> </el-select> </el-form-item> <el-form-item label="创建时间"> - <el-date-picker v-model="dateRangeCreateTime" style="width: 240px" value-format="yyyy-MM-dd" - type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"/> + <el-date-picker + v-model="dateRangeCreateTime" + style="width: 240px" + value-format="yyyy-MM-dd" + type="daterange" + range-separator="-" + start-placeholder="开始日期" + end-placeholder="结束日期" + /> </el-form-item> <el-form-item> - <el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button> + <el-button type="primary" icon="el-icon-search" @click="handleQuery" + >搜索</el-button + > <el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button> </el-form-item> </el-form> @@ -38,95 +83,150 @@ <!-- 操作工具栏 --> <el-row :gutter="10" class="mb8"> <el-col :span="1.5"> - <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd" - v-hasPermi="['product:spu:create']">新增 + <el-button + type="primary" + plain + icon="el-icon-plus" + size="mini" + @click="handleAdd" + v-hasPermi="['product:spu:create']" + >新增 </el-button> </el-col> <el-col :span="1.5"> - <el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport" - :loading="exportLoading" - v-hasPermi="['product:spu:export']">导出 + <el-button + type="warning" + plain + icon="el-icon-download" + size="mini" + @click="handleExport" + :loading="exportLoading" + v-hasPermi="['product:spu:export']" + >导出 </el-button> </el-col> - <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar> + <right-toolbar + :showSearch.sync="showSearch" + @queryTable="getList" + ></right-toolbar> </el-row> <!-- 列表 --> <el-table v-loading="loading" :data="list"> - <el-table-column label="主键" align="center" prop="id"/> - <el-table-column label="商品名称" align="center" prop="name"/> + <el-table-column label="主键" align="center" prop="id" /> + <el-table-column label="商品名称" align="center" prop="name" /> <!-- <el-table-column label="卖点" align="center" prop="sellPoint"/>--> <!-- <el-table-column label="描述" align="center" prop="description"/>--> - <el-table-column label="分类id" align="center" prop="categoryId"/> + <el-table-column label="分类id" align="center" prop="categoryId" /> <el-table-column label="商品主图地址" align="center" prop="picUrls"> <template slot-scope="scope"> - <img v-if="scope.row.picUrls" :src="scope.row.picUrls[0]" alt="分类图片" class="img-height"/> + <img + v-if="scope.row.picUrls" + :src="scope.row.picUrls[0]" + alt="分类图片" + class="img-height" + /> </template> </el-table-column> - <el-table-column label="排序字段" align="center" prop="sort"/> - <el-table-column label="点赞初始人数" align="center" prop="likeCount"/> - <el-table-column label="价格 (分)" align="center" prop="price"/> - <el-table-column label="库存数量" align="center" prop="quantity"/> + <el-table-column label="排序字段" align="center" prop="sort" /> + <el-table-column label="点赞初始人数" align="center" prop="likeCount" /> + <el-table-column label="价格 (分)" align="center" prop="price" /> + <el-table-column label="库存数量" align="center" prop="quantity" /> <!-- <el-table-column label="状态" align="center" prop="status"/>--> - <el-table-column label="创建时间" align="center" prop="createTime" width="180"> + <el-table-column + label="创建时间" + align="center" + prop="createTime" + width="180" + > <template slot-scope="scope"> <span>{{ parseTime(scope.row.createTime) }}</span> </template> </el-table-column> - <el-table-column label="操作" align="center" class-name="small-padding fixed-width"> + <el-table-column + label="操作" + align="center" + class-name="small-padding fixed-width" + > <template slot-scope="scope"> - <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)" - v-hasPermi="['product:spu:update']">修改 + <el-button + size="mini" + type="text" + icon="el-icon-edit" + @click="handleUpdate(scope.row)" + v-hasPermi="['product:spu:update']" + >修改 </el-button> - <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)" - v-hasPermi="['product:spu:delete']">删除 + <el-button + size="mini" + type="text" + icon="el-icon-delete" + @click="handleDelete(scope.row)" + v-hasPermi="['product:spu:delete']" + >删除 </el-button> </template> </el-table-column> </el-table> <!-- 分页组件 --> - <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize" - @pagination="getList"/> + <pagination + v-show="total > 0" + :total="total" + :page.sync="queryParams.pageNo" + :limit.sync="queryParams.pageSize" + @pagination="getList" + /> + +<el-dialog :title="title" :visible.sync="open" width="900px" append-to-body > + <save @closeDialog="open = false"/> +</el-dialog> <!-- 对话框(添加 / 修改) --> - <el-dialog :title="title" :visible.sync="open" width="900px" append-to-body> + <!-- <el-dialog :title="title" :visible.sync="open" width="900px" append-to-body> <el-form ref="form" :model="form" :rules="rules" label-width="80px"> <el-form-item label="商品名称" prop="name"> - <el-input v-model="form.name" placeholder="请输入商品名称"/> + <el-input v-model="form.name" placeholder="请输入商品名称" /> </el-form-item> <el-form-item label="卖点" prop="sellPoint"> - <el-input v-model="form.sellPoint" placeholder="请输入卖点"/> + <el-input v-model="form.sellPoint" placeholder="请输入卖点" /> </el-form-item> <el-form-item label="描述"> - <editor v-model="form.description" :min-height="192"/> + <editor v-model="form.description" :min-height="192" /> </el-form-item> <el-form-item label="分类id" prop="categoryIds"> <el-cascader - v-model="form.categoryIds" - placeholder="请输入分类id" - style="width: 100%" - :options="categoryList" - :props="propName" - clearable></el-cascader> + v-model="form.categoryIds" + placeholder="请输入分类id" + style="width: 100%" + :options="categoryList" + :props="propName" + clearable + ></el-cascader> </el-form-item> <el-form-item label="商品主图地址" prop="picUrls"> - <ImageUpload v-model="form.picUrls" :limit="10"/> + <ImageUpload v-model="form.picUrls" :limit="10" /> </el-form-item> <el-form-item label="商品规格"> <el-button size="mini" @click="shopTagInput()">添加规格</el-button> <div v-for="(tag, tagIndex) in skuTags" :key="tagIndex"> <span>{{ tag.name }}</span> - <el-button style="margin-left: 10px" class="button-new-tag" type="text" icon="el-icon-delete" - @click="removeTag(tagIndex)">删除 + <el-button + style="margin-left: 10px" + class="button-new-tag" + type="text" + icon="el-icon-delete" + @click="removeTag(tagIndex)" + >删除 </el-button> - <br/> + <br /> <el-tag - v-for="(tagItem, tagItemIndex) in tag.selectValues" - :key="tagItem" - style="margin-right: 10px" - :disable-transitions="false"> + v-for="(tagItem, tagItemIndex) in tag.selectValues" + :key="tagItemIndex" + style="margin-right: 10px" + :disable-transitions="false" + > {{ tagItem }} - </el-tag> + </el-tag> --> <!-- <el-input--> <!-- class="input-new-tag"--> <!-- v-if="tagItemInputs[tagIndex] && tagItemInputs[tagIndex].visible"--> @@ -136,134 +236,178 @@ <!-- @keyup.enter.native="handleInputConfirm(tagIndex)"--> <!-- @blur="handleInputConfirm(tagIndex)">--> <!-- </el-input>--> - </div> + <!-- </div> </el-form-item> <el-form-item label="规格名" v-show="isShowTagInput"> <el-col :span="8"> - <el-select v-model="addTagInput.name" filterable allow-create default-first-option placeholder="请选择" - @change="handleTagClick"> + <el-select + v-model="addTagInput.name" + filterable + allow-create + default-first-option + placeholder="请选择" + @change="handleTagClick" + > <el-option - v-for="item in unUseTags" - :key="item.id" - :label="item.name" - :value="item.name"> + v-for="item in unUseTags" + :key="item.id" + :label="item.name" + :value="item.name" + > </el-option> </el-select> </el-col> </el-form-item> <el-form-item label="规格值" v-show="isShowTagInput"> <el-col :span="8"> - <el-select v-model="addTagInput.selectValues" multiple filterable allow-create default-first-option - placeholder="请选择"> + <el-select + v-model="addTagInput.selectValues" + multiple + filterable + allow-create + default-first-option + placeholder="请选择" + > <el-option - v-for="item in dbTagValues" - :key="item.id" - :label="item.name" - :value="item.name"> + v-for="item in dbTagValues" + :key="item.id" + :label="item.name" + :value="item.name" + > </el-option> </el-select> </el-col> </el-form-item> <el-form-item> - <el-button size="mini" type="primary" @click="addTag()" v-show="isShowTagInput">确定</el-button> - <el-button size="mini" @click="hideTagInput()" v-show="isShowTagInput">取消</el-button> + <el-button + size="mini" + type="primary" + @click="addTag()" + v-show="isShowTagInput" + >确定</el-button + > + <el-button size="mini" @click="hideTagInput()" v-show="isShowTagInput" + >取消</el-button + > </el-form-item> - <el-form-item v-if="form.skus.length>0"> + <el-form-item v-if="form.skus.length > 0"> <el-table - :data="form.skus" - border - style="width: 100%; margin-top: 20px" - :span-method="tableSpanMethod"> - <el-table-column v-for="(leftTitle, index) in skuTags" :key="index" :label="leftTitle.name"> + :data="form.skus" + border + style="width: 100%; margin-top: 20px" + :span-method="tableSpanMethod" + > + <el-table-column + v-for="(leftTitle, index) in skuTags" + :key="index" + :label="leftTitle.name" + > <template slot-scope="scope"> {{ scope.row.propertyChildNames[index] }} </template> </el-table-column> - <el-table-column v-if="skuTags.length" - prop="picUrl" - label="sku图片" - width="180"> + <el-table-column + v-if="skuTags.length" + prop="picUrl" + label="sku图片" + width="180" + > <template slot-scope="scope"> <ImageUpload v-model="scope.row.picUrl" :limit="1"> </ImageUpload> </template> </el-table-column> <el-table-column - prop="prodName" - label="条形码" - width="250" v-if="skuTags.length"> + prop="prodName" + label="条形码" + width="250" + v-if="skuTags.length" + > <template slot-scope="scope"> - <el-input v-model="scope.row.barCode" type="textarea" :disabled="scope.row.status==1"></el-input> + <el-input + v-model="scope.row.barCode" + type="textarea" + :disabled="scope.row.status == 1" + ></el-input> </template> </el-table-column> - <el-table-column - prop="price" - label="销售价"> + <el-table-column prop="price" label="销售价"> <template slot-scope="scope"> <el-input-number - size="small" - v-model="scope.row.price" - controls-position="right" - :precision="2" - :max="1000000000" - :min="0.01" - :disabled="scope.row.status==1"> + size="small" + v-model="scope.row.price" + controls-position="right" + :precision="2" + :max="1000000000" + :min="0.01" + :disabled="scope.row.status == 1" + > </el-input-number> </template> </el-table-column> - <el-table-column - prop="oriPrice" - label="成本价"> + <el-table-column prop="oriPrice" label="成本价"> <template slot-scope="scope"> <el-input-number - size="small" - v-model="scope.row.costPrice" - controls-position="right" - :precision="2" - :max="1000000000" - :min="0.01" - :disabled="scope.row.status==1"> + size="small" + v-model="scope.row.costPrice" + controls-position="right" + :precision="2" + :max="1000000000" + :min="0.01" + :disabled="scope.row.status == 1" + > </el-input-number> </template> </el-table-column> - <el-table-column - prop="oriPrice" - label="原价"> + <el-table-column prop="oriPrice" label="原价"> <template slot-scope="scope"> <el-input-number - size="small" - v-model="scope.row.originalPrice" - controls-position="right" - :precision="2" - :max="1000000000" - :min="0.01" - :disabled="scope.row.status==1"> + size="small" + v-model="scope.row.originalPrice" + controls-position="right" + :precision="2" + :max="1000000000" + :min="0.01" + :disabled="scope.row.status == 1" + > </el-input-number> </template> </el-table-column> - <el-table-column - label="操作"> + <el-table-column label="操作"> <template slot-scope="scope"> - <el-button type="text" size="small" @click="changeSkuStatus(`${scope.$index}`)" - v-if="scope.row.status===0"> + <el-button + type="text" + size="small" + @click="changeSkuStatus(`${scope.$index}`)" + v-if="scope.row.status === 0" + > 正常 </el-button> - <el-button type="text" size="small" @click="changeSkuStatus(`${scope.$index}`)" v-else>已禁用</el-button> + <el-button + type="text" + size="small" + @click="changeSkuStatus(`${scope.$index}`)" + v-else + >已禁用</el-button + > </template> </el-table-column> </el-table> </el-form-item> <el-form-item label="排序字段" prop="sort"> - <el-input v-model="form.sort" placeholder="请输入排序字段"/> + <el-input v-model="form.sort" placeholder="请输入排序字段" /> </el-form-item> <el-form-item label="点赞初始人数" prop="likeCount"> - <el-input v-model="form.likeCount" placeholder="请输入点赞初始人数"/> + <el-input v-model="form.likeCount" placeholder="请输入点赞初始人数" /> </el-form-item> <el-form-item label="价格 单位使用:分" prop="price"> - <el-input v-model="form.price" placeholder="请输入价格 单位使用:分"/> + <el-input + v-model="form.price" + placeholder="请输入价格 单位使用:分" + /> </el-form-item> <el-form-item label="库存数量" prop="quantity"> - <el-input v-model="form.quantity" placeholder="请输入库存数量"/> + <el-input v-model="form.quantity" placeholder="请输入库存数量" /> </el-form-item> <el-form-item label="上下架状态" prop="status"> <el-radio-group v-model="form.status"> @@ -276,19 +420,26 @@ <el-button type="primary" @click="submitForm">确 定</el-button> <el-button @click="cancel">取 消</el-button> </div> - </el-dialog> + </el-dialog> --> </div> </template> <script> -import {createSpu, updateSpu, deleteSpu, getSpu, getSpuPage, exportSpuExcel} from "@/api/mall/product/spu"; +import { + createSpu, + updateSpu, + deleteSpu, + getSpu, + getSpuPage, + exportSpuExcel, +} from "@/api/mall/product/spu"; import { createProductCategory, deleteProductCategory, exportCategoryExcel, getProductCategory, getProductCategoryList, - updateProductCategory + updateProductCategory, } from "@/api/mall/product/category"; import { createProperty, @@ -296,16 +447,19 @@ import { deleteProperty, getProperty, getPropertyPage, - exportPropertyExcel + exportPropertyExcel, } from "@/api/mall/product/property"; -import Editor from '@/components/Editor'; -import ImageUpload from '@/components/ImageUpload'; +import Editor from "@/components/Editor"; +import ImageUpload from "@/components/ImageUpload"; +import save from "./save"; export default { name: "Spu", components: { - Editor, ImageUpload + Editor, + ImageUpload, + save, }, data() { return { @@ -316,17 +470,17 @@ export default { propertyPageList: [], isShowTagInput: false, addTagInput: { - name: '', - propertyId: '', + name: "", + propertyId: "", selectValues: [], selectValueIds: [], - selectObect:[], + selectObect: [], }, skuTags: [], propName: { checkStrictly: true, - label: 'name', - value: 'id' + label: "name", + value: "id", }, categoryList: [], // 遮罩层 @@ -378,91 +532,101 @@ export default { }, // 表单校验 rules: { - sellPoint: [{required: true, message: "卖点不能为空", trigger: "blur"}], - description: [{required: true, message: "描述不能为空", trigger: "blur"}], - categoryIds: [{required: true, message: "分类id不能为空", trigger: "blur"}], - picUrls: [{required: true, message: "商品主图地址", trigger: "blur"}], - sort: [{required: true, message: "排序字段不能为空", trigger: "blur"}], + sellPoint: [ + { required: true, message: "卖点不能为空", trigger: "blur" }, + ], + description: [ + { required: true, message: "描述不能为空", trigger: "blur" }, + ], + categoryIds: [ + { required: true, message: "分类id不能为空", trigger: "blur" }, + ], + picUrls: [{ required: true, message: "商品主图地址", trigger: "blur" }], + sort: [ + { required: true, message: "排序字段不能为空", trigger: "blur" }, + ], }, tagIndex: 0, }; }, created() { - this.getList(); this.getPropertyPageList(); this.getListCategory(); }, methods: { getTableSpecData() { - return this.value - }, - tableSpanMethod({row, column, rowIndex, columnIndex}) { - + return this.value; }, + tableSpanMethod({ row, column, rowIndex, columnIndex }) {}, changeSkuStatus(tagIndex) { if (this.form.skus[tagIndex].status == 0) { this.form.skus[tagIndex].status = 1; } else { this.form.skus[tagIndex].status = 0; } - }, skuAddProdName() { if (this.initing) { - return + return; } - let skuList = [] + let skuList = []; for (let i = 0; i < this.value.length; i++) { - const sku = Object.assign({}, this.value[i]) + const sku = Object.assign({}, this.value[i]); if (!sku.properties) { - return + return; } - sku.skuName = '' - let properties = sku.properties.split(';') + sku.skuName = ""; + let properties = sku.properties.split(";"); for (const propertiesKey in properties) { - sku.skuName += properties[propertiesKey].split(':')[1] + ' ' + sku.skuName += properties[propertiesKey].split(":")[1] + " "; } - sku.prodName = this.prodName + ' ' + sku.skuName - skuList.push(sku) + sku.prodName = this.prodName + " " + sku.skuName; + skuList.push(sku); } - this.$emit('input', skuList) - }, - handleTagClose(tagIndex, tagItemIndex) { - + this.$emit("input", skuList); }, + handleTagClose(tagIndex, tagItemIndex) {}, //确定添加sku规格 addTag() { - let skus = this.unUseTags.map(function (item, index) { - return item.name + return item.name; }); let index = skus.indexOf(this.addTagInput.name); this.addTagInput.propertyId = this.unUseTags[index].id; for (let i = 0; i < this.addTagInput.selectValues.length; i++) { - for (let j = 0; j < this.unUseTags[index].propertyValueList.length; j++) { - if (this.addTagInput.selectValues[i] === this.unUseTags[index].propertyValueList[j].name) { - this.addTagInput.selectValueIds.push(this.unUseTags[index].propertyValueList[j].id) + for ( + let j = 0; + j < this.unUseTags[index].propertyValueList.length; + j++ + ) { + if ( + this.addTagInput.selectValues[i] === + this.unUseTags[index].propertyValueList[j].name + ) { + this.addTagInput.selectValueIds.push( + this.unUseTags[index].propertyValueList[j].id + ); this.addTagInput.selectObect.push({ - id:this.unUseTags[index].propertyValueList[j].id, - name:this.unUseTags[index].propertyValueList[j].name, - }) + id: this.unUseTags[index].propertyValueList[j].id, + name: this.unUseTags[index].propertyValueList[j].name, + }); } } } - let addTagInput = JSON.parse(JSON.stringify(this.addTagInput)) + let addTagInput = JSON.parse(JSON.stringify(this.addTagInput)); this.skuTags.push(addTagInput); // if (this.skuTags.length > 1) { this.skuTags = this.skuTags.sort((a, b) => a.propertyId - b.propertyId); - this.skuTags.forEach(function (item,index) { - item.selectObect = item.selectObect.sort((a, b) => a.id - b.id) - }) + this.skuTags.forEach(function (item, index) { + item.selectObect = item.selectObect.sort((a, b) => a.id - b.id); + }); - for (let i = 0; i <this.skuTags.length ; i++) { - let selectValueIds=[]; - let selectValues=[]; + for (let i = 0; i < this.skuTags.length; i++) { + let selectValueIds = []; + let selectValues = []; for (let j = 0; j < this.skuTags[i].selectObect.length; j++) { selectValueIds.push(this.skuTags[i].selectObect[j].id); selectValues.push(this.skuTags[i].selectObect[j].name); @@ -489,17 +653,23 @@ export default { propertyNames.push(skuTags[i].name); } - let skuAll = sku1s.reduce((x, y) => { - let arr = []; - x.forEach(m => y.forEach(y => arr.push(m.concat([y])))) - return arr; - }, [[]]) + let skuAll = sku1s.reduce( + (x, y) => { + let arr = []; + x.forEach((m) => y.forEach((y) => arr.push(m.concat([y])))); + return arr; + }, + [[]] + ); - let skuIdAll = skuIds.reduce((x, y) => { - let arr = []; - x.forEach(m => y.forEach(y => arr.push(m.concat([y])))) - return arr; - }, [[]]) + let skuIdAll = skuIds.reduce( + (x, y) => { + let arr = []; + x.forEach((m) => y.forEach((y) => arr.push(m.concat([y])))); + return arr; + }, + [[]] + ); for (let i = 0; i < skuAll.length; i++) { let han = { @@ -508,33 +678,32 @@ export default { propertyChildNames: skuAll[i], propertyChildIds: skuIdAll[i], properties: [], - picUrl: '', - costPrice: '', - originalPrice: '', - spuId: '', - prodName: '', - price: '', - barCode: '', - status: '0', - } + picUrl: "", + costPrice: "", + originalPrice: "", + spuId: "", + prodName: "", + price: "", + barCode: "", + status: "0", + }; this.form.skus.push(han); } - this.form.skus.forEach(x => { + this.form.skus.forEach((x) => { x.properties = []; for (let i = 0; i < x.propertyIds.length; i++) { x.properties.push({ propertyId: x.propertyIds[i], - valueId: x.propertyChildIds[i] - }) + valueId: x.propertyChildIds[i], + }); } - }) - + }); }, hideTagInput() { this.isShowTagInput = false; this.addTagInput = { - name: '', - propertyId: '', + name: "", + propertyId: "", selectValues: [], selectValueIds: [], selectObect: [], @@ -542,12 +711,12 @@ export default { }, shopTagInput() { if (this.unUseTags.length <= 0) { - return this.$message.error("规格已经添加完毕") + return this.$message.error("规格已经添加完毕"); } this.isShowTagInput = true; this.addTagInput = { - name: '', - propertyId: '', + name: "", + propertyId: "", selectValues: [], selectValueIds: [], selectObect: [], @@ -556,8 +725,8 @@ export default { //删除已选的规格 removeTag(row) { let skus = this.allhistoryTags.map(function (item, index) { - return item.name - }) + return item.name; + }); let index = skus.indexOf(this.skuTags[row].name); this.unUseTags.push(this.allhistoryTags[index]); this.skuTags.splice(row, 1); @@ -566,38 +735,37 @@ export default { handleTagClick(row) { for (let i = 0; i < this.propertyPageList.length; i++) { if (row == this.propertyPageList[i].name) { - this.dbTagValues = this.propertyPageList[i].propertyValueList + this.dbTagValues = this.propertyPageList[i].propertyValueList; } } }, /** 查询规格 */ getPropertyPageList() { // 执行查询 - getPropertyPage().then(response => { + getPropertyPage().then((response) => { this.propertyPageList = response.data.list; this.unUseTags = this.propertyPageList.map(function (item, index) { - return item - }) + return item; + }); this.allhistoryTags = JSON.parse(JSON.stringify(this.unUseTags)); }); }, /** 查询分类 */ getListCategory() { // 执行查询 - getProductCategoryList().then(response => { + getProductCategoryList().then((response) => { this.categoryList = this.handleTree(response.data, "id", "parentId"); - }); }, /** 查询列表 */ getList() { this.loading = true; // 处理查询参数 - let params = {...this.queryParams}; - this.addBeginAndEndTime(params, this.dateRangeCreateTime, 'createTime'); + let params = { ...this.queryParams }; + this.addBeginAndEndTime(params, this.dateRangeCreateTime, "createTime"); // 执行查询 - getSpuPage(params).then(response => { + getSpuPage(params).then((response) => { this.list = response.data.list; this.total = response.data.total; this.loading = false; @@ -610,7 +778,6 @@ export default { }, /** 表单重置 */ reset() { - this.form = { id: undefined, name: undefined, @@ -652,7 +819,7 @@ export default { handleUpdate(row) { this.reset(); const id = row.id; - getSpu(id).then(response => { + getSpu(id).then((response) => { let dataSpu = response.data; this.form = { id: dataSpu.id, @@ -680,11 +847,15 @@ export default { }, getDataHandle() { let that = this; - let productPropertyViews = JSON.parse(JSON.stringify(this.form.productPropertyViews)); - productPropertyViews = productPropertyViews.sort((a, b) => a.propertyId - b.propertyId); - productPropertyViews.forEach(item => { + let productPropertyViews = JSON.parse( + JSON.stringify(this.form.productPropertyViews) + ); + productPropertyViews = productPropertyViews.sort( + (a, b) => a.propertyId - b.propertyId + ); + productPropertyViews.forEach((item) => { item.propertyValues = item.propertyValues.sort((a, b) => a.v1 - b.v1); - }) + }); let skuIds = []; for (let i = 0; i < productPropertyViews.length; i++) { let han = { @@ -692,17 +863,21 @@ export default { propertyId: productPropertyViews[i].propertyId, selectValues: [], selectValueIds: [], - } - for (let j = 0; j < productPropertyViews[i].propertyValues.length; j++) { + }; + for ( + let j = 0; + j < productPropertyViews[i].propertyValues.length; + j++ + ) { han.selectValues.push(productPropertyViews[i].propertyValues[j].v2); han.selectValueIds.push(productPropertyViews[i].propertyValues[j].v1); } - skuIds.push(han) + skuIds.push(han); } this.skuTags = skuIds; this.unUseTags = this.allhistoryTags.filter((v) => - skuIds.every((val) => val.name != v.name) - ) + skuIds.every((val) => val.name != v.name) + ); this.getHandleTable(); }, getHandleTable() { @@ -718,17 +893,23 @@ export default { propertyIds.push(skuTags[i].propertyId); propertyNames.push(skuTags[i].name); } - let skuAll = sku1s.reduce((x, y) => { - let arr = []; - x.forEach(m => y.forEach(y => arr.push(m.concat([y])))) - return arr; - }, [[]]) + let skuAll = sku1s.reduce( + (x, y) => { + let arr = []; + x.forEach((m) => y.forEach((y) => arr.push(m.concat([y])))); + return arr; + }, + [[]] + ); - let skuIdAll = skuIds.reduce((x, y) => { - let arr = []; - x.forEach(m => y.forEach(y => arr.push(m.concat([y])))) - return arr; - }, [[]]) + let skuIdAll = skuIds.reduce( + (x, y) => { + let arr = []; + x.forEach((m) => y.forEach((y) => arr.push(m.concat([y])))); + return arr; + }, + [[]] + ); for (let i = 0; i < skuAll.length; i++) { let han = { @@ -745,33 +926,32 @@ export default { price: this.form.skusList[i].price, barCode: this.form.skusList[i].barCode, status: this.form.skusList[i].status, - } + }; this.form.skus.push(han); } - this.form.skus.forEach(x => { + this.form.skus.forEach((x) => { x.properties = []; for (let i = 0; i < x.propertyIds.length; i++) { x.properties.push({ propertyId: x.propertyIds[i], - valueId: x.propertyChildIds[i] - }) + valueId: x.propertyChildIds[i], + }); } - }) - + }); }, /** 提交按钮 */ submitForm() { - - this.$refs["form"].validate(valid => { + this.$refs["form"].validate((valid) => { if (!valid) { return; } - this.form.picUrls = this.form.picUrls.split(','); - this.form.categoryId = this.form.categoryIds[(this.form.categoryIds.length - 1)]; + this.form.picUrls = this.form.picUrls.split(","); + this.form.categoryId = + this.form.categoryIds[this.form.categoryIds.length - 1]; this.form.status = Number(this.form.status); // 修改的提交 if (this.form.id != null) { - updateSpu(this.form).then(response => { + updateSpu(this.form).then((response) => { this.$modal.msgSuccess("修改成功"); this.open = false; this.getList(); @@ -779,7 +959,7 @@ export default { return; } // 添加的提交 - createSpu(this.form).then(response => { + createSpu(this.form).then((response) => { this.$modal.msgSuccess("新增成功"); this.open = false; this.getList(); @@ -789,32 +969,38 @@ export default { /** 删除按钮操作 */ handleDelete(row) { const id = row.id; - this.$modal.confirm('是否确认删除商品spu编号为"' + id + '"的数据项?').then(function () { - return deleteSpu(id); - }).then(() => { - this.getList(); - this.$modal.msgSuccess("删除成功"); - }).catch(() => { - }); + this.$modal + .confirm('是否确认删除商品spu编号为"' + id + '"的数据项?') + .then(function () { + return deleteSpu(id); + }) + .then(() => { + this.getList(); + this.$modal.msgSuccess("删除成功"); + }) + .catch(() => {}); }, /** 导出按钮操作 */ handleExport() { // 处理查询参数 - let params = {...this.queryParams}; + let params = { ...this.queryParams }; params.pageNo = undefined; params.pageSize = undefined; - this.addBeginAndEndTime(params, this.dateRangeCreateTime, 'createTime'); + this.addBeginAndEndTime(params, this.dateRangeCreateTime, "createTime"); // 执行导出 - this.$modal.confirm('是否确认导出所有商品spu数据项?').then(() => { - this.exportLoading = true; - return exportSpuExcel(params); - }).then(response => { - this.$download.excel(response, '商品spu.xls'); - this.exportLoading = false; - }).catch(() => { - }); - } - } + this.$modal + .confirm("是否确认导出所有商品spu数据项?") + .then(() => { + this.exportLoading = true; + return exportSpuExcel(params); + }) + .then((response) => { + this.$download.excel(response, "商品spu.xls"); + this.exportLoading = false; + }) + .catch(() => {}); + }, + }, }; </script> <style lang="scss"> diff --git a/yudao-ui-admin/src/views/mall/product/spu/save.vue b/yudao-ui-admin/src/views/mall/product/spu/save.vue new file mode 100644 index 000000000..93e42f79f --- /dev/null +++ b/yudao-ui-admin/src/views/mall/product/spu/save.vue @@ -0,0 +1,417 @@ +<template> + <div class="container"> + <el-dialog + title="请输入规格值,多个请换行" + :visible.sync="dialogForSpec" + append-to-body + width="400px" + @close="dialogForSpec = false; specValue = null" + > + <el-input + v-model="specValue" + type="textarea" + :autosize="{ minRows: 6, maxRows: 6}" + placeholder="请输入内容" + /> + + <div slot="footer" class="dialog-footer"> + <el-button @click="dialogForSpec = false; specValue = null">取 消</el-button> + <el-button type="primary" @click="addSpecValue">确 定</el-button> + </div> + </el-dialog> + + <el-tabs v-model="activeName" class="tabs"> + <!-- 基础设置 --> + <el-tab-pane label="基础设置" name="base"> + <el-form ref="baseForm" :model="baseForm" :rules="rules" label-width="100px" style="width: 95%"> + <el-form-item label="商品名称" prop="name"> + <el-input v-model="baseForm.name" placeholder="请输入商品名称"/> + </el-form-item> + <el-form-item label="卖点" prop="sellPoint"> + <el-input v-model="baseForm.sellPoint" placeholder="请输入卖点"/> + </el-form-item> + <el-form-item label="分类id" prop="categoryIds"> + <el-cascader + v-model="baseForm.categoryIds" + placeholder="请输入分类id" + style="width: 100%" + :options="categoryList" + :props="propName" + clearable + ></el-cascader> + </el-form-item> + <el-form-item label="商品主图" prop="picUrls"> + <ImageUpload v-model="baseForm.picUrl" :limit="1" /> + </el-form-item> + <el-form-item label="商品轮播图" prop="picUrl"> + <ImageUpload v-model="baseForm.picUrls" :limit="10" /> + </el-form-item> + <el-form-item label="排序字段" prop="sort"> + <el-input v-model="baseForm.sort" placeholder="请输入排序字段"/> + </el-form-item> + </el-form> + </el-tab-pane> + + <!-- 价格库存 --> + <el-tab-pane label="价格库存" name="rates" class="rates"> + <el-form :model="ratesForm" :rules="rules.ratesForm"> + <el-form-item label="商品规格"> + <el-radio-group v-model="ratesForm.spec" @change="changeRadio"> + <el-radio :label="0">单规格</el-radio> + <el-radio :label="1">多规格</el-radio> + </el-radio-group> + </el-form-item> + + <!-- 动态添加规格属性 --> + <div v-show="ratesForm.spec === 1"> + <div + v-for="(specs, index) in dynamicSpec" + :key="index" + class="dynamic-spec" + > + <!-- 删除按钮 --> + <el-button + type="danger" + icon="el-icon-delete" + circle + class="spec-delete" + @click="dynamicSpec.splice(index, 1)" + ></el-button> + + <div class="spec-header"> + 规格项: + <el-input + v-model="specs.spec_name" + placeholder="请填写规格项" + class="spec-name" + ></el-input> + </div> + <div class="spec-values"> + <template v-for="(specsValue, i) in specs.spec_values"> + <el-input + v-model="specs.spec_values[i]" + class="spec-value" + :key="specsValue" + ></el-input> + </template> + <el-button + type="primary" + icon="el-icon-plus" + circle + @click="dialogForSpec = true; currentSpec = index" + ></el-button> + </div> + </div> + <el-button type="primary" @click="dynamicSpec.push({spec_values: []}); ratesForm.rates = []" + >添加规格项目 + </el-button + > + </div> + + <!-- 规格明细 --> + <el-form-item label="规格明细"> + <el-table :data="ratesForm.rates" border style="width: 100%" ref="rates"> + + <template v-if="ratesForm.spec == 1" > + <el-table-column :key="index" v-for="(item, index) in dynamicSpec.filter(v=>v.spec_name != undefined)" :label="item.spec_name" > + <template slot-scope="scope"> + <el-input + v-if="scope.row.spec" + v-model="scope.row.spec[index]" + disabled + ></el-input> + </template> + </el-table-column> + </template> + + <el-table-column label="规格图片" width="120px"> + <template slot-scope="scope"> + <ImageUpload v-model="scope.row.picUrl" :limit="1" :isShowTip="false" style="width: 100px; height: 50px" /> + </template> + </el-table-column> + <el-table-column label="市场价(元)"> + <template slot-scope="scope"> + <el-input + v-model="scope.row.marketPrice" + type="number" + ></el-input> + </template> + </el-table-column> + <el-table-column label="销售价(元)" re> + <template slot-scope="scope"> + <el-input v-model="scope.row.price" type="number"></el-input> + </template> + </el-table-column> + <el-table-column label="成本价"> + <template slot-scope="scope"> + <el-input + v-model="scope.row.costPrice" + type="number" + ></el-input> + </template> + </el-table-column> + <el-table-column label="库存"> + <template slot-scope="scope"> + <el-input v-model="scope.row.stock" type="number"></el-input> + </template> + </el-table-column> + <el-table-column label="体积"> + <template slot-scope="scope"> + <el-input v-model="scope.row.volume" type="number"></el-input> + </template> + </el-table-column> + <el-table-column label="重量"> + <template slot-scope="scope"> + <el-input v-model="scope.row.weight" type="number"></el-input> + </template> + </el-table-column> + <el-table-column label="条码"> + <template slot-scope="scope"> + <el-input v-model="scope.row.barCode"></el-input> + </template> + </el-table-column> + </el-table> + </el-form-item> + </el-form> + </el-tab-pane> + + <!-- 商品详情 --> + <el-tab-pane label="商品描述" name="third"> + <editor v-model="baseForm.description" :min-height="400" /> + </el-tab-pane> + + <!-- 销售设置 --> + <el-tab-pane label="销售设置" name="fourth"> + <el-form ref="baseForm" :model="baseForm" :rules="rules" label-width="100px" style="width: 95%"> + <el-form-item label="库存数量" prop="quantity"> + <el-input v-model="baseForm.quantity" placeholder="请输入库存数量" /> + </el-form-item> + <el-form-item label="上下架状态" prop="status"> + <el-radio-group v-model="baseForm.status"> + <el-radio label="0">上架</el-radio> + <el-radio label="1">下架</el-radio> + </el-radio-group> + </el-form-item> + </el-form> + </el-tab-pane> + </el-tabs> + + <div class="buttons"> + <el-button type="info" round @click="cancel">取消</el-button> + <el-button type="success" round @click="submit">确认</el-button> + </div> + + </div> +</template> + +<script> +import { + getProductCategoryList +} from "@/api/mall/product/category"; + +import Editor from "@/components/Editor"; +import ImageUpload from "@/components/ImageUpload"; +export default { + components: { + Editor, + ImageUpload + }, + data() { + return { + activeName: "base", + propName: { + checkStrictly: true, + label: "name", + value: "id", + }, + // 基础设置 + baseForm: { + name: null, + sellPoint: null, + categoryIds: null, + sort: null, + description: null, + picUrl:null, + picUrls: [], + quantity: null + }, + categoryList: [], + + // 价格库存 + ratesForm: { + spec: 0, + // 规格明细 + rates: [{}] + }, + dynamicSpec: [ + // { + // spec_id: 86, + // spec_name: "颜色", + // spec_values: [], + // spec_value_ids: [225], + // }, + ], + dialogForSpec: false, + specValue: null, + currentSpec: null, + + // 表单校验 + rules: { + description: [ + {required: true, message: "描述不能为空", trigger: "blur"}, + ], + categoryIds: [ + {required: true, message: "分类id不能为空", trigger: "blur"}, + ], + picUrls: [{required: true, message: "商品主图地址", trigger: "blur"}], + sort: [ + {required: true, message: "排序字段不能为空", trigger: "blur"}, + ], + }, + }; + }, + created() { + this.getListCategory(); + }, + methods: { + changeRadio() { + + this.$refs.rates.doLayout() + if(this.ratesForm.spec == 0){ + this.ratesForm.rates = [{}] + }else{ + this.ratesForm.rates = [] + if(this.dynamicSpec.length > 0){ + this.buildRatesFormRates() + } + } + }, + // 构建规格明细笛卡尔积 + buildRatesFormRates(){ + let rates = []; + this.dynamicSpec.map(v=>v.spec_values) + .reduce((last, current) => { + const array = []; + last.forEach(par1 => { + current.forEach(par2 => { + let v + if(par1 instanceof Array){ + v = par1.concat(par2) + }else{ + v = [par1, par2]; + } + array.push(v) + }); + }); + return array; + }) + .forEach(v=>{ + rates.push({spec: v}) + }); + console.log(rates) + this.ratesForm.rates = rates + }, + addSpecValue() { + this.dialogForSpec = false; + let specValue = this.dynamicSpec[this.currentSpec].spec_values + .concat(this.specValue.split(/[(\r\n)\r\n]+/)) + .filter(v => v != ""); + console.log(specValue) + this.dynamicSpec[this.currentSpec].spec_values = [...new Set(specValue)]; + this.currentSpec = null; + this.buildRatesFormRates() + }, + /** 查询分类 */ + getListCategory() { + // 执行查询 + getProductCategoryList().then((response) => { + this.categoryList = this.handleTree(response.data, "id", "parentId"); + }); + }, + cancel(){ + this.$emit("closeDialog"); + }, + }, +}; +</script> + +<style lang="scss"> +.spec-dialog { + width: 400px; + height: 300px; +} + +.dynamic-spec { + background-color: #f2f2f2; + width: 85%; + margin: auto; + margin-bottom: 10px; + + .spec-header { + padding: 30px; + padding-bottom: 0; + + .spec-name { + display: inline; + + input { + width: 30%; + } + } + } + + .spec-values { + width: 84%; + padding: 25px; + margin: auto; + + .spec-value { + display: inline-block; + margin-right: 10px; + margin-bottom: 10px; + width: 13%; + + } + } + + .spec-delete { + float: right; + margin-top: 10px; + margin-right: 10px; + } +} + +.tabs{ + height: 500px; + border-bottom: 2px solid #f2f2f2; + .el-tab-pane{ + height: 445px; + overflow-y: auto; + } +} + +// 库存价格图片样式修改 +.rates{ +.component-upload-image{ + margin: auto; +} +.el-upload--picture-card{ + width: 100px; + height: 50px; + line-height: 60px; + margin: auto; +} +.el-upload-list__item{ + width: 100px !important; + height: 50px !important; +} +} +.buttons{ + margin-top: 20px; + height: 36px; + button{ + float: right; + margin-left: 15px; + } +} +</style>