feat: 商品SKU编辑

feature/task1.0.0__0514__ch
向文可 3 years ago
parent 5e190cfd4f
commit 118a4affc9

@ -34,6 +34,27 @@ export const remove = (params) => {
});
};
export const searchSkus = (id) => {
return request({
url: '/mall/product/admin/productSku/list/' + id,
method: 'get',
});
};
export const createSkus = (id, data) => {
return request({
url: '/mall/product/admin/productSku/' + id,
method: 'post',
data,
});
};
export const createAndClearSkus = (id, data) => {
return request({
url: '/mall/product/admin/productSku/deleteAllAndAdd/' + id,
method: 'post',
data,
});
};
export const searchAttrs = (id) => {
return request({
url: '/mall/product/admin/productAttributeGroup/' + id,
@ -54,6 +75,13 @@ export const updateAttrs = (data) => {
data,
});
};
export const updateAttrsSort = (data) => {
return request({
url: '/mall/product/admin/productAttributeGroup/updateSort',
method: 'put',
data,
});
};
export const removeAttrs = (params) => {
return request({
url: '/mall/product/admin/productAttributeGroup',
@ -64,7 +92,7 @@ export const removeAttrs = (params) => {
export const searchAttrsValue = (id) => {
return request({
url: '/mall/product/admin/productAttribute/' + id,
url: '/mall/product/admin/productAttribute/list/' + id,
method: 'get',
});
};

@ -21,13 +21,23 @@ const actions = {
}
return res;
},
sort: async (context, data) => {
let res = await api.updateAttrsSort(data);
if (res) {
ElMessage.success('保存成功');
} else {
ElMessage.error('保存失败');
}
return res;
},
remove: async (context, ids) => {
let res = null;
if (!ids.length) {
ElMessage.warning('请选择要删除的数据');
} else {
try {
await ElMessageBox.confirm('数据删除后无法恢复,确定要删除吗?', '危险操作');
let res = await api.removeAttrs({ id: ids.join(',') });
res = await api.removeAttrs({ id: ids.join(',') });
if (res) {
ElMessage.success('删除成功');
} else {
@ -37,6 +47,7 @@ const actions = {
console.info('取消删除', e);
}
}
return res;
},
};
export default {

@ -22,12 +22,13 @@ const actions = {
return res;
},
remove: async (context, ids) => {
let res = null;
if (!ids.length) {
ElMessage.warning('请选择要删除的数据');
} else {
try {
await ElMessageBox.confirm('数据删除后无法恢复,确定要删除吗?', '危险操作');
let res = await api.removeAttrsValue({ id: ids.join(',') });
res = await api.removeAttrsValue({ id: ids.join(',') });
if (res) {
ElMessage.success('删除成功');
} else {
@ -37,6 +38,7 @@ const actions = {
console.info('取消删除', e);
}
}
return res;
},
};
export default {

@ -0,0 +1,30 @@
import * as api from '@/api/sales/product.js';
import { ElMessage } from '@/plugins/element-plus';
const state = () => ({});
const getters = {};
const mutations = {};
const actions = {
search: async (context, id) => {
let res = await api.searchSkus(id);
if (!res) {
ElMessage.error('查询商品SKU列表失败');
}
return res || [];
},
save: async (context, { id, data }) => {
let save = data.every((item) => !item.id) ? api.createAndClearSkus : api.createSkus;
let res = await save(id, data);
if (res) {
ElMessage.success('保存成功');
} else {
ElMessage.error('保存失败');
}
return res;
},
};
export default {
state,
getters,
mutations,
actions,
};

@ -49,19 +49,38 @@
:label="sku.name"
:prop="sku.id + ''"
/>
<el-table-column align="center" header-align="center" label="售价(元)" prop="sales" width="160px">
<el-table-column align="center" header-align="center" label="售价(元)" prop="sellPrice" width="160px">
<template #default="{ row }">
<el-input-number v-model="row.sales" />
<el-input-number v-model="row.sellPrice" />
</template>
</el-table-column>
<el-table-column align="center" header-align="center" label="商品库存" prop="inventory" width="160px">
<el-table-column align="center" header-align="center" label="商品库存" prop="stock" width="160px">
<template #default="{ row }">
<el-input-number v-model="row.inventory" />
<span v-if="row.id">{{ row.stock }}</span>
<el-input-number v-else v-model="row.stock" />
</template>
</el-table-column>
<el-table-column align="center" header-align="center" label="成本价(元)" prop="price" width="160px">
<el-table-column align="center" header-align="center" label="增减库存" prop="stockChange" width="160px">
<template #default="{ row }">
<el-input-number v-model="row.price" />
<el-input-number v-model="row.stockChange" @change="handleStockChange(row)" />
</template>
</el-table-column>
<el-table-column
align="center"
header-align="center"
label="改后库存"
prop="stockAfter"
width="160px"
/>
<el-table-column
align="center"
header-align="center"
label="成本价(元)"
prop="costPrice"
width="160px"
>
<template #default="{ row }">
<el-input-number v-model="row.costPrice" />
</template>
</el-table-column>
<el-table-column align="center" header-align="center" label="库存预警值" prop="warn" width="160px">
@ -70,15 +89,17 @@
</template>
</el-table-column>
<el-table-column align="center" header-align="center" label="SKU编号" min-width="100px" prop="id" />
<el-table-column align="center" header-align="center" label="启用" prop="enabled" width="80px">
<el-table-column align="center" header-align="center" label="启用" prop="isEnable" width="80px">
<template #default="{ row }">
<el-switch v-model="row.enabled" />
<el-switch v-model="row.isEnable" />
</template>
</el-table-column>
</el-table>
</el-scrollbar>
<div class="step-footer">
<el-button type="primary" @click="handleSave"></el-button>
<el-button type="text" @click="handleBack"></el-button>
<el-button plain type="primary" @click="handleSave(false)"></el-button>
<el-button type="primary" @click="handleSave(true)"></el-button>
</div>
</div>
</template>
@ -109,7 +130,17 @@
const id = route.params.id;
if (id && id !== state.form.id) {
state.form.id = id;
let res = await store.dispatch('productAttrsGroup/search', id);
let res = await store.dispatch('productSkus/search', id);
state.form.skuInfos = res.map((item) => {
return {
...item,
name: item.name?.split(',') || [],
attributeSymbolList: item.attributeSymbolList?.split(',') || [],
stockChange: 0,
stockAfter: item.stock,
};
});
res = await store.dispatch('productAttrsGroup/search', id);
let arr = [];
res.forEach((item) => {
arr.push(
@ -134,7 +165,8 @@
attrsGroup.values?.forEach((value) => {
let temp = _.cloneDeep(row);
temp[attrsGroup.id + ''] = value.name;
temp.groups.push(value.id);
temp.attributeSymbolList.push(value.symbol);
temp.name.push(value.name);
res.push(temp);
});
});
@ -143,29 +175,42 @@
}
return res;
},
[{ sales: 0, inventory: 0, price: 0, warn: 100, groups: [] }]
[
{
sellPrice: 0,
stock: 0,
stockChange: 0,
costPrice: 0,
warn: 100,
isEnable: false,
name: [],
attributeSymbolList: [],
},
]
)
.map((info) => {
let row = old.find((item) => item.groups.sort().join() === info.groups.sort().join());
let row = old.find(
(item) =>
item.attributeSymbolList.sort().join() === info.attributeSymbolList.sort().join()
);
if (row) {
Object.assign(info, row);
}
return info;
});
console.info(state.form.skuInfos, old);
},
{ deep: true }
);
const handleAddSku = async () => {
if (state.skuName) {
let res = await store.dispatch('productAttrsGroup', {
let res = await store.dispatch('productAttrsGroup/save', {
name: state.skuName,
productId: route.params.id,
sort: state.form.attrsGroupList.length,
});
if (res) {
state.form.skuInfos = [];
state.form.attrsGroupList.push({ name: state.skuName, values: [] });
state.form.attrsGroupList.push({ id: res, name: state.skuName, values: [] });
state.skuName = null;
} else {
proxy.$message.error('添加属性规格失败');
@ -178,15 +223,17 @@
let res = await store.dispatch('productAttrsGroup/remove', [state.form.attrsGroupList[index].id]);
if (res) {
state.form.attrsGroupList.splice(index, 1);
proxy.$message.success('删除成功');
} else {
proxy.$message.error('删除失败');
}
};
const handleMove = (oldIndex, newIndex) => {
let temp = state.form.attrsGroupList[oldIndex];
state.form.attrsGroupList[oldIndex] = state.form.attrsGroupList[newIndex];
state.form.attrsGroupList[newIndex] = temp;
const handleMove = async (oldSort, currentSort) => {
let temp = state.form.attrsGroupList[oldSort];
let res = await store.dispatch('productAttrsGroup/sort', { id: temp.id, oldSort, currentSort });
if (res) {
state.form.attrsGroupList[oldSort] = state.form.attrsGroupList[currentSort];
state.form.attrsGroupList[currentSort] = temp;
} else {
proxy.$message.error('移动失败');
}
};
const handleAddValue = async (sku, index) => {
let value = state.skuValue[index];
@ -211,36 +258,49 @@
let res = await store.dispatch('productAttrsValue/remove', [sku.values[index].id]);
if (res) {
sku.values.splice(index, 1);
proxy.$message.success('删除成功');
} else {
proxy.$message.error('删除失败');
}
};
const handleSave = async () => {
const handleStockChange = (row) => {
row.stockAfter = row.stock + row.stockChange;
};
const handleBack = () => {
router.push({
name: 'UpdateProduct',
params: {
id: route.params.id,
step: 1,
},
});
};
const handleSave = async (enable) => {
state.loading = true;
try {
await state.refsForm.validate();
router.push({
name: 'UpdateProduct',
params: {
id: route.params.id || state.form.id,
step: 2,
},
if (state.form.skuInfos.length) {
let data = _.cloneDeep(state.form.skuInfos).map((item) => {
return {
...item,
name: item.name.join(','),
attributeSymbolList: item.attributeSymbolList.join(','),
};
});
} catch (e) {
console.info('取消保存', e);
await store.dispatch('productSkus/save', { id: route.params.id, data });
if (enable) {
//
}
await handleLoad();
}
state.loading = false;
};
return {
...toRefs(state),
handleBack,
handleSave,
handleAddSku,
handleDelSku,
handleMove,
handleAddValue,
handleDelValue,
handleStockChange,
};
},
});
@ -251,6 +311,7 @@
display: flex;
flex-direction: column;
overflow: hidden;
width: 100%;
.step-content {
flex: 1;
overflow: auto;

@ -22,6 +22,7 @@ export default (configEnv) => {
'/api': {
// target: 'http://192.168.10.109:8090/', // 显雨
// target: 'http://192.168.10.251:8090', // 高玉
// target: 'http://192.168.10.67:8090', // 罗战
target: 'https://k8s-horse-gateway.mashibing.cn/', // 测试地址
// target: 'https://gateway.mashibing.cn', // 预发地址
// target: 'https://gateway.mashibing.com', // 生产环境

Loading…
Cancel
Save