This commit is contained in:
liushiwei
2024-07-18 14:48:44 +08:00
parent 6356004d74
commit 0808f42ce7
37 changed files with 2456 additions and 158 deletions

View File

@@ -9,6 +9,7 @@
"dependencies": {
"@antv/g2plot": "^2.4.25",
"axios": "^1.4.0",
"bi-vue-mindmap": "^0.6.12",
"core-js": "^3.8.3",
"crypto-js": "^4.0.0",
"dayjs": "^1.11.9",

274
public/js/temuSeller.js Normal file
View File

@@ -0,0 +1,274 @@
function matchTemuDomain(url) {
const urlPattern = /https:\/\/([\da-z\.-]+)\.kuajingmaihuo\.com\//
return urlPattern.test(url);
}
function init() {
if (matchTemuDomain(window.location.href)) {
let j = 0
let timer = setInterval(() => {
let models = document.querySelectorAll('div[class^="MDL_header"]')
let flag = false
for (let i = 0; i < models.length; i++) {
if (models[i].textContent.includes("商品降价提醒") || models[i].textContent.includes("降价,提升竞争力,避免限制备货")) {
const popup = document.createElement("div")
popup.innerText = "拒绝调价"
const styles = {
padding: "8px",
background: "#fb7701",
color: "#fff",
display: 'inline',
borderRadius: "8px",
cursor: "pointer"
}
for (const e in styles) {
popup.style[e] = styles[e]
}
models[i].appendChild(popup)
popup.addEventListener('click', async () => {
let tbodyObj = models[i].parentElement.querySelector('tbody')
let trList = tbodyObj.querySelectorAll('tr')
for (let i = 0; i < trList.length; i++) {
let tdObj = trList[i].querySelector('td:last-child')
let firstLabelObj = tdObj.querySelector('div label:first-child')
if (firstLabelObj.getAttribute("data-checked")) {
let labelObj = tdObj.querySelector('div label:nth-child(2)')
let radioObj = labelObj.querySelector('div[class^="RD_radioWrapper"]')
// await sleepSync(50)
radioObj.click()
}
}
})
flag = true
}
}
let models2 = document.querySelectorAll('div[class^="price-adjust-confirm-system_contentWrp"]')
for (let i = 0; i < models2.length; i++) {
let tipsObj = models2[i].querySelector('div[class^="price-adjust-confirm-system_tips"]')
let spanObj = tipsObj.querySelector('div span:last-child')
if (spanObj) {
const popup = document.createElement("div")
popup.innerText = "拒绝调价"
const styles = {
padding: "8px",
background: "#fb7701",
color: "#fff",
display: 'inline',
borderRadius: "8px",
cursor: "pointer"
}
for (const e in styles) {
popup.style[e] = styles[e]
}
spanObj.appendChild(popup)
popup.addEventListener('click', async () => {
let tbodyObj = models2[i].querySelector('tbody')
let trList = tbodyObj.querySelectorAll('tr')
for (let i = 0; i < trList.length; i++) {
let tdObj = trList[i].querySelector('td:last-child')
let firstLabelObj = tdObj.querySelector('div label:first-child')
if (firstLabelObj.getAttribute("data-checked")) {
let labelObj = tdObj.querySelector('div label:nth-child(2)')
let radioObj = labelObj.querySelector('div[class^="RD_radioWrapper"]')
// await sleepSync(50)
radioObj.click()
}
}
})
flag = true
}
}
let models3 = document.querySelectorAll('div[class^="price-adjust-confirm-new_content"]')
for (let i = 0; i < models3.length; i++) {
let tipsObj = models3[i].querySelector('div[class^="price-adjust-confirm-new_tips"]')
let spanObj = tipsObj.querySelector('div span:last-child')
if (spanObj) {
const popup = document.createElement("div")
popup.innerText = "拒绝调价"
const styles = {
padding: "8px",
background: "#fb7701",
color: "#fff",
display: 'inline',
borderRadius: "8px",
cursor: "pointer"
}
for (const e in styles) {
popup.style[e] = styles[e]
}
spanObj.appendChild(popup)
popup.addEventListener('click', async () => {
let tbodyObj = models3[i].querySelector('tbody')
let trList = tbodyObj.querySelectorAll('tr')
for (let i = 0; i < trList.length; i++) {
let tdObj = trList[i].querySelector('td:last-child')
let firstLabelObj = tdObj.querySelector('div label:first-child')
if (firstLabelObj.getAttribute("data-checked")) {
let labelObj = tdObj.querySelector('div label:nth-child(2)')
let radioObj = labelObj.querySelector('div[class^="RD_radioWrapper"]')
// await sleepSync(50)
radioObj.click()
}
}
})
flag = true
}
}
let models4 = document.querySelectorAll('div[class^="price-adjust-confirm-system-old_contentWrp"]')
for (let i = 0; i < models4.length; i++) {
let tipsObj = models4[i].querySelector('div[class^="price-adjust-confirm-system-old_tips"]')
let spanObj = tipsObj.querySelector('div span:last-child')
if (spanObj) {
const popup = document.createElement("div")
popup.innerText = "拒绝调价"
const styles = {
padding: "8px",
background: "#fb7701",
color: "#fff",
display: 'inline',
borderRadius: "8px",
cursor: "pointer"
}
for (const e in styles) {
popup.style[e] = styles[e]
}
spanObj.appendChild(popup)
popup.addEventListener('click', async () => {
let tbodyObj = models4[i].querySelector('tbody')
let trList = tbodyObj.querySelectorAll('tr')
for (let i = 0; i < trList.length; i++) {
let tdObj = trList[i].querySelector('td:last-child')
let firstLabelObj = tdObj.querySelector('div label:first-child')
if (firstLabelObj.getAttribute("data-checked")) {
let labelObj = tdObj.querySelector('div label:nth-child(2)')
let radioObj = labelObj.querySelector('div[class^="RD_radioWrapper"]')
// await sleepSync(50)
radioObj.click()
}
}
})
flag = true
}
}
let models5 = document.querySelectorAll('div[class^="new-price-adjust-confirm_content"]')
for (let i = 0; i < models5.length; i++) {
let tipsObj = models5[i].querySelector('div[class^="new-price-adjust-confirm_tips"]')
let spanObj = tipsObj.querySelector('div span:last-child')
if (spanObj) {
const popup = document.createElement("div")
popup.innerText = "拒绝调价"
const styles = {
padding: "8px",
background: "#fb7701",
color: "#fff",
display: 'inline',
borderRadius: "8px",
cursor: "pointer"
}
for (const e in styles) {
popup.style[e] = styles[e]
}
spanObj.appendChild(popup)
popup.addEventListener('click', async () => {
let tbodyObj = models5[i].querySelector('tbody')
let trList = tbodyObj.querySelectorAll('tr')
for (let i = 0; i < trList.length; i++) {
let tdObj = trList[i].querySelector('td:last-child')
let firstLabelObj = tdObj.querySelector('div label:first-child')
if (firstLabelObj.getAttribute("data-checked")) {
let labelObj = tdObj.querySelector('div label:nth-child(2)')
let radioObj = labelObj.querySelector('div[class^="RD_radioWrapper"]')
// await sleepSync(50)
radioObj.click()
}
}
})
flag = true
}
}
if (flag) {
clearInterval(timer)
} else {
j++
if (j == 10) {
clearInterval(timer)
}
}
}, 3000)
// document.body.appendChild(popup)
}
}
/*
function createElement() {
const popup = document.createElement("div")
popup.innerText = "拒绝调价"
const styles = {
position: "fixed",
right: '10px',
top: '60px',
zIndex: 999999,
padding: "8px",
background: "#409EFF",
color: "#fff",
borderRadius: "8px",
cursor: "pointer"
}
for (const e in styles) {
popup.style[e] = styles[e]
}
popup.addEventListener('click', async () => {
let divObj1 = document.querySelector('div[class^="price-adjust-confirm-system_contentWrp"]')
if (divObj1) {
let tbodyObj = divObj1.querySelector('tbody')
let trList = tbodyObj.querySelectorAll('tr')
for (let i = 0; i < trList.length; i++) {
let tdObj = trList[i].querySelector('td:last-child')
let labelObj = tdObj.querySelector('div label:last-child')
let radioObj = labelObj.querySelector('div[class^="RD_radioWrapper"]')
// await sleepSync(50)
radioObj.click()
}
}
let divObj2 = document.querySelector('div[class^="price-adjust-confirm_header"]')
if (divObj2) {
let divObj = divObj2.nextElementSibling
let tbodyObj = divObj.querySelector('tbody')
let trList = tbodyObj.querySelectorAll('tr')
for (let i = 0; i < trList.length; i++) {
let tdObj = trList[i].querySelector('td:last-child')
let labelObj = tdObj.querySelector('div label:last-child')
//let radioObj = labelObj.querySelector("[type='radio']")
// await sleepSync(50)
let radioObj = labelObj.querySelector('div[class^="RD_radioWrapper"]')
radioObj.click()
}
}
let divObj3 = document.querySelector('div[class^="price-adjust-confirm-new_banner"]')
if (divObj3) {
let divObj = divObj3.nextElementSibling
let tbodyObj = divObj.querySelector('tbody')
let trList = tbodyObj.querySelectorAll('tr')
for (let i = 0; i < trList.length; i++) {
let tdObj = trList[i].querySelector('td:last-child')
let labelObj = tdObj.querySelector('div label:last-child')
//let radioObj = labelObj.querySelector("[type='radio']")
// await sleepSync(50)
let radioObj = labelObj.querySelector('div[class^="RD_radioWrapper"]')
radioObj.click()
}
}
})
return popup
}
*/
init()

View File

@@ -0,0 +1,8 @@
function injectScript(file, node) {
var th = document.getElementsByTagName(node)[0];
var s = document.createElement('script');
s.setAttribute('type', 'text/javascript');
s.setAttribute('src', file);
th.appendChild(s);
}
injectScript( chrome.runtime.getURL('/js/temuSeller.js'), 'body');

View File

@@ -426,13 +426,14 @@ export default {
content['cat' + (i+1) + 'Id'] = this.form.targetCatId[i]
}
}
if (content['cat'+(i+1)+'Id'] != reqData.catId) {
if (content['cat'+(i)+'Id'] != reqData.catId) {
content['cat'+(++i)+'Id'] = reqData.catId
}
for (; i < 10; i++) {
content['cat' + (i+1) + 'Id'] = ''
}
content.personalizationSwitch = 0
content.productDraftId = draftId
this.createProduct(content)

View File

@@ -8,3 +8,4 @@ function injectScript(file, node) {
injectScript( chrome.runtime.getURL('/js/jszip.min.js'), 'body');
injectScript( chrome.runtime.getURL('/js/FileSaver.js'), 'body');
injectScript( chrome.runtime.getURL('/js/download.js'), 'body');
injectScript( chrome.runtime.getURL('/js/temuSeller.js'), 'body');

View File

@@ -76,12 +76,24 @@
"js": [
"/content.js"
]
},
{
"matches": [
"*://*.kuajingmaihuo.com/*"
],
"js": [
"/js/temuSellerContent.js"
]
}
],
"web_accessible_resources": [
{
"resources": [ "js/download.js","js/jszip.min.js","js/FileSaver.js" ],
"matches": [ "*://*.aliexpress.com/*", "*://*.amazon.com/*", "*://*.shein.com/*" ]
},
{
"resources": [ "js/temuSeller.js" ],
"matches": [ "*://*.kuajingmaihuo.com/*" ]
}
]
}

View File

@@ -2,7 +2,7 @@
"manifest_version": 3,
"name": "TEMU助手",
"description": "TEMU助手 - 自动化提高生产效率",
"version": "3.2.3",
"version": "3.2.8",
"background": {
"service_worker": "/background.js"
},
@@ -80,12 +80,24 @@
"js": [
"/content.js"
]
},
{
"matches": [
"*://*.kuajingmaihuo.com/*"
],
"js": [
"/js/temuSellerContent.js"
]
}
],
"web_accessible_resources": [
{
"resources": [ "js/download.js","js/jszip.min.js","js/FileSaver.js" ],
"matches": [ "*://*.aliexpress.com/*", "*://*.amazon.com/*", "*://*.shein.com/*" ]
},
{
"resources": [ "js/temuSeller.js" ],
"matches": [ "*://*.kuajingmaihuo.com/*" ]
}
]
}

View File

@@ -65,6 +65,11 @@ const router = new VueRouter({
name: 'myUrgencyOrder',
component: () => import('../view/shipping/MyUrgencyOrder.vue')
},
{
path: 'productLabel',
name: 'productLabel',
component: () => import('../view/shipping/ProductLabel.vue')
},
{
path: 'returnPackage',
name: 'returnPackage',
@@ -202,6 +207,11 @@ const router = new VueRouter({
name: 'afterSaleDeductStat',
component: () => import('../view/sale/AfterSaleDeductStat.vue')
},
{
path: 'saleStatTemu',
name: 'saleStatTemu',
component: () => import('../view/sale/ExportSaleStatTemu.vue')
},
{
path: 'costManageShein',
name: 'costManageShein',

View File

@@ -135,6 +135,7 @@ export function transform(leftData) {
countryShortName: leftData.productWhExtAttr.productOrigin ? leftData.productWhExtAttr.productOrigin.countryShortName: 'CN'
}
};
rightData.personalizationSwitch = leftData.productWhExtAttr.personalizationSwitch || "0"
rightData.productCarouseVideoReqList = leftData.carouseVideoVOList;
rightData.goodsAdvantageLabelTypes = leftData.goodsAdvantageLabelVOList;
rightData.productDetailVideoReqList = leftData.detailVideoVOList;
@@ -297,6 +298,7 @@ export function transformSubmitForHalf(leftData, config, draftId) {
countryShortName: leftData.productWhExtAttr.productOrigin ? leftData.productWhExtAttr.productOrigin.countryShortName: 'CN'
}
};
rightData.personalizationSwitch = leftData.productWhExtAttr.personalizationSwitch || 0
rightData.productCarouseVideoReqList = leftData.carouseVideoVOList;
rightData.goodsAdvantageLabelTypes = leftData.goodsAdvantageLabelVOList;
rightData.productDetailVideoReqList = leftData.detailVideoVOList;
@@ -323,14 +325,20 @@ export function transformSubmitForHalf(leftData, config, draftId) {
freightTemplateId: config.freightTemplateId,
shipmentLimitSecond: config.sendGoodsSecond
}
let bindSiteIds = []
if (leftData.productSaleExtAttr?.productSemiManaged?.bindSites) {
leftData.productSaleExtAttr?.productSemiManaged?.bindSites.map(ii => {
bindSiteIds.push(ii.siteId)
})
}
rightData.productSemiManagedReq = {
bindSiteIds: config.siteList
bindSiteIds: bindSiteIds
}
let targetRouteList = []
for (let m = 0; m < config.wareHouseList.length; m++) {
targetRouteList.push({
warehouseId: config.wareHouseList[m],
siteIdList: config.siteList
siteIdList: bindSiteIds
})
}
rightData.productWarehouseRouteReq = {

View File

@@ -61,6 +61,7 @@
<el-menu-item index="/shippingList">已收货发货单</el-menu-item>
<el-menu-item index="/myNormalOrder">普通备货单</el-menu-item>
<el-menu-item index="/myUrgencyOrder">紧急备货单</el-menu-item>
<el-menu-item index="/productLabel">商品条码管理</el-menu-item>
</el-submenu>
<el-submenu index="/copyProduct">
@@ -131,6 +132,7 @@
</template>
<el-menu-item index="/costManageTemu">成本管理</el-menu-item>
<el-menu-item index="/saleData">销售管理</el-menu-item>
<el-menu-item index="/saleStatTemu">销售统计</el-menu-item>
<el-menu-item index="/saleOut">售罄看板</el-menu-item>
<el-menu-item index="/afterSaleStat">售后统计</el-menu-item>
<el-menu-item index="/afterSaleDeductStat">售后赔付统计</el-menu-item>

View File

@@ -106,6 +106,7 @@
productName: item.productName,
skcId: item.skcId,
popUpType: 1,
createTime: res.result.createTime,
versionId: res.result.popUpAutoPass12.versionId,
newSupplyPrice: item.newSupplyPrice / 100,
}
@@ -119,6 +120,7 @@
productName: item.productName,
skcId: item.skcId,
popUpType: 2,
createTime: res.result.createTime,
versionId: res.result.popUpAutoPass24.versionId,
newSupplyPrice: item.newSupplyPrice / 100,
}
@@ -132,6 +134,7 @@
productName: item.productName,
skcId: item.skcId,
popUpType: 3,
createTime: res.result.createTime,
versionId: res.result.popUpOthers.versionId,
newSupplyPrice: item.newSupplyPrice / 100,
}
@@ -166,10 +169,12 @@
let popUpType1VersionId = ''
let popUpType2VersionId = ''
let popUpType3VersionId = ''
let createTime = null
let ids = []
this.priceList.map(item => {
if (item.popUpType == 1) {
popUpType1VersionId = item.versionId
createTime = item.createTime
ids.push(item.id)
}
})
@@ -183,12 +188,13 @@
"rejectOrderIdList": ids,
"maxOrderId": popUpType1VersionId,
"popUpType": 1,
"createTime": new Date().getTime()
"createTime": createTime
}})
}
ids = []
this.priceList.map(item => {
if (item.popUpType == 2) {
createTime = item.createTime
popUpType2VersionId = item.versionId
ids.push(item.id)
}
@@ -202,12 +208,13 @@
"rejectOrderIdList": ids,
"maxOrderId": popUpType2VersionId,
"popUpType": 2,
"createTime": new Date().getTime()
"createTime": createTime
}})
}
ids = []
this.priceList.map(item => {
if (item.popUpType == 3) {
createTime = item.createTime
popUpType3VersionId = item.versionId
ids.push(item.id)
}
@@ -221,7 +228,7 @@
"rejectOrderIdList": ids,
"maxOrderId": popUpType3VersionId,
"popUpType": 3,
"createTime": new Date().getTime()
"createTime": createTime
}})
}
if (res.success && res.errorCode == 1000000) {

View File

@@ -32,9 +32,12 @@
</div>
</ai-card>
</div>
<ai-card title="常用工具" v-if="false">
<div class="">
dsad
<ai-card title="TEMU助手功能概览">
<template #right>
<a href="https://www.yuque.com/liushiwei-f582m/kb/bmqqls0o5ybd6c8p?singleDoc" style="color: blue; font-size: 18px; text-decoration: underline;" target="_blank">在线帮助手册</a>
</template>
<div style="height: 1000px">
<BiVueMindmap ref="bi-vue-mindmap" :isReadonly="true" :flatNodes="mindmapNodes" />
</div>
</ai-card>
<AiDialog
@@ -58,9 +61,13 @@
</template>
<script>
import BiVueMindmap from "bi-vue-mindmap";
export default {
name: 'AdminHome',
components: {
BiVueMindmap,
},
data () {
return {
noticeList: [],
@@ -70,7 +77,258 @@
changeLogList: [],
isImportant: false,
version: '',
isShowDownload: false
isShowDownload: false,
mindmapNodes: [
{
id: "01",
parentId: null,
title: "TEMU助手"
},
{
id: "0101",
parentId: "01",
title: "TEMU"
},
{
id: "010101",
parentId: "0101",
title: "辅助运营"
},
{
id: "01010101",
parentId: "010101",
title: "备货单管理",
isFolded: true
},
{
id: "0101010101",
parentId: "01010101",
title: "创建备货单:批量领取系统下的备货单"
},
{
id: "0101010102",
parentId: "01010101",
title: "抢仓发货:同时操作多个店铺自动抢仓并创建发货单",
resources: [{
type: "VIDEO",
url: "http://temu.jjcp52.com/dist/qiangcang.mp4"
}]
},
{
id: "0101010103",
parentId: "01010101",
title: "发货台管理:批量从“发货台”创建发货单"
},
{
id: "0101010104",
parentId: "01010101",
title: "待装箱发货单:对应“备货单管理”->“发货单列表”,“待装箱发货”列表,支持导出"
},
{
id: "0101010105",
parentId: "01010101",
title: "待收货发货单:对应“备货单管理”->“发货单列表”,“待仓库收货”列表,支持导出"
},
{
id: "0101010106",
parentId: "01010101",
title: "已收货发货单:对应“备货单管理”->“发货单列表”,“已收货”列表,支持导出"
},
{
id: "0101010107",
parentId: "01010101",
title: "普通备货单:对应“备货单管理”->“我的备货单”,“普通备货单”列表,支持导出、成本统计"
},
{
id: "0101010108",
parentId: "01010101",
title: "紧急备货单:对应“备货单管理”->“我的备货单”,“紧急备货单”列表,支持导出、成本统计"
},
{
id: "0101010109",
parentId: "01010101",
title: "商品条码管理:对应“备货单管理”->“商品条码管理”,支持导出,可用于自定义生成标签,提高贴标效率"
},
{
id: "01010102",
parentId: "010101",
title: "商品管理",
isFolded: true
},
{
id: "0101010201",
parentId: "01010102",
title: "商品管理:对应“商品管理”->“商品列表”,支持导出,支持半托管"
},
{
id: "0101010202",
parentId: "01010102",
title: "商品复制:店铺之间快速商品拷贝"
},
{
id: "0101010203",
parentId: "01010102",
title: "查找买手根据SKC查询买手名字"
},
{
id: "0101010204",
parentId: "01010102",
title: "上新生命周期:对应“商品管理”->“上新生命周期管理”,支持导出未发布到站点、已下架的数据"
},
{
id: "01010103",
parentId: "010101",
title: "库存管理",
isFolded: true
},
{
id: "0101010301",
parentId: "01010103",
title: "退货包裹管理:对应“库存管理”->“退货包裹管理”,支持导出"
},
{
id: "0101010302",
parentId: "01010103",
title: "退货明细:对应“库存管理”->“退货明细”,支持导出"
},
{
id: "01010104",
parentId: "010101",
title: "销售管理",
isFolded: true
},
{
id: "0101010401",
parentId: "01010104",
title: "成本管理维护SKU的成本价格用于成本、利润的计算和统计"
},
{
id: "0101010402",
parentId: "01010104",
title: "销售管理:对应“销售管理”->“销售管理”,统计今日销量/销售额、今日利润/利润率、库存/在途库存,支持数据导出"
},
{
id: "0101010403",
parentId: "01010104",
title: "销售统计:统计过去一段时间内,总体销售额/单量/成本/利润/利润率的统计以及SKC/SKU维度的销售额/利润/单量的统计,支持导出"
},
{
id: "0101010404",
parentId: "01010104",
title: "售罄看板:对应“销售管理”->“售罄看板”,支持导出"
},
{
id: "0101010405",
parentId: "01010104",
title: "售后统计:对应“结算管理”->“售后管理”,计算预计扣款,白卖件数,支持导出"
},
{
id: "0101010406",
parentId: "01010104",
title: "售后赔付统计:对应“结算管理”->“对账中心”->“扣款详情”,统计过去一段时间内店铺的扣款总金额/次数,支持导出"
},
{
id: "01010105",
parentId: "010101",
title: "其他",
isFolded: true
},
{
id: "0101010501",
parentId: "01010105",
title: "弹窗消息:支持一键已读所有店铺的弹窗消息"
},
{
id: "0101010502",
parentId: "01010105",
title: "拒绝调价:辅助批量点击“我不接受”按钮,减轻工作量,避免遗漏",
resources: [{
type: "PIC",
url: "http://temu.jjcp52.com/dist/refuse-price.png"
}]
},
{
id: "010102",
parentId: "0101",
title: "选品采集"
},
{
id: "01010201",
parentId: "010102",
title: "商品采集根据TEMU前端地址采集商品信息到店铺草稿箱减轻上品工作量",
resources: [{
type: "VIDEO",
url: "http://temu.jjcp52.com/dist/xuanpin.mp4"
}]
},
{
id: "01010202",
parentId: "010102",
title: "速卖通采集:根据“速卖通”前端地址,采集商品信息到店铺草稿箱,减轻上品工作量"
},
{
id: "01010203",
parentId: "010102",
title: "选品跟踪",
isFolded: true
},
{
id: "0101020301",
parentId: "01010203",
title: "店铺跟踪:跟踪指定店铺的销售趋势、价格趋势,采集跟卖。(暂时不可用)"
},
{
id: "0101020302",
parentId: "01010203",
title: "关键字跟踪根据筛选关键字跟踪该关键字在TEMU前端搜索结果的销售趋势、价格趋势采集跟卖"
},
{
id: "0101020303",
parentId: "01010203",
title: "新品跟踪跟踪TEMU前端“Best Sellers”->“Within last 7 days”的新品采集跟卖"
},
{
id: "0101020304",
parentId: "01010203",
title: "单品跟踪根据TEMU前端地址采集销售趋势、价格趋势"
},
{
id: "0102",
parentId: "01",
title: "SHEIN(希音)"
},
{
id: "010201",
parentId: "0102",
title: "辅助运营",
isFolded: true
},
{
id: "01020101",
parentId: "010201",
title: "成本管理维护SKU的成本价格用于成本、利润的计算和统计"
},
{
id: "01020102",
parentId: "010201",
title: "销售管理对应SHEIN商家后台“商品管理”->“备货信息”,统计当天的销售额、销量、库存等信息,计算成本和利润"
},
{
id: "01020103",
parentId: "010201",
title: "证书中心对应SHEIN商家后台“商品管理”->“证书中心”,导出已驳回和待补充的证书列表,线下跟踪"
},
{
id: "01020104",
parentId: "010201",
title: "商品复制:希音店铺间商品进行快速复制,节省上品时间"
},
{
id: "01020105",
parentId: "010201",
title: "商家账单统计对应SHEIN商家后台“财务管理”->“商家账单”统计一段时期内销售额、单量、成本、利润、利润率SKC/SKU维度统计排名支持导出"
},
],
}
},

View File

@@ -93,9 +93,12 @@ import CryptoJS from 'crypto-js'
this.$message.success('两次密码输入不一致');
return;
}
const devVersion = require('../../manifest.development.json').version
const prodVersion = require('../../manifest.production.json').version
this.btnLoading = true
this.$http.post(`/api/malluser/reg`, {
...this.form
...this.form,
version: process.env.NODE_ENV === 'production' ? prodVersion : devVersion
}, {
headers: {
Authorization: 'Basic cGM6cGM='

View File

@@ -26,6 +26,7 @@
style="margin-top: 8px;"
:current.sync="search.current" :size.sync="search.size"
@selection-change="handleSelectionChange"
height="700"
@getList="getList">
</ai-table>
</div>
@@ -545,6 +546,7 @@ import AiLazyCascader from "@/components/AiLazyCascader.vue"
bindSiteIds: this.form.siteId
}
}
content.personalizationSwitch = content.personalizationSwitch || 0
setTimeout(() => {
sendChromeAPIMessage({
url: 'bg-visage-mms/product/draft/add',

View File

@@ -323,7 +323,8 @@ import JsonExcel from 'vue-json-excel'
supplierPrice: item.productSkuSummaries[k].supplierPrice / 100,
specName: temp.join(""),
skuStockQuantity,
todaySalesVolume: item.productSkuSummaries[k].todaySalesVolume}
todaySalesVolume: item.productSkuSummaries[k].todaySalesVolume
}
this.tableData.push(data)
}

View File

@@ -226,25 +226,6 @@ import JsonExcel from 'vue-json-excel'
}
}
},
async getSkuCostList() {
this.$http.post(`/api/skuCost/listAll`, null, {
params: {
mallId: this.mallId
}
}).then(res => {
if (res.code == 0) {
this.costList = res.data
this.tableData.map(item => {
for (let i = 0; i < this.costList.length; i++) {
if (item.productSkuId == this.costList[i].sku) {
item.cost = this.costList[i].costPrice
item.profitTimes = Math.round((item.supplierPrice * item.punishRatio + item.cost * item.times) / (item.supplierPrice - item.cost) * 100) / 100
}
}
})
}
})
},
}
}
</script>

View File

@@ -3,6 +3,7 @@
<ai-title
slot="title"
title="售后统计"
tips="请事先在“成本管理”维护好成本,否则部分计算不准确"
isShowBottomBorder>
<template #rightBtn>
<div class="title-right">
@@ -172,8 +173,7 @@ import JsonExcel from 'vue-json-excel'
this.reqData.pageNo = 1
await this.getProductList({page: this.reqData.pageNo,
pageSize: this.reqData.pageSize,
productSkuIds: skuIds})
pageSize: this.reqData.pageSize}, skuIds)
this.costList = []
await this.getSkuCostList()
@@ -227,13 +227,24 @@ import JsonExcel from 'vue-json-excel'
this.$store.commit("setTemuAlertShow", true)
}
},
async getProductList(params) {
async getProductList(params, skuIds) {
let productSkuIds = []
let i = (params.page - 1) * params.pageSize
let j = 0
for (; i < skuIds.length; i++) {
productSkuIds.push(skuIds[i])
j ++
if (j == params.pageSize) break
}
if (productSkuIds.length == 0) return
let res = await sendChromeAPIMessage({
url: 'bg-visage-mms/product/skc/pageQuery',
needMallId: true,
mallId: this.mallId,
data: {
...params
page: 1,
pageSize: params.pageSize,
productSkuIds
}})
if (res.errorCode == 1000000) {
res.result.pageItems.map((item) => {
@@ -251,10 +262,8 @@ import JsonExcel from 'vue-json-excel'
})
})
if ((params.page * params.pageSize) < res.result.total) {
params.page ++
await this.getProductList(params)
}
params.page ++
await this.getProductList(params, skuIds)
}
},
async getSkuCostList() {

View File

@@ -206,6 +206,7 @@ import { saveAs } from 'file-saver'
this.isLoading = true
this.getList()
}).catch((err) => {
this.mallId = ''
this.isLoading = false
})
},

View File

@@ -3,6 +3,7 @@
<ai-title
slot="title"
title="销售数据"
tips="请事先在“成本管理”维护好成本,否则部分计算不准确"
isShowBottomBorder>
<template #rightBtn>
<div class="title-right">
@@ -133,7 +134,7 @@
ref="table0"
:isShowPagination="false"
:tableData="filteredData"
height="500"
height="700"
:col-configs="colConfigs"
:total="filteredData.length"
style="margin-top: 8px;"
@@ -706,6 +707,7 @@ import { Message } from 'element-ui'
this.getSkuCostList()
this.getList()
}).catch((err) => {
this.mallId = ''
console.log(err)
this.isLoading = false
})

View File

@@ -47,7 +47,7 @@
:tableData="tableData"
:col-configs="colConfigs"
:total="tableData.length"
height="500"
height="700"
style="margin-top: 8px;"
@getList="() => {}">
</ai-table>
@@ -150,6 +150,7 @@ import { Message } from 'element-ui'
this.getList(2)
}
}).catch((err) => {
this.mallId = ''
this.isLoading = false
})
},

View File

@@ -0,0 +1,888 @@
<template>
<ai-list class="list" v-loading="isLoading" element-loading-text="拼命加载中" element-loading-spinner="el-icon-loading">
<ai-title
slot="title"
title="销售统计"
tips="最多只能统计近60天的销售数据"
isShowBottomBorder>
<template #rightBtn>
<div class="title-right">
<div>
<label style="width:90px">时间范围</label>
<el-date-picker
v-model="dateRange"
type="daterange"
start-placeholder="开始日期"
end-placeholder="结束日期"
format="yyyy-MM-dd"
value-format="yyyy-MM-dd">
</el-date-picker>
</div>
<div>
<label style="width:90px">店铺</label>
<el-select v-model="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>
<el-button type="button" :class="'el-button el-button--primary'" @click="toBeginStat">开始统计</el-button>
<el-button type="primary" icon="el-icon-download" @click="downloadPicture">下载图片</el-button>
<json-excel
:data="skcList"
:fields="skcJsonFields"
name="SKC销售统计.xls"
worksheet="SKC销售统计">
<el-button type="primary" icon="el-icon-download">下载SKC统计</el-button>
</json-excel>
<json-excel
:data="skuList"
:fields="skuJsonFields"
name="SKU销售统计.xls"
worksheet="SKU销售统计">
<el-button type="primary" icon="el-icon-download">下载SKU统计</el-button>
</json-excel>
</div>
</template>
</ai-title>
<template slot="content">
<div id="app-content">
<ai-card title="数据概览" style="padding-bottom: 40px;">
<div>
<el-row :gutter="20">
<el-col :span="5">
<div>
<el-statistic
group-separator=","
:precision="2"
:value="saleAmount"
title="销售额"
>
</el-statistic>
</div>
</el-col>
<el-col :span="5">
<div>
<el-statistic
group-separator=","
:value="saleCount"
title="单量"
>
</el-statistic>
</div>
</el-col>
<el-col :span="5">
<div>
<el-statistic
group-separator=","
:precision="2"
:value="costAmount"
title="成本"
></el-statistic>
</div>
</el-col>
<el-col :span="5">
<div>
<el-statistic
group-separator=","
:precision="2"
:value="profitAmount"
title="利润"
></el-statistic>
</div>
</el-col>
<el-col :span="4">
<div>
<el-statistic
group-separator=","
:precision="2"
:value="profitPercent"
title="利润率"
>
<template slot="suffix">%</template>
</el-statistic>
</div>
</el-col>
</el-row>
</div>
</ai-card>
<ai-card title="趋势分析" style="padding-bottom: 40px;">
<div>
<div id="chart1"></div>
</div>
</ai-card>
<div>
<el-row :gutter="20">
<el-col :span="12">
<ai-card title="SKC销售额TOP10排行">
<ai-table
ref="table0"
:isShowPagination="false"
:tableData="topSaleAmountSkcList"
:col-configs="skcColConfigs"
style="margin-top: 8px;">
<el-table-column slot="saleAmount" label="销售额">
<template slot-scope="scope">
<div style="color: red">{{ scope.row.saleAmount }}</div>
</template>
</el-table-column>
<el-table-column slot="profitAmount" label="利润">
<template slot-scope="scope">
<div>{{ scope.row.profitAmount }}</div>
</template>
</el-table-column>
<el-table-column slot="saleCount" label="单量">
<template slot-scope="scope">
<div>{{ scope.row.saleCount }}</div>
</template>
</el-table-column>
</ai-table>
</ai-card>
</el-col>
<el-col :span="12">
<ai-card title="SKC利润TOP10排行">
<ai-table
ref="table1"
:isShowPagination="false"
:tableData="topSaleProfitSkcList"
:col-configs="skcColConfigs"
style="margin-top: 8px;">
<el-table-column slot="saleAmount" label="销售额">
<template slot-scope="scope">
<div>{{ scope.row.saleAmount }}</div>
</template>
</el-table-column>
<el-table-column slot="profitAmount" label="利润">
<template slot-scope="scope">
<div style="color: red">{{ scope.row.profitAmount }}</div>
</template>
</el-table-column>
<el-table-column slot="saleCount" label="单量">
<template slot-scope="scope">
<div>{{ scope.row.saleCount }}</div>
</template>
</el-table-column>
</ai-table>
</ai-card>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<ai-card title="SKC单量TOP10排行">
<ai-table
ref="table2"
:isShowPagination="false"
:tableData="topSaleCountSkcList"
:col-configs="skcColConfigs"
style="margin-top: 8px;">
<el-table-column slot="saleAmount" label="销售额">
<template slot-scope="scope">
<div>{{ scope.row.saleAmount }}</div>
</template>
</el-table-column>
<el-table-column slot="profitAmount" label="利润">
<template slot-scope="scope">
<div>{{ scope.row.profitAmount }}</div>
</template>
</el-table-column>
<el-table-column slot="saleCount" label="单量">
<template slot-scope="scope">
<div style="color: red">{{ scope.row.saleCount }}</div>
</template>
</el-table-column>
</ai-table>
</ai-card>
</el-col>
<el-col :span="12">
<ai-card title="SKU销售额TOP10排行">
<ai-table
ref="table3"
:isShowPagination="false"
:tableData="topSaleAmountSkuList"
:col-configs="skuColConfigs"
style="margin-top: 8px;">
<el-table-column slot="skuExtCode" label="SKC属性/SKU属性" width="250px" :show-overflow-tooltip="true">
<template slot-scope="scope">
<div>{{ scope.row.skcExtCode + '/' + scope.row.skuExtCode }}</div>
</template>
</el-table-column>
<el-table-column slot="saleAmount" label="销售额">
<template slot-scope="scope">
<div style="color: red">{{ scope.row.saleAmount }}</div>
</template>
</el-table-column>
<el-table-column slot="profitAmount" label="利润">
<template slot-scope="scope">
<div>{{ scope.row.profitAmount }}</div>
</template>
</el-table-column>
<el-table-column slot="saleCount" label="单量">
<template slot-scope="scope">
<div>{{ scope.row.saleCount }}</div>
</template>
</el-table-column>
</ai-table>
</ai-card>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<ai-card title="SKU利润TOP10排行">
<ai-table
ref="table4"
:isShowPagination="false"
:tableData="topSaleProfitSkuList"
:col-configs="skuColConfigs"
style="margin-top: 8px;">
<el-table-column slot="skuExtCode" label="SKC属性/SKU属性" width="250px" :show-overflow-tooltip="true">
<template slot-scope="scope">
<div>{{ scope.row.skcExtCode + '/' + scope.row.skuExtCode }}</div>
</template>
</el-table-column>
<el-table-column slot="saleAmount" label="销售额">
<template slot-scope="scope">
<div>{{ scope.row.saleAmount }}</div>
</template>
</el-table-column>
<el-table-column slot="profitAmount" label="利润">
<template slot-scope="scope">
<div style="color: red">{{ scope.row.profitAmount }}</div>
</template>
</el-table-column>
<el-table-column slot="saleCount" label="单量">
<template slot-scope="scope">
<div>{{ scope.row.saleCount }}</div>
</template>
</el-table-column>
</ai-table>
</ai-card>
</el-col>
<el-col :span="12">
<ai-card title="SKU单量TOP10排行">
<ai-table
ref="table5"
:isShowPagination="false"
:tableData="topSaleCountSkuList"
:col-configs="skuColConfigs"
style="margin-top: 8px;">
<el-table-column slot="skuExtCode" label="SKC属性/SKU属性" width="250px" :show-overflow-tooltip="true">
<template slot-scope="scope">
<div>{{ scope.row.skcExtCode + '/' + scope.row.skuExtCode }}</div>
</template>
</el-table-column>
<el-table-column slot="saleAmount" label="销售额">
<template slot-scope="scope">
<div>{{ scope.row.saleAmount }}</div>
</template>
</el-table-column>
<el-table-column slot="profitAmount" label="利润">
<template slot-scope="scope">
<div>{{ scope.row.profitAmount }}</div>
</template>
</el-table-column>
<el-table-column slot="saleCount" label="单量">
<template slot-scope="scope">
<div style="color: red">{{ scope.row.saleCount }}</div>
</template>
</el-table-column>
</ai-table>
</ai-card>
</el-col>
</el-row>
</div>
</div>
</template>
</ai-list>
</template>
<script>
import {sendChromeAPIMessage } from '@/api/chromeApi'
import JsonExcel from 'vue-json-excel'
import { Message } from 'element-ui'
import {formatDate} from '@/utils/date'
import html2canvas from 'html2canvas'
import { DualAxes } from '@antv/g2plot'
export default {
name: 'ExportSaleStatTemu',
data () {
return {
mallId: null,
storeCode: '',
dateRange: null,
currentPage: 1,
pageSize: 100,
productList: [],
productCostList: [],
saleAmount: 0.0,
saleCount: 0,
costAmount: 0.0,
profitAmount: 0.0,
profitPercent: 0.0,
deductionAmount: 0.0,
skcList: [],
skuList: [],
leftChartData: [],
rightChartData: [],
isLoading: false,
skcColConfigs: [
{ prop: 'skcExtCode', label: 'SKC货号', width: '250px' },
{ slot: 'saleAmount', label: '销售额', align: 'center' },
{ slot: 'saleCount', label: '单量', align: 'center' },
{ prop: 'costAmount', label: '成本', align: 'center'},
{ slot: 'profitAmount', label: '利润', align: 'center' }
],
skcJsonFields: {
"SKC": "productSkcId",
"SKC货号": "skcExtCode",
"销售额": "saleAmount",
"单量": "saleCount",
"成本": "costAmount",
"利润": "profitAmount"
},
skuColConfigs: [
{ slot: 'skuExtCode', label: 'SKC货号/SKU货号' },
{ slot: 'saleAmount', label: '销售额', align: 'center' },
{ slot: 'saleCount', label: '单量', align: 'center' },
{ prop: 'costAmount', label: '成本', align: 'center'},
{ slot: 'profitAmount', label: '利润', align: 'center' }
],
skuJsonFields: {
"SKC": "productSkcId",
"SKU": "productSkuId",
"SKC货号": "skcExtCode",
"SKU货号": "skuExtCode",
"销售额": "saleAmount",
"单量": "saleCount",
"成本": "costAmount",
"利润": "profitAmount"
},
chartObj: null
}
},
computed: {
topSaleAmountSkcList() {
const list = Object.assign([], this.skcList)
list.sort((a, b) => b.amount - a.amount)
return list.slice(0, 10)
},
topSaleProfitSkcList() {
const list = Object.assign([], this.skcList)
list.sort((a, b) => b.profitAmount - a.profitAmount)
return list.slice(0, 10)
},
topSaleCountSkcList() {
const list = Object.assign([], this.skcList)
list.sort((a, b) => b.saleCount - a.saleCount)
return list.slice(0, 10)
},
topSaleAmountSkuList() {
const list = Object.assign([], this.skuList)
list.sort((a, b) => b.saleAmount - a.saleAmount)
return list.slice(0, 10)
},
topSaleProfitSkuList() {
const list = Object.assign([], this.skuList)
list.sort((a, b) => b.profitAmount - a.profitAmount)
return list.slice(0, 10)
},
topSaleCountSkuList() {
const list = Object.assign([], this.skuList)
list.sort((a, b) => b.saleCount - a.saleCount)
return list.slice(0, 10)
}
},
components: {
JsonExcel
},
mounted () {
this.initChart1()
},
methods: {
initChart1 () {
this.chartObj = new DualAxes('chart1', {
data: [this.leftChartData, this.rightChartData],
xField: 'day',
yField: ['value', 'value1'],
yAxis: {
value: {
title: {
text: '金额'
},
label: {
formatter: (value) => {
return `${value}`;
}
}
},
value1: {
max: 100,
title: {
text: '利润率'
},
label: {
formatter: (value) => {
return `${value}%`;
}
}
}
},
geometryOptions: [
{
geometry: 'line',
color: ['#FF9A49', '#7A8AA1', '#1EEB73', '#C947AE' ],
isGroup: true,
smooth: true, // 是否平滑
seriesField: 'type'
},
{
geometry: 'line',
color: ['red' ],
lineStyle: {
fill: 'red',
fillOpacity: 0.5,
stroke: 'red',
lineWidth: 4,
strokeOpacity: 0.7,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 5,
shadowOffsetY: 5,
cursor: 'pointer'
},
isStack: true,
smooth: true, // 是否平滑
seriesField: 'type', // 指定使用第二个Y轴字段
}],
});
this.chartObj.render();
},
toBeginStat() {
if (!this.dateRange) {
Message.error("请选择统计时间范围")
return
}
if (!this.mallId) {
Message.error("请选择店铺")
return
}
this.$userCheck(this.mallId).then(() => {
this.beginStat()
}).catch((err) => {
this.mallId = ''
this.isLoading = false
})
},
async beginStat() {
this.currentPage = 1
this.isLoading = true
this.saleAmount = 0.0
this.saleCount = 0
this.costAmount = 0.0
this.profitAmount = 0.0
this.profitPercent = 0.0
this.productList = []
this.productCostList = []
this.skcList = []
this.skuList = []
this.leftChartData = []
this.rightChartData = []
this.chartObj.changeData([this.leftChartData, this.rightChartData])
await this.getProductList()
await this.getSkuCostList()
await this.getSkuSaleNumber(0)
this.leftChartData.sort((a, b) => {
let leftDate = new Date(a.day)
let rightDate = new Date(b.day)
return leftDate.getTime() - rightDate.getTime()
})
this.leftChartData.map(item => {
if (item.type == '销售额' || item.type == '成本' || item.type == '利润') {
item.value = Math.round(item.value * 100) / 100
}
if (item.type == '销售额') {
this.leftChartData.map(item1 => {
if (item1.type == '成本' && item1.day == item.day) {
this.rightChartData.push({
day: item1.day,
value1: Math.round((item.value - item1.value) / item.value * 10000) / 100,
type: '利润率'
})
}
})
}
})
this.rightChartData.sort((a, b) => {
let leftDate = new Date(a.day)
let rightDate = new Date(b.day)
return leftDate.getTime() - rightDate.getTime()
})
this.skuList = this.skuList.filter(item => {
return item.saleCount > 0
})
this.skuList.map(item => {
item.saleAmount = Math.round(item.saleAmount * 100) / 100
item.costAmount = Math.round(item.costAmount * 100) / 100
item.profitAmount = Math.round(item.profitAmount * 100) / 100
})
this.skuList.map(item => {
let flag = false
for (let i = 0; i < this.skcList.length; i++) {
if (item.productSkcId == this.skcList[i].productSkcId) {
this.skcList[i].saleAmount = this.skcList[i].saleAmount + item.saleAmount
this.skcList[i].costAmount = this.skcList[i].costAmount + item.costAmount
this.skcList[i].profitAmount = this.skcList[i].profitAmount + item.profitAmount
flag = true
break
}
}
if (!flag) {
this.skcList.push({
productSkcId: item.productSkcId,
skcExtCode: item.skcExtCode,
saleAmount: item.saleAmount,
saleCount: item.saleCount,
costAmount: item.costAmount,
profitAmount: item.profitAmount,
profitPercent: item.profitPercent
})
}
})
this.skcList.map(item => {
item.saleAmount = Math.round(item.saleAmount * 100) / 100
item.costAmount = Math.round(item.costAmount * 100) / 100
item.profitAmount = Math.round(item.profitAmount * 100) / 100
})
this.leftChartData.map(item => {
if (item.type == '销售额') {
this.saleAmount = this.saleAmount + item.value
}
if (item.type == '成本') {
this.costAmount = this.costAmount + item.value
}
if (item.type == '利润') {
this.profitAmount = this.profitAmount + item.value
}
if (item.type == '单量') {
this.saleCount = this.saleCount + item.value
}
})
this.saleAmount = Math.round(this.saleAmount * 100) / 100
this.costAmount = Math.round(this.costAmount * 100) / 100
this.profitAmount = Math.round(this.profitAmount * 100) / 100
this.profitPercent = Math.round((this.saleAmount - this.costAmount) / this.saleAmount * 10000) / 100
this.chartObj.changeData([this.leftChartData, this.rightChartData])
this.isLoading = false
},
getPorductList() {
this.$http.post(`/api/skuCost/listAll`, null, {
params: {
mallId: this.storeCode
}
}).then(res => {
if (res.code == 0) {
this.productList = res.data
}
})
},
async getProductList() {
let res = await sendChromeAPIMessage({
url: 'marvel-mms/cn/api/kiana/venom/sales/management/listWarehouse',
needMallId: true,
mallId: this.mallId,
data: {
pageNo: this.currentPage,
pageSize: this.pageSize,
isLack: 0,
priceAdjustRecentDays: 7
}})
if (res.errorCode == 1000000) {
for(let i = 0;i < res.result.subOrderList.length; i++) {
let item = res.result.subOrderList[i]
let data = {}
data.productName = item.productName
data.productId = item.productId
data.productSkcId = item.productSkcId
data.skcExtCode = item.skcExtCode
for(let j = 0;j < item.skuQuantityDetailList.length; j++) {
data = {...data,
skuExtCode: item.skuQuantityDetailList[j].skuExtCode,
supplierPrice: item.skuQuantityDetailList[j].supplierPrice / 100,
productSkuId: item.skuQuantityDetailList[j].productSkuId,
className: item.skuQuantityDetailList[j].className
}
this.productList.push(data)
}
}
if ((this.currentPage * this.pageSize) < res.result.total) {
this.currentPage ++
await this.getProductList()
}
} else {
await this.getProductList()
}
},
async getSkuSaleNumber (page) {
let tempSkuId = []
let i = page * 500
let j = 0
for (; i < this.productList.length; i++) {
tempSkuId.push(this.productList[i].productSkuId)
j ++
if (j == 500) break
}
if (tempSkuId.length == 0) return
let res = await sendChromeAPIMessage({
url: 'oms/bg/venom/api/supplier/sales/management/querySkuSalesNumber',
needMallId: true,
mallId: this.mallId,
data: {
productSkuIds: tempSkuId,
startDate: this.dateRange[0],
endDate: this.dateRange[1]
}})
if (res.errorCode == 1000000) {
for (let i = 0; i < res.result.length; i++) {
let cost = this.getCost(res.result[i].prodSkuId)
let flag = false
// 计算每日销售额
let skuObj = 0
for (let k = 0; k < this.productList.length; k++) {
if (this.productList[k].productSkuId == res.result[i].prodSkuId) {
skuObj = this.productList[k]
break
}
}
for (let j = 0; j < this.leftChartData.length; j++) {
if (this.leftChartData[j].type == '销售额' && this.leftChartData[j].day == res.result[i].date) {
this.leftChartData[j].value = this.leftChartData[j].value + skuObj.supplierPrice * res.result[i].salesNumber
flag = true
break
}
}
if (!flag) {
this.leftChartData.push({
type: '销售额',
value: skuObj.supplierPrice * res.result[i].salesNumber,
day: res.result[i].date
})
}
// 计算每日销量
flag = false
for (let j = 0; j < this.leftChartData.length; j++) {
if (this.leftChartData[j].type == '单量' && this.leftChartData[j].day == res.result[i].date) {
this.leftChartData[j].value = this.leftChartData[j].value + res.result[i].salesNumber
flag = true
break
}
}
if (!flag) {
this.leftChartData.push({
type: '单量',
value: res.result[i].salesNumber,
day: res.result[i].date
})
}
// 计算每日成本
flag = false
for (let j = 0; j < this.leftChartData.length; j++) {
if (this.leftChartData[j].type == '成本' && this.leftChartData[j].day == res.result[i].date) {
this.leftChartData[j].value = this.leftChartData[j].value + cost * res.result[i].salesNumber
flag = true
break
}
}
if (!flag) {
this.leftChartData.push({
type: '成本',
value: cost * res.result[i].salesNumber,
day: res.result[i].date
})
}
// 计算每日利润
flag = false
for (let j = 0; j < this.leftChartData.length; j++) {
if (this.leftChartData[j].type == '利润' && this.leftChartData[j].day == res.result[i].date) {
this.leftChartData[j].value = this.leftChartData[j].value + (skuObj.supplierPrice - cost) * res.result[i].salesNumber
flag = true
break
}
}
if (!flag) {
this.leftChartData.push({
type: '利润',
value: (skuObj.supplierPrice - cost) * res.result[i].salesNumber,
day: res.result[i].date
})
}
// 计算SKU维度销售额
flag = false
for (let j = 0; j < this.skuList.length; j++) {
if (this.skuList[j].productSkuId == res.result[i].prodSkuId) {
this.skuList[j].saleAmount = this.skuList[j].saleAmount + skuObj.supplierPrice * res.result[i].salesNumber
this.skuList[j].costAmount = this.skuList[j].costAmount + cost * res.result[i].salesNumber
this.skuList[j].saleCount = this.skuList[j].saleCount + res.result[i].salesNumber
this.skuList[j].profitAmount = this.skuList[j].profitAmount + (skuObj.supplierPrice - cost) * res.result[i].salesNumber
flag = true
break
}
}
if (!flag) {
this.skuList.push({
productSkcId: skuObj.productSkcId,
productSkuId: skuObj.productSkuId,
skcExtCode: skuObj.skcExtCode,
skuExtCode: skuObj.skuExtCode,
saleAmount: skuObj.supplierPrice * res.result[i].salesNumber,
costAmount: cost * res.result[i].salesNumber,
profitAmount: (skuObj.supplierPrice - cost) * res.result[i].salesNumber,
saleCount: res.result[i].salesNumber,
profitPercent: Math.round((skuObj.supplierPrice - cost) / skuObj.supplierPrice * 10000) / 100
})
}
}
await this.getSkuSaleNumber(page + 1)
} else {
await this.getSkuSaleNumber(page)
}
},
async getSkuCostList() {
let res = await this.$http.post(`/api/skuCost/listAll`, null, {
params: {
mallId: this.mallId
}
})
if (res.code == 0) {
this.productCostList = res.data
}
},
getCost(sku) {
for (let i = 0; i < this.productCostList.length; i++) {
if (sku == this.productCostList[i].sku) {
return this.productCostList[i].costPrice
}
}
return 0
},
sleepSync(milliseconds) {
return new Promise(resolve => setTimeout(resolve, milliseconds));
},
async downloadPicture() {
try {
const element = document.getElementById('app-content');
const canvas = await html2canvas(element);
// 创建一个图片元素
const img = new Image();
img.src = canvas.toDataURL('image/png');
// 添加到body中以便下载
document.body.appendChild(img);
// 触发下载
const a = document.createElement('a');
a.style.display = 'none'
a.href = img.src;
a.download = '近60天销售统计.png';
a.click();
document.body.removeChild(img);
} catch (error) {
console.error('Error saving image:', error);
}
}
}
}
</script>
<style scoped lang="scss">
.list {
.title-right {
display: flex;
align-items: center;
& > div:first-child {
margin-right: 20px;
}
}
::v-deep.ai-list {
.ai-list__content--right-wrapper {
background: transparent;
box-shadow: none;
padding: 0!important;
}
}
.top {
display: flex;
justify-content: space-between;
margin-bottom: 24px;
.item {
flex: 1;
margin-right: 20px;
padding: 16px 24px;
background: #FFF;
box-shadow: 0px 4px 6px -2px rgba(15, 15, 21, 0.15);
border-radius: 4px;
&:last-child {
margin-right: 0;
}
&:nth-of-type(1) {
color: #2266ff;
}
&:nth-of-type(2) {
color: #f8b426;
}
&:nth-of-type(3) {
color: #21aa99;
}
&:nth-of-type(4) {
color: #F46;
}
&:nth-of-type(5) {
color: #11A265;
}
h2 {
margin-bottom: 30px;
font-size: 16px;
color: #999;
}
p {
font-weight: 600;
font-size: 28px;
}
}
}
}
.like {
cursor: pointer;
font-size: 25px;
display: inline-block;
}
</style>

View File

@@ -6,15 +6,50 @@
isShowBottomBorder>
</ai-title>
<template slot="content">
<ai-card title="待补充证书列表" style="padding-bottom: 40px;">
<ai-search-bar>
<template #left>
<el-radio-group v-model="certStatus" @change="getList">
<el-radio-button label="refused">已驳回</el-radio-button>
<el-radio-button label="waitUpload">待补充</el-radio-button>
</el-radio-group>
</template>
<template #right>
<el-button type="primary" @click="exportToExcel">导出</el-button>
</template>
</ai-search-bar>
<ai-card v-if="certStatus == 'refused'" title="已驳回证书列表" style="padding-bottom: 40px;">
<template #right>
<el-button type="primary" @click="exportRefusedToExcel">导出</el-button>
</template>
<ai-table
:isShowPagination="false"
:tableData="list"
:col-configs="colConfigs"
height="600"
:tableData="refusedList"
:col-configs="refusedColConfigs"
height="700"
style="margin-top: 8px;"
@getList="() => {}">
<el-table-column slot="auditStatus" width="120px" label="状态" align="left">
<template slot-scope="scope">
<div style="color: red">
审批失败
</div>
</template>
</el-table-column>
<el-table-column slot="certName" label="证书名称" align="left">
<template slot-scope="scope">
<a v-for="item in scope.row.certName" :href="item.certificate_url" target="_blank">{{ item.certificate_url_name }}</a>
</template>
</el-table-column>
</ai-table>
</ai-card>
<ai-card v-if="certStatus == 'waitUpload'" title="待补充证书列表" style="padding-bottom: 40px;">
<template #right>
<el-button type="primary" @click="exportWaitUploadToExcel">导出</el-button>
</template>
<ai-table
:isShowPagination="false"
:tableData="waitUploadList"
:col-configs="waitUploadColConfigs"
height="700"
style="margin-top: 8px;"
@getList="() => {}">
</ai-table>
@@ -36,9 +71,10 @@ import { saveAs } from 'file-saver'
data () {
return {
isLoading: false,
list: [],
mallId: '',
colConfigs: [
certStatus: 'refused',
waitUploadList: [],
waitUploadColConfigs: [
{ prop: 'spu', label: 'SPU', align: 'left' },
{ prop: 'productName', label: '商品标题', align: 'left' },
{ prop: 'skc', label: 'SKC ID', align: 'left' },
@@ -46,7 +82,20 @@ import { saveAs } from 'file-saver'
{ prop: 'certificateTypeName', label: '证书类型', align: 'left' },
{ prop: 'mergeSiteName', label: '管控地区', align: 'left' },
{ prop: 'subSite', label: '管控子站点', align: 'left' },
{ slot: 'uploadEndTime', label: '上传截止时间', align: 'left' }
{ prop: 'uploadEndTime', label: '上传截止时间', align: 'left' }
],
refusedList: [],
refusedColConfigs: [
{ prop: 'spu', label: 'SPU', align: 'left' },
{ prop: 'productName', label: '商品标题', align: 'left' },
{ prop: 'skc', label: 'SKC ID', align: 'left' },
{ prop: 'mainAttrName', label: '主规格', align: 'left' },
{ slot: 'auditStatus', label: '状态' },
{ prop: 'certificateTypeName', label: '证书类型', align: 'left' },
{ slot: 'certName', label: '证书名称' },
{ prop: 'refusedReason', label: '审核备注', align: 'left' },
{ prop: 'mergeSiteName', label: '管控地区', align: 'left' },
{ prop: 'subSite', label: '管控子站点', align: 'left' }
],
tableData: [],
@@ -55,12 +104,33 @@ import { saveAs } from 'file-saver'
},
mounted () {
this.isLoading = true
this.getList()
this.$http.post('/api/malluser/info').then(res => {
if (res.code == 0) {
this.$store.commit('setUserInfo', res.data)
if (res.data.flag != 1) {
Message.error('您的账号未激活或已失效,请激活后使用')
this.$store.commit('setActiveDlgShow', true)
return;
}
this.getList()
}
})
},
methods: {
async getList () {
this.isLoading = true
this.currentPage = 1
if (this.certStatus == 'refused') {
this.refusedList = []
await this.getRefusedList()
} else {
this.waitUploadList = []
await this.getWaitUploadList()
}
this.isLoading = false
},
async getWaitUploadList() {
let res = await sendGeiwohuoAPIMessage({
url: `spmp-api-prefix/spmp/certificate/get_skc_certificate_miss_list?page_num=${this.currentPage}&page_size=200`,
method: 'POST',
@@ -84,30 +154,95 @@ import { saveAs } from 'file-saver'
subSite: subSite.join(',')
}
this.list.push(data)
this.waitUploadList.push(data)
}
if (res.info.data.length == 200 && (res.info.meta.count > 200*this.currentPage)) {
this.currentPage++
await this.sleepSync(200)
await this.getList()
} else {
this.isLoading = false
await this.getWaitUploadList()
}
} else if (res.code == 100004 || res.code == 20302) {
this.isLoading = false
this.$store.commit("setSheinAlertShow", true)
}
},
async getRefusedList() {
let res = await sendGeiwohuoAPIMessage({
url: `spmp-api-prefix/spmp/certificate/get_skc_certificate_list?page_num=${this.currentPage}&page_size=200`,
method: 'POST',
data: {
audit_status: 3
}})
if (res.code == '0') {
for(let i = 0;i < res.info.data.length; i++) {
let item = res.info.data[i];
let mainSite = []
let subSite = []
item.merge_site_info_list.map(e => {
mainSite.push(e.merge_site_name)
subSite = subSite.concat(e.sub_site_list)
})
let data = {
pqmsCertificateSn: item.pqms_certificate_sn,
auditStatus: item.audit_status,
spu: item.spu_name,
productName: item.skc_name_cn,
skc: item.skc_name,
mainAttrName: item.main_attribute_name,
mergeSiteName: mainSite.join(','),
certificateTypeName: item.certificate_type_name,
certName: item.cert_file_list,
refusedReason: null,
subSite: subSite.join(',')
}
this.refusedList.push(data)
}
if (res.info.data.length == 200 && (res.info.meta.count > 200*this.currentPage)) {
this.currentPage++
await this.sleepSync(200)
await this.getRefusedList()
} else {
await this.getAuditInfo()
}
} else if (res.code == 100004 || res.code == 20302) {
this.$store.commit("setSheinAlertShow", true)
}
},
async getAuditInfo() {
let pqmsList = []
this.refusedList.map(item => {
pqmsList.push(item.pqmsCertificateSn)
})
let res = await sendGeiwohuoAPIMessage({
url: `spmp-api-prefix/spmp/certificate/get_cert_audit_fail_reason`,
method: 'POST',
data: {
pqms_certificate_sn_list: pqmsList
}})
if (res.code == '0') {
res.info.data.map(item => {
for (let i = 0; i < this.refusedList.length; i++) {
if (this.refusedList[i].pqmsCertificateSn == item.certificate_sn) {
this.refusedList[i].refusedReason = item.fail_reason
break
}
}
})
} else if (res.code == 100004 || res.code == 20302) {
this.$store.commit("setSheinAlertShow", true)
}
},
sleepSync(milliseconds) {
return new Promise(resolve => setTimeout(resolve, milliseconds));
},
exportToExcel() {
exportWaitUploadToExcel() {
// 假设你有一个表格数据的数组
const data = [
["SPU", "商品标题", "SKC ID", "主规格", "证书类型", "管控地区", "管控子站点", "上传截止时间"]
]
this.list.map(item => {
this.waitUploadList.map(item => {
data.push([item.spu, item.productName, item.skc, item.mainAttrName, item.certificateTypeName, item.mergeSiteName, item.subSite, item.uploadEndTime])
})
@@ -128,6 +263,41 @@ import { saveAs } from 'file-saver'
// 使用saveAs下载文件
saveAs(dataBlob, '待补充证书列表.xlsx');
// 清理
window.URL.revokeObjectURL(blobUrl);
},
exportRefusedToExcel() {
// 假设你有一个表格数据的数组
const data = [
["SPU", "商品标题", "SKC ID", "主规格", "证书类型","证书名称", "证书地址", "审核备注", "管控地区", "管控子站点"]
]
this.refusedList.map(item => {
let certName = [], certUrl = []
item.certName.map(item1 => {
certName.push(item1.certificate_url_name)
certUrl.push(item1.certificate_url)
})
data.push([item.spu, item.productName, item.skc, item.mainAttrName, item.certificateTypeName, certName.join(','), certUrl.join(','), item.refusedReason, item.mergeSiteName, item.subSite])
})
// 将数据转换为工作表
const worksheet = XLSX.utils.aoa_to_sheet(data);
// 创建工作簿并添加工作表
const workbook = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1');
// 生成Excel文件
const excelBuffer = XLSX.write(workbook, { bookType: 'xlsx', type: 'array' });
// 使用blob和FileReader创建一个Blob URL
const dataBlob = new Blob([excelBuffer], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8' });
const blobUrl = window.URL.createObjectURL(dataBlob);
// 使用saveAs下载文件
saveAs(dataBlob, '已驳回证书列表.xlsx');
// 清理
window.URL.revokeObjectURL(blobUrl);
}

View File

@@ -26,6 +26,7 @@
style="margin-top: 8px;"
:current.sync="search.current" :size.sync="search.size"
@selection-change="handleSelectionChange"
height="700"
@getList="getList">
</ai-table>
</div>
@@ -140,7 +141,17 @@ import { Message } from 'element-ui'
},
created () {
this.getList()
this.$http.post('/api/malluser/info').then(res => {
if (res.code == 0) {
this.$store.commit('setUserInfo', res.data)
if (res.data.flag != 1) {
Message.error('您的账号未激活或已失效,请激活后使用')
this.$store.commit('setActiveDlgShow', true)
return;
}
this.getList()
}
})
},
methods: {

View File

@@ -179,9 +179,19 @@ import { saveAs } from 'file-saver'
},
mounted () {
this.getUserInfo()
this.isLoading = true
this.getList()
this.$http.post('/api/malluser/info').then(res => {
if (res.code == 0) {
this.$store.commit('setUserInfo', res.data)
if (res.data.flag != 1) {
Message.error('您的账号未激活或已失效,请激活后使用')
this.$store.commit('setActiveDlgShow', true)
return;
}
this.getUserInfo()
this.isLoading = true
this.getList()
}
})
},
methods: {

View File

@@ -54,7 +54,7 @@
ref="table0"
:isShowPagination="false"
:tableData="filteredData"
height="500"
height="700"
:col-configs="colConfigs"
:total="filteredData.length"
style="margin-top: 8px;"
@@ -134,7 +134,9 @@ import { Message } from 'element-ui'
{prop: 'ableSaleDays',label: '可售天数',align: 'center'},
{prop: 'cost',label: '价格',width: '120px',align: 'center'},
{prop: 'costPrice',label: '成本',width: '120px',align: 'center'},
{prop: 'todaySale',label: '今日销量',width: '120px',align: 'center'},
{prop: 'todaySale',label: '今日销量',width: '120px',align: 'center',sortable: true,'sort-method': (a, b) => {
return a.todaySale - b.todaySale
}},
{prop: 'todayProfit',label: '利润',width: '120px',align: 'center',sortable: true,'sort-method': (a, b) => {
return a.todayProfit - b.todayProfit
}},

View File

@@ -30,8 +30,8 @@
<json-excel
:data="skuList"
:fields="skuJsonFields"
name="SKC账单数据.xls"
worksheet="SKC账单数据">
name="SKU账单数据.xls"
worksheet="SKU账单数据">
<el-button type="primary" icon="el-icon-download">下载SKU统计</el-button>
</json-excel>
</div>
@@ -310,7 +310,7 @@ import { DualAxes } from '@antv/g2plot'
isLoading: false,
skcColConfigs: [
{ prop: 'skcCode', label: '货号', width: '180px' },
{ prop: 'skcCode', label: '货号', width: '250px' },
{ slot: 'amount', label: '销售额', align: 'center' },
{ prop: 'quantity', label: '单数', align: 'center' },
{ prop: 'cost', label: '成本', align: 'center'},
@@ -327,7 +327,7 @@ import { DualAxes } from '@antv/g2plot'
"利润率": "profitPercent",
},
skuColConfigs: [
{ prop: 'skuCode', label: '属性集', width: '220px' },
{ prop: 'skuCode', label: '属性集', width: '250px' },
{ slot: 'amount', label: '销售额', align: 'center' },
{ prop: 'quantity', label: '单数', align: 'center' },
{ prop: 'cost', label: '成本', align: 'center'},
@@ -602,7 +602,6 @@ import { DualAxes } from '@antv/g2plot'
}
}
}
console.log(this.leftChartData)
this.chartObj.changeData([this.leftChartData, this.rightChartData])
this.isLoading = false
}
@@ -665,6 +664,9 @@ import { DualAxes } from '@antv/g2plot'
} else {
break
}
} else if (res2.code == 100004 || res2.code == 20302) {
this.isLoading = false
this.$store.commit("setSheinAlertShow", true)
}
}
}

View File

@@ -21,26 +21,36 @@
</template>
</ai-title>
<template slot="content">
<ai-search-bar>
<template #left>
<div class="search-item">
<label>状态</label>
<el-select v-model="form.status" multiple placeholder="请选择">
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</div>
<div class="search-item">
<label style="width:120px">备货单创建时间</label>
<el-date-picker
v-model="form.date"
type="daterange"
range-separator=""
start-placeholder="开始日期"
end-placeholder="结束日期">
</el-date-picker>
</div>
</template>
<template #right>
<el-button type="primary" @click="toLoad">加载</el-button>
</template>
</ai-search-bar>
<ai-card title="数据明细" style="padding-bottom: 40px;">
<template #right>
<label style="width:80px">状态</label>
<el-select v-model="form.status" multiple placeholder="请选择">
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
<label style="width:120px">备货单创建时间</label>
<el-date-picker
v-model="form.date"
type="daterange"
range-separator=""
start-placeholder="开始日期"
end-placeholder="结束日期">
</el-date-picker>
<el-button type="primary" @click="toLoad">加载</el-button>&nbsp;
<json-excel
:data="tableData"
:fields="jsonFields"
@@ -59,6 +69,26 @@
@getList="() => {}">
</ai-table>
</ai-card>
<ai-card title="数据统计" style="padding-bottom: 40px;">
<template #right>
<json-excel
:data="sumTableData"
:fields="sumJsonFields"
name="普通备货单统计.xls"
worksheet="普通备货单统计">
<el-button type="primary" :disabled="sumTableData.length == 0">下载数据</el-button>
</json-excel>
</template>
<ai-table
:isShowPagination="false"
:tableData="sumTableData"
:col-configs="sumColConfigs"
:total="sumTableData.length"
height="500"
style="margin-top: 8px;"
@getList="() => {}">
</ai-table>
</ai-card>
</template>
</ai-list>
</template>
@@ -116,6 +146,7 @@ import JsonExcel from 'vue-json-excel'
{ prop: 'extCode', label: 'SKU货号', width: '160px', align: 'left' },
{ prop: 'specName', label: 'SKU属性', width: '100px', align: 'left' },
{ prop: 'supplierPrice', label: '申报价格(CNY)', width: '180px', align: 'left' },
{ prop: 'cost', label: '成本价格(CNY)', width: '180px', align: 'left' },
{ prop: 'purchaseQuantity', label: '备货件数', width: '100px', align: 'left' },
{ prop: 'xiadan', label: '送货数量', width: '100px', align: 'left' },
{ prop: 'skuNum', label: '入库数量', width: '100px', align: 'left' },
@@ -123,8 +154,25 @@ import JsonExcel from 'vue-json-excel'
{ prop: 'deliverTime', label: '发货时间', width: '160px', align: 'left' },
{ prop: 'receiveTime', label: '收货时间', width: '160px', align: 'left' }
],
sumTableData: [],
sumColConfigs: [
{ prop: 'productName', label: '商品名称', width: '240px', align: 'left', fixed: 'left' },
{ prop: 'productSkcId', label: 'SKC ID', width: '120px', align: 'left' },
{ prop: 'skcExtCode', label: 'SKC货号', width: '100px', align: 'left' },
{ prop: 'productSkuId', label: 'SKU ID', width: '120px', align: 'left' },
{ prop: 'extCode', label: 'SKU货号', width: '160px', align: 'left' },
{ prop: 'specName', label: 'SKU属性', width: '100px', align: 'left' },
{ prop: 'supplierPrice', label: '申报价格(CNY)', width: '180px', align: 'left' },
{ prop: 'cost', label: '成本价格(CNY)', width: '180px', align: 'left', sortable: true, 'sort-method': (a, b) => a.cost - b.cost },
{ prop: 'purchaseQuantity', label: '备货总件数', width: '100px', align: 'left', sortable: true, 'sort-method': (a, b) => a.purchaseQuantity - b.purchaseQuantity },
{ prop: 'xiadan', label: '送货总数量', width: '100px', align: 'left', sortable: true, 'sort-method': (a, b) => a.xiadan - b.xiadan },
{ prop: 'skuNum', label: '实际入库总数量', width: '100px', align: 'left', sortable: true, 'sort-method': (a, b) => a.skuNum - b.skuNum },
{ prop: 'costAmount', label: '成本总额', width: '140px', align: 'left', sortable: true, 'sort-method': (a, b) => a.costAmount - b.costAmount },
{ prop: 'profit', label: '预计利润总额', width: '160px', align: 'left', sortable: true, 'sort-method': (a, b) => a.profit - b.profit },
],
isLoading: false,
tableData: [],
costList: [],
jsonFields: {
"备货单创建时间": "purchaseTime",
"备货单号": "subPurchaseOrderSn",
@@ -137,6 +185,7 @@ import JsonExcel from 'vue-json-excel'
"SKU货号": "extCode",
"SKU属性": "specName",
"申报价格(CNY)": "supplierPrice",
"成本价格(CNY)": "cost",
"备货件数": "purchaseQuantity",
"下单数量": "xiadan",
"实际入库数量": "skuNum",
@@ -144,7 +193,22 @@ import JsonExcel from 'vue-json-excel'
"发货时间": "deliverTime",
"收货时间": "receiveTime"
},
snList: [],
sumJsonFields: {
"商品名称": "productName",
"商品图片": "productSkcPicture",
"SKC ID": "productSkcId",
"SKC货号": "skcExtCode",
"SKU ID": "productSkuId",
"SKU货号": "extCode",
"SKU属性": "specName",
"申报价格(CNY)": "supplierPrice",
"成本价格(CNY)": "cost",
"备货总件数": "purchaseQuantity",
"送货总数量": "xiadan",
"实际入库总数量": "skuNum",
"成本总额": "costAmount",
"预计利润总额": "profit"
},
currentIndex: 0
}
},
@@ -168,64 +232,123 @@ import JsonExcel from 'vue-json-excel'
Message.error("请选择时间")
return
}
this.getSkuCostList()
this.reqData.purchaseTimeFrom = this.form.date[0].getTime()
this.reqData.purchaseTimeTo = this.form.date[1].getTime() + 86400 * 1000
this.reqData.pageNo = 1
this.reqData.statusList = this.form.status
this.tableData = []
this.sumTableData = []
this.packageNumber = 0
this.snList = []
this.currentIndex = 0
this.costList = []
this.isLoading = true
this.load()
},
load() {
sendChromeAPIMessage({
async load() {
let res = await sendChromeAPIMessage({
url: 'oms/bg/venom/api/supplier/purchase/manager/querySubOrderList',
needMallId: true,
mallId: this.form.mallId,
anti: true,
data: this.reqData}).then((res) => {
if (res.errorCode == 1000000) {
for(let i = 0;i < res.result.subOrderForSupplierList.length; i++) {
let item = res.result.subOrderForSupplierList[i];
let data = {};
data.purchaseTime = timestampToTime(item.purchaseTime)
data.subPurchaseOrderSn = item.subPurchaseOrderSn
data.productName = item.productName
data.productSkcPicture = item.productSkcPicture
data.productSkcId = item.productSkcId
data.skcExtCode = item.productSn
data.status = this.options.filter(i => {return i.value == item.status})[0].label
data.deliveryOrderSn = item.deliverInfo.deliveryOrderSn
data.deliverTime = timestampToTime(item.deliverInfo.deliverTime)
data.receiveTime = timestampToTime(item.deliverInfo.receiveTime)
for(let k = 0; k < item.skuQuantityDetailList.length; k++) {
data = {...data,
productSkuId: item.skuQuantityDetailList[k].productSkuId,
specName: item.skuQuantityDetailList[k].className,
extCode: item.skuQuantityDetailList[k].extCode,
supplierPrice: item.skuQuantityDetailList[k].supplierPrice / 100,
purchaseQuantity: item.skuQuantityDetailList[k].purchaseQuantity,
xiadan: item.skuQuantityDetailList[k].deliverQuantity,
skuNum: item.skuQuantityDetailList[k].realReceiveAuthenticQuantity}
data: this.reqData})
if (res.errorCode == 1000000) {
for(let i = 0;i < res.result.subOrderForSupplierList.length; i++) {
let item = res.result.subOrderForSupplierList[i];
let data = {};
data.purchaseTime = timestampToTime(item.purchaseTime)
data.subPurchaseOrderSn = item.subPurchaseOrderSn
data.productName = item.productName
data.productSkcPicture = item.productSkcPicture
data.productSkcId = item.productSkcId
data.skcExtCode = item.productSn
data.status = this.options.filter(i => {return i.value == item.status})[0].label
data.deliveryOrderSn = item.deliverInfo.deliveryOrderSn
data.deliverTime = timestampToTime(item.deliverInfo.deliverTime)
data.receiveTime = timestampToTime(item.deliverInfo.receiveTime)
for(let k = 0; k < item.skuQuantityDetailList.length; k++) {
data = {...data,
productSkuId: item.skuQuantityDetailList[k].productSkuId,
specName: item.skuQuantityDetailList[k].className,
extCode: item.skuQuantityDetailList[k].extCode,
supplierPrice: item.skuQuantityDetailList[k].supplierPrice / 100,
purchaseQuantity: item.skuQuantityDetailList[k].purchaseQuantity,
xiadan: item.skuQuantityDetailList[k].deliverQuantity,
skuNum: item.skuQuantityDetailList[k].realReceiveAuthenticQuantity,
cost: null}
this.tableData.push(data)
}
}
if (this.reqData.pageNo == 1 && res.result.subOrderForSupplierList.length == 0) {
this.isLoading = false
}
else if (res.result.subOrderForSupplierList.length == 100) {
this.reqData.pageNo ++
this.load()
} else {
this.isLoading = false
}
this.tableData.push(data)
}
})
}
if (this.reqData.pageNo == 1 && res.result.subOrderForSupplierList.length == 0) {
this.isLoading = false
}
else if (res.result.subOrderForSupplierList.length == 100) {
this.reqData.pageNo ++
this.load()
} else {
this.tableData.map(item => {
for (let i = 0; i < this.costList.length; i++) {
if (this.costList[i].sku == item.productSkuId) {
item.cost = this.costList[i].costPrice
break
}
}
let flag = false
for (let i = 0; i < this.sumTableData.length; i++) {
if (this.sumTableData[i].productSkuId == item.productSkuId) {
this.sumTableData[i].xiadan += item.xiadan
this.sumTableData[i].purchaseQuantity += item.purchaseQuantity
this.sumTableData[i].skuNum += item.skuNum
flag = true
break
}
}
if (!flag) {
this.sumTableData.push({
productName: item.productName,
productSkcPicture: item.productSkcPicture,
productSkcId: item.productSkcId,
productSkuId: item.productSkuId,
xiadan: item.xiadan,
purchaseQuantity: item.purchaseQuantity,
skuNum: item.skuNum,
skcExtCode: item.skcExtCode,
extCode: item.extCode,
supplierPrice: item.supplierPrice,
specName: item.specName,
cost: null,
costAmount: null,
profit: null
})
}
})
this.sumTableData.map(item => {
for (let i = 0; i < this.costList.length; i++) {
if (this.costList[i].sku == item.productSkuId) {
item.cost = this.costList[i].costPrice
item.costAmount = Math.round(this.costList[i].costPrice * item.skuNum * 100) / 100
item.profit = Math.round((item.supplierPrice - item.cost) * item.skuNum * 100) / 100
break
}
}
})
this.isLoading = false
}
}
},
async getSkuCostList() {
let res = await this.$http.post(`/api/skuCost/listAll`, null, {
params: {
mallId: this.form.mallId
}
})
if (res.code == 0) {
this.costList = res.data
}
}
}
}

View File

@@ -21,26 +21,36 @@
</template>
</ai-title>
<template slot="content">
<ai-search-bar>
<template #left>
<div class="search-item">
<label>状态</label>
<el-select v-model="form.status" multiple placeholder="请选择">
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</div>
<div class="search-item">
<label style="width:120px">备货单创建时间</label>
<el-date-picker
v-model="form.date"
type="daterange"
range-separator=""
start-placeholder="开始日期"
end-placeholder="结束日期">
</el-date-picker>
</div>
</template>
<template #right>
<el-button type="primary" @click="toLoad">加载</el-button>
</template>
</ai-search-bar>
<ai-card title="数据明细" style="padding-bottom: 40px;">
<template #right>
<label style="width:80px">状态</label>
<el-select v-model="form.status" multiple placeholder="请选择">
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
<label style="width:120px">备货单创建时间</label>
<el-date-picker
v-model="form.date"
type="daterange"
range-separator=""
start-placeholder="开始日期"
end-placeholder="结束日期">
</el-date-picker>
<el-button type="primary" @click="toLoad">加载</el-button>&nbsp;
<json-excel
:data="tableData"
:fields="jsonFields"
@@ -59,6 +69,26 @@
@getList="() => {}">
</ai-table>
</ai-card>
<ai-card title="数据统计" style="padding-bottom: 40px;">
<template #right>
<json-excel
:data="sumTableData"
:fields="sumJsonFields"
name="紧急备货单统计.xls"
worksheet="紧急备货单统计">
<el-button type="primary" :disabled="sumTableData.length == 0">下载数据</el-button>
</json-excel>
</template>
<ai-table
:isShowPagination="false"
:tableData="sumTableData"
:col-configs="sumColConfigs"
:total="sumTableData.length"
height="500"
style="margin-top: 8px;"
@getList="() => {}">
</ai-table>
</ai-card>
</template>
</ai-list>
</template>
@@ -123,8 +153,24 @@ import JsonExcel from 'vue-json-excel'
{ prop: 'deliverTime', label: '发货时间', width: '160px', align: 'left' },
{ prop: 'receiveTime', label: '收货时间', width: '160px', align: 'left' }
],
sumTableData: [],
sumColConfigs: [
{ prop: 'productName', label: '商品名称', width: '240px', align: 'left', fixed: 'left' },
{ prop: 'productSkcId', label: 'SKC ID', width: '120px', align: 'left' },
{ prop: 'skcExtCode', label: 'SKC货号', width: '100px', align: 'left' },
{ prop: 'productSkuId', label: 'SKU ID', width: '120px', align: 'left' },
{ prop: 'extCode', label: 'SKU货号', width: '160px', align: 'left' },
{ prop: 'specName', label: 'SKU属性', width: '100px', align: 'left' },
{ prop: 'supplierPrice', label: '申报价格(CNY)', width: '180px', align: 'left' },
{ prop: 'cost', label: '成本价格(CNY)', width: '180px', align: 'left', sortable: true, 'sort-method': (a, b) => a.cost - b.cost },
{ prop: 'xiadan', label: '送货总数量', width: '100px', align: 'left', sortable: true, 'sort-method': (a, b) => a.xiadan - b.xiadan },
{ prop: 'skuNum', label: '实际入库总数量', width: '100px', align: 'left', sortable: true, 'sort-method': (a, b) => a.skuNum - b.skuNum },
{ prop: 'costAmount', label: '成本总额', width: '140px', align: 'left', sortable: true, 'sort-method': (a, b) => a.costAmount - b.costAmount },
{ prop: 'profit', label: '预计利润总额', width: '160px', align: 'left', sortable: true, 'sort-method': (a, b) => a.profit - b.profit },
],
isLoading: false,
tableData: [],
costList: [],
jsonFields: {
"备货单创建时间": "purchaseTime",
"备货单号": "subPurchaseOrderSn",
@@ -143,7 +189,21 @@ import JsonExcel from 'vue-json-excel'
"发货时间": "deliverTime",
"收货时间": "receiveTime"
},
snList: [],
sumJsonFields: {
"商品名称": "productName",
"商品图片": "productSkcPicture",
"SKC ID": "productSkcId",
"SKC货号": "skcExtCode",
"SKU ID": "productSkuId",
"SKU货号": "extCode",
"SKU属性": "specName",
"申报价格(CNY)": "supplierPrice",
"成本价格(CNY)": "cost",
"送货总数量": "xiadan",
"实际入库总数量": "skuNum",
"成本总额": "costAmount",
"预计利润总额": "profit"
},
currentIndex: 0
}
},
@@ -167,13 +227,14 @@ import JsonExcel from 'vue-json-excel'
Message.error("请选择时间")
return
}
this.getSkuCostList()
this.reqData.purchaseTimeFrom = this.form.date[0].getTime()
this.reqData.purchaseTimeTo = this.form.date[1].getTime() + 86400 * 1000
this.reqData.pageNo = 1
this.reqData.statusList = this.form.status
this.tableData = []
this.costList = []
this.packageNumber = 0
this.snList = []
this.currentIndex = 0
this.isLoading = true
this.load()
@@ -220,10 +281,59 @@ import JsonExcel from 'vue-json-excel'
this.reqData.pageNo ++
this.load()
} else {
this.tableData.map(item => {
let flag = false
for (let i = 0; i < this.sumTableData.length; i++) {
if (this.sumTableData[i].productSkuId == item.productSkuId) {
this.sumTableData[i].xiadan += item.xiadan
this.sumTableData[i].purchaseQuantity += item.purchaseQuantity
this.sumTableData[i].skuNum += item.skuNum
flag = true
break
}
}
if (!flag) {
this.sumTableData.push({
productName: item.productName,
productSkcPicture: item.productSkcPicture,
productSkcId: item.productSkcId,
productSkuId: item.productSkuId,
xiadan: item.xiadan,
skuNum: item.skuNum,
skcExtCode: item.skcExtCode,
extCode: item.extCode,
supplierPrice: item.supplierPrice,
specName: item.specName,
cost: null,
costAmount: null,
profit: null
})
}
})
this.sumTableData.map(item => {
for (let i = 0; i < this.costList.length; i++) {
if (this.costList[i].sku == item.productSkuId) {
item.cost = this.costList[i].costPrice
item.costAmount = Math.round(this.costList[i].costPrice * item.skuNum * 100) / 100
item.profit = Math.round((item.supplierPrice - item.cost) * item.skuNum * 100) / 100
break
}
}
})
this.isLoading = false
}
}
})
},
async getSkuCostList() {
let res = await this.$http.post(`/api/skuCost/listAll`, null, {
params: {
mallId: this.form.mallId
}
})
if (res.code == 0) {
this.costList = res.data
}
}
}
}

View File

@@ -432,6 +432,7 @@
this.isDlgLoading = true
this.getList(this.tableData, this.mallId, this.mallName, 1)
}).catch((err) => {
this.mallId = ''
console.log(err)
})
},
@@ -688,11 +689,19 @@
this.createDeliveryBill(sn, mallId)
}
} else {
this.choosedSnMallList.push(obj)
for (let j = 0; j < this.choosedList.length; j++) {
if (this.choosedList[j].subPurchaseOrderSn == sn) {
this.choosedList[j].robTotal ++;
break;
if (res.result?.errorInfoList[0] && res.result?.errorInfoList[0].errorCode == 60002) {
for (let j = 0; j < this.choosedList.length; j++) {
if (this.choosedList[j].subPurchaseOrderSn == sn) {
this.choosedList.splice(j, 1);
}
}
} else {
this.choosedSnMallList.push(obj)
for (let j = 0; j < this.choosedList.length; j++) {
if (this.choosedList[j].subPurchaseOrderSn == sn) {
this.choosedList[j].robTotal ++;
break;
}
}
}
}

View File

@@ -0,0 +1,237 @@
<template>
<ai-list class="list" v-loading="isLoading" element-loading-text="拼命加载中" element-loading-spinner="el-icon-loading">
<ai-title
slot="title"
title="商品条码管理"
tips="每页为100条商品数据"
isShowBottomBorder>
<template #rightBtn>
<div class="title-right">
<div>
<label style="width:90px">店铺</label>
<el-select v-model="form.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>
</template>
</ai-title>
<template slot="content">
<div class="content">
<ai-search-bar>
<template #left>
<div class="search-item">
<label>起始页</label>
<el-input size="small" placeholder="请输入起始页" type="number" v-model="startPage"></el-input>
</div>
<div class="search-item">
<label>结束页</label>
<el-input size="small" placeholder="请输入起始页" type="number" v-model="endPage"></el-input>
</div>
</template>
<template #right>
<el-button type="primary" @click="toLoad">加载</el-button>
</template>
</ai-search-bar>
<ai-card title="数据明细" style="padding-bottom: 40px;">
<template #right>
<el-button type="primary" :disabled="tableData.length == 0" @click="exportWaitUploadToExcel">导出</el-button>
</template>
<ai-table
:isShowPagination="false"
:tableData="tableData"
:col-configs="colConfigs"
:total="tableData.length"
height="700"
style="margin-top: 8px;"
@getList="() => {}">
<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>
</ai-card>
</div>
</template>
</ai-list>
</template>
<script>
import { Message } from 'element-ui'
import {sendChromeAPIMessage} from '@/api/chromeApi'
import {timestampToTime} from '@/utils/date'
import * as XLSX from 'xlsx'
import { saveAs } from 'file-saver'
export default {
name: 'ProductLabel',
data () {
return {
form: {
mallId: ''
},
startPage: 1,
endPage: 10,
reqData: {
page: 1,
pageSize: 100
},
colConfigs: [
{ slot: 'productName', label: '商品名称', width: '300px', align: 'left', fixed: 'left' },
{ prop: 'category', label: '分类', width: '140px', align: 'left', fixed: 'left' },
{ prop: 'labelCode', label: '条码编码', align: 'left' },
{ prop: 'productSkcId', label: 'SKC', align: 'left' },
{ prop: 'productSkuId', label: 'SKU', align: 'left' },
{ prop: 'extCode', label: 'SKC货号', align: 'left' },
{ prop: 'skuExtCode', label: 'SKU货号', align: 'left' },
{ prop: 'skcSpecName', label: '主销售属性', align: 'left' },
{ prop: 'skuSpecName', label: '次销售属性', width: '100px', align: 'left' }
],
isLoading: false,
tableData: [],
currentIndex: 0
}
},
created () {
},
methods: {
beforeGetList() {
this.$userCheck(this.form.mallId).then(() => {
this.toLoad()
}).catch((err) => {
this.form.mallId = ''
})
},
toLoad() {
if (!this.form.mallId) {
Message.error("请选择店铺")
return
}
if (!this.startPage || (this.startPage < 1)) {
Message.error("起始页不能为空且不能小于1")
return
}
if (!this.endPage || (this.startPage < 1)) {
Message.error("结束页不能为空")
return
}
if (this.startPage > this.endPage) {
Message.error("起始页不能大于结束页")
return
}
this.$userCheck(this.form.mallId).then(() => {
this.reqData.page = this.startPage
this.tableData = []
this.currentIndex = 0
this.isLoading = true
this.load()
}).catch((err) => {
this.form.mallId = ''
})
},
load() {
sendChromeAPIMessage({
url: 'bg-visage-mms/labelcode/pageQuery',
needMallId: true,
mallId: this.form.mallId,
anti: true,
data: this.reqData}).then((res) => {
if (res.errorCode == 1000000) {
for(let i = 0;i < res.result.pageItems.length; i++) {
let item = res.result.pageItems[i];
let data = {};
data.productName = item.productName
data.mainImageUrl = item.displayImage
data.productSkcId = item.labelCodeVO.productSkcId
data.productSkuId = item.labelCodeVO.productSkuId
data.labelCode = item.labelCodeVO.labelCode
data.extCode = item.labelCodeVO.skcExtCode
data.skuExtCode = item.labelCodeVO.skuExtCode
data.category = item.leafCat.catName
let temp = item.productSkcSpecList.map(item2 => {
return item2.specName
})
data.skcSpecName = temp.join(',')
temp = item.productSkuSpecList.map(item2 => {
return item2.specName
})
data.skuSpecName = temp.join(',')
this.tableData.push(data)
}
if (res.result.pageItems.length == this.reqData.pageSize && this.reqData.page < this.endPage) {
this.reqData.page ++
this.load()
} else {
this.isLoading = false
}
}
})
},
exportWaitUploadToExcel() {
// 假设你有一个表格数据的数组
const data = [
["商品名称", "分类", "条码编码", "SKC","SKU", "SKC货号", "SKU货号", "主销售属性", "次销售属性"]
]
this.tableData.map(item => {
data.push([item.productName, item.category, item.labelCode, item.productSkcId, item.productSkuId, item.extCode, item.skuExtCode, item.skcSpecName, item.skuSpecName])
})
// 将数据转换为工作表
const worksheet = XLSX.utils.aoa_to_sheet(data);
// 创建工作簿并添加工作表
const workbook = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1');
// 生成Excel文件
const excelBuffer = XLSX.write(workbook, { bookType: 'xlsx', type: 'array' });
// 使用blob和FileReader创建一个Blob URL
const dataBlob = new Blob([excelBuffer], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8' });
const blobUrl = window.URL.createObjectURL(dataBlob);
// 使用saveAs下载文件
saveAs(dataBlob, '商品条码列表.xlsx');
// 清理
window.URL.revokeObjectURL(blobUrl);
}
}
}
</script>
<style scoped lang="scss">
.list {
.title-right {
display: flex;
align-items: center;
& > div:first-child {
margin-right: 20px;
}
}
::v-deep.ai-list {
.ai-list__content--right-wrapper {
background: transparent;
box-shadow: none;
padding: 0!important;
}
}
}
</style>

View File

@@ -256,6 +256,7 @@
this.isDlgLoading = true
this.getList(this.tableData, this.mallId, this.mallName, 1)
}).catch((err) => {
this.mallId = ''
console.log(err)
})
},

View File

@@ -216,6 +216,7 @@
this.isDlgLoading = true
this.getList(this.tableData, this.mallId, this.mallName, 1)
}).catch((err) => {
this.mallId = ''
console.log(err)
})
},

View File

@@ -123,6 +123,7 @@ import { Message } from 'element-ui'
this.skcIds = []
this.getList()
}).catch((err) => {
this.mallId = ''
this.isLoading = false
})
},

View File

@@ -121,6 +121,7 @@ import { Message } from 'element-ui'
this.isLoading = true
this.getList()
}).catch((err) => {
this.mallId = ''
this.isLoading = false
})
},

View File

@@ -51,6 +51,7 @@
</json-excel>
</template>
<ai-table
:isShowPagination="false"
:tableData="tableData"
:col-configs="colConfigs"
:total="total"
@@ -70,6 +71,26 @@
</el-table-column>
</ai-table>
</ai-card>
<ai-card title="数据统计" style="padding-bottom: 40px;">
<template #right>
<json-excel
:data="sumTableData"
:fields="sumJsonFields"
name="退货统计.xls"
worksheet="退货统计">
<el-button type="primary" :disabled="sumTableData.length == 0">下载数据</el-button>
</json-excel>
</template>
<ai-table
:isShowPagination="false"
:tableData="sumTableData"
:col-configs="sumColConfigs"
:total="sumTableData.length"
height="500"
style="margin-top: 8px;"
@getList="() => {}">
</ai-table>
</ai-card>
</div>
</template>
</ai-list>
@@ -98,8 +119,18 @@ import { Message } from 'element-ui'
{ prop: 'orderTypeDesc', label: '退货原因',width: '220px', align: 'left' },
{ prop: 'packageSn', label: '退货包裹号', width: '200px',align: 'left' },
{ prop: 'quantity', label: 'SKU件数',width: '100px', },
{ prop: 'cost', label: '成本单价' },
{ prop: 'outboundTime', label: '出库时间', width: '160px'}
],
sumColConfigs: [
{ prop: 'productSkcId', label: 'SKC', align: 'left', fixed: 'left' },
{ prop: 'productSkuId', label: 'SKU', align: 'left', fixed: 'left' },
{ prop: 'skuExtCode', label: 'SKU属性', align: 'left', fixed: 'left' },
{ prop: 'secondarySaleSpec', label: '属性集', align: 'left', fixed: 'left' },
{ prop: 'quantity', label: 'SKU总件数', sortable: true, 'sort-method': (a, b) => a.quantity - b.quantity },
{ prop: 'costPrice', label: '成本价', sortable: true, 'sort-method': (a, b) => a.costPrice - b.costPrice},
{ prop: 'costAmount', label: '成本总额', sortable: true, 'sort-method': (a, b) => a.costAmount - b.costAmount}
],
jsonFields: {
"SPU": "productSpuId",
"SKC": "productSkcId",
@@ -112,8 +143,19 @@ import { Message } from 'element-ui'
"退货原因": "orderTypeDesc",
"退货包裹号": "packageSn",
"SKU件数": "quantity",
"成本单价": "cost",
"出库时间": "outboundTime"
},
sumJsonFields: {
"SKC": "productSkcId",
"SKU": "productSkuId",
"SKU属性": "skuExtCode",
"图片地址": "thumbUrl",
"属性集": "secondarySaleSpec",
"SKU总件数": "quantity",
"成本价": "costPrice",
"成本总额": "costAmount"
},
form: {
mallId: '',
date: ''
@@ -122,6 +164,8 @@ import { Message } from 'element-ui'
pageSize: 100,
tableData: [],
sumTableData: [],
costList: [],
total: 0,
search: {
current: 1,
@@ -163,6 +207,7 @@ import { Message } from 'element-ui'
}
this.currentPage = 1
this.tableData = []
this.sumTableData = []
let startTime = this.form.date[1].getTime() - 30 * 24 * 60 * 60 * 1000
if (startTime < this.form.date[0].getTime()) {
@@ -196,6 +241,7 @@ import { Message } from 'element-ui'
data.packageSn = item.packageSn
data.quantity = item.quantity
data.outboundTime = timestampToTime(item.outboundTime)
data.cost = null
this.tableData.push(data)
}
@@ -215,7 +261,8 @@ import { Message } from 'element-ui'
this.getList(startTimeTemp, endTimeTemp)
} else {
this.getDeliverySn(1)
this.getSkuExtCode(1)
this.getSkuCostList()
this.isLoading = false
}
}
@@ -288,6 +335,58 @@ import { Message } from 'element-ui'
await getSkuExtCode(pageNo + 1)
}
},
calcAmount() {
this.tableData.map(item => {
for (let i = 0; i < this.costList.length; i++) {
if (item.productSkuId == this.costList[i].sku) {
item.cost = this.costList[i].costPrice
break
}
}
let flag = false
for (let i = 0; i < this.sumTableData.length; i++) {
if (item.productSkuId == this.sumTableData[i].productSkuId) {
this.sumTableData[i].quantity += item.quantity
flag = true
break
}
}
if (!flag) {
this.sumTableData.push({
productSkcId: item.productSkcId,
productSkuId: item.productSkuId,
skuExtCode: item.skuExtCode,
secondarySaleSpec: item.secondarySaleSpec,
thumbUrl: item.thumbUrl,
quantity: item.quantity,
costPrice: null,
costAmount: null
})
}
})
this.sumTableData.map(item => {
for (let i = 0; i < this.costList.length; i++) {
if (this.costList[i].sku == item.productSkuId) {
item.costPrice = this.costList[i].costPrice
item.costAmount = Math.round(this.costList[i].costPrice * item.quantity * 100) / 100
break
}
}
})
},
async getSkuCostList() {
await this.getSkuExtCode(1)
let res = await this.$http.post(`/api/skuCost/listAll`, null, {
params: {
mallId: this.form.mallId
}
})
if (res.code == 0) {
this.costList = res.data
this.calcAmount()
}
},
startDownload() {
this.$http.post('/api/malluser/info').then(res => {
if (res.code == 0) {

View File

@@ -54,7 +54,7 @@
:tableData="tableData"
:col-configs="colConfigs"
:total="total"
height="500"
height="700"
style="margin-top: 8px;"
@getList="getList">
</ai-table>

View File

@@ -492,6 +492,11 @@
resolved "https://registry.npmmirror.com/@babel/parser/-/parser-7.22.10.tgz"
integrity sha512-lNbdGsQb9ekfsnjFGhEiF4hfFqGgfOP3H3d27re3n+CGhNuTSUEQdfWk556sTLNTloczcdM5TYF2LhzmDQKyvQ==
"@babel/parser@^7.23.5":
version "7.24.8"
resolved "https://registry.npmmirror.com/@babel/parser/-/parser-7.24.8.tgz#58a4dbbcad7eb1d48930524a3fd93d93e9084c6f"
integrity sha512-WzfbgXOkGzZiXXCqk43kKwZjzwx4oulxZi3nq2TYL9mOjQv6kYwul9mz6ID36njuL7Xkp6nJEfok848Zj10j/w==
"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.22.5":
version "7.22.5"
resolved "https://registry.npmmirror.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.22.5.tgz"
@@ -1848,6 +1853,17 @@
postcss "^8.4.14"
source-map "^0.6.1"
"@vue/compiler-sfc@2.7.16":
version "2.7.16"
resolved "https://registry.npmmirror.com/@vue/compiler-sfc/-/compiler-sfc-2.7.16.tgz#ff81711a0fac9c68683d8bb00b63f857de77dc83"
integrity sha512-KWhJ9k5nXuNtygPU7+t1rX6baZeqOYLEforUPjgNDBnLicfHCoi48H87Q8XyLZOrNNsmhuwKqtpDQWjEFe6Ekg==
dependencies:
"@babel/parser" "^7.23.5"
postcss "^8.4.14"
source-map "^0.6.1"
optionalDependencies:
prettier "^1.18.2 || ^2.0.0"
"@vue/component-compiler-utils@^3.1.0", "@vue/component-compiler-utils@^3.3.0":
version "3.3.0"
resolved "https://registry.npmmirror.com/@vue/component-compiler-utils/-/component-compiler-utils-3.3.0.tgz"
@@ -2378,6 +2394,16 @@ batch@0.6.1:
resolved "https://registry.npmmirror.com/batch/-/batch-0.6.1.tgz"
integrity sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==
bi-vue-mindmap@^0.6.12:
version "0.6.12"
resolved "https://registry.npmmirror.com/bi-vue-mindmap/-/bi-vue-mindmap-0.6.12.tgz#092202bd224ed49dd133a1c6490fe7330848a280"
integrity sha512-cKfKB5rm3L+391iV9RPkfC8lIKx9xAhW6shpGnXHPwZcboIpW+ZjPpq2vaJ0qlXH96i4VMW2Xk6StBMVRQ2GDw==
dependencies:
core-js "^3.6.5"
vue "^2.6.11"
vue-router "^3.2.0"
vuex "^3.4.0"
big.js@^5.2.2:
version "5.2.2"
resolved "https://registry.npmmirror.com/big.js/-/big.js-5.2.2.tgz"
@@ -2955,6 +2981,11 @@ core-js@^2.4.0:
resolved "https://registry.npmmirror.com/core-js/-/core-js-2.6.12.tgz"
integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==
core-js@^3.6.5:
version "3.37.1"
resolved "https://registry.npmmirror.com/core-js/-/core-js-3.37.1.tgz#d21751ddb756518ac5a00e4d66499df981a62db9"
integrity sha512-Xn6qmxrQZyB0FFY8E3bgRXei3lWDJHhvI+u0q9TKIYM49G8pAr0FgnnrFRAmsbptZL1yxRADVXn+x5AGsbBfyw==
core-js@^3.8.3:
version "3.32.0"
resolved "https://registry.npmmirror.com/core-js/-/core-js-3.32.0.tgz"
@@ -7536,6 +7567,14 @@ vue-template-es2015-compiler@^1.9.0:
resolved "https://registry.npmmirror.com/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz"
integrity sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==
vue@^2.6.11:
version "2.7.16"
resolved "https://registry.npmmirror.com/vue/-/vue-2.7.16.tgz#98c60de9def99c0e3da8dae59b304ead43b967c9"
integrity sha512-4gCtFXaAA3zYZdTp5s4Hl2sozuySsgz4jy1EnpBHNfpMa9dK1ZCG7viqBPCwXtmgc8nHqUsAu3G4gtmXkkY3Sw==
dependencies:
"@vue/compiler-sfc" "2.7.16"
csstype "^3.1.0"
vue@^2.6.14:
version "2.7.14"
resolved "https://registry.npmmirror.com/vue/-/vue-2.7.14.tgz"