feat(GoodsStock.vue): 商品库存管理升级vue3
This commit is contained in:
parent
932c78f988
commit
d591ddde7c
|
|
@ -17,6 +17,7 @@
|
||||||
"path-to-regexp": "^6.2.0",
|
"path-to-regexp": "^6.2.0",
|
||||||
"pinia": "^2.0.9",
|
"pinia": "^2.0.9",
|
||||||
"screenfull": "^6.0.0",
|
"screenfull": "^6.0.0",
|
||||||
|
"sortablejs": "^1.14.0",
|
||||||
"vue": "^3.2.16",
|
"vue": "^3.2.16",
|
||||||
"vue-router": "^4.0.12"
|
"vue-router": "^4.0.12"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,6 @@ import {listAttributes, saveAttributeBatch} from "@/api/pms/attribute";
|
||||||
import {computed, reactive, toRefs, watch} from "vue";
|
import {computed, reactive, toRefs, watch} from "vue";
|
||||||
import {Plus, Check, Delete} from '@element-plus/icons'
|
import {Plus, Check, Delete} from '@element-plus/icons'
|
||||||
import {ElMessage} from "element-plus";
|
import {ElMessage} from "element-plus";
|
||||||
import {listRoleMenuIds} from "@api/system/role";
|
|
||||||
import SvgIcon from '@/components/SvgIcon/index.vue';
|
import SvgIcon from '@/components/SvgIcon/index.vue';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
|
|
|
||||||
|
|
@ -1,32 +1,37 @@
|
||||||
<!--
|
|
||||||
<template>
|
<template>
|
||||||
<div class="components-container">
|
<div class="components-container">
|
||||||
<div class="components-container__main">
|
<div class="components-container__main">
|
||||||
<el-card class="box-card">
|
<el-card class="box-card">
|
||||||
<div slot="header">
|
<template #header>
|
||||||
<span>商品属性</span>
|
<span>商品属性</span>
|
||||||
<el-button style="float: right;" type="primary" size="mini" @click="handleAttributeAdd">
|
<el-button
|
||||||
|
style="float: right;"
|
||||||
|
type="success"
|
||||||
|
:icon="Plus"
|
||||||
|
size="mini"
|
||||||
|
@click="handleAdd"
|
||||||
|
>
|
||||||
添加属性
|
添加属性
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</template>
|
||||||
<el-form
|
<el-form
|
||||||
ref="attributeForm"
|
ref="dataForm"
|
||||||
:model="value"
|
:model="modelValue"
|
||||||
:rules="rules"
|
:rules="rules"
|
||||||
size="mini"
|
size="mini"
|
||||||
:inline="true"
|
:inline="true"
|
||||||
>
|
>
|
||||||
<el-table
|
<el-table
|
||||||
:data="value.attrList"
|
:data="modelValue.attrList"
|
||||||
size="mini"
|
size="mini"
|
||||||
highlight-current-row
|
highlight-current-row
|
||||||
border
|
border
|
||||||
>
|
>
|
||||||
<el-table-column property="name" label="属性名称">
|
<el-table-column property="name" label="属性名称">
|
||||||
<template slot-scope="scope">
|
<template #default="scope">
|
||||||
<el-form-item
|
<el-form-item
|
||||||
:prop="'attrList[' + scope.$index + '].name'"
|
:prop="'attrList[' + scope.$index + '].name'"
|
||||||
:rules="rules.attribute.name"
|
:rules="rules.attribute.name"
|
||||||
>
|
>
|
||||||
<el-input v-model="scope.row.name"/>
|
<el-input v-model="scope.row.name"/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
@ -34,10 +39,10 @@
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|
||||||
<el-table-column property="value" label="属性值">
|
<el-table-column property="value" label="属性值">
|
||||||
<template slot-scope="scope">
|
<template #default="scope">
|
||||||
<el-form-item
|
<el-form-item
|
||||||
:prop="'attrList[' + scope.$index + '].value'"
|
:prop="'attrList[' + scope.$index + '].value'"
|
||||||
:rules="rules.attribute.value"
|
:rules="rules.attribute.value"
|
||||||
>
|
>
|
||||||
<el-input v-model="scope.row.value"/>
|
<el-input v-model="scope.row.value"/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
@ -45,9 +50,15 @@
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|
||||||
<el-table-column label="操作" width="150">
|
<el-table-column label="操作" width="150">
|
||||||
<template slot-scope="scope">
|
<template #default="scope">
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button type="danger" icon="el-icon-minus" circle @click="handleAttributeRemove(scope.$index)"/>
|
<el-button
|
||||||
|
v-if="scope.$index>0"
|
||||||
|
type="danger"
|
||||||
|
icon="Minus"
|
||||||
|
circle
|
||||||
|
@click="handleRemove(scope.$index)"
|
||||||
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|
@ -63,53 +74,77 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script setup lang="ts">
|
||||||
import {listAttribute} from "@/api/pms/attribute";
|
import {listAttributes} from "@/api/pms/attribute";
|
||||||
|
import {computed, nextTick, reactive, ref, toRefs, unref, watch} from "vue";
|
||||||
|
import {ElForm} from "element-plus";
|
||||||
|
import {Minus, Plus} from '@element-plus/icons'
|
||||||
|
|
||||||
export default {
|
const emit = defineEmits(['prev', 'next'])
|
||||||
name: "GoodsAttribute",
|
const dataForm = ref(ElForm)
|
||||||
props: {
|
|
||||||
value: Object
|
const props = defineProps({
|
||||||
},
|
modelValue: {
|
||||||
watch:{
|
type: Object,
|
||||||
// 监听选择的商品分类关联商品属性
|
default: {}
|
||||||
'value.categoryId':{
|
}
|
||||||
handler(newVal,oldVal){
|
})
|
||||||
listAttribute({categoryId: newVal, type: 2}).then(res => {
|
|
||||||
this.value.attrList = res.data
|
const categoryId = computed(() => props.modelValue.categoryId);
|
||||||
})
|
|
||||||
}
|
watch(categoryId, (newVal, oldVal) => {
|
||||||
|
if (newVal) {
|
||||||
|
// type=2 商品普通属性(非销售属性)
|
||||||
|
listAttributes({categoryId: newVal, type: 2}).then(response => {
|
||||||
|
const attrList = response.data
|
||||||
|
if (attrList && attrList.length > 0) {
|
||||||
|
props.modelValue.attrList = attrList
|
||||||
|
} else {
|
||||||
|
props.modelValue.attrList = [{}]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
props.modelValue.attrList = [{}]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
immediate: true,
|
||||||
|
deep: true
|
||||||
}
|
}
|
||||||
},
|
)
|
||||||
data() {
|
|
||||||
return {
|
const state = reactive({
|
||||||
rules: {
|
rules: {
|
||||||
attribute: {
|
attribute: {
|
||||||
name: [{required: true, message: '请填写属性名称', trigger: 'blur'}],
|
name: [{required: true, message: '请填写属性名称', trigger: 'blur'}],
|
||||||
value: [{required: true, message: '请填写属性值', trigger: 'blur'}]
|
value: [{required: true, message: '请填写属性值', trigger: 'blur'}]
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
handleAttributeAdd: function () {
|
|
||||||
this.value.attrList.push({})
|
|
||||||
},
|
|
||||||
handleAttributeRemove: function (index) {
|
|
||||||
this.value.attrList.splice(index, 1)
|
|
||||||
},
|
|
||||||
handlePrev: function () {
|
|
||||||
this.$emit('prev')
|
|
||||||
},
|
|
||||||
handleNext: function () {
|
|
||||||
this.$refs["attributeForm"].validate((valid) => {
|
|
||||||
if (valid) {
|
|
||||||
this.$emit('next')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const {rules} = toRefs(state)
|
||||||
|
|
||||||
|
function handleAdd() {
|
||||||
|
props.modelValue.attrList.push({})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleRemove(index:number) {
|
||||||
|
props.modelValue.attrList.splice(index, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
function handlePrev() {
|
||||||
|
emit('prev')
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleNext() {
|
||||||
|
const form = unref(dataForm)
|
||||||
|
form.validate((valid: any) => {
|
||||||
|
if (valid) {
|
||||||
|
emit('next')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|
@ -125,8 +160,8 @@ export default {
|
||||||
right: 20px;
|
right: 20px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.el-form-item--mini.el-form-item{
|
|
||||||
|
.el-form-item--mini.el-form-item {
|
||||||
margin-top: 18px;
|
margin-top: 18px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
-->
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
<el-cascader-panel
|
<el-cascader-panel
|
||||||
ref="categoryRef"
|
ref="categoryRef"
|
||||||
:options="categoryOptions"
|
:options="categoryOptions"
|
||||||
v-model="categoryId"
|
v-model="modelValue.categoryId"
|
||||||
:props="{emitPath:false}"
|
:props="{emitPath:false}"
|
||||||
@change="handleCategoryChange"
|
@change="handleCategoryChange"
|
||||||
|
|
||||||
|
|
@ -40,17 +40,15 @@ const props = defineProps({
|
||||||
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
categoryOptions: [],
|
categoryOptions: [],
|
||||||
pathLabels: [],
|
pathLabels: []
|
||||||
categoryId: undefined
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const {categoryOptions, pathLabels, categoryId} = toRefs(state)
|
const {categoryOptions, pathLabels} = toRefs(state)
|
||||||
|
|
||||||
function loadData() {
|
function loadData() {
|
||||||
listCascadeCategories({}).then(response => {
|
listCascadeCategories({}).then(response => {
|
||||||
state.categoryOptions = response.data
|
state.categoryOptions = response.data
|
||||||
if (props.modelValue.id) {
|
if (props.modelValue.id) {
|
||||||
state.categoryId = props.modelValue.categoryId
|
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
handleCategoryChange()
|
handleCategoryChange()
|
||||||
})
|
})
|
||||||
|
|
@ -66,7 +64,8 @@ function handleCategoryChange() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleNext() {
|
function handleNext() {
|
||||||
if (!state.categoryId) {
|
console.log('商品属性',props.modelValue.categoryId)
|
||||||
|
if (!props.modelValue.categoryId) {
|
||||||
ElMessage.warning('请选择商品分类')
|
ElMessage.warning('请选择商品分类')
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,25 @@
|
||||||
<!--
|
|
||||||
<template>
|
<template>
|
||||||
<div class="components-container">
|
<div class="components-container">
|
||||||
<div class="components-container__main">
|
<div class="components-container__main">
|
||||||
<el-card class="box-card">
|
<el-card class="box-card">
|
||||||
<div slot="header">
|
<template #header>
|
||||||
<span>商品规格</span>
|
<span>商品规格</span>
|
||||||
<el-button style="float: right;" type="primary" size="mini" @click="handleSpecAdd">
|
<el-button style="float: right;" type="primary" size="mini" @click="handleSpecAdd">
|
||||||
添加规格项
|
添加规格项
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</template>
|
||||||
|
|
||||||
<el-form
|
<el-form
|
||||||
size="mini"
|
ref="specFormRef"
|
||||||
ref="specForm"
|
:model="specForm"
|
||||||
:model="specForm"
|
:inline="true"
|
||||||
:inline="true">
|
|
||||||
<el-table
|
|
||||||
ref="specTable"
|
|
||||||
:data="specForm.specList"
|
|
||||||
row-key="id"
|
|
||||||
size="mini"
|
size="mini"
|
||||||
|
>
|
||||||
|
<el-table
|
||||||
|
ref="specTableRef"
|
||||||
|
:data="specForm.specList"
|
||||||
|
row-key="id"
|
||||||
|
size="mini"
|
||||||
>
|
>
|
||||||
<el-table-column align="center" width="50">
|
<el-table-column align="center" width="50">
|
||||||
<template>
|
<template>
|
||||||
|
|
@ -26,16 +27,16 @@
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="规格名" width="200">
|
<el-table-column label="规格名" width="200">
|
||||||
<template slot-scope="scope">
|
<template #default="scope">
|
||||||
<el-form-item
|
<el-form-item
|
||||||
:prop="'specList[' + scope.$index + '].name'"
|
:prop="'specList[' + scope.$index + '].name'"
|
||||||
:rules="rules.specification.name"
|
:rules="rules.spec.name"
|
||||||
>
|
>
|
||||||
<el-input
|
<el-input
|
||||||
type="text"
|
type="text"
|
||||||
v-model="scope.row.name"
|
v-model="scope.row.name"
|
||||||
size="mini"
|
size="mini"
|
||||||
@input="changeSpec()"
|
@input="handleSpecChange()"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -48,20 +49,20 @@
|
||||||
<template slot-scope="{row}">
|
<template slot-scope="{row}">
|
||||||
<div style="margin-right:15px;display: inline-block" v-for="item in row.values">
|
<div style="margin-right:15px;display: inline-block" v-for="item in row.values">
|
||||||
<el-tag
|
<el-tag
|
||||||
closable
|
closable
|
||||||
:type="colors[row.index%colors.length]"
|
:type="colors[row.index%colors.length]"
|
||||||
@close="handleSpecValueRemove(row.index,item.id)">
|
@close="handleSpecValueRemove(row.index,item.id)">
|
||||||
{{ item.value }}
|
{{ item.value }}
|
||||||
</el-tag>
|
</el-tag>
|
||||||
<mini-card-upload v-if="row.index==0" style="margin-top: 5px" v-model="item.picUrl"/>
|
<mini-card-upload v-if="row.index==0" style="margin-top: 5px" v-model="item.picUrl"/>
|
||||||
</div>
|
</div>
|
||||||
<el-input
|
<el-input
|
||||||
style="width: 80px;vertical-align: top"
|
style="width: 80px;vertical-align: top"
|
||||||
size="mini"
|
size="mini"
|
||||||
v-if="tagInputs[row.index].visible"
|
v-if="tagInputs[row.index].visible"
|
||||||
v-model="tagInputs[row.index].value"
|
v-model="tagInputs[row.index].value"
|
||||||
@keyup.enter.native="handleSpecValueInput(row.index)"
|
@keyup.enter.native="handleSpecValueInput(row.index)"
|
||||||
@blur="handleSpecValueInput(row.index)"/>
|
@blur="handleSpecValueInput(row.index)"/>
|
||||||
<el-button v-else size="mini" icon="el-icon-plus" style="vertical-align: top"
|
<el-button v-else size="mini" icon="el-icon-plus" style="vertical-align: top"
|
||||||
@click="handleSpecValueAdd(row.index)">添加规格值
|
@click="handleSpecValueAdd(row.index)">添加规格值
|
||||||
</el-button>
|
</el-button>
|
||||||
|
|
@ -69,65 +70,73 @@
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|
||||||
<el-table-column width="60" label="操作">
|
<el-table-column width="60" label="操作">
|
||||||
<template slot-scope="scope">
|
<template #default="scope">
|
||||||
<el-button
|
<el-button
|
||||||
type="danger"
|
type="danger"
|
||||||
icon="el-icon-delete"
|
icon="el-icon-delete"
|
||||||
size="mini"
|
size="mini"
|
||||||
circle
|
circle
|
||||||
plain
|
plain
|
||||||
@click.stop="handleSpecRemove(scope.$index)"/>
|
@click.stop="handleSpecRemove(scope.$index)"/>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
</el-form>
|
</el-form>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
<el-card class="box-card">
|
<el-card class="box-card">
|
||||||
<div slot="header">
|
<template #header>
|
||||||
<span>商品库存</span>
|
<span>商品库存</span>
|
||||||
</div>
|
</template>
|
||||||
<el-form
|
<el-form
|
||||||
:model="skuForm"
|
ref="skuFormRef"
|
||||||
size="mini"
|
:model="skuForm"
|
||||||
ref="skuForm"
|
size="mini"
|
||||||
:inline="true"
|
:inline="true"
|
||||||
>
|
>
|
||||||
<el-table
|
<el-table
|
||||||
:data="skuForm.skuList"
|
:data="skuForm.skuList"
|
||||||
:span-method="handleCellMerge"
|
:span-method="handleCellMerge"
|
||||||
size="mini"
|
highlight-current-row
|
||||||
fit highlight-current-row border
|
size="mini"
|
||||||
|
fit
|
||||||
|
border
|
||||||
>
|
>
|
||||||
|
|
||||||
<el-table-column
|
<el-table-column
|
||||||
v-for="(title,index) in specTitleList"
|
v-for="(title,index) in specTitles"
|
||||||
align="center"
|
align="center"
|
||||||
:prop="'specValue'+(index+1)"
|
:prop="'specValue'+(index+1)"
|
||||||
:label="title">
|
:label="title">
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|
||||||
<el-table-column
|
<el-table-column
|
||||||
label="商品编码"
|
label="商品编码"
|
||||||
align="center"
|
align="center"
|
||||||
>
|
>
|
||||||
<template slot-scope="scope">
|
<template #default="scope">
|
||||||
<el-form-item :prop="'skuList['+scope.$index+'].sn'" :rules="rules.sku.sn">
|
<el-form-item :prop="'skuList['+scope.$index+'].sn'" :rules="rules.sku.sn">
|
||||||
<el-input v-model="scope.row.sn"/>
|
<el-input v-model="scope.row.sn"/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|
||||||
<el-table-column label="价格" align="center">
|
<el-table-column label="价格" align="center">
|
||||||
<template slot-scope="scope">
|
<template #default="scope">
|
||||||
<el-form-item :prop="'skuList['+scope.$index+'].price'" :rules="rules.sku.price">
|
<el-form-item :prop="'skuList['+scope.$index+'].price'" :rules="rules.sku.price">
|
||||||
<el-input v-model="scope.row.price"/>
|
<el-input v-model="scope.row.price"/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|
||||||
<el-table-column label="库存" align="center">
|
<el-table-column label="库存" align="center">
|
||||||
<template slot-scope="scope">
|
<template #default="scope">
|
||||||
<el-form-item :prop="'skuList['+scope.$index+'].stock'" :rules="rules.sku.stock">
|
<el-form-item :prop="'skuList['+scope.$index+'].stock'" :rules="rules.sku.stock">
|
||||||
<el-input v-model="scope.row.stock"/>
|
<el-input v-model="scope.row.stock"/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|
||||||
</el-table>
|
</el-table>
|
||||||
</el-form>
|
</el-form>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
@ -139,343 +148,420 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script setup lang="ts">
|
||||||
import {listAttribute} from "@/api/pms/attribute";
|
import {listAttributes} from "@/api/pms/attribute";
|
||||||
import MiniCardUpload from '@/components/Upload/MiniCardUpload'
|
import MiniCardUpload from '@/components/Upload/MiniCardUpload.vue'
|
||||||
import Sortable from "sortablejs";
|
import Sortable from 'sortablejs'
|
||||||
import {addGoods, updateGoods} from "@/api/pms/goods";
|
import {addGoods, updateGoods} from "@/api/pms/goods";
|
||||||
|
import {computed, getCurrentInstance, nextTick, onMounted, reactive, ref, toRefs, unref, watch} from "vue";
|
||||||
|
import {ElMessage, ElTable, ElForm} from "element-plus"
|
||||||
|
import {useRouter} from "vue-router";
|
||||||
|
|
||||||
|
const emit = defineEmits(['prev', 'next'])
|
||||||
|
|
||||||
export default {
|
const proxy = getCurrentInstance() as any
|
||||||
name: "GoodsStock",
|
const router = useRouter()
|
||||||
components: {MiniCardUpload},
|
|
||||||
props: {
|
const specTableRef = ref(ElTable)
|
||||||
value: Object
|
const specFormRef = ref(ElForm)
|
||||||
|
const skuFormRef = ref(ElForm)
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
modelValue: {
|
||||||
|
type: Object,
|
||||||
|
default: {}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const categoryId = computed(() => props.modelValue.categoryId);
|
||||||
|
|
||||||
|
const state = reactive({
|
||||||
|
specForm: {
|
||||||
|
specList: [] as Array<any>,
|
||||||
},
|
},
|
||||||
watch: {
|
skuForm: {
|
||||||
// 监听选择的商品分类关联商品属性项
|
skuList: []
|
||||||
'value.categoryId': {
|
},
|
||||||
handler(newVal, oldVal) {
|
// 规格项表格标题
|
||||||
listAttribute({categoryId: newVal, type: 1}).then(res => {
|
specTitles: [],
|
||||||
res.data.forEach(item => {
|
rules: {
|
||||||
console.log('规格项目', item)
|
spec: {
|
||||||
this.specForm.specList.push({
|
name: [{required: true, message: '请输入规格名称', trigger: 'blur'}],
|
||||||
name: item.name,
|
value: [{required: true, message: '请输入规格值', trigger: 'blur'}]
|
||||||
values: []
|
},
|
||||||
|
sku: {
|
||||||
|
sn: [{required: true, message: '请输入商品编号', trigger: 'blur'}],
|
||||||
|
price: [{required: true, message: '请输入商品价格', trigger: 'blur'}],
|
||||||
|
stock: [{required: true, message: '请输入商品库存', trigger: 'blur'}],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
colors: ['', 'success', 'warning', 'danger'],
|
||||||
|
tagInputs: [{value: undefined, visible: false}], // 规格值标签临时值和显隐控制
|
||||||
|
loading: undefined
|
||||||
|
})
|
||||||
|
|
||||||
|
const {specForm, skuForm, specTitles, rules, colors, tagInputs, loading} = toRefs(state)
|
||||||
|
|
||||||
|
watch(categoryId, (newVal, oldVal) => {
|
||||||
|
if (newVal) {
|
||||||
|
// type=1 商品规格(销售属性)
|
||||||
|
listAttributes({categoryId: newVal, type: 1}).then(response => {
|
||||||
|
const specList = response.data
|
||||||
|
if (specList && specList.length > 0) {
|
||||||
|
specList.forEach((item: any) => {
|
||||||
|
state.specForm.specList.push({
|
||||||
|
name: item.name,
|
||||||
|
values: []
|
||||||
|
})
|
||||||
})
|
})
|
||||||
this.loadData()
|
|
||||||
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
// 包装一层用于表单验证
|
|
||||||
specForm: {
|
|
||||||
specList: [],
|
|
||||||
},
|
|
||||||
skuForm: {
|
|
||||||
skuList: []
|
|
||||||
},
|
|
||||||
specTitleList: [], // 规格项表格标题
|
|
||||||
rules: {
|
|
||||||
specification: {
|
|
||||||
name: [{required: true, message: '请输入规格名称', trigger: 'blur'}],
|
|
||||||
value: [{required: true, message: '请输入规格值', trigger: 'blur'}]
|
|
||||||
},
|
|
||||||
sku: {
|
|
||||||
sn: [{required: true, message: '请输入商品编号', trigger: 'blur'}],
|
|
||||||
price: [{required: true, message: '请输入商品价格', trigger: 'blur'}],
|
|
||||||
stock: [{required: true, message: '请输入商品库存', trigger: 'blur'}],
|
|
||||||
}
|
|
||||||
},
|
|
||||||
colors: ['', 'success', 'warning', 'danger'],
|
|
||||||
tagInputs: [{value: undefined, visible: false}], // 规格值标签临时值和显隐控制
|
|
||||||
loading: undefined
|
|
||||||
}
|
|
||||||
},
|
|
||||||
created() {
|
|
||||||
if (this.value.id) {
|
|
||||||
this.loadData()
|
|
||||||
}
|
|
||||||
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
async loadData() {
|
|
||||||
this.value.specList.forEach(spec => {
|
|
||||||
const index = this.specForm.specList.findIndex(item => item.name == spec.name)
|
|
||||||
if (index > -1) {
|
|
||||||
this.specForm.specList[index].values.push({id: spec.id, value: spec.value, picUrl: spec.picUrl})
|
|
||||||
} else {
|
|
||||||
this.specForm.specList.push({
|
|
||||||
name: spec.name,
|
|
||||||
values: [{id: spec.id, value: spec.value, picUrl: spec.picUrl}]
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
// 每个规格项追加一个添加规格值按钮
|
|
||||||
for (let i = 0; i < this.specForm.specList.length; i++) {
|
|
||||||
this.tagInputs.push({'value': undefined, 'visible': false})
|
|
||||||
}
|
|
||||||
// SKU规格ID拼接字符串处理
|
|
||||||
this.value.skuList.forEach(sku => {
|
|
||||||
sku.specIdArr = sku.specIds.split('_')
|
|
||||||
})
|
|
||||||
|
|
||||||
this.generateSku()
|
|
||||||
this.changeSpec()
|
|
||||||
this.sortSpec()
|
|
||||||
this.$nextTick(() => {
|
|
||||||
this.setSort()
|
|
||||||
})
|
|
||||||
},
|
|
||||||
handleSpecAdd: function () {
|
|
||||||
if (this.specForm.specList.length >= 3) {
|
|
||||||
this.$message.warning('最多支持3组规格')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this.specForm.specList.push({})
|
|
||||||
this.tagInputs.push({'value': undefined, 'visible': false})
|
|
||||||
this.sortSpec()
|
|
||||||
},
|
|
||||||
handleSpecRemove: function (index) {
|
|
||||||
this.specForm.specList.splice(index, 1)
|
|
||||||
this.tagInputs.splice(index, 1)
|
|
||||||
this.generateSku()
|
|
||||||
this.sortSpec()
|
|
||||||
this.changeSpec()
|
|
||||||
},
|
|
||||||
sortSpec: function () {
|
|
||||||
this.specForm.specList.forEach((item, index) => {
|
|
||||||
item.index = index
|
|
||||||
})
|
|
||||||
},
|
|
||||||
handleSpecValueRemove: function (rowIndex, specValueId) {
|
|
||||||
const specList = JSON.parse(JSON.stringify(this.specForm.specList))
|
|
||||||
const removeIndex = specList[rowIndex].values.map(item => item.id).indexOf(specValueId)
|
|
||||||
console.log('removeIndex', removeIndex)
|
|
||||||
|
|
||||||
specList[rowIndex].values.splice(removeIndex, 1)
|
|
||||||
this.specForm.specList = specList
|
|
||||||
this.changeSpec()
|
|
||||||
this.generateSku()
|
|
||||||
},
|
|
||||||
handleSpecValueInput: function (rowIndex) {
|
|
||||||
const currSpecValue = this.tagInputs[rowIndex].value
|
|
||||||
const specValues = this.specForm.specList[rowIndex].values
|
|
||||||
if (specValues && specValues.length > 0 && specValues.map(item => item.value).includes(currSpecValue)) {
|
|
||||||
this.$message.warning("规格值重复,请重新输入")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if (currSpecValue) {
|
|
||||||
if (specValues && specValues.length > 0) {
|
|
||||||
// 临时规格值ID tid_1_1
|
|
||||||
let maxSpecValueIndex = specValues.filter(item => item.id.includes('tid_')).map(item => item.id.split('_')[2]).reduce((acc, curr) => {
|
|
||||||
return acc > curr ? acc : curr
|
|
||||||
}, 0)
|
|
||||||
console.log('maxSpecValueIndex', maxSpecValueIndex)
|
|
||||||
this.specForm.specList[rowIndex].values[specValues.length] = {
|
|
||||||
'value': currSpecValue,
|
|
||||||
'id': 'tid_' + (rowIndex + 1) + '_' + ++maxSpecValueIndex
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.specForm.specList[rowIndex].values = [{'value': currSpecValue, 'id': 'tid_' + (rowIndex + 1) + '_1'}]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.tagInputs[rowIndex].value = undefined
|
|
||||||
this.tagInputs[rowIndex].visible = false
|
|
||||||
|
|
||||||
// 生成SKU列表
|
|
||||||
this.generateSku()
|
|
||||||
},
|
|
||||||
handleSpecValueAdd: function (rowIndex) {
|
|
||||||
this.tagInputs[rowIndex].visible = true
|
|
||||||
},
|
|
||||||
setSort() {
|
|
||||||
const el = this.$refs.specTable.$el.querySelectorAll('.el-table__body-wrapper > table > tbody')[0]
|
|
||||||
Sortable.create(el, {
|
|
||||||
ghostClass: 'sortable-ghost', // Class name for the drop placeholder,
|
|
||||||
setData: function (dataTransfer) {
|
|
||||||
dataTransfer.setData('Text', '')
|
|
||||||
},
|
|
||||||
onEnd: evt => {
|
|
||||||
// oldIndex 拖拽行当前所在索引
|
|
||||||
// newIndex 拖拽行目标索引
|
|
||||||
const targetRow = this.specForm.specList.splice(evt.oldIndex, 1)[0] // 返回被删除的行
|
|
||||||
this.specForm.specList.splice(evt.newIndex, 0, targetRow) // 拼接
|
|
||||||
this.generateSku() // 重新生成sku
|
|
||||||
this.sortSpec()
|
|
||||||
this.changeSpec()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
generateSku: function () {
|
|
||||||
// [
|
|
||||||
// { 'id':1,'name':'颜色','values':[{id:1,value:'白色'},{id:2,value:'黑色'},{id:3,value:'蓝色'}] },
|
|
||||||
// { 'id':2,'name':'版本','values':[{id:1,value:'6+128G'},{id:2,value:'8+128G'},{id:3,value:'8G+256G'}] }
|
|
||||||
// ]
|
|
||||||
const specList = JSON.parse(JSON.stringify(this.specForm.specList.filter(item => item.values.length > 0))) // 深拷贝,取有属性的规格项,否则笛卡尔积运算得到的SKU列表值为空
|
|
||||||
|
|
||||||
const skuList = specList.reduce((acc, curr) => {
|
|
||||||
let result = []
|
|
||||||
acc.forEach(item => {
|
|
||||||
// curr => { 'id':1,'name':'颜色','values':[{id:1,value:'白色'},{id:2,value:'黑色'},{id:3,value:'蓝色'}] }
|
|
||||||
curr.values.forEach(v => { // v=>{id:1,value:'白色'}
|
|
||||||
let temp = Object.assign({}, item)
|
|
||||||
temp.specValues += v.value + '_' // 规格值拼接
|
|
||||||
temp.specIds += v.id + '|' // 规格ID拼接
|
|
||||||
result.push(temp)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
return result
|
|
||||||
}, [{specValues: '', specIds: ''}])
|
|
||||||
|
|
||||||
skuList.forEach(item => {
|
|
||||||
item.specIds = item.specIds.substring(0, item.specIds.length - 1)
|
|
||||||
item.name = item.specValues.substring(0, item.specIds.length - 1).replaceAll('_', ' ')
|
|
||||||
const specIdArr = item.specIds.split('|')
|
|
||||||
const skus = this.value.skuList.filter(sku => sku.specIdArr.equals(specIdArr)) // 数据库的SKU列表
|
|
||||||
if (skus && skus.length > 0) {
|
|
||||||
const sku = skus[0]
|
|
||||||
item.id = sku.id
|
|
||||||
item.sn = sku.sn
|
|
||||||
item.price = sku.price / 100
|
|
||||||
item.stock = sku.stock
|
|
||||||
}
|
|
||||||
const specValueArr = item.specValues.substring(0, item.specValues.length - 1).split('_') // ['黑','6+128G','官方标配']
|
|
||||||
specValueArr.forEach((v, i) => {
|
|
||||||
const key = 'specValue' + (i + 1)
|
|
||||||
item[key] = v
|
|
||||||
if (i == 0 && this.specForm.specList.length > 0) {
|
|
||||||
const valueIndex = this.specForm.specList[0].values.findIndex(specValue => specValue.value == v)
|
|
||||||
if (valueIndex > -1) {
|
|
||||||
item.picUrl = this.specForm.specList[0].values[valueIndex].picUrl
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
immediate: true,
|
||||||
|
deep: true
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
function loadData() {
|
||||||
|
const goodsId = props.modelValue.id
|
||||||
|
// 编辑数据加载
|
||||||
|
if (goodsId) {
|
||||||
|
props.modelValue.specList.forEach((specItem: any) => {
|
||||||
|
const specIndex = state.specForm.specList.findIndex(item => item.name == specItem.name)
|
||||||
|
if (specIndex > -1) {
|
||||||
|
state.specForm.specList[specIndex].values.push({
|
||||||
|
id: specItem.id,
|
||||||
|
value: specItem.value,
|
||||||
|
picUrl: specItem.picUrl
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
state.specForm.specList.push({
|
||||||
|
name: specItem.name,
|
||||||
|
values: [{id: specItem.id, value: specItem.value, picUrl: specItem.picUrl}]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 每个规格项追加一个添加规格值按钮
|
||||||
|
for (let i = 0; i < state.specForm.specList.length; i++) {
|
||||||
|
state.tagInputs.push({'value': undefined, 'visible': false})
|
||||||
|
}
|
||||||
|
|
||||||
|
// SKU规格ID拼接字符串处理
|
||||||
|
props.modelValue.skuList.forEach((sku: any) => {
|
||||||
|
sku.specIdArr = sku.specIds.split('_')
|
||||||
|
})
|
||||||
|
|
||||||
|
generateSkuList()
|
||||||
|
|
||||||
|
handleSpecChange()
|
||||||
|
|
||||||
|
handleSpecReorder()
|
||||||
|
|
||||||
|
nextTick(() => {
|
||||||
|
registerSpecDragSortEvent()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成SKU列表的title
|
||||||
|
*/
|
||||||
|
function handleSpecChange() {
|
||||||
|
const specList = JSON.parse(JSON.stringify(state.specForm.specList))
|
||||||
|
state.specTitles = specList.map((item: any) => item.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 规格列表重排序
|
||||||
|
*/
|
||||||
|
function handleSpecReorder() {
|
||||||
|
state.specForm.specList.forEach((item, index) => {
|
||||||
|
item.index = index
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册拖拽排序事件
|
||||||
|
*/
|
||||||
|
function registerSpecDragSortEvent() {
|
||||||
|
const el = specTableRef.value.$el.querySelectorAll('.el-table__body-wrapper > table > tbody')[0]
|
||||||
|
Sortable.create(el, {
|
||||||
|
ghostClass: 'sortable-ghost', // Class name for the drop placeholder,
|
||||||
|
setData: function (dataTransfer: any) {
|
||||||
|
dataTransfer.setData('Text', '')
|
||||||
|
},
|
||||||
|
onEnd: (evt: any) => {
|
||||||
|
// oldIndex 拖拽行当前所在索引
|
||||||
|
// newIndex 拖拽行目标索引
|
||||||
|
const targetRow = state.specForm.specList.splice(evt.oldIndex, 1)[0] // 返回被删除的行
|
||||||
|
state.specForm.specList.splice(evt.newIndex, 0, targetRow) // 拼接
|
||||||
|
generateSkuList() // 重新生成sku
|
||||||
|
handleSpecChange()
|
||||||
|
handleSpecReorder()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据商品规格笛卡尔积生成SKU列表
|
||||||
|
*
|
||||||
|
* 规格列表:
|
||||||
|
* [
|
||||||
|
* { 'id':1,'name':'颜色','values':[{id:1,value:'白色'},{id:2,value:'黑色'},{id:3,value:'蓝色'}] },
|
||||||
|
* { 'id':2,'name':'版本','values':[{id:1,value:'6+128G'},{id:2,value:'8+128G'},{id:3,value:'8G+256G'}] }
|
||||||
|
* ]
|
||||||
|
*/
|
||||||
|
function generateSkuList() {
|
||||||
|
const specList = JSON.parse(JSON.stringify(state.specForm.specList.filter(item => item.values.length > 0))) // 深拷贝,取有属性的规格项,否则笛卡尔积运算得到的SKU列表值为空
|
||||||
|
const skuList = specList.reduce((acc: any, curr: any) => {
|
||||||
|
let result = [] as any
|
||||||
|
acc.forEach((item: any) => {
|
||||||
|
// curr => { 'id':1,'name':'颜色','values':[{id:1,value:'白色'},{id:2,value:'黑色'},{id:3,value:'蓝色'}] }
|
||||||
|
curr.values.forEach((v: any) => { // v=>{id:1,value:'白色'}
|
||||||
|
let temp = Object.assign({}, item)
|
||||||
|
temp.specValues += v.value + '_' // 规格值拼接
|
||||||
|
temp.specIds += v.id + '|' // 规格ID拼接
|
||||||
|
result.push(temp)
|
||||||
})
|
})
|
||||||
this.skuForm.skuList = JSON.parse(JSON.stringify(skuList))
|
})
|
||||||
},
|
return result
|
||||||
changeSpec: function () {
|
}, [{specValues: '', specIds: ''}])
|
||||||
const specList = JSON.parse(JSON.stringify(this.specForm.specList))
|
|
||||||
this.specTitleList = specList.map(item => item.name)
|
skuList.forEach((item: any) => {
|
||||||
},
|
item.specIds = item.specIds.substring(0, item.specIds.length - 1)
|
||||||
/**
|
item.name = item.specValues.substring(0, item.specIds.length - 1).replaceAll('_', ' ')
|
||||||
* 合并规格值单元格
|
const specIdArr = item.specIds.split('|')
|
||||||
*/
|
const skus = props.modelValue.skuList.filter((sku: any) =>
|
||||||
handleCellMerge({row, column, rowIndex, columnIndex}) {
|
sku.specIdArr.length === specIdArr.length &&
|
||||||
let mergeRows = [1, 1, 1] // 分别对应规格1、规格2、规格3列合并的行数
|
sku.specIdArr.every((a: number) => specIdArr.some((b: number) => a === b)) &&
|
||||||
const specLen = this.specForm.specList.filter(item => item.values && item.values.length > 0).length
|
specIdArr.every((x: number) => sku.specIdArr.some((y: number) => x === y))
|
||||||
if (specLen == 2) {
|
) // 数据库的SKU列表
|
||||||
const values_len_2 = this.specForm.specList[1].values ? this.specForm.specList[1].values.length : 1 // 第2个规格项的规格值的数量
|
|
||||||
mergeRows = [values_len_2, 1, 1]
|
if (skus && skus.length > 0) {
|
||||||
} else if (specLen == 3) {
|
const sku = skus[0]
|
||||||
const values_len_2 = this.specForm.specList[1].values ? this.specForm.specList[1].values.length : 1 // 第2个规格项的规格值的数量
|
item.id = sku.id
|
||||||
const values_len_3 = this.specForm.specList[2].values ? this.specForm.specList[2].values.length : 1 // 第3个规格项的规格值的数量
|
item.sn = sku.sn
|
||||||
mergeRows = [values_len_2 * values_len_3, values_len_3, 1]
|
item.price = sku.price / 100
|
||||||
}
|
item.stock = sku.stock
|
||||||
if (columnIndex == 0) {
|
}
|
||||||
if (rowIndex % mergeRows[0] === 0) {
|
const specValueArr = item.specValues.substring(0, item.specValues.length - 1).split('_') // ['黑','6+128G','官方标配']
|
||||||
return [mergeRows[0], 1]// 合并单元格
|
specValueArr.forEach((v: any, i: any) => {
|
||||||
} else {
|
const key = 'specValue' + (i + 1)
|
||||||
return [0, 0] // 隐藏单元格
|
item[key] = v
|
||||||
|
if (i == 0 && state.specForm.specList.length > 0) {
|
||||||
|
const valueIndex = state.specForm.specList[0].values.findIndex((specValue: any) => specValue.value == v)
|
||||||
|
if (valueIndex > -1) {
|
||||||
|
item.picUrl = state.specForm.specList[0].values[valueIndex].picUrl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (columnIndex == 1) {
|
})
|
||||||
if (rowIndex % mergeRows[1] === 0) {
|
})
|
||||||
return [mergeRows[1], 1]// 合并单元格
|
state.skuForm.skuList = JSON.parse(JSON.stringify(skuList))
|
||||||
} else {
|
}
|
||||||
return [0, 0] // 隐藏单元格
|
|
||||||
}
|
/**
|
||||||
|
* 添加规格
|
||||||
|
*/
|
||||||
|
function handleSpecAdd() {
|
||||||
|
if (state.specForm.specList.length >= 3) {
|
||||||
|
ElMessage.warning('最多支持3组规格')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
state.specForm.specList.push({})
|
||||||
|
state.tagInputs.push({'value': undefined, 'visible': false})
|
||||||
|
handleSpecReorder()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除规格
|
||||||
|
* @param index
|
||||||
|
*/
|
||||||
|
function handleSpecRemove(index: number) {
|
||||||
|
state.specForm.specList.splice(index, 1)
|
||||||
|
state.tagInputs.splice(index, 1)
|
||||||
|
generateSkuList()
|
||||||
|
handleSpecReorder()
|
||||||
|
handleSpecChange()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加规格值
|
||||||
|
*
|
||||||
|
* @param specIndex
|
||||||
|
*/
|
||||||
|
function handleSpecValueAdd(specIndex: number) {
|
||||||
|
state.tagInputs[specIndex].visible = true
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除规格值
|
||||||
|
*
|
||||||
|
* @param rowIndex
|
||||||
|
* @param specValueId
|
||||||
|
*/
|
||||||
|
function handleSpecValueRemove(rowIndex: number, specValueId: number) {
|
||||||
|
const specList = JSON.parse(JSON.stringify(state.specForm.specList))
|
||||||
|
const removeIndex = specList[rowIndex].values.map((item: any) => item.id).indexOf(specValueId)
|
||||||
|
specList[rowIndex].values.splice(removeIndex, 1)
|
||||||
|
state.specForm.specList = specList
|
||||||
|
handleSpecChange()
|
||||||
|
handleSpecReorder()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 规格值输入
|
||||||
|
*/
|
||||||
|
function handleSpecValueInput(rowIndex: number) {
|
||||||
|
const currSpecValue = state.tagInputs[rowIndex].value
|
||||||
|
const specValues = state.specForm.specList[rowIndex].values
|
||||||
|
if (specValues && specValues.length > 0 && specValues.map((item: any) => item.value).includes(currSpecValue)) {
|
||||||
|
ElMessage.warning("规格值重复,请重新输入")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if (currSpecValue) {
|
||||||
|
if (specValues && specValues.length > 0) {
|
||||||
|
// 临时规格值ID tid_1_1
|
||||||
|
let maxSpecValueIndex = specValues.filter((item: any) => item.id.includes('tid_')).map((item: any) => item.id.split('_')[2]).reduce((acc: any, curr: any) => {
|
||||||
|
return acc > curr ? acc : curr
|
||||||
|
}, 0)
|
||||||
|
console.log('maxSpecValueIndex', maxSpecValueIndex)
|
||||||
|
state.specForm.specList[rowIndex].values[specValues.length] = {
|
||||||
|
'value': currSpecValue,
|
||||||
|
'id': 'tid_' + (rowIndex + 1) + '_' + ++maxSpecValueIndex
|
||||||
}
|
}
|
||||||
},
|
} else {
|
||||||
handlePrev: function () {
|
state.specForm.specList[rowIndex].values = [{'value': currSpecValue, 'id': 'tid_' + (rowIndex + 1) + '_1'}]
|
||||||
this.$emit('prev')
|
}
|
||||||
},
|
}
|
||||||
handleSubmit: function () {
|
state.tagInputs[rowIndex].value = undefined
|
||||||
this.$refs.specForm.validate((specValid) => {
|
state.tagInputs[rowIndex].visible = false
|
||||||
if (specValid) {
|
generateSkuList()
|
||||||
this.$refs.skuForm.validate((skuValid) => {
|
}
|
||||||
if (skuValid) {
|
|
||||||
this.openFullScreen()
|
|
||||||
let submitGoodsData = Object.assign({}, this.value)
|
|
||||||
delete submitGoodsData.specList
|
|
||||||
delete submitGoodsData.skuList
|
|
||||||
|
|
||||||
let specList = []
|
/**
|
||||||
this.specForm.specList.forEach(item => {
|
* 合并规格单元格
|
||||||
item.values.forEach(value => {
|
*
|
||||||
value.name = item.name
|
* @param cellObj 单元格对象
|
||||||
})
|
*/
|
||||||
specList = specList.concat(item.values)
|
function handleCellMerge(cellObj: any) {
|
||||||
})
|
const {rowIndex, columnIndex} = cellObj
|
||||||
submitGoodsData.specList = specList // 规格列表
|
let mergeRows = [1, 1, 1] // 分别对应规格1、规格2、规格3列合并的行数
|
||||||
|
const specLen = state.specForm.specList.filter(item => item.values && item.values.length > 0).length
|
||||||
submitGoodsData.price *= 100 // 金额转成分保存至数据库
|
if (specLen == 2) {
|
||||||
submitGoodsData.originPrice *= 100
|
const values_len_2 = state.specForm.specList[1].values ? state.specForm.specList[1].values.length : 1 // 第2个规格项的规格值的数量
|
||||||
|
mergeRows = [values_len_2, 1, 1]
|
||||||
let skuList = JSON.parse(JSON.stringify(this.skuForm.skuList))
|
} else if (specLen == 3) {
|
||||||
skuList.map(item => {
|
const values_len_2 = state.specForm.specList[1].values ? state.specForm.specList[1].values.length : 1 // 第2个规格项的规格值的数量
|
||||||
item.price *= 100
|
const values_len_3 = state.specForm.specList[2].values ? state.specForm.specList[2].values.length : 1 // 第3个规格项的规格值的数量
|
||||||
return item
|
mergeRows = [values_len_2 * values_len_3, values_len_3, 1]
|
||||||
})
|
}
|
||||||
submitGoodsData.skuList = skuList
|
if (columnIndex == 0) {
|
||||||
console.log('提交数据', submitGoodsData)
|
if (rowIndex % mergeRows[0] === 0) {
|
||||||
const goodsId = this.value.id
|
return [mergeRows[0], 1]// 合并单元格
|
||||||
if (goodsId) { // 编辑商品提交
|
} else {
|
||||||
updateGoods(goodsId, submitGoodsData).then((res) => {
|
return [0, 0] // 隐藏单元格
|
||||||
this.$router.push({path: '/pms/goods'})
|
}
|
||||||
this.$notify.success('修改商品成功')
|
}
|
||||||
this.closeFullScreen()
|
if (columnIndex == 1) {
|
||||||
}, (err) => {
|
if (rowIndex % mergeRows[1] === 0) {
|
||||||
this.closeFullScreen()
|
return [mergeRows[1], 1]// 合并单元格
|
||||||
}
|
} else {
|
||||||
)
|
return [0, 0] // 隐藏单元格
|
||||||
} else { // 新增商品提交
|
|
||||||
addGoods(submitGoodsData).then(response => {
|
|
||||||
this.$router.push({path: '/pms/goods'})
|
|
||||||
this.$notify.success('新增商品成功')
|
|
||||||
this.closeFullScreen()
|
|
||||||
}, (err) => {
|
|
||||||
this.closeFullScreen()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
openFullScreen: function () {
|
|
||||||
this.loading = this.$loading({
|
|
||||||
lock: true,
|
|
||||||
text: '商品信息提交中,请等待...',
|
|
||||||
spinner: 'el-icon-loading',
|
|
||||||
background: 'rgba(0, 0, 0, 0.7)'
|
|
||||||
});
|
|
||||||
},
|
|
||||||
closeFullScreen: function () {
|
|
||||||
if (this.loading) {
|
|
||||||
this.loading.close()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 重写数组equals方法,数组元素完全相同不论顺序
|
* 商品表单提交
|
||||||
* @param target
|
|
||||||
* @returns {boolean}
|
|
||||||
*/
|
*/
|
||||||
Array.prototype.equals = function (target) {
|
function submitForm() {
|
||||||
return this.length === target.length &&
|
const specForm = unref(specFormRef)
|
||||||
this.every(a => target.some(b => a === b)) &&
|
specForm.validate((specValid: boolean) => {
|
||||||
target.every(x => this.some(y => x === y));
|
if (specValid) {
|
||||||
|
const skuForm = unref(skuFormRef)
|
||||||
|
skuForm.validate((skuValid: boolean) => {
|
||||||
|
if (skuValid) {
|
||||||
|
openFullScreen()
|
||||||
|
let submitsData = Object.assign({}, props.modelValue)
|
||||||
|
delete submitsData.specList
|
||||||
|
delete submitsData.skuList
|
||||||
|
|
||||||
|
let specList = [] as Array<any>
|
||||||
|
state.specForm.specList.forEach(item => {
|
||||||
|
item.values.forEach((value: any) => {
|
||||||
|
value.name = item.name
|
||||||
|
})
|
||||||
|
specList = specList.concat(item.values)
|
||||||
|
})
|
||||||
|
submitsData.specList = specList // 规格列表
|
||||||
|
|
||||||
|
submitsData.price *= 100 // 金额转成分保存至数据库
|
||||||
|
submitsData.originPrice *= 100
|
||||||
|
|
||||||
|
let skuList = JSON.parse(JSON.stringify(state.skuForm.skuList))
|
||||||
|
skuList.map((item: any) => {
|
||||||
|
item.price *= 100
|
||||||
|
return item
|
||||||
|
})
|
||||||
|
submitsData.skuList = skuList
|
||||||
|
console.log('提交数据', submitsData)
|
||||||
|
const goodsId = props.modelValue.id
|
||||||
|
if (goodsId) { // 编辑商品提交
|
||||||
|
updateGoods(goodsId, submitsData).then((res) => {
|
||||||
|
router.push({path: '/pms/good'})
|
||||||
|
proxy.$notify.success('修改商品成功')
|
||||||
|
closeFullScreen()
|
||||||
|
}, (err) => {
|
||||||
|
closeFullScreen()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
} else { // 新增商品提交
|
||||||
|
addGoods(submitsData).then(response => {
|
||||||
|
router.push({path: '/pms/good'})
|
||||||
|
proxy.$notify.success('新增商品成功')
|
||||||
|
closeFullScreen()
|
||||||
|
}, (err) => {
|
||||||
|
closeFullScreen()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function openFullScreen() {
|
||||||
|
state.loading = proxy.$loading({
|
||||||
|
lock: true,
|
||||||
|
text: '商品信息提交中,请等待...',
|
||||||
|
spinner: 'el-icon-loading',
|
||||||
|
background: 'rgba(0, 0, 0, 0.7)'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeFullScreen() {
|
||||||
|
if (state.loading) {
|
||||||
|
(state.loading as any).close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handlePrev() {
|
||||||
|
emit('prev')
|
||||||
|
}
|
||||||
|
|
||||||
|
function handNext() {
|
||||||
|
emit('next')
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
loadData()
|
||||||
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|
@ -496,8 +582,7 @@ Array.prototype.equals = function (target) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-form-item--mini.el-form-item{
|
.el-form-item--mini.el-form-item {
|
||||||
margin-top: 18px;
|
margin-top: 18px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
-->
|
|
||||||
|
|
|
||||||
|
|
@ -78,6 +78,7 @@ export default {
|
||||||
methods: {
|
methods: {
|
||||||
loadData() {
|
loadData() {
|
||||||
const goodsId = this.$route.query.goodsId
|
const goodsId = this.$route.query.goodsId
|
||||||
|
console.log('goodsId',goodsId)
|
||||||
if (goodsId) {
|
if (goodsId) {
|
||||||
getGoodsDetail(goodsId).then(response => {
|
getGoodsDetail(goodsId).then(response => {
|
||||||
this.goods = response.data
|
this.goods = response.data
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@
|
||||||
|
|
||||||
<el-table
|
<el-table
|
||||||
v-loading="loading"
|
v-loading="loading"
|
||||||
ref="multipleTable"
|
ref="dataTableRef"
|
||||||
:data="pageList"
|
:data="pageList"
|
||||||
@selection-change="handleSelectionChange"
|
@selection-change="handleSelectionChange"
|
||||||
@row-click="handleRowClick"
|
@row-click="handleRowClick"
|
||||||
|
|
@ -87,12 +87,12 @@
|
||||||
<el-table-column label="操作" width="120">
|
<el-table-column label="操作" width="120">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-button
|
<el-button
|
||||||
@click="handleUpdate(scope.row)"
|
|
||||||
type="primary"
|
type="primary"
|
||||||
:icon="Edit"
|
:icon="Edit"
|
||||||
size="mini"
|
size="mini"
|
||||||
circle
|
circle
|
||||||
plain
|
plain
|
||||||
|
@click.stop="handleUpdate(scope.row)"
|
||||||
/>
|
/>
|
||||||
<el-button
|
<el-button
|
||||||
type="danger"
|
type="danger"
|
||||||
|
|
@ -100,7 +100,7 @@
|
||||||
size="mini"
|
size="mini"
|
||||||
circle
|
circle
|
||||||
plain
|
plain
|
||||||
@click="handleDelete(scope.row)"
|
@click.stop="handleDelete(scope.row)"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|
@ -121,12 +121,16 @@
|
||||||
import {Search, Plus, Edit, Refresh, Delete} from '@element-plus/icons'
|
import {Search, Plus, Edit, Refresh, Delete} from '@element-plus/icons'
|
||||||
import {listGoodsWithPage, deleteGoods} from '@/api/pms/goods'
|
import {listGoodsWithPage, deleteGoods} from '@/api/pms/goods'
|
||||||
import {listCascadeCategories} from '@/api/pms/category'
|
import {listCascadeCategories} from '@/api/pms/category'
|
||||||
import {reactive, ref, onMounted, toRefs} from 'vue'
|
import {reactive, ref, onMounted, toRefs, unref} from 'vue'
|
||||||
import {ElMessage, ElMessageBox, ElTree} from 'element-plus'
|
import {ElTable, ElMessage, ElMessageBox, ElTree} from 'element-plus'
|
||||||
import {getCurrentInstance} from 'vue'
|
import {getCurrentInstance} from 'vue'
|
||||||
import {moneyFormatter} from '@/utils/filter'
|
import {moneyFormatter} from '@/utils/filter'
|
||||||
|
|
||||||
const {proxy}: any = getCurrentInstance();
|
const dataTableRef = ref(ElTable)
|
||||||
|
|
||||||
|
import {useRouter} from "vue-router"
|
||||||
|
|
||||||
|
const router=useRouter()
|
||||||
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
// 遮罩层
|
// 遮罩层
|
||||||
|
|
@ -185,18 +189,17 @@ function resetQuery() {
|
||||||
handleQuery()
|
handleQuery()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function handleGoodsView(detail: any) {
|
function handleGoodsView(detail: any) {
|
||||||
state.goodDetail = detail
|
state.goodDetail = detail
|
||||||
state.dialogVisible = true
|
state.dialogVisible = true
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleAdd() {
|
function handleAdd() {
|
||||||
proxy.$router.push({path: 'goods-detail'})
|
router.push({path: 'goods-detail'})
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleUpdate(row: any) {
|
function handleUpdate(row: any) {
|
||||||
proxy.$router.push({path: 'goods-detail', query: {goodsId: row.id,categoryId:row.categoryId}})
|
router.push({path: 'goods-detail', query: {goodsId: row.id, categoryId: row.categoryId}})
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleDelete(row: any) {
|
function handleDelete(row: any) {
|
||||||
|
|
@ -214,7 +217,7 @@ function handleDelete(row: any) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleRowClick(row: any) {
|
function handleRowClick(row: any) {
|
||||||
proxy.$refs.multipleTable.toggleRowSelection(row);
|
dataTableRef.value.toggleRowSelection(row);
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleSelectionChange(selection: any) {
|
function handleSelectionChange(selection: any) {
|
||||||
|
|
|
||||||
|
|
@ -11,10 +11,8 @@
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"lib": ["esnext", "dom"],
|
"lib": ["esnext", "dom"],
|
||||||
|
|
||||||
/* Vite 路径别名报错 */
|
|
||||||
"baseUrl": "./",
|
"baseUrl": "./",
|
||||||
"paths": {
|
"paths": {
|
||||||
"@": ["src"],
|
|
||||||
"@*": ["src/*"],
|
"@*": ["src/*"],
|
||||||
},
|
},
|
||||||
"extends": "./tsconfig.extends.json",
|
"extends": "./tsconfig.extends.json",
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue