|
@@ -0,0 +1,399 @@
|
|
|
+<template>
|
|
|
+ <div v-if="multiSku === 1" style="padding: 16px 0px">
|
|
|
+ <el-form ref="spec" :model="{ specList }" :inline="false" label-width="80px" @submit.native.prevent>
|
|
|
+ <div v-for="(spec, index) in specList" :key="index" style="margin-bottom: 20px">
|
|
|
+ <el-row style="margin-bottom: 10px">
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item :label="`规格项${index + 1}`" :prop="`specList.${index}.name`" :rules="{ required: true, message: '请输入规格名称', trigger: 'blur' }">
|
|
|
+ <el-input v-model="spec.name" :disabled="!spec.edit" @keyup.enter.native="checkSpecName(spec)" />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="16">
|
|
|
+ <el-button v-if="spec.edit" type="text" style="margin-left: 10px" @click="checkSpecName(spec)">确定</el-button>
|
|
|
+ <template v-else>
|
|
|
+ <el-button type="text" style="margin-left: 10px" @click="spec.edit = true">编辑</el-button>
|
|
|
+ <el-button type="text" class="del" style="margin-left: 10px" @click="specList.splice(index, 1)">删除</el-button>
|
|
|
+ </template>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ <el-row>
|
|
|
+ <el-form-item :prop="`specList.${index}.vals`">
|
|
|
+ <el-col :span="24">
|
|
|
+ <el-tag v-for="(tag, index) in spec.vals" :key="index" closable style="margin-right: 10px" @close="spec.vals.splice(index, 1)">{{ tag }}</el-tag>
|
|
|
+ <el-input v-if="spec.editVals" v-model="specValTmp" v-focus style="display: inline-block;width: 120px; margin-right: 10px" size="mini" @keyup.enter.native="checkSpecVal(spec, `specList.${index}.vals`)" />
|
|
|
+ <el-button v-if="!spec.edit&&!spec.editVals" type="text" style="margin-left: 10px" icon="el-icon-plus" size="small" @click="spec.editVals = true">添加规格值</el-button>
|
|
|
+ <el-button v-if="spec.editVals" type="text" @click="checkSpecVal(spec, `specList.${index}.vals`)">确认</el-button>
|
|
|
+ <el-button v-if="spec.editVals" type="text" @click="spec.editVals = false;specValTmp = ''">取消</el-button>
|
|
|
+ </el-col>
|
|
|
+ </el-form-item>
|
|
|
+ </el-row>
|
|
|
+ </div>
|
|
|
+ </el-form>
|
|
|
+ <el-button type="primary" size="small" plain @click="specList.push({ name: '', vals: [], edit: true, editVals: false })" :disabled="!!specList.find(item => item.edit)" style="margin-bottom: 10px">添加规格</el-button>
|
|
|
+ <el-button type="primary" size="small" style="margin-bottom: 10px;margin-left: 10px" :disabled="specList.length === 0 || !!specList.find(item => item.edit)" @click="genSku">{{ skuList.length > 0 ? '重新生成SKU表格' : '生成SKU表格' }}</el-button>
|
|
|
+ <br>
|
|
|
+ <el-form ref="sku" :model="{ skuList }" :inline="false">
|
|
|
+ <table v-if="skuList instanceof Array && skuList.length > 0" class="spec-table" border="1" bordercolor="#CCC">
|
|
|
+ <tr>
|
|
|
+ <th :colspan="specListTmp.length">商品规格</th>
|
|
|
+ <th rowspan="2" class="required"><span>*</span>SKU主图</th>
|
|
|
+ <th rowspan="2" class="required"><span>*</span>名称</th>
|
|
|
+ <th rowspan="2" class="required"><span>*</span>价格(元)</th>
|
|
|
+ <th rowspan="2" class="required"><span>*</span>采购成本(元)</th>
|
|
|
+ <th rowspan="2" class="required"><span>*</span>零售价(元)</th>
|
|
|
+ <th rowspan="2" class="required"><span>*</span>兑换盲豆数量</th>
|
|
|
+ <th rowspan="2" class="required"><span>*</span>回收折扣(%)</th>
|
|
|
+ <th rowspan="2">盲豆划线价</th>
|
|
|
+ <th rowspan="2">商品成本(元)</th>
|
|
|
+ <th rowspan="2">SKU编码</th>
|
|
|
+ <th rowspan="2" class="required"><span>*</span>库存</th>
|
|
|
+ <th rowspan="2">启用</th>
|
|
|
+ </tr>
|
|
|
+ <tr>
|
|
|
+ <th v-for="(spec, index) in specListTmp" :key="index" style="width: 80px">{{ spec.name }}</th>
|
|
|
+ </tr>
|
|
|
+ <!-- k1:v1;k2:v2 -->
|
|
|
+ <tr v-for="(sku, index) in skuList" :key="index">
|
|
|
+ <td v-for="(spec, i) in specListTmp" :key="i" style="min-width: 50px">
|
|
|
+ {{ formatObj(sku.properties)[spec.name] }}
|
|
|
+ </td>
|
|
|
+ <td>
|
|
|
+ <el-form-item :prop="`skuList.${index}.picUrlArr`" :rules="{ required: true, message: '请上传SKU图片', trigger: ['blur', 'change'] }" style="display:flex ;width: 76px;height: 80px">
|
|
|
+ <Upload v-model="sku.picUrlArr" :limit="1" style="width: 100%" @change="$refs.sku.validateField([`skuList.${index}.picUrlArr`])" />
|
|
|
+ </el-form-item>
|
|
|
+ </td>
|
|
|
+ <td class="pd">
|
|
|
+ <el-form-item :prop="`skuList.${index}.name`" :rules="{ required: true, message: '名称不能为空', trigger: 'blur' }">
|
|
|
+ <el-input v-model="sku.name" />
|
|
|
+ </el-form-item>
|
|
|
+ </td>
|
|
|
+ <td class="pd">
|
|
|
+ <el-form-item :prop="`skuList.${index}.valueY`" :rules="valueYRules">
|
|
|
+ <el-input v-model="sku.valueY" />
|
|
|
+ </el-form-item>
|
|
|
+ </td>
|
|
|
+ <td class="pd">
|
|
|
+ <el-form-item :prop="`skuList.${index}.purchaseCostY`" :rules="purchaseCostYRules">
|
|
|
+ <el-input v-model="sku.purchaseCostY" />
|
|
|
+ </el-form-item>
|
|
|
+ </td>
|
|
|
+ <td class="pd">
|
|
|
+ <el-form-item :prop="`skuList.${index}.purchasePriceY`" :rules="purchasePriceYRules">
|
|
|
+ <el-input v-model="sku.purchasePriceY" />
|
|
|
+ </el-form-item>
|
|
|
+ </td>
|
|
|
+ <td class="pd">
|
|
|
+ <el-form-item :prop="`skuList.${index}.exchange`" :rules="exchangeRules">
|
|
|
+<!-- <p>{{ (sku.valueY * 10).toFixed(0) }}</p>-->
|
|
|
+ <el-input v-model="sku.exchange" />
|
|
|
+ </el-form-item>
|
|
|
+ </td>
|
|
|
+<!-- 1111111111111111111111-->
|
|
|
+ <td class="pd">
|
|
|
+ <el-form-item :prop="`skuList.${index}.discountRate`" :rules="discountRateRules">
|
|
|
+ <!-- <p>{{ (sku.valueY * 10).toFixed(0) }}</p>-->
|
|
|
+ <el-input v-model="sku.discountRate" />
|
|
|
+ </el-form-item>
|
|
|
+ </td>
|
|
|
+ <td class="pd">
|
|
|
+ <el-form-item :prop="`skuList.${index}.originPrice`">
|
|
|
+ <el-input v-model="sku.originPrice" />
|
|
|
+ </el-form-item>
|
|
|
+ </td>
|
|
|
+ <td class="pd">
|
|
|
+ <el-form-item :prop="`skuList.${index}.costY`" :rules="costYRules">
|
|
|
+ <el-input v-model="sku.costY" />
|
|
|
+ </el-form-item>
|
|
|
+ </td>
|
|
|
+ <td class="pd">
|
|
|
+ <el-form-item :prop="`skuList.${index}.skuCode`">
|
|
|
+ <el-input v-model="sku.skuCode" />
|
|
|
+ </el-form-item>
|
|
|
+ </td>
|
|
|
+ <td class="pd">
|
|
|
+ <el-form-item :prop="`skuList.${index}.quantity`" :rules="{ required: true, message: '请输入库存', trigger: 'blur' }">
|
|
|
+ <el-input-number style="width: 130px;" v-model="sku.quantity" :min="0" @change="$event === 0 ? sku.status = false : sku.status = true" />
|
|
|
+ </el-form-item>
|
|
|
+ </td>
|
|
|
+ <td style="padding: 0px 10px">
|
|
|
+ <el-form-item :prop="`skuList.${index}.status`">
|
|
|
+ <el-switch v-model="sku.status" active-color="#13ce66" inactive-color="#ff4949" @change="!$event ? sku.quantity = 0 : sku.quantity = 1" />
|
|
|
+ </el-form-item>
|
|
|
+ </td>
|
|
|
+ </tr>
|
|
|
+ </table>
|
|
|
+ </el-form>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+<script>
|
|
|
+import Upload from '@/components/ImageUpload'
|
|
|
+import { accMul, accDiv } from '@/utils/util'
|
|
|
+export default {
|
|
|
+ name: 'Spec',
|
|
|
+ components: {
|
|
|
+ Upload
|
|
|
+ },
|
|
|
+ props: {
|
|
|
+ multiSku: {
|
|
|
+ type: Number,
|
|
|
+ default: 0
|
|
|
+ },
|
|
|
+ sku: {
|
|
|
+ type: Array,
|
|
|
+ default: () => []
|
|
|
+ }
|
|
|
+ },
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ specList: [],
|
|
|
+ specListTmp: [],
|
|
|
+ skuList: [],
|
|
|
+ specValTmp: '',
|
|
|
+ specifications: [],
|
|
|
+ valueYRules: [
|
|
|
+ { required: true, message: '请输入价格', trigger: 'blur' },
|
|
|
+ { pattern: /^([1-9]\d*(\.\d{1,2})?|([0](\.([0][1-9]|[1-9]\d{0,1}))))$/, message: "请输入正确的金额,最多两位小数", trigger: ["blur", "change"]}],
|
|
|
+ purchaseCostYRules: [
|
|
|
+ { required: true, message: '请输入采购成本', trigger: 'blur' },
|
|
|
+ { pattern: /^([1-9]\d*(\.\d{1,2})?|([0](\.([0][1-9]|[1-9]\d{0,1}))))$/, message: "请输入正确的金额,最多两位小数", trigger: ["blur", "change"]}],
|
|
|
+ purchasePriceYRules: [
|
|
|
+ { required: true, message: '请输入零售价', trigger: 'blur' },
|
|
|
+ { pattern: /^([1-9]\d*(\.\d{1,2})?|([0](\.([0][1-9]|[1-9]\d{0,1}))))$/, message: "请输入正确的金额,最多两位小数", trigger: ["blur", "change"]}],
|
|
|
+ costYRules: [
|
|
|
+ { required: false, message: '请输入商品成本', trigger: 'blur' },
|
|
|
+ { pattern: /^([1-9]\d*(\.\d{1,2})?|([0](\.([0][1-9]|[1-9]\d{0,1}))))$/, message: "请输入正确的金额,最多两位小数", trigger: ["blur", "change"] }],
|
|
|
+ exchangeRules: [
|
|
|
+ { required: true,message:'请输入盲豆数量', trigger: 'blur' },
|
|
|
+ { pattern: /^([1-9]\d*)$/, message: "请输入正确的盲豆数量", trigger: ["blur", "change"] }
|
|
|
+ ],
|
|
|
+ discountRateRules: [
|
|
|
+ { required: true,message:'请输入回收折扣', trigger: 'blur' },
|
|
|
+ { pattern: /^([0-9]\d*(\.\d{1,2})?|([0](\.([0][1-9]|[1-9]\d{0,1}))))$/, message: "请输入正确的折扣,最多两位小数", trigger: ["blur", "change"] }
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ },
|
|
|
+ directives: {
|
|
|
+ focus: {
|
|
|
+ inserted: function (el) {
|
|
|
+ el.querySelector('input').focus()
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ setSkuList(sku) {
|
|
|
+ let specObj = {}
|
|
|
+ sku.forEach(item => {
|
|
|
+ item.properties.split(';').forEach(p => {
|
|
|
+ const key = p.split(':')[0]
|
|
|
+ // console.log(specObj[key] instanceof Array)
|
|
|
+ if (!specObj[key]) {
|
|
|
+ specObj[key] = []
|
|
|
+ // console.log(specObj[key])
|
|
|
+ }
|
|
|
+ specObj[key].push(p.split(':')[1])
|
|
|
+ })
|
|
|
+ })
|
|
|
+ this.specList = Object.keys(specObj).map(key => {
|
|
|
+ return {
|
|
|
+ name: key,
|
|
|
+ vals: [...new Set(specObj[key])],
|
|
|
+ edit: false,
|
|
|
+ editVals: false
|
|
|
+ }
|
|
|
+ })
|
|
|
+ this.specListTmp = JSON.parse(JSON.stringify(this.specList))
|
|
|
+ this.skuList = sku.map(item => {
|
|
|
+ this.$set(item, 'valueY', accDiv(item.value, 100))
|
|
|
+ this.$set(item, 'purchaseCostY', accDiv(item.purchaseCost,100))
|
|
|
+ this.$set(item, 'purchasePriceY', accDiv(item.purchasePrice,100))
|
|
|
+ this.$set(item, 'exchange', accDiv(item.exchangePrice,1))
|
|
|
+ this.$set(item, 'originPrice', accDiv(item.originPrice,1))
|
|
|
+ this.$set(item, 'discountRate', accDiv(item.discountRate,1))
|
|
|
+ this.$set(item, 'costY', item.cost == null ? '' : accDiv(item.cost, 100) )
|
|
|
+ this.$set(item, 'picUrlArr', item.picUrl.split(',').map(item => { return { fileName: item }}))
|
|
|
+ this.$set(item, 'status', !!item.quantity)
|
|
|
+ return item
|
|
|
+ })
|
|
|
+ },
|
|
|
+ formatObj(properties) {
|
|
|
+ if (properties) {
|
|
|
+ let obj = {}
|
|
|
+ properties.split(';').forEach(item => {
|
|
|
+ obj[item.split(':')[0]] = item.split(':')[1]
|
|
|
+ })
|
|
|
+ return obj
|
|
|
+ }
|
|
|
+ return {}
|
|
|
+ },
|
|
|
+ checkSpecVal(spec, prop) {
|
|
|
+ if (!this.specValTmp) {
|
|
|
+ this.$message.warning('请输入规格值')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (spec.vals.find(item => item === this.specValTmp)) {
|
|
|
+ this.$message.warning('规格值已存在')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ spec.vals.push(this.specValTmp)
|
|
|
+ this.specValTmp = ''
|
|
|
+ spec.editVals = false
|
|
|
+ this.$refs.spec.validateField([prop])
|
|
|
+ },
|
|
|
+ checkSpecName(spec) {
|
|
|
+ if (this.specList.filter(item => item.name === spec.name).length > 1) {
|
|
|
+ this.$message.warning('规格名已存在')
|
|
|
+ } else {
|
|
|
+ spec.edit = false
|
|
|
+ }
|
|
|
+ },
|
|
|
+ genSku() {
|
|
|
+ this.$refs.spec.validate((valid, items) => {
|
|
|
+ if (valid) {
|
|
|
+ this.genSkuList()
|
|
|
+ }
|
|
|
+ })
|
|
|
+ },
|
|
|
+ genSkuList() {
|
|
|
+ let specificationsTmp = []
|
|
|
+ this.specList.forEach(spec => {
|
|
|
+ spec.vals.forEach(val => {
|
|
|
+ specificationsTmp.push({
|
|
|
+ specification: spec.name,
|
|
|
+ value: val
|
|
|
+ })
|
|
|
+ })
|
|
|
+ })
|
|
|
+ var specValues = []
|
|
|
+ var spec = specificationsTmp[0].specification
|
|
|
+ var values = []
|
|
|
+ values.push(0)
|
|
|
+
|
|
|
+ for (var i = 1; i < specificationsTmp.length; i++) {
|
|
|
+ const aspec = specificationsTmp[i].specification
|
|
|
+
|
|
|
+ if (aspec === spec) {
|
|
|
+ values.push(i)
|
|
|
+ } else {
|
|
|
+ specValues.push(values)
|
|
|
+ spec = aspec
|
|
|
+ values = []
|
|
|
+ values.push(i)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ specValues.push(values)
|
|
|
+ var productsIndex = 0
|
|
|
+ var skuList = []
|
|
|
+ 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 = []
|
|
|
+ var properties = ''
|
|
|
+ for (var x = 0; x < n; x++) {
|
|
|
+ var z = specValues[x][combination[x]]
|
|
|
+ specifications.push(specificationsTmp[z].value)
|
|
|
+ properties = `${properties ? (properties + ';') : ''}${specificationsTmp[z].specification}:${specificationsTmp[z].value}`
|
|
|
+ }
|
|
|
+ skuList[productsIndex] = {
|
|
|
+ idx: productsIndex,
|
|
|
+ name: specifications.toString(),
|
|
|
+ picUrlArr: [],
|
|
|
+ valueY: 0.00,
|
|
|
+ purchaseCostY: 0.00,
|
|
|
+ purchasePriceY: 0.00,
|
|
|
+ costY: '',
|
|
|
+ skuCode:'',
|
|
|
+ originPrice: 0,
|
|
|
+ discountRate: '',
|
|
|
+ quantity: 0,
|
|
|
+ status: true,
|
|
|
+ properties
|
|
|
+ }
|
|
|
+ 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.skuList = skuList
|
|
|
+ this.specListTmp = JSON.parse(JSON.stringify(this.specList))
|
|
|
+ },
|
|
|
+ getSkuList() {
|
|
|
+ if (this.skuList.length === 0) {
|
|
|
+ this.$message.warning('请完善规格并生成sku表格')
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ this.$refs.sku.validate((valid, items) => {
|
|
|
+ if (valid) {
|
|
|
+ this.skuList.forEach(item => {
|
|
|
+ const { valueY,exchange, purchaseCostY,purchasePriceY,costY, originPrice, discountRate } = item
|
|
|
+ item.value = accMul(valueY, 100)
|
|
|
+ item.purchaseCost = accMul(purchaseCostY, 100)
|
|
|
+ item.purchasePrice = accMul(purchasePriceY, 100)
|
|
|
+ item.exchangePrice = accMul(exchange, 1)
|
|
|
+ item.originPrice = accMul(originPrice, 1)
|
|
|
+ item.discountRate = accMul(discountRate, 1)
|
|
|
+ item.cost = costY == '' ? '' : accMul(costY, 100)
|
|
|
+ item.picUrl = item.picUrlArr.map(item => { return item.fileName }).toString()
|
|
|
+ })
|
|
|
+ this.$emit('valid', this.skuList)
|
|
|
+ } else {
|
|
|
+ if (items && Object.keys(items).length>0) {
|
|
|
+ this.$message({
|
|
|
+ message: items[Object.keys(items)[0]][0].message,
|
|
|
+ type: 'warning'
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</script>
|
|
|
+<style lang="scss" scoped>
|
|
|
+.spec-table {
|
|
|
+ border-collapse: collapse;
|
|
|
+ width: 100%;
|
|
|
+ line-height: 32px;
|
|
|
+ color: #606266;
|
|
|
+ font-size: 14px;
|
|
|
+ th {
|
|
|
+ background-color: #ECECEC;
|
|
|
+ }
|
|
|
+ td {
|
|
|
+ text-align: center;
|
|
|
+ }
|
|
|
+ .pd {
|
|
|
+ padding: 10px;
|
|
|
+ }
|
|
|
+ .required {
|
|
|
+ position: relative;
|
|
|
+ span {
|
|
|
+ position: relative;
|
|
|
+ top: -6px;
|
|
|
+ left: 2px;
|
|
|
+ font-size: 10px;
|
|
|
+ color: red;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+</style>
|