Compare commits

..

No commits in common. "a04db00c4f42a11f776db238665a1f142f1d562c" and "6339fa6d27bf359ad33af55d93357fdbf4c2e6dd" have entirely different histories.

2 changed files with 1845 additions and 1885 deletions

View File

@ -1,134 +1,125 @@
import request from '@/utils/request' import request from "@/utils/request";
import { stringify } from 'qs' import { stringify } from "qs";
export async function getProductMapperList(data) { export async function getProductMapperList(data) {
data = stringify(data) data = stringify(data);
return request({ return request({
url: `/admin/shop/shop-sync-productMapper/list?${data}`, url: `/admin/shop/shop-sync-productMapper/list?${data}`,
method: 'get', method: "get",
}) });
} }
export async function getShopList() { export async function getShopList() {
return request({ return request({
url: '/admin/shop/shop-store-base/list?pageNum=1&pageSize=99999&store_type=1', url: "/admin/shop/shop-store-base/list?pageNum=1&pageSize=99999&store_type=1",
method: 'get', method: "get",
}) });
} }
export async function updateGoods(data) { export async function updateGoods(data) {
return request({ return request({
url: '/admin/shop/shop-sync-productMapper/udpateProductMapping', url: "/admin/shop/shop-sync-productMapper/udpateProductMapping",
method: 'put', method: "put",
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
}, },
data, data,
}) });
} }
export async function deleteGoods(data) { export async function deleteGoods(data) {
return request({ return request({
url: '/admin/shop/shop-sync-productMapper/delProductMapping', url: "/admin/shop/shop-sync-productMapper/delProductMapping",
method: 'delete', method: "delete",
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
}, },
data, data,
}) });
} }
export async function downloadTempGoods(data) { export async function downloadTempGoods(data) {
data = stringify(data) data = stringify(data);
return request({ return request({
url: `/admin/shop/shop-sync-productMapper/template?${data}`, url: `/admin/shop/shop-sync-productMapper/template?${data}`,
method: 'get', method: "get",
}) });
} }
export async function batchCreateGoods(data) { export async function batchCreateGoods(data) {
return request({ return request({
url: '/admin/shop/shop-sync-productMapper/saveProductMappingBatch', url: "/admin/shop/shop-sync-productMapper/saveProductMappingBatch",
method: 'post', method: "post",
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
}, },
data, data,
}) });
} }
export async function batchExportGoods(data) { export async function batchExportGoods(data) {
return request({ return request({
url: '/admin/shop/shop-sync-productMapper/exportSelected', url: "/admin/shop/shop-sync-productMapper/exportSelected",
method: 'post', method: "post",
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
}, },
data, data,
}) });
} }
export async function getProductMapping(data) { export async function getProductMapping(data) {
return request({ return request({
url: '/admin/shop/shop-sync-productMapper/getProductMapping', url: "/admin/shop/shop-sync-productMapper/getProductMapping",
method: 'get', method: "get",
data, data,
}) });
} }
export async function getSyncBaseMapingProducts() { export async function getSyncBaseMapingProducts() {
return request({ return request({
url: '/admin/shop/shop-sync-productMapper/getSyncBaseMapingProducts', url: "/admin/shop/shop-sync-productMapper/getSyncBaseMapingProducts",
method: 'get', method: "get",
}) });
} }
export async function downloadErrorReport(data) { export async function HandleDownloadErrorReport(data) {
data = stringify(data) data = stringify(data);
return request({ return request({
url: `/admin/shop/shop-sync-productMapper/download?${data}`, url: `/admin/shop/shop-sync-productMapper/download?${data}`,
method: 'get', method: "get",
}) });
} }
export async function syncProductMaping() { export async function syncProductMaping() {
return request({ return request({
url: `/admin/shop/shop-sync-productMapper/syncProductMaping`, url: `/admin/shop/shop-sync-productMapper/syncProductMaping`,
method: 'put', method: "put",
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
}, },
}) });
} }
export async function importGoodsData(data) { export async function importGoodsData(data) {
return request({ return request({
url: `/admin/shop/shop-sync-productMapper/importData`, url: `/admin/shop/shop-sync-productMapper/importData`,
method: 'post', method: "post",
data, data,
}) });
}
export async function syncShopImages(data) {
data = stringify(data)
return request({
url: `/admin/shop/shop-sync-productMapper/syncShopImages?${data}`,
method: 'get',
})
} }
export default { export default {
getProductMapperList, getProductMapperList,
getShopList, getShopList,
updateGoods, updateGoods,
deleteGoods /* */, deleteGoods,/* */
downloadTempGoods, downloadTempGoods,
batchCreateGoods, batchCreateGoods,
batchExportGoods, batchExportGoods,
getProductMapping, getProductMapping,
getSyncBaseMapingProducts, getSyncBaseMapingProducts,
downloadErrorReport, HandleDownloadErrorReport,
syncProductMaping, syncProductMaping,
importGoodsData, importGoodsData,
syncShopImages, };
}

View File

@ -2,27 +2,28 @@
<div class="goods_tool_container"> <div class="goods_tool_container">
<div class="filter"> <div class="filter">
<el-input <el-input
v-model="filter.productName"
class="input_item" class="input_item"
clearable
placeholder="输入商品名称" placeholder="输入商品名称"
prefix-icon="el-icon-search" prefix-icon="el-icon-search"
/> v-model="filter.productName"
clearable
></el-input>
<el-select <el-select
v-model="filter.storeId" v-model="filter.storeId"
clearable
filterable
placeholder="选择店铺" placeholder="选择店铺"
filterable
clearable
> >
<el-option <el-option
v-for="item in shopList" v-for="item in shopList"
:key="item.store_id" :key="item.store_id"
:label="item.store_name" :label="item.store_name"
:value="item.store_id" :value="item.store_id"
/> >
</el-option>
</el-select> </el-select>
<el-button size="medium" type="primary" @click="handleSearch"> <el-button type="primary" size="medium" @click="handleSearch">
搜索 搜索
</el-button> </el-button>
</div> </div>
@ -32,29 +33,20 @@
<el-button type="primary" @click="openBatchAdd">批量新增</el-button> <el-button type="primary" @click="openBatchAdd">批量新增</el-button>
<el-button <el-button
:disabled="!selectedRowKeys.length"
type="success" type="success"
@click="handleExport" @click="handleExport"
:disabled="!selectedRowKeys.length"
> >
导出数据 导出数据
</el-button> </el-button>
<el-upload <el-upload action="" :show-file-list="false" :limit="1" :before-upload="beforeGoodsDataUpload">
action=""
:before-upload="beforeGoodsDataUpload"
:limit="1"
:show-file-list="false"
>
<el-button type="warning"> 导入数据 </el-button> <el-button type="warning"> 导入数据 </el-button>
</el-upload> </el-upload>
<el-button type="danger" @click="handleSyncGoods">同步数据</el-button> <el-button type="danger" @click="HandleSyncGoods">同步数据</el-button>
<el-button type="danger" @click="handleSyncShopImages"> <el-popover placement="bottom" :width="400" trigger="click">
商品图库匹配
</el-button>
<el-popover placement="bottom" trigger="click" :width="400">
<template slot="reference"> <template slot="reference">
<el-button >下载错误报告</el-button> <el-button >下载错误报告</el-button>
</template> </template>
@ -62,8 +54,8 @@
<el-input v-model="errReportFilePath" placeholder="输入文件地址"> <el-input v-model="errReportFilePath" placeholder="输入文件地址">
<template slot="append"> <template slot="append">
<el-button <el-button
size="medium"
type="primary" type="primary"
size="medium"
@click="HandleDownloadErrorReport" @click="HandleDownloadErrorReport"
> >
确定 确定
@ -73,22 +65,22 @@
</div> </div>
</el-popover> </el-popover>
<el-button plain type="info" @click="handleSyncProductMaping"> <el-button type="info" plain @click="handleSyncProductMaping">
自动计算并上架商品 自动计算并上架商品
</el-button> </el-button>
</div> </div>
<el-table <el-table
ref="productTable"
:data="tableData" :data="tableData"
style="width: 100%" style="width: 100%"
@selection-change="handleSelectionChange" @selection-change="handleSelectionChange"
ref="productTable"
> >
<el-table-column type="selection" width="55" /> <el-table-column type="selection" width="55"></el-table-column>
<el-table-column label="ID" prop="id" /> <el-table-column prop="id" label="ID" />
<el-table-column label="店铺ID" prop="storeId" /> <el-table-column prop="storeId" label="店铺ID" />
<el-table-column label="商品名称" prop="productName" /> <el-table-column prop="productName" label="商品名称" />
<el-table-column label="商品描述" prop="description" /> <el-table-column prop="description" label="商品描述" />
<el-table-column label="商品规格" prop="specValue"> <el-table-column prop="specValue" label="商品规格">
<template #default="scope"> <template #default="scope">
{{ scope.row.specValue }}{{ scope.row.specUnit }} {{ scope.row.specValue }}{{ scope.row.specUnit }}
</template> </template>
@ -96,45 +88,41 @@
<el-table-column label="操作" width="400"> <el-table-column label="操作" width="400">
<template #default="scope"> <template #default="scope">
<el-button <el-button
plain
size="mini" size="mini"
type="primary" type="primary"
@click="editGoods(scope.row)"
>
编辑配置
</el-button>
<el-button
plain plain
@click="editGoods(scope.row)"
>编辑配置</el-button
>
<el-button
size="mini" size="mini"
type="danger" type="danger"
@click="handleDelete(scope.row)"
>
删除配置
</el-button>
<el-button
plain plain
@click="handleDelete(scope.row)"
>删除配置</el-button
>
<el-button
size="mini" size="mini"
type="info" type="info"
@click="downloadTemplate(scope.row)"
>
下载模板
</el-button>
<el-button
plain plain
@click="downloadTemplate(scope.row)"
>下载模板</el-button
>
<el-button
size="mini" size="mini"
type="success" type="success"
plain
@click="getProductMapping(scope.row)" @click="getProductMapping(scope.row)"
>店铺商品映射</el-button
> >
店铺商品映射
</el-button>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
<el-pagination <el-pagination
background background
:current-page="pagination.pageNum"
layout="total, sizes, prev, pager, next, jumper" layout="total, sizes, prev, pager, next, jumper"
:current-page="pagination.pageNum"
:page-size="pagination.pageSize" :page-size="pagination.pageSize"
:total="pagination.total" :total="pagination.total"
@current-change="handleCurrentChange" @current-change="handleCurrentChange"
@ -144,17 +132,17 @@
<GoodsItem <GoodsItem
ref="batchFormRef" ref="batchFormRef"
:initial-data="formData"
:mode="formMode" :mode="formMode"
:shop-list-data="shopList" :initialData="formData"
:shopListData="shopList"
@success="handleSuccess" @success="handleSuccess"
/> ></GoodsItem>
</div> </div>
</template> </template>
<script> <script>
import GoodsToolApi from '@/api/goodsTool' import GoodsToolApi from "@/api/goodsTool";
import GoodsItem from './GoodsItem.vue' import GoodsItem from "./GoodsItem.vue";
export default { export default {
components: { components: {
@ -163,8 +151,8 @@
data() { data() {
return { return {
filter: { filter: {
productName: '', productName: "",
storeId: '', storeId: "",
}, },
pagination: { pagination: {
pageNum: 1, pageNum: 1,
@ -174,19 +162,19 @@
shopList: [], shopList: [],
tableData: [], tableData: [],
selectedRowKeys: [], selectedRowKeys: [],
formMode: 'add', formMode: "add",
formData: [], formData: [],
errReportFilePath: '', errReportFilePath: "",
} };
}, },
mounted() { mounted() {
this.getShopList() this.getShopList();
this.getGoodsList() this.getGoodsList();
}, },
methods: { methods: {
handleSearch(){ handleSearch(){
this.pagination.pageNum = 1 this.pagination.pageNum = 1;
this.pagination.pageSize = 10 this.pagination.pageSize = 10;
this.getGoodsList() this.getGoodsList()
}, },
async getGoodsList() { async getGoodsList() {
@ -194,7 +182,7 @@
...this.filter, ...this.filter,
pageNum: this.pagination.pageNum, pageNum: this.pagination.pageNum,
pageSize: this.pagination.pageSize, pageSize: this.pagination.pageSize,
}) });
// res = { // res = {
// code: 0, // code: 0,
// status: 200, // status: 200,
@ -614,11 +602,11 @@
// ], // ],
// }, // },
// }; // };
this.tableData = res.data.items this.tableData = res.data.items;
this.pagination.total = res.data.records this.pagination.total = res.data.records;
}, },
async getShopList() { async getShopList() {
let res = await GoodsToolApi.getShopList() let res = await GoodsToolApi.getShopList();
// res = { // res = {
// code: 0, // code: 0,
// status: 200, // status: 200,
@ -1721,192 +1709,172 @@
// ], // ],
// }, // },
// }; // };
this.shopList = res.data.items this.shopList = res.data.items;
}, },
handleCurrentChange(val) { handleCurrentChange(val) {
this.pagination.pageNum = val this.pagination.pageNum = val;
this.getGoodsList() this.getGoodsList();
}, },
handleSizeChange(val) { handleSizeChange(val) {
this.pagination.pageSize = val this.pagination.pageSize = val;
this.getGoodsList() this.getGoodsList();
}, },
openBatchAdd() { openBatchAdd() {
this.formMode = 'add' this.formMode = "add";
this.formData = [] this.formData = [];
this.$refs.batchFormRef.open() this.$refs.batchFormRef.open();
}, },
openBatchEdit() { openBatchEdit() {
const selectedProducts = this.tableData.filter((item) => item.selected) const selectedProducts = this.tableData.filter((item) => item.selected);
if (selectedProducts.length === 0) { if (selectedProducts.length === 0) {
this.$message.warning('请先选择要编辑的商品') this.$message.warning("请先选择要编辑的商品");
return return;
} }
this.formMode = 'edit' this.formMode = "edit";
this.formData = selectedProducts this.formData = selectedProducts;
this.$refs.batchFormRef.open() this.$refs.batchFormRef.open();
}, },
editGoods(data) { editGoods(data) {
this.formMode = 'edit' this.formMode = "edit";
this.formData = [data] this.formData = [data];
this.$refs.batchFormRef.open() this.$refs.batchFormRef.open();
}, },
async getProductMapping(data) { async getProductMapping(data) {
this.$confirm('确定要映射选中的商品配置吗?', '友情提示', { this.$confirm("确定要映射选中的商品配置吗?", "友情提示", {
confirmButtonText: '确定', confirmButtonText: "确定",
cancelButtonText: '取消', cancelButtonText: "取消",
type: 'danger', type: "danger",
}).then(async () => { }).then(async () => {
console.log(data) console.log(data);
const res = await GoodsToolApi.getProductMapping({ id: data.id }) const res = await GoodsToolApi.getProductMapping({ id: data.id });
if (res.status == 200) { if (res.status == 200) {
this.$message.success('操作成功') this.$message.success("操作成功");
this.getProductMapperList() this.getProductMapperList();
} }
}) });
}, },
handleSuccess() { handleSuccess(data) {
this.fetchProductList() this.fetchProductList();
}, },
handleSelectionChange(selection) { handleSelectionChange(selection) {
this.selectedRowKeys = selection.map((item) => item.id) this.selectedRowKeys = selection.map((item) => item.id);
}, },
handleDelete(data) { handleDelete(data) {
this.$confirm( this.$confirm(
'确定要删除选中的商品配置吗?此操作不可撤销。', "确定要删除选中的商品配置吗?此操作不可撤销。",
'友情提示', "友情提示",
{ {
confirmButtonText: '确定', confirmButtonText: "确定",
cancelButtonText: '取消', cancelButtonText: "取消",
type: 'danger', type: "danger",
} }
).then(async () => { ).then(async () => {
console.log(data) console.log(data);
const res = await GoodsToolApi.deleteGoods({ id: data.id }) const res = await GoodsToolApi.deleteGoods({ id: data.id });
if (res.status == 200) { if (res.status == 200) {
this.$message.success('已删除') this.$message.success("已删除");
this.getProductMapperList() this.getProductMapperList();
} }
}) });
}, },
handleSyncGoods() { HandleSyncGoods() {
this.$confirm('确定要获取同步未分配的商品数据?', '友情提示', { this.$confirm("确定要获取同步未分配的商品数据?", "友情提示", {
confirmButtonText: '确定', confirmButtonText: "确定",
cancelButtonText: '取消', cancelButtonText: "取消",
type: 'danger', type: "danger",
}).then(async () => { }).then(async () => {
const res = await GoodsToolApi.getSyncBaseMapingProducts() const res = await GoodsToolApi.getSyncBaseMapingProducts();
if (res.status == 200) { if (res.status == 200) {
this.$message.success('操作成功') this.$message.success("操作成功");
this.getProductMapperList() this.getProductMapperList();
} }
}) });
},
handleSyncShopImages() {
if (!this.filter.storeId) {
this.$message.error('请选择店铺')
return
}
this.$confirm('确定要匹配当前选择店铺的商品图库?', '友情提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'danger',
}).then(async () => {
const res = await GoodsToolApi.syncShopImages({
id: this.filter.storeId,
})
if (res.status == 200) {
this.$message.success('操作成功')
this.getProductMapperList()
}
})
}, },
async HandleDownloadErrorReport() { async HandleDownloadErrorReport() {
if (!this.errReportFilePath) { if (!this.errReportFilePath) {
this.$message.warning('请输入文件地址') this.$message.warning("请输入文件地址");
return return;
} }
const res = await GoodsToolApi.downloadErrorReport({ const res = await GoodsToolApi.HandleDownloadErrorReport({
file: this.errReportFilePath, file: this.errReportFilePath,
}) });
if (res.status == 200) { if (res.status == 200) {
this.$message.success('操作成功') this.$message.success("操作成功");
this.downloadFile(res.data, `${this.errReportFilePath}.xlsx`) this.downloadFile(res.data, `${this.errReportFilePath}.xlsx`);
} }
}, },
async handleSyncProductMaping() { async handleSyncProductMaping() {
const res = await GoodsToolApi.syncProductMaping() const res = await GoodsToolApi.syncProductMaping();
if (res.status == 200) { if (res.status == 200) {
this.$message.success('操作成功') this.$message.success("操作成功");
} }
}, },
async handleExport() { async handleExport() {
if (!this.selectedRowKeys.length) { if (!this.selectedRowKeys.length) {
this.$message.warning('请先选择要导出的商品') this.$message.warning("请先选择要导出的商品");
return return;
} }
const res = await GoodsToolApi.batchExportGoods(this.selectedRowKeys) const res = await GoodsToolApi.batchExportGoods(this.selectedRowKeys);
if (res.status == 200) { if (res.status == 200) {
this.downloadFile(res.data, '商品映射实体数据.xlsx') this.downloadFile(response.data, "商品映射实体数据.xlsx");
} }
}, },
async beforeGoodsDataUpload(file) { async beforeGoodsDataUpload(file) {
const name = file.name.toLocaleLowerCase() const name = file.name.toLocaleLowerCase();
if (name.endsWith('.xlsx') || name.endsWith('.csv')) { if(name.endsWith(".xlsx") || name.endsWith(".csv")){
this.handleImportGoodsData(file) handleImportGoodsData(file)
}else{ }else{
this.$message.error('文件格式错误仅支持xlsx或csv格式') this.$message.error("文件格式错误仅支持xlsx或csv格式");
} }
}, },
async handleImportGoodsData(file) { async handleImportGoodsData(file) {
const data = new FormData() const data = new FormData();
data.append('file', file) data.append("file", file);
const res = await GoodsToolApi.importGoodsData(data) const res = await GoodsToolApi.importGoodsData(data);
if (res.status == 200) { if (res.status == 200) {
this.$message.success('操作成功') this.$message.success("操作成功");
} }
}, },
async downloadTemplate(data) { async downloadTemplate(data) {
const res = await GoodsToolApi.downloadTempGoods({ id: data.id }) const res = await GoodsToolApi.downloadTempGoods({ id: data.id });
if (res.status == 200) { if (res.status == 200) {
this.$message.success('操作成功') this.$message.success("操作成功");
this.downloadFile(res, '商品商品映射数据模板.xlsx') this.downloadFile(res, "商品商品映射数据模板.xlsx");
} }
}, },
downloadFile(blobData, fileName) { downloadFile(blobData, fileName) {
const url = window.URL.createObjectURL(new Blob([blobData])) const url = window.URL.createObjectURL(new Blob([blobData]));
const link = document.createElement('a') const link = document.createElement("a");
link.href = url link.href = url;
link.setAttribute('download', fileName) link.setAttribute("download", fileName);
document.body.appendChild(link) document.body.appendChild(link);
link.click() link.click();
document.body.removeChild(link) document.body.removeChild(link);
window.URL.revokeObjectURL(url) window.URL.revokeObjectURL(url);
}, },
}, },
} };
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@ -1941,4 +1909,5 @@
margin-left: 0 !important; margin-left: 0 !important;
} }
} }
</style> </style>