feat: 商品实体映射数据
This commit is contained in:
parent
86e3825433
commit
0323cb0962
113
src/api/goodsTool.js
Normal file
113
src/api/goodsTool.js
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
import request from "@/utils/request";
|
||||||
|
import { stringify } from "qs";
|
||||||
|
|
||||||
|
export async function getProductMapperList(data) {
|
||||||
|
data = stringify(data);
|
||||||
|
return request({
|
||||||
|
url: `/admin/shop/shop-sync-productMapper/list?${data}`,
|
||||||
|
method: "get",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getShopList() {
|
||||||
|
return request({
|
||||||
|
url: "/admin/shop/shop-store-base/list?pageNum=1&pageSize=99999&store_type=1",
|
||||||
|
method: "get",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function updateGoods(data) {
|
||||||
|
return request({
|
||||||
|
url: "/admin/shop/shop-sync-productMapper/udpateProductMapping",
|
||||||
|
method: "put",
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function deleteGoods(data) {
|
||||||
|
return request({
|
||||||
|
url: "/admin/shop/shop-sync-productMapper/delProductMapping",
|
||||||
|
method: "delete",
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function downloadTempGoods(data) {
|
||||||
|
data = stringify(data);
|
||||||
|
return request({
|
||||||
|
url: `/admin/shop/shop-sync-productMapper/template?${data}`,
|
||||||
|
method: "get",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function batchCreateGoods(data) {
|
||||||
|
return request({
|
||||||
|
url: "/admin/shop/shop-sync-productMapper/saveProductMappingBatch",
|
||||||
|
method: "post",
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function batchExportGoods(data) {
|
||||||
|
return request({
|
||||||
|
url: "/admin/shop/shop-sync-productMapper/exportSelected",
|
||||||
|
method: "post",
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getProductMapping(data) {
|
||||||
|
return request({
|
||||||
|
url: "/admin/shop/shop-sync-productMapper/getProductMapping",
|
||||||
|
method: "post",
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getSyncBaseMapingProducts() {
|
||||||
|
return request({
|
||||||
|
url: "/admin/shop/shop-sync-productMapper/getSyncBaseMapingProducts",
|
||||||
|
method: "get",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function HandleDownloadErrorReport(data) {
|
||||||
|
data = stringify(data);
|
||||||
|
return request({
|
||||||
|
url: `/admin/shop/shop-sync-productMapper/download?${data}`,
|
||||||
|
method: "get",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function syncProductMaping() {
|
||||||
|
return request({
|
||||||
|
url: `/admin/shop/shop-sync-productMapper/syncProductMaping`,
|
||||||
|
method: "put",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function importGoodsData(data) {
|
||||||
|
return request({
|
||||||
|
url: `/admin/shop/shop-sync-productMapper/importData`,
|
||||||
|
method: "post",
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
getProductMapperList,
|
||||||
|
getShopList,
|
||||||
|
updateGoods,
|
||||||
|
deleteGoods,
|
||||||
|
downloadTempGoods,
|
||||||
|
batchCreateGoods,
|
||||||
|
batchExportGoods,
|
||||||
|
getProductMapping,
|
||||||
|
getSyncBaseMapingProducts,
|
||||||
|
HandleDownloadErrorReport,
|
||||||
|
syncProductMaping,
|
||||||
|
importGoodsData,
|
||||||
|
};
|
||||||
@ -13,6 +13,24 @@ import icon from '../views/403.vue'
|
|||||||
*/
|
*/
|
||||||
export function convertRouter(asyncRoutes) {
|
export function convertRouter(asyncRoutes) {
|
||||||
return asyncRoutes.map((route) => {
|
return asyncRoutes.map((route) => {
|
||||||
|
if (route.meta.title == '商品' && route.name == 'Vab320') {
|
||||||
|
const obj = {
|
||||||
|
path: '/goodsTool',
|
||||||
|
component: '@/views/product/goodsTool/index',
|
||||||
|
name: 'Vab88000',
|
||||||
|
redirect: null,
|
||||||
|
meta: {
|
||||||
|
title: '商品映射配置',
|
||||||
|
icon: '',
|
||||||
|
noClosable: 0,
|
||||||
|
hidden: null,
|
||||||
|
},
|
||||||
|
menuHidden: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
route.children.splice(0, 0, obj)
|
||||||
|
}
|
||||||
|
|
||||||
if (route.meta.title == '店铺' && route.name == 'Vab330') {
|
if (route.meta.title == '店铺' && route.name == 'Vab330') {
|
||||||
const obj = {
|
const obj = {
|
||||||
path: '/shopAudit',
|
path: '/shopAudit',
|
||||||
|
|||||||
411
src/views/product/goodsTool/GoodsItem.vue
Normal file
411
src/views/product/goodsTool/GoodsItem.vue
Normal file
@ -0,0 +1,411 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<el-drawer
|
||||||
|
:title="mode === 'add' ? '批量新增商品配置' : '编辑商品配置'"
|
||||||
|
:visible.sync="drawerVisible"
|
||||||
|
direction="rtl"
|
||||||
|
size="50%"
|
||||||
|
:before-close="handleClose"
|
||||||
|
>
|
||||||
|
<div class="fixed-header">
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
icon="el-icon-plus"
|
||||||
|
v-if="mode === 'add'"
|
||||||
|
@click="addNewItem"
|
||||||
|
>添加组</el-button
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="scrollable-content">
|
||||||
|
<el-form :model="batchForm" label-width="80px" ref="batchFormRef">
|
||||||
|
<div
|
||||||
|
v-for="(item, index) in batchForm.items"
|
||||||
|
:key="index"
|
||||||
|
class="product-card"
|
||||||
|
>
|
||||||
|
<div class="card-header">
|
||||||
|
<span>组{{ index + 1 }}</span>
|
||||||
|
<el-button
|
||||||
|
type="danger"
|
||||||
|
size="small"
|
||||||
|
v-if="mode === 'add' || batchForm.items.length > 1"
|
||||||
|
@click="removeItem(index)"
|
||||||
|
>删除</el-button
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-row">
|
||||||
|
<el-form-item
|
||||||
|
:prop="'items.' + index + '.storeId'"
|
||||||
|
:rules="rules.storeId"
|
||||||
|
label="店铺"
|
||||||
|
>
|
||||||
|
<el-select
|
||||||
|
style="width: 100%"
|
||||||
|
v-model="item.storeId"
|
||||||
|
placeholder="选择店铺"
|
||||||
|
filterable
|
||||||
|
clearable
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in shopListData"
|
||||||
|
:key="item.store_id"
|
||||||
|
:label="item.store_name"
|
||||||
|
:value="item.store_id"
|
||||||
|
>
|
||||||
|
</el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item
|
||||||
|
:prop="'items.' + index + '.productName'"
|
||||||
|
:rules="rules.productName"
|
||||||
|
label="商品名称"
|
||||||
|
>
|
||||||
|
<el-input
|
||||||
|
v-model="item.productName"
|
||||||
|
placeholder="请输入商品名称"
|
||||||
|
></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-row">
|
||||||
|
<el-form-item
|
||||||
|
:prop="'items.' + index + '.specValue'"
|
||||||
|
:rules="rules.specValue"
|
||||||
|
label="规格值"
|
||||||
|
>
|
||||||
|
<el-input
|
||||||
|
v-model.number="item.specValue"
|
||||||
|
type="number"
|
||||||
|
placeholder="请输入规格值"
|
||||||
|
></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-row">
|
||||||
|
<el-form-item
|
||||||
|
:prop="'items.' + index + '.specUnit'"
|
||||||
|
:rules="rules.specUnit"
|
||||||
|
label="规格单位"
|
||||||
|
>
|
||||||
|
<el-input
|
||||||
|
v-model="item.specUnit"
|
||||||
|
placeholder="请输入规格单位"
|
||||||
|
></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item
|
||||||
|
:prop="'items.' + index + '.sortOrder'"
|
||||||
|
:rules="rules.sortOrder"
|
||||||
|
label="排序"
|
||||||
|
>
|
||||||
|
<el-input
|
||||||
|
v-model.number="item.sortOrder"
|
||||||
|
type="number"
|
||||||
|
placeholder="请输入排序"
|
||||||
|
></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-row">
|
||||||
|
<el-form-item
|
||||||
|
:prop="'items.' + index + '.description'"
|
||||||
|
:rules="rules.description"
|
||||||
|
label="描述"
|
||||||
|
>
|
||||||
|
<el-input
|
||||||
|
style="display: block"
|
||||||
|
v-model="item.description"
|
||||||
|
type="textarea"
|
||||||
|
:rows="1"
|
||||||
|
placeholder="请输入描述"
|
||||||
|
></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="fixed-footer">
|
||||||
|
<el-button @click="drawerVisible = false">取消</el-button>
|
||||||
|
<el-button type="primary" :loading="loading" @click="submitForm">{{
|
||||||
|
mode === "add" ? "提交" : "保存"
|
||||||
|
}}</el-button>
|
||||||
|
</div>
|
||||||
|
</el-drawer>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import GoodsToolApi from "@/api/goodsTool";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "BatchProductForm",
|
||||||
|
props: {
|
||||||
|
mode: {
|
||||||
|
type: String,
|
||||||
|
default: "add",
|
||||||
|
validator: (value) => ["add", "edit"].includes(value),
|
||||||
|
},
|
||||||
|
initialData: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
shopListData: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
drawerVisible: false,
|
||||||
|
loading: false,
|
||||||
|
batchForm: {
|
||||||
|
items: [],
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
productName: [
|
||||||
|
{ required: true, message: "请输入商品名称", trigger: "blur" },
|
||||||
|
],
|
||||||
|
storeId: [{ required: true, message: "请选择店铺", trigger: "change" }],
|
||||||
|
specValue: [
|
||||||
|
{ required: true, message: "请输入规格值", trigger: "blur" },
|
||||||
|
{ type: "number", message: "规格值必须为数字", trigger: "blur" },
|
||||||
|
],
|
||||||
|
specUnit: [
|
||||||
|
{ required: true, message: "请输入规格单位", trigger: "blur" },
|
||||||
|
],
|
||||||
|
sortOrder: [
|
||||||
|
{ required: true, message: "请输入排序", trigger: "blur" },
|
||||||
|
],
|
||||||
|
description: [
|
||||||
|
{ required: true, message: "请输入描述", trigger: "blur" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
// 监听props变化,更新表单数据
|
||||||
|
initialData: {
|
||||||
|
handler(newVal) {
|
||||||
|
if (this.mode === "edit" && newVal && newVal.length > 0) {
|
||||||
|
// 深拷贝初始数据,避免修改原始数据
|
||||||
|
this.batchForm.items = JSON.parse(JSON.stringify(newVal));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
immediate: true,
|
||||||
|
deep: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// 打开抽屉
|
||||||
|
open() {
|
||||||
|
this.drawerVisible = true;
|
||||||
|
|
||||||
|
// 如果是新增模式,确保有一个空项
|
||||||
|
if (this.mode === "add" && this.batchForm.items.length === 0) {
|
||||||
|
this.addNewItem();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 关闭抽屉前的确认
|
||||||
|
handleClose(done) {
|
||||||
|
if (this.hasUnsavedChanges()) {
|
||||||
|
this.$confirm("确定要关闭吗?未保存的数据将会丢失。", "提示", {
|
||||||
|
confirmButtonText: "确定",
|
||||||
|
cancelButtonText: "取消",
|
||||||
|
type: "warning",
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
done();
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
// 取消关闭
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 检查是否有未保存的更改
|
||||||
|
hasUnsavedChanges() {
|
||||||
|
if (this.mode === "add") {
|
||||||
|
return this.batchForm.items.some(
|
||||||
|
(item) =>
|
||||||
|
item.productName || item.storeId || item.specValue || item.specUnit
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 编辑模式下的比较逻辑
|
||||||
|
if (this.initialData && this.initialData.length > 0) {
|
||||||
|
return (
|
||||||
|
JSON.stringify(this.batchForm.items) !==
|
||||||
|
JSON.stringify(this.initialData)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
|
// 添加新项目
|
||||||
|
addNewItem() {
|
||||||
|
this.batchForm.items.push({
|
||||||
|
productName: "",
|
||||||
|
storeId: "",
|
||||||
|
specValue: "",
|
||||||
|
specUnit: "",
|
||||||
|
description: "",
|
||||||
|
sortOrder: "",
|
||||||
|
});
|
||||||
|
|
||||||
|
// 滚动到底部
|
||||||
|
this.$nextTick(() => {
|
||||||
|
const container = document.querySelector(".scrollable-content");
|
||||||
|
if (container) {
|
||||||
|
container.scrollTop = container.scrollHeight;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
// 删除项目
|
||||||
|
removeItem(index) {
|
||||||
|
if (this.mode === "add" && this.batchForm.items.length > 1) {
|
||||||
|
console.log(111);
|
||||||
|
this.batchForm.items.splice(index, 1);
|
||||||
|
} else {
|
||||||
|
this.$message.warning("至少保留一个商品组配置");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 提交表单
|
||||||
|
submitForm() {
|
||||||
|
this.$refs.batchFormRef.validate(async(valid) => {
|
||||||
|
if (valid) {
|
||||||
|
this.loading = true;
|
||||||
|
|
||||||
|
// 准备提交数据
|
||||||
|
const submitData = this.batchForm.items.map((item) => ({
|
||||||
|
productName: item.productName,
|
||||||
|
storeId: item.storeId,
|
||||||
|
specValue: item.specValue,
|
||||||
|
specUnit: item.specUnit,
|
||||||
|
description: item.description,
|
||||||
|
sortOrder: item.sortOrder,
|
||||||
|
}));
|
||||||
|
|
||||||
|
// 过滤掉空项(新增模式下)
|
||||||
|
const filteredData =
|
||||||
|
this.mode === "add"
|
||||||
|
? submitData.filter(
|
||||||
|
(item) =>
|
||||||
|
item.productName ||
|
||||||
|
item.storeId ||
|
||||||
|
item.specValue ||
|
||||||
|
item.specUnit
|
||||||
|
)
|
||||||
|
: submitData;
|
||||||
|
|
||||||
|
if (filteredData.length === 0) {
|
||||||
|
this.$message.warning("请添加商品配置组数据");
|
||||||
|
this.loading = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
let res = null;
|
||||||
|
if(this.mode=='add'){
|
||||||
|
res = await GoodsToolApi.batchCreateGoods(submitData)
|
||||||
|
}else{
|
||||||
|
res = await GoodsToolApi.updateGoods({
|
||||||
|
...submitData?.[0],
|
||||||
|
id: this.batchForm.items?.[0].id
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if(res.status==200){
|
||||||
|
this.$message.success("操作成功");
|
||||||
|
} else {
|
||||||
|
this.loading = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
this.$message.error("请完善表单信息");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.fixed-header {
|
||||||
|
padding: 0 12px 12px;
|
||||||
|
border-bottom: 1px solid #ebeef5;
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scrollable-content {
|
||||||
|
padding: 12px;
|
||||||
|
height: calc(100vh - 195px);
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fixed-footer {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
padding: 12px;
|
||||||
|
border-top: 1px solid #ebeef5;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.product-card {
|
||||||
|
width: 100%;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
padding: 12px 12px 0;
|
||||||
|
border: 1px solid #dcdfe6;
|
||||||
|
border-radius: 4px;
|
||||||
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
border-bottom: 1px solid #ebeef5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-row {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 10px;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-row .el-form-item {
|
||||||
|
flex: 1 1 calc(33.33% - 12px);
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-row .el-form-item:last-child {
|
||||||
|
flex: 1 1 calc(33.34% - 12px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-row .el-form-item:nth-child(3n) {
|
||||||
|
flex: 1 1 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-row .el-input__inner {
|
||||||
|
height: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-row .el-input--textarea .el-input__inner {
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
396
src/views/product/goodsTool/index.vue
Normal file
396
src/views/product/goodsTool/index.vue
Normal file
@ -0,0 +1,396 @@
|
|||||||
|
<template>
|
||||||
|
<div class="container">
|
||||||
|
<div class="filter">
|
||||||
|
<el-input
|
||||||
|
class="input_item"
|
||||||
|
placeholder="输入商品名称"
|
||||||
|
prefix-icon="el-icon-search"
|
||||||
|
v-model="filter.productName"
|
||||||
|
clearable
|
||||||
|
></el-input>
|
||||||
|
<el-select
|
||||||
|
v-model="filter.storeId"
|
||||||
|
placeholder="选择店铺"
|
||||||
|
filterable
|
||||||
|
clearable
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in shopList"
|
||||||
|
:key="item.store_id"
|
||||||
|
:label="item.store_name"
|
||||||
|
:value="item.store_id"
|
||||||
|
></el-option>
|
||||||
|
</el-select>
|
||||||
|
|
||||||
|
<el-button type="primary" size="medium" @click="getGoodsList">
|
||||||
|
搜索
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="list">
|
||||||
|
<div class="tool">
|
||||||
|
<el-button type="primary" @click="openBatchAdd">批量新增</el-button>
|
||||||
|
|
||||||
|
<el-button
|
||||||
|
type="success"
|
||||||
|
@click="handleExport"
|
||||||
|
:disabled="!selectedRowKeys.length"
|
||||||
|
>
|
||||||
|
导出数据
|
||||||
|
</el-button>
|
||||||
|
|
||||||
|
<el-upload
|
||||||
|
action=""
|
||||||
|
:show-file-list="false"
|
||||||
|
:limit="1"
|
||||||
|
:before-upload="beforeGoodsDataUpload"
|
||||||
|
>
|
||||||
|
<el-button type="warning">导入数据</el-button>
|
||||||
|
</el-upload>
|
||||||
|
|
||||||
|
<el-button type="danger" @click="HandleSyncGoods">同步数据</el-button>
|
||||||
|
|
||||||
|
<el-popover placement="bottom" :width="400" trigger="click">
|
||||||
|
<template slot="reference">
|
||||||
|
<el-button>下载错误报告</el-button>
|
||||||
|
</template>
|
||||||
|
<div>
|
||||||
|
<el-input v-model="errReportFilePath" placeholder="输入文件地址">
|
||||||
|
<template slot="append">
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
size="medium"
|
||||||
|
@click="HandleDownloadErrorReport"
|
||||||
|
>
|
||||||
|
确定
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</el-input>
|
||||||
|
</div>
|
||||||
|
</el-popover>
|
||||||
|
|
||||||
|
<el-button type="info" plain @click="handleSyncProductMaping">
|
||||||
|
自动计算并上架商品
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
<el-table
|
||||||
|
:data="tableData"
|
||||||
|
style="width: 100%"
|
||||||
|
@selection-change="handleSelectionChange"
|
||||||
|
ref="productTable"
|
||||||
|
>
|
||||||
|
<el-table-column type="selection" width="55"></el-table-column>
|
||||||
|
<el-table-column prop="id" label="ID" />
|
||||||
|
<el-table-column prop="storeId" label="店铺ID" />
|
||||||
|
<el-table-column prop="productName" label="商品名称" />
|
||||||
|
<el-table-column prop="description" label="商品描述" />
|
||||||
|
<el-table-column prop="specValue" label="商品规格">
|
||||||
|
<template #default="scope">
|
||||||
|
{{ scope.row.specValue }}{{ scope.row.specUnit }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="操作" width="400">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-button
|
||||||
|
size="mini"
|
||||||
|
type="primary"
|
||||||
|
plain
|
||||||
|
@click="editGoods(scope.row)"
|
||||||
|
>
|
||||||
|
编辑配置
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
size="mini"
|
||||||
|
type="danger"
|
||||||
|
plain
|
||||||
|
@click="handleDelete(scope.row)"
|
||||||
|
>
|
||||||
|
删除配置
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
size="mini"
|
||||||
|
type="info"
|
||||||
|
plain
|
||||||
|
@click="downloadTemplate(scope.row)"
|
||||||
|
>
|
||||||
|
下载模板
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
size="mini"
|
||||||
|
type="success"
|
||||||
|
plain
|
||||||
|
@click="getProductMapping(scope.row)"
|
||||||
|
>
|
||||||
|
店铺商品映射
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
|
||||||
|
<el-pagination
|
||||||
|
background
|
||||||
|
layout="total, sizes, prev, pager, next, jumper"
|
||||||
|
:current-page="pagination.pageNum"
|
||||||
|
:page-size="pagination.pageSize"
|
||||||
|
:total="pagination.total"
|
||||||
|
@current-change="handleCurrentChange"
|
||||||
|
@size-change="handleSizeChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<GoodsItem
|
||||||
|
ref="batchFormRef"
|
||||||
|
:mode="formMode"
|
||||||
|
:initialData="formData"
|
||||||
|
:shopListData="shopList"
|
||||||
|
@success="handleSuccess"
|
||||||
|
></GoodsItem>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import GoodsToolApi from '@/api/goodsTool'
|
||||||
|
import GoodsItem from './GoodsItem.vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
GoodsItem,
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
filter: {
|
||||||
|
productName: '',
|
||||||
|
storeId: '',
|
||||||
|
},
|
||||||
|
pagination: {
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
total: 0,
|
||||||
|
},
|
||||||
|
shopList: [],
|
||||||
|
tableData: [],
|
||||||
|
selectedRowKeys: [],
|
||||||
|
formMode: 'add',
|
||||||
|
formData: [],
|
||||||
|
apiUrl: '/api/products',
|
||||||
|
errReportFilePath: '',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.getShopList()
|
||||||
|
this.getGoodsList()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async getGoodsList() {
|
||||||
|
let res = await GoodsToolApi.getProductMapperList({
|
||||||
|
...this.filter,
|
||||||
|
pageNum: this.pagination.pageNum,
|
||||||
|
pageSize: this.pagination.pageSize,
|
||||||
|
})
|
||||||
|
this.tableData = res.data.items
|
||||||
|
this.pagination.total = res.data.records
|
||||||
|
},
|
||||||
|
|
||||||
|
async getShopList() {
|
||||||
|
let res = await GoodsToolApi.getShopList()
|
||||||
|
this.shopList = res.data.items
|
||||||
|
},
|
||||||
|
|
||||||
|
handleCurrentChange(val) {
|
||||||
|
this.pagination.pageNum = val
|
||||||
|
this.getGoodsList()
|
||||||
|
},
|
||||||
|
|
||||||
|
handleSizeChange(val) {
|
||||||
|
this.pagination.pageSize = val
|
||||||
|
this.getGoodsList()
|
||||||
|
},
|
||||||
|
|
||||||
|
openBatchAdd() {
|
||||||
|
this.formMode = 'add'
|
||||||
|
this.formData = []
|
||||||
|
this.$refs.batchFormRef.open()
|
||||||
|
},
|
||||||
|
|
||||||
|
openBatchEdit() {
|
||||||
|
const selectedProducts = this.tableData.filter((item) => item.selected)
|
||||||
|
|
||||||
|
if (selectedProducts.length === 0) {
|
||||||
|
this.$message.warning('请先选择要编辑的商品')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.formMode = 'edit'
|
||||||
|
this.formData = selectedProducts
|
||||||
|
this.$refs.batchFormRef.open()
|
||||||
|
},
|
||||||
|
|
||||||
|
editGoods(data) {
|
||||||
|
this.formMode = 'edit'
|
||||||
|
this.formData = [data]
|
||||||
|
this.$refs.batchFormRef.open()
|
||||||
|
},
|
||||||
|
|
||||||
|
async getProductMapping(data) {
|
||||||
|
this.$confirm('确定要映射选中的商品配置吗?', '友情提示', {
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'danger',
|
||||||
|
}).then(async () => {
|
||||||
|
console.log(data)
|
||||||
|
const res = await GoodsToolApi.getProductMapping({ id: data.id })
|
||||||
|
if (res.status == 200) {
|
||||||
|
this.$message.success('操作成功')
|
||||||
|
this.getProductMapperList()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
handleSuccess(data) {
|
||||||
|
this.fetchProductList()
|
||||||
|
},
|
||||||
|
|
||||||
|
handleSelectionChange(selection) {
|
||||||
|
this.selectedRowKeys = selection.map((item) => item.id)
|
||||||
|
},
|
||||||
|
|
||||||
|
handleDelete(data) {
|
||||||
|
this.$confirm(
|
||||||
|
'确定要删除选中的商品配置吗?此操作不可撤销。',
|
||||||
|
'友情提示',
|
||||||
|
{
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'danger',
|
||||||
|
}
|
||||||
|
).then(async () => {
|
||||||
|
console.log(data)
|
||||||
|
const res = await GoodsToolApi.deleteGoods({ id: data.id })
|
||||||
|
if (res.status == 200) {
|
||||||
|
this.$message.success('已删除')
|
||||||
|
this.getProductMapperList()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
HandleSyncGoods() {
|
||||||
|
this.$confirm('确定要获取同步未分配的商品数据?', '友情提示', {
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'danger',
|
||||||
|
}).then(async () => {
|
||||||
|
const res = await GoodsToolApi.getSyncBaseMapingProducts()
|
||||||
|
if (res.status == 200) {
|
||||||
|
this.$message.success('操作成功')
|
||||||
|
this.getProductMapperList()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
async HandleDownloadErrorReport() {
|
||||||
|
if (!this.errReportFilePath) {
|
||||||
|
this.$message.warning('请输入文件地址')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const res = await GoodsToolApi.HandleDownloadErrorReport({
|
||||||
|
file: this.errReportFilePath,
|
||||||
|
})
|
||||||
|
if (res.status == 200) {
|
||||||
|
this.$message.success('操作成功')
|
||||||
|
this.downloadFile(res.data, `${this.errReportFilePath}.xlsx`)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async handleSyncProductMaping() {
|
||||||
|
const res = await GoodsToolApi.syncProductMaping()
|
||||||
|
if (res.status == 200) {
|
||||||
|
this.$message.success('操作成功')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async handleExport() {
|
||||||
|
if (!this.selectedRowKeys.length) {
|
||||||
|
this.$message.warning('请先选择要导出的商品')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await GoodsToolApi.batchExportGoods(this.selectedRowKeys)
|
||||||
|
if (res.status == 200) {
|
||||||
|
this.downloadFile(response.data, '商品映射实体数据.xlsx')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async beforeGoodsDataUpload(file) {
|
||||||
|
const name = file.name.toLocaleLowerCase()
|
||||||
|
if (!name.endsWith('.xlsx') || !name.endsWith('.csv')) {
|
||||||
|
this.$message.error('文件格式错误,仅支持xlsx或csv格式')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
handleImportGoodsData(file)
|
||||||
|
},
|
||||||
|
|
||||||
|
async handleImportGoodsData(file) {
|
||||||
|
const data = new FormData()
|
||||||
|
data.append('file', file)
|
||||||
|
const res = await GoodsToolApi.importGoodsData(data)
|
||||||
|
if (res.status == 200) {
|
||||||
|
this.$message.success('操作成功')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async downloadTemplate(data) {
|
||||||
|
const res = await GoodsToolApi.downloadTempGoods({ id: data.id })
|
||||||
|
if (res.status == 200) {
|
||||||
|
this.$message.success('操作成功')
|
||||||
|
this.downloadFile(res, '商品商品映射数据模板.xlsx')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
downloadFile(blobData, fileName) {
|
||||||
|
const url = window.URL.createObjectURL(new Blob([blobData]))
|
||||||
|
|
||||||
|
const link = document.createElement('a')
|
||||||
|
link.href = url
|
||||||
|
link.setAttribute('download', fileName)
|
||||||
|
|
||||||
|
document.body.appendChild(link)
|
||||||
|
link.click()
|
||||||
|
|
||||||
|
document.body.removeChild(link)
|
||||||
|
window.URL.revokeObjectURL(url)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.filter {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 20px;
|
||||||
|
margin: 20px;
|
||||||
|
gap: 10px;
|
||||||
|
border-radius: 5px;
|
||||||
|
box-shadow: 1px 1px 6px rgba(0, 0, 0, 0.1);
|
||||||
|
|
||||||
|
.input_item {
|
||||||
|
width: 250px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.list {
|
||||||
|
padding: 20px;
|
||||||
|
margin: 20px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 10px;
|
||||||
|
border-radius: 5px;
|
||||||
|
box-shadow: 1px 1px 6px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
.tool {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
::v-deep .el-button {
|
||||||
|
margin-left: 0 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Loading…
Reference in New Issue
Block a user