571 lines
17 KiB
Vue
571 lines
17 KiB
Vue
<template>
|
||
<ai-list class="Template">
|
||
<ai-title
|
||
slot="title"
|
||
title="管理SKU"
|
||
isShowBack
|
||
isShowBottomBorder
|
||
@onBackClick="$router.go(-1)">
|
||
</ai-title>
|
||
<template slot="content">
|
||
<ai-search-bar>
|
||
<template #left>
|
||
<el-button type="primary" size="small" @click="chooseSkuList = [], isShow = true">添加</el-button>
|
||
<el-upload
|
||
action
|
||
:limit="1"
|
||
:show-file-list="false"
|
||
accept=".xls,.xlsx"
|
||
:auto-upload="false"
|
||
:file-list="fileList"
|
||
:on-change="onExcelChange">
|
||
<el-button size="small" type="danger" :disabled="!skuList.length">Excel导入</el-button>
|
||
</el-upload>
|
||
<json-excel
|
||
:data="skuList"
|
||
:fields="jsonFields"
|
||
name="SKU列表.xls"
|
||
worksheet="SKU列表">
|
||
<el-button size="small" type="warning" :disabled="!skuList.length">Excel导出</el-button>
|
||
</json-excel>
|
||
</template>
|
||
</ai-search-bar>
|
||
<ai-search-bar>
|
||
<template #left>
|
||
<div class="search-item" style="margin-bottom: 0;">
|
||
<label>SKU:</label>
|
||
<el-input
|
||
v-model="search.productSkuId"
|
||
style="width: 250px"
|
||
size="small"
|
||
clearable
|
||
placeholder="请输入SKU"
|
||
suffix-icon="iconfont iconSearch"
|
||
@clear="getList">
|
||
</el-input>
|
||
</div>
|
||
<div class="search-item" style="margin-bottom: 0;">
|
||
<label>SKC:</label>
|
||
<el-input
|
||
v-model="search.productSkcId"
|
||
style="width: 250px"
|
||
size="small"
|
||
placeholder="请输入SKC"
|
||
clearable
|
||
suffix-icon="iconfont iconSearch"
|
||
@clear="getList">
|
||
</el-input>
|
||
</div>
|
||
<div class="search-item" style="margin-bottom: 0;">
|
||
<label style="width: 100px;">仅显示未填写:</label>
|
||
<el-select v-model="search.isShowWhite" placeholder="请选择" clearable size="small">
|
||
<el-option label="是" value="1"></el-option>
|
||
<el-option label="否" value="0"></el-option>
|
||
</el-select>
|
||
</div>
|
||
<el-button style="margin-left: 10px;" @click="getList" size="small" :loading="pageShow">查询</el-button>
|
||
</template>
|
||
</ai-search-bar>
|
||
<ai-table
|
||
:tableData="list"
|
||
:col-configs="colConfigs"
|
||
style="margin-top: 8px;"
|
||
@getList="getList"
|
||
@selection-change="handleSelectionChange"
|
||
v-loading="pageShow"
|
||
:isShowPagination="false">
|
||
<el-table-column
|
||
v-for="(item, index) in relationList"
|
||
:key="index"
|
||
:prop="item.field"
|
||
:show-overflow-tooltip="true"
|
||
:label="item.name"
|
||
align="center">
|
||
</el-table-column>
|
||
<el-table-column slot="options" label="操作" align="center" fixed="right" width="120px">
|
||
<template v-slot="{ row }">
|
||
<div class="table-options">
|
||
<el-button type="text" @click="remove(row.id)">删除</el-button>
|
||
</div>
|
||
</template>
|
||
</el-table-column>
|
||
</ai-table>
|
||
<ai-dialog
|
||
:visible.sync="isShow"
|
||
title="添加SKU"
|
||
width="1400px"
|
||
customFooter
|
||
@confirm="onConfirm">
|
||
<div class="search-item__wrapper">
|
||
<div class="left">
|
||
<div class="search-item">
|
||
<label>添加方式:</label>
|
||
<el-radio-group v-model="addType" size="small" @change="onSearchRest">
|
||
<el-radio-button label="1">按类目添加</el-radio-button>
|
||
<el-radio-button label="2">按SKC添加</el-radio-button>
|
||
<el-radio-button label="3">按SKU添加</el-radio-button>
|
||
</el-radio-group>
|
||
</div>
|
||
<div class="search-item">
|
||
<label>店铺:</label>
|
||
<el-select v-model="lableSearch.mallId" placeholder="请选择店铺" size="small">
|
||
<el-option
|
||
v-for="item in $store.state.mallList"
|
||
:key="item.mallId"
|
||
:label="item.mallName"
|
||
:value="item.mallId">
|
||
</el-option>
|
||
</el-select>
|
||
</div>
|
||
</div>
|
||
<div class="right"></div>
|
||
</div>
|
||
<div class="search-item__wrapper">
|
||
<div class="left">
|
||
<div class="search-item" v-show="addType === '1'">
|
||
<label>商品分类:</label>
|
||
<el-cascader
|
||
style="width: 280px;"
|
||
v-model="targetCatId"
|
||
:props="props"
|
||
size="small"
|
||
filterable
|
||
:show-all-levels="false"
|
||
collapse-tags
|
||
clearable>
|
||
</el-cascader>
|
||
<el-button style="margin-left: 10px;" @click="onCateChange" size="small" :disabled="!lableSearch.mallId" :loading="isLoading">查询</el-button>
|
||
</div>
|
||
<div class="search-item" v-show="addType === '2'">
|
||
<label>SKC:</label>
|
||
<el-input
|
||
v-model="skuReqParams.SKC"
|
||
style="width: 250px"
|
||
size="small"
|
||
placeholder="多个查询请用户逗号分割"
|
||
clearable
|
||
@clear="getSkuList()"
|
||
suffix-icon="iconfont iconSearch">
|
||
</el-input>
|
||
<el-button style="margin-left: 10px;" @click="getSkuList" size="small" :disabled="!lableSearch.mallId" :loading="isLoading">查询</el-button>
|
||
</div>
|
||
<div class="search-item" v-show="addType === '3'">
|
||
<label>SKU:</label>
|
||
<el-input
|
||
v-if="addType === '3'"
|
||
v-model="skuReqParams.SKU"
|
||
style="width: 250px"
|
||
size="small"
|
||
placeholder="多个查询请用户逗号分割"
|
||
clearable
|
||
@clear="getSkuList()"
|
||
suffix-icon="iconfont iconSearch">
|
||
</el-input>
|
||
<el-button style="margin-left: 10px;" @click="getSkuList" size="small" :disabled="!lableSearch.mallId" :loading="isLoading">查询</el-button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<ai-table
|
||
height="370"
|
||
:tableData="lableList"
|
||
:col-configs="colConfigs"
|
||
:total="lableTotal"
|
||
:current.sync="lableSearch.current"
|
||
:size.sync="lableSearch.size"
|
||
style="margin-top: 8px;"
|
||
:pageSizes="[10, 20, 50, 100, 500, 1000]"
|
||
v-loading="isLoading"
|
||
:isShowPagination="false"
|
||
@getList="() => {}"
|
||
@selection-change="handleSelectionChange">
|
||
<el-table-column slot="productName" width="300px" :show-overflow-tooltip="true" label="商品名称" fixed="left">
|
||
<template slot-scope="scope">
|
||
<div>
|
||
<el-image :src="scope.row.mainImageUrl" style="width: 40px; height: 40px" class="image" :preview-src-list="[scope.row.mainImageUrl]" />
|
||
{{ scope.row.productName }}
|
||
</div>
|
||
</template>
|
||
</el-table-column>
|
||
</ai-table>
|
||
<template #footer>
|
||
<el-button @click="isShow = false">取消</el-button>
|
||
<el-button @click="onConfirm" type="primary" :loading="btnLoading">确认</el-button>
|
||
</template>
|
||
</ai-dialog>
|
||
</template>
|
||
</ai-list>
|
||
</template>
|
||
|
||
<script>
|
||
import { sendChromeAPIMessage } from '@/api/chromeApi'
|
||
import * as XLSX from 'xlsx'
|
||
import JsonExcel from 'vue-json-excel'
|
||
export default {
|
||
name: 'SkuManage',
|
||
|
||
components: {
|
||
JsonExcel
|
||
},
|
||
|
||
data () {
|
||
return {
|
||
total: 0,
|
||
search: {
|
||
current: 1,
|
||
size: -1,
|
||
productSkuId: '',
|
||
productSkcId: '',
|
||
isShowWhite: ''
|
||
},
|
||
lableSearch: {
|
||
current: 1,
|
||
size: 100,
|
||
mallId: ''
|
||
},
|
||
lableTotal: 0,
|
||
lableList: [],
|
||
isShow: false,
|
||
skuReqParams: {
|
||
page: 1,
|
||
pageSize: 100,
|
||
SKC: '',
|
||
SKU: ''
|
||
},
|
||
isLoading: false,
|
||
addType: '1',
|
||
props: {
|
||
value: 'catId',
|
||
label: 'catName',
|
||
multiple: true,
|
||
checkStrictly: true,
|
||
lazy: true,
|
||
lazyLoad (value, resolve) {
|
||
sendChromeAPIMessage({
|
||
url: 'bg-anniston-mms/category/children/list',
|
||
needMallId: true,
|
||
data: {
|
||
parentCatId: value.level === 0 ? '' : value.value
|
||
}
|
||
}).then(res => {
|
||
if (res.errorCode === 1000000) {
|
||
resolve(res.result.categoryNodeVOS.map(v => {
|
||
return {
|
||
...v,
|
||
leaf: v.isLeaf
|
||
}
|
||
}))
|
||
}
|
||
})
|
||
}
|
||
},
|
||
targetCatId: [],
|
||
skuList: [],
|
||
chooseSkuList: [],
|
||
id: '',
|
||
fileList: [],
|
||
pageShow: false,
|
||
relationList: [],
|
||
btnLoading: false
|
||
}
|
||
},
|
||
|
||
computed: {
|
||
list () {
|
||
if (!this.skuList.length) {
|
||
return []
|
||
}
|
||
|
||
if (this.search.isShowWhite !== '1') {
|
||
return this.skuList
|
||
}
|
||
|
||
const keys = this.relationList.map(v => v.field)
|
||
return this.skuList.filter(v => keys.some(e => !v[e]))
|
||
},
|
||
|
||
currMall () {
|
||
if (!this.$store.state.mallList.length) {
|
||
return {}
|
||
}
|
||
|
||
return this.$store.state.mallList.filter(v => v.mallId === this.lableSearch.mallId)[0]
|
||
},
|
||
|
||
colConfigs () {
|
||
const fields = this.isShow ? [] : this.relationList.map(v => {
|
||
return {
|
||
prop: v.field,
|
||
label: v.name,
|
||
align: 'center'
|
||
}
|
||
})
|
||
|
||
return [
|
||
{ type: 'selection' },
|
||
{ prop: 'mallName', label: '店铺名称', align: 'left' },
|
||
{ prop: 'productName', label: '商品名称', align: 'center' },
|
||
{ prop: 'labelCode', label: '条码编码', align: 'center' },
|
||
{ prop: 'productSkcId', label: 'SKC', align: 'center' },
|
||
{ prop: 'productSkuId', label: 'SKU', align: 'center' },
|
||
{ prop: 'skuExtCode', label: 'SKU货号', align: 'center' },
|
||
{ prop: 'skuSpecName', label: '次销售属性', align: 'center' },
|
||
...fields
|
||
]
|
||
},
|
||
|
||
jsonFields () {
|
||
const obj = {}
|
||
this.colConfigs.filter(v => !!v.prop).forEach(v => {
|
||
obj[v.label] = v.prop
|
||
})
|
||
|
||
return {
|
||
...obj
|
||
}
|
||
}
|
||
},
|
||
|
||
created () {
|
||
this.id = this.$route.query.id || ''
|
||
this.getRelation()
|
||
this.getList()
|
||
},
|
||
|
||
methods: {
|
||
toAdd () {
|
||
this.$router.push('/addLabelsTemplate')
|
||
},
|
||
|
||
getRelation () {
|
||
this.$http.post(`/api/templateRelation/getRelation?templateId=${this.$route.query.id}`).then(res => {
|
||
if (res.code === 0) {
|
||
this.relationList = res.data
|
||
}
|
||
})
|
||
},
|
||
|
||
readXLSX(file) {
|
||
return new Promise(resolve => {
|
||
const reader = new FileReader()
|
||
reader.readAsBinaryString(file)
|
||
reader.onload = evt => {
|
||
const data = evt.target.result
|
||
const workbook = XLSX.read(data, { type: 'binary' })
|
||
const ws = workbook.Sheets[workbook.SheetNames[0]]
|
||
const jsonData = XLSX.utils.sheet_to_json(ws)
|
||
resolve(jsonData)
|
||
|
||
this.fileList = []
|
||
}
|
||
})
|
||
},
|
||
|
||
onExcelChange (file) {
|
||
this.pageShow = true
|
||
this.readXLSX(file.raw).then(res => {
|
||
this.$http.post(`/api/templateSku/updateBatchSku`, res.map(v => {
|
||
const result = {
|
||
templateId: this.id
|
||
}
|
||
Object.keys(this.jsonFields).forEach(item => {
|
||
result[this.jsonFields[item]] = v[item]
|
||
})
|
||
|
||
return result
|
||
})).then(res => {
|
||
if (res.code === 0) {
|
||
this.$message.success('导入成功')
|
||
this.isShow = false
|
||
this.getList()
|
||
}
|
||
this.pageShow = false
|
||
})
|
||
})
|
||
},
|
||
|
||
onSearchRest() {
|
||
this.skuReqParams.SKC = ''
|
||
this.skuReqParams.SKU = ''
|
||
},
|
||
|
||
handleSelectionChange(e) {
|
||
this.chooseSkuList = e
|
||
},
|
||
|
||
getSKCList(catIds, page) {
|
||
return new Promise(resolve => {
|
||
sendChromeAPIMessage({
|
||
url: 'bg-visage-mms/product/skc/pageQuery',
|
||
needMallId: true,
|
||
mallId: this.lableSearch.mallId,
|
||
anti: true,
|
||
data: {
|
||
page,
|
||
pageSize: 200,
|
||
catIds: catIds
|
||
}
|
||
}).then(res => {
|
||
if (res.errorCode == 1000000) {
|
||
resolve({
|
||
list: res.result.pageItems.map(v => v.productSkcId),
|
||
isHasNext: res.result.total && res.result.pageItems.length && (res.result.pageItems.length < 200 && res.result.total > 200)
|
||
})
|
||
} else {
|
||
resolve({ list: [], isHasNext: false })
|
||
}
|
||
}).catch(() => {
|
||
resolve({ list: [], isHasNext: false })
|
||
})
|
||
})
|
||
},
|
||
|
||
async onCateChange() {
|
||
let page = 1
|
||
let list = []
|
||
let isHasNext = true
|
||
this.lableList = []
|
||
this.isLoading = true
|
||
while (isHasNext) {
|
||
const result = await this.getSKCList([].concat(this.targetCatId.flat()), page)
|
||
page = page + 1
|
||
isHasNext = result.isHasNext ? true : false
|
||
list.push(...result.list)
|
||
|
||
await this.$sleepSync(1000)
|
||
}
|
||
|
||
const skcList = [...new Set(list)]
|
||
const len = Math.ceil(skcList.length / 100)
|
||
for (let i = 0; i < len; i++) {
|
||
this.skuReqParams.page = 1
|
||
this.skuReqParams.SKC = [...new Set(list)].slice(i * 100, i * 100 + 100).join(',')
|
||
await this.requestSKUList(true)
|
||
await this.$sleepSync(500)
|
||
}
|
||
},
|
||
|
||
requestSKUList(flag) {
|
||
return sendChromeAPIMessage({
|
||
url: 'bg-visage-mms/labelcode/pageQuery',
|
||
needMallId: true,
|
||
mallId: this.lableSearch.mallId,
|
||
anti: true,
|
||
data: {
|
||
page: this.skuReqParams.page,
|
||
pageSize: 200,
|
||
productSkcIdList: (['2', '1'].includes(this.addType)) ? this.skuReqParams.SKC.split(',') : [],
|
||
productSkuIdList: this.addType === '3' ? this.skuReqParams.SKU.split(',') : []
|
||
}
|
||
}).then(async (res) => {
|
||
if (res.errorCode == 1000000) {
|
||
const list = res.result.pageItems.map(v => {
|
||
return {
|
||
mallId: this.lableSearch.mallId,
|
||
mallName: this.currMall.mallName,
|
||
productName: v.productName,
|
||
productSkcId: v.labelCodeVO.productSkcId,
|
||
productSkuId: v.labelCodeVO.productSkuId,
|
||
labelCode: v.labelCodeVO.labelCode,
|
||
skuExtCode: v.labelCodeVO.skuExtCode,
|
||
skuSpecName: v.productSkuSpecList.map(item => {
|
||
return item.specName
|
||
}).join(',')
|
||
}
|
||
})
|
||
this.lableTotal = res.result.total
|
||
this.lableList.push(...list)
|
||
|
||
if (res.result.total > this.lableList.length) {
|
||
this.skuReqParams.page++
|
||
await this.$sleepSync(500)
|
||
await this.requestSKUList()
|
||
} else {
|
||
!flag && (this.isLoading = false)
|
||
}
|
||
}
|
||
})
|
||
},
|
||
|
||
getSkuList () {
|
||
if (!this.lableSearch.mallId) {
|
||
return this.$message.error('请选择店铺')
|
||
}
|
||
|
||
this.lableList = []
|
||
this.skuReqParams.page = 1
|
||
this.isLoading = true
|
||
this.requestSKUList()
|
||
},
|
||
|
||
getList () {
|
||
this.pageShow = true
|
||
this.$http.post(`/api/templateSku/getPage`, null, {
|
||
params: {
|
||
...this.search,
|
||
templateId: this.id
|
||
}
|
||
}).then(res => {
|
||
if (res.code === 0) {
|
||
this.skuList = res.data.records
|
||
}
|
||
|
||
this.pageShow = false
|
||
})
|
||
},
|
||
|
||
onConfirm () {
|
||
if (!this.chooseSkuList.length) {
|
||
return this.$message.error('请选择SKU')
|
||
}
|
||
|
||
this.btnLoading = true
|
||
this.$http.post(`/api/templateSku/addBatchSku`, this.chooseSkuList.map(v => {
|
||
return {
|
||
...v,
|
||
templateId: this.id
|
||
}
|
||
})).then(res => {
|
||
if (res.code === 0) {
|
||
this.$message.success('添加成功')
|
||
this.isShow = false
|
||
this.getList()
|
||
}
|
||
|
||
this.btnLoading = false
|
||
}).catch(() => {
|
||
this.btnLoading = false
|
||
})
|
||
},
|
||
|
||
remove (id) {
|
||
this.$confirm('确定删除该数据?', '温馨提示', {
|
||
type: 'warning'
|
||
}).then(() => {
|
||
this.$http.post(`/api/templateSku/removeById?id=${id}`).then(res => {
|
||
if (res.code == 0) {
|
||
this.$message.success('删除成功')
|
||
|
||
this.getList()
|
||
}
|
||
})
|
||
})
|
||
},
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style scoped lang="scss">
|
||
.Template {
|
||
.search-item__wrapper {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
|
||
&>div {
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
}
|
||
}
|
||
</style>
|