|
|
@@ -4,11 +4,14 @@
|
|
|
<el-card class="box-card">
|
|
|
<h3>商品介绍</h3>
|
|
|
<el-form ref="goods" :rules="rules" :model="goods" label-width="150px">
|
|
|
- <el-form-item label="商品编号" prop="goodsSn">
|
|
|
- <el-input v-model="goods.goodsSn"/>
|
|
|
+ <el-form-item label="商品ID" prop="id">
|
|
|
+ <el-input v-model="goods.id" disabled />
|
|
|
</el-form-item>
|
|
|
<el-form-item label="商品名称" prop="name">
|
|
|
- <el-input v-model="goods.name"/>
|
|
|
+ <el-input v-model="goods.name" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="商品编号" prop="goodsSn">
|
|
|
+ <el-input v-model="goods.goodsSn" />
|
|
|
</el-form-item>
|
|
|
<el-form-item label="专柜价格" prop="counterPrice">
|
|
|
<el-input v-model="goods.counterPrice" placeholder="0.00">
|
|
|
@@ -46,9 +49,10 @@
|
|
|
:show-file-list="false"
|
|
|
:on-success="uploadPicUrl"
|
|
|
class="avatar-uploader"
|
|
|
- accept=".jpg,.jpeg,.png,.gif">
|
|
|
+ accept=".jpg,.jpeg,.png,.gif"
|
|
|
+ >
|
|
|
<img v-if="goods.picUrl" :src="goods.picUrl" class="avatar">
|
|
|
- <i v-else class="el-icon-plus avatar-uploader-icon"/>
|
|
|
+ <i v-else class="el-icon-plus avatar-uploader-icon" />
|
|
|
</el-upload>
|
|
|
</el-form-item>
|
|
|
|
|
|
@@ -63,50 +67,49 @@
|
|
|
:on-remove="handleRemove"
|
|
|
multiple
|
|
|
accept=".jpg,.jpeg,.png,.gif"
|
|
|
- list-type="picture-card">
|
|
|
- <i class="el-icon-plus"/>
|
|
|
+ list-type="picture-card"
|
|
|
+ >
|
|
|
+ <i class="el-icon-plus" />
|
|
|
</el-upload>
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item label="商品单位">
|
|
|
- <el-input v-model="goods.unit" placeholder="件 / 个 / 盒"/>
|
|
|
+ <el-input v-model="goods.unit" placeholder="件 / 个 / 盒" />
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item label="关键字">
|
|
|
<el-tag v-for="tag in keywords" :key="tag" closable type="primary" @close="handleClose(tag)">
|
|
|
{{ tag }}
|
|
|
</el-tag>
|
|
|
- <el-input v-if="newKeywordVisible" ref="newKeywordInput" v-model="newKeyword" class="input-new-keyword" @keyup.enter.native="handleInputConfirm" @blur="handleInputConfirm"/>
|
|
|
+ <el-input v-if="newKeywordVisible" ref="newKeywordInput" v-model="newKeyword" class="input-new-keyword" @keyup.enter.native="handleInputConfirm" @blur="handleInputConfirm" />
|
|
|
<el-button v-else class="button-new-keyword" type="primary" @click="showInput">+ 增加</el-button>
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item label="所属分类">
|
|
|
- <el-cascader :options="categoryList" v-model="categoryIds" expand-trigger="hover" @change="handleCategoryChange"/>
|
|
|
+ <el-cascader v-model="categoryIds" :options="categoryList" expand-trigger="hover" @change="handleCategoryChange" />
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item label="所属品牌商">
|
|
|
<el-select v-model="goods.brandId">
|
|
|
- <el-option v-for="item in brandList" :key="item.value" :label="item.label" :value="item.value"/>
|
|
|
+ <el-option v-for="item in brandList" :key="item.value" :label="item.label" :value="item.value" />
|
|
|
</el-select>
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item label="商品简介">
|
|
|
- <el-input v-model="goods.brief"/>
|
|
|
+ <el-input v-model="goods.brief" />
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item label="商品详细介绍">
|
|
|
- <editor :init="editorInit" v-model="goods.detail"/>
|
|
|
+ <editor v-model="goods.detail" :init="editorInit" />
|
|
|
</el-form-item>
|
|
|
</el-form>
|
|
|
</el-card>
|
|
|
|
|
|
<el-card class="box-card">
|
|
|
<h3>商品规格</h3>
|
|
|
- <el-button :plain="true" type="primary" @click="handleSpecificationShow">添加</el-button>
|
|
|
-
|
|
|
<el-table :data="specifications">
|
|
|
<el-table-column property="specification" label="规格名" />
|
|
|
- <el-table-column property="value" label="规格值" >
|
|
|
+ <el-table-column property="value" label="规格值">
|
|
|
<template slot-scope="scope">
|
|
|
<el-tag type="primary">
|
|
|
{{ scope.row.value }}
|
|
|
@@ -118,9 +121,9 @@
|
|
|
<img v-if="scope.row.picUrl" :src="scope.row.picUrl" width="40">
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
- <el-table-column align="center" label="操作" width="250" class-name="small-padding fixed-width">
|
|
|
+ <el-table-column align="center" label="操作" width="200" class-name="small-padding fixed-width">
|
|
|
<template slot-scope="scope">
|
|
|
- <el-button type="danger" size="mini" @click="handleSpecificationDelete(scope.row)">删除</el-button>
|
|
|
+ <el-button type="primary" size="mini" @click="handleSpecificationShow(scope.row)">设置</el-button>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
</el-table>
|
|
|
@@ -128,10 +131,10 @@
|
|
|
<el-dialog :visible.sync="specVisiable" title="设置规格">
|
|
|
<el-form ref="specForm" :rules="rules" :model="specForm" status-icon label-position="left" label-width="100px" style="width: 400px; margin-left:50px;">
|
|
|
<el-form-item label="规格名" prop="specification">
|
|
|
- <el-input v-model="specForm.specification"/>
|
|
|
+ <el-input v-model="specForm.specification" disabled />
|
|
|
</el-form-item>
|
|
|
<el-form-item label="规格值" prop="value">
|
|
|
- <el-input v-model="specForm.value"/>
|
|
|
+ <el-input v-model="specForm.value" disabled />
|
|
|
</el-form-item>
|
|
|
<el-form-item label="规格图片" prop="picUrl">
|
|
|
<el-upload
|
|
|
@@ -140,15 +143,16 @@
|
|
|
:show-file-list="false"
|
|
|
:on-success="uploadSpecPicUrl"
|
|
|
class="avatar-uploader"
|
|
|
- accept=".jpg,.jpeg,.png,.gif">
|
|
|
+ accept=".jpg,.jpeg,.png,.gif"
|
|
|
+ >
|
|
|
<img v-if="specForm.picUrl" :src="specForm.picUrl" class="avatar">
|
|
|
- <i v-else class="el-icon-plus avatar-uploader-icon"/>
|
|
|
+ <i v-else class="el-icon-plus avatar-uploader-icon" />
|
|
|
</el-upload>
|
|
|
</el-form-item>
|
|
|
</el-form>
|
|
|
<div slot="footer" class="dialog-footer">
|
|
|
<el-button @click="specVisiable = false">取消</el-button>
|
|
|
- <el-button type="primary" @click="handleSpecificationAdd">确定</el-button>
|
|
|
+ <el-button type="primary" @click="handleSpecificationEdit">确定</el-button>
|
|
|
</div>
|
|
|
</el-dialog>
|
|
|
</el-card>
|
|
|
@@ -156,28 +160,28 @@
|
|
|
<el-card class="box-card">
|
|
|
<h3>商品库存</h3>
|
|
|
<el-table :data="products">
|
|
|
- <el-table-column property="value" label="货品规格" >
|
|
|
+ <el-table-column property="value" label="货品规格">
|
|
|
<template slot-scope="scope">
|
|
|
<el-tag v-for="tag in scope.row.specifications" :key="tag">
|
|
|
{{ tag }}
|
|
|
</el-tag>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
- <el-table-column property="price" width="100" label="货品售价"/>
|
|
|
- <el-table-column property="number" width="100" label="货品数量"/>
|
|
|
- <el-table-column property="url" width="100" label="货品图片">
|
|
|
+ <el-table-column property="price" label="货品售价" />
|
|
|
+ <el-table-column property="number" label="货品数量" />
|
|
|
+ <el-table-column property="url" label="货品图片">
|
|
|
<template slot-scope="scope">
|
|
|
<img v-if="scope.row.url" :src="scope.row.url" width="40">
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
- <el-table-column align="center" label="操作" width="100" class-name="small-padding fixed-width">
|
|
|
+ <el-table-column align="center" label="操作" width="200" class-name="small-padding fixed-width">
|
|
|
<template slot-scope="scope">
|
|
|
<el-button type="primary" size="mini" @click="handleProductShow(scope.row)">设置</el-button>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
</el-table>
|
|
|
|
|
|
- <el-dialog :visible.sync="productVisiable" title="设置货品">
|
|
|
+ <el-dialog :visible.sync="productVisiable" title="编辑货品">
|
|
|
<el-form ref="productForm" :model="productForm" status-icon label-position="left" label-width="100px" style="width: 400px; margin-left:50px;">
|
|
|
<el-form-item label="货品规格列" prop="specifications">
|
|
|
<el-tag v-for="tag in productForm.specifications" :key="tag">
|
|
|
@@ -185,10 +189,10 @@
|
|
|
</el-tag>
|
|
|
</el-form-item>
|
|
|
<el-form-item label="货品售价" prop="price">
|
|
|
- <el-input v-model="productForm.price"/>
|
|
|
+ <el-input v-model="productForm.price" />
|
|
|
</el-form-item>
|
|
|
<el-form-item label="货品数量" prop="number">
|
|
|
- <el-input v-model="productForm.number"/>
|
|
|
+ <el-input v-model="productForm.number" />
|
|
|
</el-form-item>
|
|
|
<el-form-item label="货品图片" prop="url">
|
|
|
<el-upload
|
|
|
@@ -197,9 +201,10 @@
|
|
|
:show-file-list="false"
|
|
|
:on-success="uploadProductUrl"
|
|
|
class="avatar-uploader"
|
|
|
- accept=".jpg,.jpeg,.png,.gif">
|
|
|
+ accept=".jpg,.jpeg,.png,.gif"
|
|
|
+ >
|
|
|
<img v-if="productForm.url" :src="productForm.url" class="avatar">
|
|
|
- <i v-else class="el-icon-plus avatar-uploader-icon"/>
|
|
|
+ <i v-else class="el-icon-plus avatar-uploader-icon" />
|
|
|
</el-upload>
|
|
|
</el-form-item>
|
|
|
</el-form>
|
|
|
@@ -212,29 +217,31 @@
|
|
|
|
|
|
<el-card class="box-card">
|
|
|
<h3>商品参数</h3>
|
|
|
- <el-button :plain="true" type="primary" @click="handleAttributeShow">添加</el-button>
|
|
|
- <el-table :data="attributes">
|
|
|
- <el-table-column property="attribute" label="商品参数名称"/>
|
|
|
- <el-table-column property="value" label="商品参数值"/>
|
|
|
- <el-table-column align="center" label="操作" width="100" class-name="small-padding fixed-width">
|
|
|
+ <el-button type="primary" @click="handleAttributeShow">添加</el-button>
|
|
|
+ <el-table :data="attributesData">
|
|
|
+ <el-table-column property="attribute" label="商品参数名称" />
|
|
|
+ <el-table-column property="value" label="商品参数值" />
|
|
|
+ <el-table-column align="center" label="操作" width="200" class-name="small-padding fixed-width">
|
|
|
<template slot-scope="scope">
|
|
|
+ <el-button type="primary" size="mini" @click="handleAttributeShow(scope.row)">设置</el-button>
|
|
|
<el-button type="danger" size="mini" @click="handleAttributeDelete(scope.row)">删除</el-button>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
</el-table>
|
|
|
|
|
|
- <el-dialog :visible.sync="attributeVisiable" title="设置商品参数">
|
|
|
+ <el-dialog :visible.sync="attributeVisiable" :title="attributeAdd ? '添加商品参数' : '编辑商品参数'">
|
|
|
<el-form ref="attributeForm" :model="attributeForm" status-icon label-position="left" label-width="100px" style="width: 400px; margin-left:50px;">
|
|
|
<el-form-item label="商品参数名称" prop="attribute">
|
|
|
- <el-input v-model="attributeForm.attribute"/>
|
|
|
+ <el-input v-model="attributeForm.attribute" />
|
|
|
</el-form-item>
|
|
|
<el-form-item label="商品参数值" prop="value">
|
|
|
- <el-input v-model="attributeForm.value"/>
|
|
|
+ <el-input v-model="attributeForm.value" />
|
|
|
</el-form-item>
|
|
|
</el-form>
|
|
|
<div slot="footer" class="dialog-footer">
|
|
|
<el-button @click="attributeVisiable = false">取消</el-button>
|
|
|
- <el-button type="primary" @click="handleAttributeAdd">确定</el-button>
|
|
|
+ <el-button v-if="attributeAdd" type="primary" @click="handleAttributeAdd">确定</el-button>
|
|
|
+ <el-button v-else type="primary" @click="handleAttributeEdit">确定</el-button>
|
|
|
</div>
|
|
|
</el-dialog>
|
|
|
</el-card>
|
|
|
@@ -282,6 +289,10 @@
|
|
|
height: 145px;
|
|
|
display: block;
|
|
|
}
|
|
|
+.op-container {
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+}
|
|
|
</style>
|
|
|
|
|
|
<script>
|
|
|
@@ -320,16 +331,15 @@ export default {
|
|
|
{ id: 0, specifications: ['标准'], price: 0.0, number: 0, url: '' }
|
|
|
],
|
|
|
attributeVisiable: false,
|
|
|
+ attributeAdd: true,
|
|
|
attributeForm: { attribute: '', value: '' },
|
|
|
attributes: [],
|
|
|
rules: {
|
|
|
- goodsSn: [
|
|
|
- { required: true, message: '商品编号不能为空', trigger: 'blur' }
|
|
|
- ],
|
|
|
name: [{ required: true, message: '商品名称不能为空', trigger: 'blur' }]
|
|
|
},
|
|
|
editorInit: {
|
|
|
language: 'zh_CN',
|
|
|
+ height: '400px',
|
|
|
convert_urls: false,
|
|
|
plugins: [
|
|
|
'advlist anchor autolink autosave code codesample colorpicker colorpicker contextmenu directionality emoticons fullscreen hr image imagetools importcss insertdatetime link lists media nonbreaking noneditable pagebreak paste preview print save searchreplace spellchecker tabfocus table template textcolor textpattern visualblocks visualchars wordcount'
|
|
|
@@ -357,6 +367,16 @@ export default {
|
|
|
return {
|
|
|
'X-Litemall-Admin-Token': getToken()
|
|
|
}
|
|
|
+ },
|
|
|
+ attributesData() {
|
|
|
+ var attributesData = []
|
|
|
+ for (var i = 0; i < this.attributes.length; i++) {
|
|
|
+ if (this.attributes[i].deleted) {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ attributesData.push(this.attributes[i])
|
|
|
+ }
|
|
|
+ return attributesData
|
|
|
}
|
|
|
},
|
|
|
created() {
|
|
|
@@ -488,99 +508,20 @@ export default {
|
|
|
uploadSpecPicUrl: function(response) {
|
|
|
this.specForm.picUrl = response.data.url
|
|
|
},
|
|
|
- handleSpecificationShow() {
|
|
|
- this.specForm = { specification: '', value: '', picUrl: '' }
|
|
|
+ handleSpecificationShow(row) {
|
|
|
+ this.specForm = Object.assign({}, row)
|
|
|
this.specVisiable = true
|
|
|
},
|
|
|
- handleSpecificationAdd() {
|
|
|
- var index = this.specifications.length - 1
|
|
|
+ handleSpecificationEdit() {
|
|
|
+ this.specForm.updateTime = ''
|
|
|
for (var i = 0; i < this.specifications.length; i++) {
|
|
|
const v = this.specifications[i]
|
|
|
- if (v.specification === this.specForm.specification) {
|
|
|
- index = i
|
|
|
+ if (v.id === this.specForm.id) {
|
|
|
+ this.specifications.splice(i, 1, this.specForm)
|
|
|
+ break
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- this.specifications.splice(index + 1, 0, this.specForm)
|
|
|
this.specVisiable = false
|
|
|
-
|
|
|
- this.specToProduct()
|
|
|
- },
|
|
|
- handleSpecificationDelete(row) {
|
|
|
- const index = this.specifications.indexOf(row)
|
|
|
- this.specifications.splice(index, 1)
|
|
|
- this.specToProduct()
|
|
|
- },
|
|
|
- specToProduct() {
|
|
|
- if (this.specifications.length === 0) {
|
|
|
- return
|
|
|
- }
|
|
|
- // 根据specifications创建临时规格列表
|
|
|
- var specValues = []
|
|
|
- var spec = this.specifications[0].specification
|
|
|
- var values = []
|
|
|
- values.push(0)
|
|
|
-
|
|
|
- for (var i = 1; i < this.specifications.length; i++) {
|
|
|
- const aspec = this.specifications[i].specification
|
|
|
-
|
|
|
- if (aspec === spec) {
|
|
|
- values.push(i)
|
|
|
- } else {
|
|
|
- specValues.push(values)
|
|
|
- spec = aspec
|
|
|
- values = []
|
|
|
- values.push(i)
|
|
|
- }
|
|
|
- }
|
|
|
- specValues.push(values)
|
|
|
-
|
|
|
- // 根据临时规格列表生产货品规格
|
|
|
- // 算法基于 https://blog.csdn.net/tyhj_sf/article/details/53893125
|
|
|
- var productsIndex = 0
|
|
|
- var products = []
|
|
|
- var combination = []
|
|
|
- var n = specValues.length
|
|
|
- for (var s = 0; s < n; s++) {
|
|
|
- combination[s] = 0
|
|
|
- }
|
|
|
- var index = 0
|
|
|
- var isContinue = false
|
|
|
- do {
|
|
|
- var specifications = []
|
|
|
- for (var x = 0; x < n; x++) {
|
|
|
- var z = specValues[x][combination[x]]
|
|
|
- specifications.push(this.specifications[z].value)
|
|
|
- }
|
|
|
- products[productsIndex] = {
|
|
|
- id: productsIndex,
|
|
|
- specifications: specifications,
|
|
|
- price: 0.0,
|
|
|
- number: 0,
|
|
|
- url: ''
|
|
|
- }
|
|
|
- productsIndex++
|
|
|
-
|
|
|
- index++
|
|
|
- combination[n - 1] = index
|
|
|
- for (var j = n - 1; j >= 0; j--) {
|
|
|
- if (combination[j] >= specValues[j].length) {
|
|
|
- combination[j] = 0
|
|
|
- index = 0
|
|
|
- if (j - 1 >= 0) {
|
|
|
- combination[j - 1] = combination[j - 1] + 1
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- isContinue = false
|
|
|
- for (var p = 0; p < n; p++) {
|
|
|
- if (combination[p] !== 0) {
|
|
|
- isContinue = true
|
|
|
- }
|
|
|
- }
|
|
|
- } while (isContinue)
|
|
|
-
|
|
|
- this.products = products
|
|
|
},
|
|
|
handleProductShow(row) {
|
|
|
this.productForm = Object.assign({}, row)
|
|
|
@@ -590,6 +531,7 @@ export default {
|
|
|
this.productForm.url = response.data.url
|
|
|
},
|
|
|
handleProductEdit() {
|
|
|
+ this.productForm.updateTime = ''
|
|
|
for (var i = 0; i < this.products.length; i++) {
|
|
|
const v = this.products[i]
|
|
|
if (v.id === this.productForm.id) {
|
|
|
@@ -599,17 +541,34 @@ export default {
|
|
|
}
|
|
|
this.productVisiable = false
|
|
|
},
|
|
|
- handleAttributeShow() {
|
|
|
- this.attributeForm = {}
|
|
|
+ handleAttributeShow(row) {
|
|
|
+ if (row.id) {
|
|
|
+ this.attributeForm = Object.assign({}, row)
|
|
|
+ this.attributeAdd = false
|
|
|
+ } else {
|
|
|
+ this.attributeForm = {}
|
|
|
+ this.attributeAdd = true
|
|
|
+ }
|
|
|
this.attributeVisiable = true
|
|
|
},
|
|
|
handleAttributeAdd() {
|
|
|
this.attributes.unshift(this.attributeForm)
|
|
|
this.attributeVisiable = false
|
|
|
},
|
|
|
+ handleAttributeEdit() {
|
|
|
+ // 这是一个trick,设置updateTime的值为空,告诉后端这个记录已编辑需要更新。
|
|
|
+ this.attributeForm.updateTime = ''
|
|
|
+ for (var i = 0; i < this.attributes.length; i++) {
|
|
|
+ const v = this.attributes[i]
|
|
|
+ if (v.id === this.attributeForm.id) {
|
|
|
+ this.attributes.splice(i, 1, this.attributeForm)
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+ this.attributeVisiable = false
|
|
|
+ },
|
|
|
handleAttributeDelete(row) {
|
|
|
- const index = this.attributes.indexOf(row)
|
|
|
- this.attributes.splice(index, 1)
|
|
|
+ row.deleted = true
|
|
|
}
|
|
|
}
|
|
|
}
|