java-mall-admin/src/views/product/goodsTool/index.vue
2025-06-26 14:32:27 +08:00

397 lines
11 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<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>