调整
This commit is contained in:
@@ -13,6 +13,8 @@
|
||||
"crypto-js": "^4.0.0",
|
||||
"dayjs": "^1.11.9",
|
||||
"element-ui": "^2.15.13",
|
||||
"file-saver": "^2.0.5",
|
||||
"html2canvas": "^1.4.1",
|
||||
"query-string": "^9.0.0",
|
||||
"spark-md5": "^3.0.2",
|
||||
"v-viewer": "^1.6.4",
|
||||
@@ -22,7 +24,8 @@
|
||||
"vue-qr": "^4.0.9",
|
||||
"vue-router": "^3.2.0",
|
||||
"vuex": "^3.4.0",
|
||||
"vuex-persistedstate": "^4.1.0"
|
||||
"vuex-persistedstate": "^4.1.0",
|
||||
"xlsx": "^0.18.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.12.16",
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
function matchSheinDomain(url) {
|
||||
const urlPattern = /https:\/\/([\da-z\.-]+)\.shein\.com\/([\S.-]+)-p-([\S.-]+)/
|
||||
return urlPattern.test(url);
|
||||
}
|
||||
|
||||
function init() {
|
||||
if (window.location.href.startsWith('https://www.aliexpress.com/item/')) {
|
||||
const popup = document.createElement("div")
|
||||
@@ -187,6 +192,111 @@ function init() {
|
||||
})
|
||||
document.body.appendChild(popup)
|
||||
}
|
||||
} else if (matchSheinDomain(window.location.href)) {
|
||||
const popup = document.createElement("div")
|
||||
popup.innerText = "下载图片"
|
||||
const styles = {
|
||||
position: "fixed",
|
||||
right: '10px',
|
||||
top: '60px',
|
||||
zIndex: 9999,
|
||||
padding: "8px",
|
||||
background: "#409EFF",
|
||||
color: "#fff",
|
||||
borderRadius: "8px",
|
||||
cursor: "pointer"
|
||||
}
|
||||
for (const e in styles) {
|
||||
popup.style[e] = styles[e]
|
||||
}
|
||||
|
||||
popup.addEventListener('click', async () => {
|
||||
var baseList = [];
|
||||
var downloadList = []
|
||||
|
||||
let bannerIdx = 1, detailIdx = 1
|
||||
baseList.push({type: 0, index: bannerIdx++, src: window.gbRawData.productIntroData.goods_imgs.main_image.origin_image})
|
||||
var detailImages = window.gbRawData.productIntroData.goods_imgs.detail_image
|
||||
|
||||
for (var i = 0; i < detailImages.length; i++) {
|
||||
if (!(detailImages[i].isMoreDetail)) {
|
||||
baseList.push({type: 0, index: bannerIdx++, src: detailImages[i].origin_image})
|
||||
} else {
|
||||
baseList.push({type: 1, index: detailIdx++, src: detailImages[i].origin_image})
|
||||
}
|
||||
}
|
||||
|
||||
var video = document.querySelector('video')
|
||||
if (window.gbRawData.productIntroData.goods_imgs.video_url) {
|
||||
baseList.push({type: 2, index: 1, src: window.gbRawData.productIntroData.goods_imgs.video_url})
|
||||
}
|
||||
|
||||
var zip = new JSZip();
|
||||
var imgsBanner = zip.folder("轮播图");
|
||||
var imgsDetail = zip.folder("详情图");
|
||||
var videos = zip.folder("视频");
|
||||
|
||||
for (var k = 0; k < baseList.length; k++) {
|
||||
let type = baseList[k].type
|
||||
let index = baseList[k].index
|
||||
if (type == 2) {
|
||||
let x = new XMLHttpRequest()
|
||||
x.open('GET', baseList[k].src, true)
|
||||
x.responseType = 'blob'
|
||||
x.onload = (e) => {
|
||||
downloadList.push({type: type, index: index, data: x.response});
|
||||
if (downloadList.length === baseList.length && downloadList.length > 0) {
|
||||
for (let l = 0; l < downloadList.length; l++) {
|
||||
if (downloadList[l].type == '0') {
|
||||
imgsDetail.file(`详情图${downloadList[l].index}.png`, downloadList[l].data, { base64: true });
|
||||
} else if (downloadList[l].type == '1') {
|
||||
imgsBanner.file(`轮播图${downloadList[l].index}.png`, downloadList[l].data, { base64: true });
|
||||
} else if (downloadList[l].type == '2') {
|
||||
videos.file(`视频.mp4`, downloadList[l].data, { Blob: true });
|
||||
}
|
||||
}
|
||||
zip.generateAsync({ type: "blob" }).then(function (content) {
|
||||
// see FileSaver.js
|
||||
saveAs(content, "shein_" + id + ".zip");
|
||||
});
|
||||
}
|
||||
}
|
||||
x.send()
|
||||
} else {
|
||||
let image = new Image();
|
||||
// 解决跨域 Canvas 污染问题
|
||||
image.setAttribute("crossOrigin", "anonymous");
|
||||
image.onload = function () {
|
||||
let canvas = document.createElement("canvas");
|
||||
canvas.width = image.width;
|
||||
canvas.height = image.height;
|
||||
let context = canvas.getContext("2d");
|
||||
context.drawImage(image, 0, 0, image.width, image.height);
|
||||
let url = canvas.toDataURL(); // 得到图片的base64编码数据
|
||||
canvas.toDataURL("image/png");
|
||||
downloadList.push({type: type, index: index, data: url.substring(22)}); // 去掉base64编码前的 data:image/png;base64,
|
||||
if (downloadList.length === baseList.length && downloadList.length > 0) {
|
||||
for (let l = 0; l < downloadList.length; l++) {
|
||||
if (downloadList[l].type == '0') {
|
||||
imgsDetail.file(`详情图${downloadList[l].index}.png`, downloadList[l].data, { base64: true });
|
||||
} else if (downloadList[l].type == '1') {
|
||||
imgsBanner.file(`轮播图${downloadList[l].index}.png`, downloadList[l].data, { base64: true });
|
||||
} else if (downloadList[l].type == '2') {
|
||||
videos.file(`视频.mp4`, downloadList[l].data, { Blob: true });
|
||||
}
|
||||
}
|
||||
zip.generateAsync({ type: "blob" }).then(function (content) {
|
||||
// see FileSaver.js
|
||||
saveAs(content, "shein_" + id + ".zip");
|
||||
});
|
||||
}
|
||||
};
|
||||
image.src = baseList[k].src;
|
||||
}
|
||||
}
|
||||
})
|
||||
document.body.appendChild(popup)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
29
public/rules_7.json
Normal file
29
public/rules_7.json
Normal file
@@ -0,0 +1,29 @@
|
||||
[
|
||||
{
|
||||
"id": 18,
|
||||
"priority": 1,
|
||||
"action": {
|
||||
"type": "modifyHeaders",
|
||||
"requestHeaders": [
|
||||
{
|
||||
"header": "Origin",
|
||||
"operation": "set",
|
||||
"value": "https://img.ltwebstatic.com"
|
||||
},
|
||||
{
|
||||
"header": "Referer",
|
||||
"operation": "set",
|
||||
"value": "https://img.ltwebstatic.com"
|
||||
},
|
||||
{
|
||||
"header": "Sec-Fetch-Mode",
|
||||
"operation": "set",
|
||||
"value": "no-cors"
|
||||
}
|
||||
]
|
||||
},
|
||||
"condition": {
|
||||
"urlFilter": "||img.ltwebstatic.com"
|
||||
}
|
||||
}
|
||||
]
|
||||
24
public/rules_8.json
Normal file
24
public/rules_8.json
Normal file
@@ -0,0 +1,24 @@
|
||||
[
|
||||
{
|
||||
"id": 19,
|
||||
"priority": 1,
|
||||
"action": {
|
||||
"type": "modifyHeaders",
|
||||
"requestHeaders": [
|
||||
{
|
||||
"header": "Origin",
|
||||
"operation": "set",
|
||||
"value": "https://www.geiwohuo.com/"
|
||||
},
|
||||
{
|
||||
"header": "Referer",
|
||||
"operation": "set",
|
||||
"value": "https://www.geiwohuo.com/"
|
||||
}
|
||||
]
|
||||
},
|
||||
"condition": {
|
||||
"urlFilter": "||www.geiwohuo.com"
|
||||
}
|
||||
}
|
||||
]
|
||||
24
public/rules_9.json
Normal file
24
public/rules_9.json
Normal file
@@ -0,0 +1,24 @@
|
||||
[
|
||||
{
|
||||
"id": 20,
|
||||
"priority": 1,
|
||||
"action": {
|
||||
"type": "modifyHeaders",
|
||||
"requestHeaders": [
|
||||
{
|
||||
"header": "Origin",
|
||||
"operation": "set",
|
||||
"value": "https://agentseller.temu.com/"
|
||||
},
|
||||
{
|
||||
"header": "Referer",
|
||||
"operation": "set",
|
||||
"value": "https://agentseller.temu.com/"
|
||||
}
|
||||
]
|
||||
},
|
||||
"condition": {
|
||||
"urlFilter": "||agentseller.temu.com"
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -26,6 +26,32 @@ export async function sendChromeAPIMessage(message) {
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 向Chrome发送消息
|
||||
* @param message 消息
|
||||
*/
|
||||
export async function sendTemuSellerAgentMessage(message) {
|
||||
message.type = 'api'
|
||||
if (!message.url.startsWith('http')) {
|
||||
message.url = "https://agentseller.temu.com/" + message.url;
|
||||
}
|
||||
message.anti = message.anti || false
|
||||
if (message.needMallId) {
|
||||
// 如果参数中没有携带MallId,则从state中获取
|
||||
if (!message.mallId) {
|
||||
message.mallId = store.state.mallId;
|
||||
}
|
||||
}
|
||||
if (message.anti) {
|
||||
message.anti = await genAnti.a()
|
||||
}
|
||||
return new Promise((resolve) => {
|
||||
// @ts-ignore
|
||||
chrome.runtime.sendMessage(message, resolve)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 向Chrome发送消息
|
||||
* @param message 消息
|
||||
@@ -74,7 +100,11 @@ export async function sendSheinAPIMessage(message) {
|
||||
*/
|
||||
export async function sendGeiwohuoAPIMessage(message) {
|
||||
message.type = 'geiwohuoApi'
|
||||
message.url = "https://sso.geiwohuo.com/" + message.url;
|
||||
if (message.isWWW) {
|
||||
message.url = "https://www.geiwohuo.com/" + message.url;
|
||||
} else {
|
||||
message.url = "https://sso.geiwohuo.com/" + message.url;
|
||||
}
|
||||
return new Promise((resolve) => {
|
||||
// @ts-ignore
|
||||
chrome.runtime.sendMessage(message, resolve)
|
||||
|
||||
@@ -368,13 +368,17 @@ export default {
|
||||
let content = data
|
||||
let i = 0
|
||||
if (this.form.isSameCategory) {
|
||||
let res2 = await this.$http.post('/api/innerCategory/fullById',null , {
|
||||
/*let res2 = await this.$http.post('/api/innerCategory/fullById',null , {
|
||||
params: {
|
||||
id: reqData.catId
|
||||
}
|
||||
})
|
||||
for (; i < res2.data.length; i++) {
|
||||
content['cat' + (i+1) + 'Id'] = res2.data[i]
|
||||
})*/
|
||||
for (; i < 10; i++) {
|
||||
if (content['cat' + (i+1) + 'Id']) {
|
||||
continue
|
||||
}else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
let res3 = await sendChromeAPIMessage({
|
||||
@@ -422,6 +426,9 @@ export default {
|
||||
content['cat' + (i+1) + 'Id'] = this.form.targetCatId[i]
|
||||
}
|
||||
}
|
||||
if (content['cat'+(i+1)+'Id'] != reqData.catId) {
|
||||
content['cat'+(++i)+'Id'] = reqData.catId
|
||||
}
|
||||
for (; i < 10; i++) {
|
||||
content['cat' + (i+1) + 'Id'] = ''
|
||||
}
|
||||
|
||||
@@ -21,7 +21,8 @@
|
||||
"*://*.alicdn.com/",
|
||||
"*://*.amazon.com/",
|
||||
"*://*.shein.com/",
|
||||
"*://*.geiwohuo.com/"
|
||||
"*://*.geiwohuo.com/",
|
||||
"*://*.ltwebstatic.com/"
|
||||
],
|
||||
"permissions": [
|
||||
"cookies",
|
||||
@@ -51,13 +52,26 @@
|
||||
"id": "6",
|
||||
"enabled": true,
|
||||
"path": "rules_6.json"
|
||||
},{
|
||||
"id": "7",
|
||||
"enabled": true,
|
||||
"path": "rules_7.json"
|
||||
},{
|
||||
"id": "8",
|
||||
"enabled": true,
|
||||
"path": "rules_8.json"
|
||||
},{
|
||||
"id": "9",
|
||||
"enabled": true,
|
||||
"path": "rules_9.json"
|
||||
}]
|
||||
},
|
||||
"content_scripts": [
|
||||
{
|
||||
"matches": [
|
||||
"*://*.aliexpress.com/item/*",
|
||||
"*://*.amazon.com/*"
|
||||
"*://*.amazon.com/*",
|
||||
"*://*.shein.com/*"
|
||||
],
|
||||
"js": [
|
||||
"/content.js"
|
||||
@@ -67,7 +81,7 @@
|
||||
"web_accessible_resources": [
|
||||
{
|
||||
"resources": [ "js/download.js","js/jszip.min.js","js/FileSaver.js" ],
|
||||
"matches": [ "*://*.aliexpress.com/*", "*://*.amazon.com/*" ]
|
||||
"matches": [ "*://*.aliexpress.com/*", "*://*.amazon.com/*", "*://*.shein.com/*" ]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"manifest_version": 3,
|
||||
"name": "TEMU助手",
|
||||
"description": "TEMU助手 - 自动化提高生产效率",
|
||||
"version": "3.2.1",
|
||||
"version": "3.2.3",
|
||||
"background": {
|
||||
"service_worker": "/background.js"
|
||||
},
|
||||
@@ -21,7 +21,8 @@
|
||||
"*://*.alicdn.com/",
|
||||
"*://*.amazon.com/",
|
||||
"*://*.shein.com/",
|
||||
"*://*.geiwohuo.com/"
|
||||
"*://*.geiwohuo.com/",
|
||||
"*://*.ltwebstatic.com/"
|
||||
],
|
||||
"permissions": [
|
||||
"cookies",
|
||||
@@ -55,13 +56,26 @@
|
||||
"id": "6",
|
||||
"enabled": true,
|
||||
"path": "rules_6.json"
|
||||
},{
|
||||
"id": "7",
|
||||
"enabled": true,
|
||||
"path": "rules_7.json"
|
||||
},{
|
||||
"id": "8",
|
||||
"enabled": true,
|
||||
"path": "rules_8.json"
|
||||
},{
|
||||
"id": "9",
|
||||
"enabled": true,
|
||||
"path": "rules_9.json"
|
||||
}]
|
||||
},
|
||||
"content_scripts": [
|
||||
{
|
||||
"matches": [
|
||||
"*://*.aliexpress.com/item/*",
|
||||
"*://*.amazon.com/*"
|
||||
"*://*.amazon.com/*",
|
||||
"*://*.shein.com/*"
|
||||
],
|
||||
"js": [
|
||||
"/content.js"
|
||||
@@ -71,7 +85,7 @@
|
||||
"web_accessible_resources": [
|
||||
{
|
||||
"resources": [ "js/download.js","js/jszip.min.js","js/FileSaver.js" ],
|
||||
"matches": [ "*://*.aliexpress.com/*", "*://*.amazon.com/*" ]
|
||||
"matches": [ "*://*.aliexpress.com/*", "*://*.amazon.com/*", "*://*.shein.com/*" ]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -85,15 +85,20 @@ const router = new VueRouter({
|
||||
name: 'copyProduct',
|
||||
component: () => import('../view/product/CopyProduct.vue')
|
||||
},
|
||||
{
|
||||
path: 'sellerSelect',
|
||||
name: 'sellerSelect',
|
||||
component: () => import('../view/product/SellerSelect.vue')
|
||||
},
|
||||
{
|
||||
path: 'draft',
|
||||
name: 'draft',
|
||||
component: () => import('../view/product/Draft.vue')
|
||||
},
|
||||
{
|
||||
path: 'copyProductShein',
|
||||
name: 'copyProductShein',
|
||||
component: () => import('../view/product/CopyProductShein.vue')
|
||||
path: 'findSeller',
|
||||
name: 'findSeller',
|
||||
component: () => import('../view/product/FindSeller.vue')
|
||||
},
|
||||
{
|
||||
path: 'copyProductAliExpress',
|
||||
@@ -172,21 +177,56 @@ const router = new VueRouter({
|
||||
component: () => import('../view/CoinFlow.vue')
|
||||
},
|
||||
|
||||
{
|
||||
path: 'costManageTemu',
|
||||
name: 'costManageTemu',
|
||||
component: () => import('../view/sale/CostManageTemu.vue')
|
||||
},
|
||||
{
|
||||
path: 'saleData',
|
||||
name: 'saleData',
|
||||
component: () => import('../view/sale/ExportSaleData.vue')
|
||||
},
|
||||
{
|
||||
path: 'saleDataShein',
|
||||
name: 'saleDataShein',
|
||||
component: () => import('../view/sale/ExportSaleDataShein.vue')
|
||||
},
|
||||
{
|
||||
path: 'saleOut',
|
||||
name: 'saleOut',
|
||||
component: () => import('../view/sale/ExportSaleOutData.vue')
|
||||
},
|
||||
{
|
||||
path: 'afterSaleStat',
|
||||
name: 'afterSaleStat',
|
||||
component: () => import('../view/sale/AfterSaleStat.vue')
|
||||
},
|
||||
{
|
||||
path: 'afterSaleDeductStat',
|
||||
name: 'afterSaleDeductStat',
|
||||
component: () => import('../view/sale/AfterSaleDeductStat.vue')
|
||||
},
|
||||
{
|
||||
path: 'costManageShein',
|
||||
name: 'costManageShein',
|
||||
component: () => import('../view/shein/CostManageShein.vue')
|
||||
},
|
||||
{
|
||||
path: 'certCenterShein',
|
||||
name: 'certCenterShein',
|
||||
component: () => import('../view/shein/CertCenterShein.vue')
|
||||
},
|
||||
{
|
||||
path: 'saleDataShein',
|
||||
name: 'saleDataShein',
|
||||
component: () => import('../view/shein/ExportSaleDataShein.vue')
|
||||
},
|
||||
{
|
||||
path: 'saleStatShein',
|
||||
name: 'saleStatShein',
|
||||
component: () => import('../view/shein/ExportSaleStatShein.vue')
|
||||
},
|
||||
{
|
||||
path: 'copyProductShein',
|
||||
name: 'copyProductShein',
|
||||
component: () => import('../view/shein/CopyProductShein.vue')
|
||||
},
|
||||
|
||||
// {
|
||||
// path: 'statistics',
|
||||
|
||||
@@ -13,6 +13,8 @@ export default new Vuex.Store({
|
||||
mallName: '',
|
||||
mallList: [],
|
||||
activeDlgShow: false,
|
||||
showSheinAlert: false,
|
||||
showTemuAlert: false,
|
||||
userInfo: {}
|
||||
},
|
||||
|
||||
@@ -46,6 +48,12 @@ export default new Vuex.Store({
|
||||
},
|
||||
setActiveDlgShow(state, flag) {
|
||||
state.activeDlgShow = flag
|
||||
},
|
||||
setSheinAlertShow(state, flag) {
|
||||
state.showSheinAlert = flag
|
||||
},
|
||||
setTemuAlertShow(state, flag) {
|
||||
state.showTemuAlert = flag
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -18,8 +18,9 @@ export function transform(leftData) {
|
||||
rightData.materialMultiLanguages = leftData.productLocalExtAttr.materialMultiLanguages;
|
||||
rightData.productI18nReqs = leftData.productI18nList;
|
||||
rightData.productPropertyReqs = [];
|
||||
let flag = false
|
||||
for (let i = 0; i < leftData.productPropertyList.length; i++) {
|
||||
rightData.productPropertyReqs.push({
|
||||
let val = {
|
||||
valueUnit: leftData.productPropertyList[i].valueUnit,
|
||||
propValue: leftData.productPropertyList[i].propValue,
|
||||
propName: leftData.productPropertyList[i].propName,
|
||||
@@ -29,9 +30,31 @@ export function transform(leftData) {
|
||||
pid: leftData.productPropertyList[i].pid,
|
||||
templatePid: leftData.productPropertyList[i].templatePid,
|
||||
valueExtendInfo: leftData.productPropertyList[i].valueExtendInfo
|
||||
});
|
||||
}
|
||||
/*if (leftData.productPropertyList[i].vid == 41500) {
|
||||
if (config.brandId) {
|
||||
flag = true
|
||||
val.pid = 41500
|
||||
val.propName = config.brandName
|
||||
}
|
||||
}*/
|
||||
rightData.productPropertyReqs.push(val);
|
||||
}
|
||||
|
||||
/*if (config.brandId && !flag) {
|
||||
rightData.productPropertyReqs.push({
|
||||
"valueUnit": "",
|
||||
"propValue": config.brandName,
|
||||
"propName": "品牌名",
|
||||
"refPid": 1960,
|
||||
"vid": 41500,
|
||||
"controlType": 1,
|
||||
"pid": config.brandId,
|
||||
"templatePid": 1151553,
|
||||
"valueExtendInfo": ""
|
||||
})
|
||||
}*/
|
||||
|
||||
// SKC
|
||||
let rightSkc = [];
|
||||
let leftSkc = leftData.productSkcList;
|
||||
@@ -159,6 +182,7 @@ export function transformSubmitForHalf(leftData, config, draftId) {
|
||||
rightData.materialMultiLanguages = leftData.productLocalExtAttr.materialMultiLanguages;
|
||||
rightData.productI18nReqs = leftData.productI18nList;
|
||||
rightData.productPropertyReqs = [];
|
||||
if (!leftData.productPropertyList) return rightData
|
||||
for (let i = 0; i < leftData.productPropertyList.length; i++) {
|
||||
rightData.productPropertyReqs.push({
|
||||
valueUnit: leftData.productPropertyList[i].valueUnit,
|
||||
@@ -240,6 +264,7 @@ export function transformSubmitForHalf(leftData, config, draftId) {
|
||||
}
|
||||
rightSkuItem.productSkuStockQuantityReq = productSkuStockQuantityReq
|
||||
rightSkuItem.currencyType = leftSkuItem.currencyType;
|
||||
rightSkuItem.supplierPrice = leftSkuItem.supplierPrice + config.upMoney * 100;
|
||||
|
||||
rightSkcItem.productSkuReqs.push(rightSkuItem);
|
||||
}
|
||||
@@ -255,6 +280,14 @@ export function transformSubmitForHalf(leftData, config, draftId) {
|
||||
rightData.carouselImageI18nReqs = leftData.carouselImageI18nVOList;
|
||||
rightData.materialImgUrl = leftData.materialImgUrl;
|
||||
rightData.goodsLayerDecorationReqs = leftData.goodsLayerDecorationVOList;
|
||||
rightData.goodsLayerDecorationReqs.map(item => {
|
||||
if (item.type == 'image') {
|
||||
item.contentList.map(item1 => {
|
||||
delete item1.text
|
||||
delete item1.textModuleDetails
|
||||
})
|
||||
}
|
||||
})
|
||||
rightData.sizeTemplateIds = !leftData.sizeTemplateIds ? []: leftData.sizeTemplateIds;
|
||||
rightData.showSizeTemplateIds = !leftData.showSizeTemplateIds ? []: leftData.showSizeTemplateIds;
|
||||
rightData.goodsModelReqs = !leftData.goodsModelList ? []: leftData.goodsModelList;
|
||||
|
||||
@@ -70,8 +70,11 @@
|
||||
</template>
|
||||
<el-menu-item index="/productList">商品列表</el-menu-item>
|
||||
<el-menu-item index="/copyProduct">商品复制</el-menu-item>
|
||||
<el-menu-item index="/draft">草稿箱管理</el-menu-item>
|
||||
<el-menu-item index="/copyProductShein">商品复制(希音)</el-menu-item>
|
||||
<el-menu-item index="/findSeller">查找买手</el-menu-item>
|
||||
<el-menu-item v-if="$store.state.userInfo.phone == '18610967550' || $store.state.userInfo.phone == '18571466720'" index="/draft">
|
||||
草稿箱管理
|
||||
</el-menu-item>
|
||||
<el-menu-item index="/sellerSelect">上新生命周期管理</el-menu-item>
|
||||
<!--<el-menu-item index="/copyProductAliExpress">商品复制(速卖通)</el-menu-item>-->
|
||||
</el-submenu>
|
||||
<el-submenu index="/stock">
|
||||
@@ -126,18 +129,31 @@
|
||||
<i class="el-icon-s-data"></i>
|
||||
<span slot="title">销售管理</span>
|
||||
</template>
|
||||
<el-menu-item index="/saleData">销售管理(TEMU)</el-menu-item>
|
||||
<el-menu-item index="/saleDataShein">销售数据(SHEIN)</el-menu-item>
|
||||
<el-menu-item index="/costManageTemu">成本管理</el-menu-item>
|
||||
<el-menu-item index="/saleData">销售管理</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>
|
||||
</el-submenu>
|
||||
<el-submenu index="/shein">
|
||||
<template slot="title">
|
||||
<i class="el-icon-s-goods"></i>
|
||||
<span slot="title">SHEIN希音</span>
|
||||
</template>
|
||||
<el-menu-item index="/costManageShein">成本管理</el-menu-item>
|
||||
<el-menu-item index="/saleDataShein">销售数据</el-menu-item>
|
||||
<el-menu-item index="/certCenterShein">证书中心</el-menu-item>
|
||||
<el-menu-item index="/copyProductShein">商品复制</el-menu-item>
|
||||
<el-menu-item index="/saleStatShein">商家账单统计</el-menu-item>
|
||||
</el-submenu>
|
||||
<el-menu-item index="/info">
|
||||
<i class="el-icon-info"></i>
|
||||
<span slot="title">弹窗消息</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item index="/priceFollow">
|
||||
<!--<el-menu-item index="/priceFollow">
|
||||
<i class="el-icon-money"></i>
|
||||
<span slot="title">调价管理</span>
|
||||
</el-menu-item>
|
||||
</el-menu-item>-->
|
||||
<el-menu-item index="/learning">
|
||||
<i class="el-icon-eleme"></i>
|
||||
<span slot="title">新手园地</span>
|
||||
@@ -164,6 +180,27 @@
|
||||
:before-close="handleClose">
|
||||
<ai-payment/>
|
||||
</el-dialog>
|
||||
<el-dialog
|
||||
title="温馨提示"
|
||||
:visible="$store.state.showSheinAlert"
|
||||
:close-on-click-modal="false"
|
||||
width="1200">
|
||||
<span style="font-size: large">1、检查“SHEIN商家后台”是否登录,如没登录,请先登录,之后再刷新助手<br></span>
|
||||
<span style="font-size: large">2、如果SHEIN商家后台已经登录,仍然弹出当前窗口,则需要SHEIN进行二次授权,二次授权可在菜单“商品管理->商品列表”,任意选择一个商品,在“价格”一栏,点击修改,在新打开的页面中可看到“正在鉴权”的字样,即可完成二次授权</span>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="closeSheinAlert">关 闭</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
<el-dialog
|
||||
title="温馨提示"
|
||||
:visible="$store.state.showTemuAlert"
|
||||
:close-on-click-modal="false"
|
||||
width="1200">
|
||||
<span style="font-size: large">请先打开卖家中心“结算数据->售后管理”页面进行二次授权,<a target="_blank" style="text-decoration: underline" href="https://seller.kuajingmaihuo.com/main/aftersales/information">去打开</a><br></span>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="closeTemuAlert">关 闭</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
|
||||
<div id="kefu" @click="gotoKefu">
|
||||
<label slot="reference" class="topBtn" title="联系客服"></label>
|
||||
@@ -174,7 +211,7 @@
|
||||
<script>
|
||||
import {mapMutations, mapState} from 'vuex'
|
||||
import AiPayment from "@/components/AiPayment.vue";
|
||||
import {sendAliexpressAPIMessage} from "@/api/chromeApi";
|
||||
import {sendAliexpressAPIMessage, sendTemuSellerAgentMessage} from "@/api/chromeApi";
|
||||
|
||||
export default {
|
||||
components: {AiPayment},
|
||||
@@ -222,6 +259,7 @@ export default {
|
||||
const prodVersion = require('../manifest.production.json').version
|
||||
this.version = process.env.NODE_ENV === 'production' ? prodVersion : devVersion
|
||||
this.activePath = this.$route.fullPath
|
||||
//this.getAfterSalesList()
|
||||
},
|
||||
|
||||
methods: {
|
||||
@@ -293,6 +331,12 @@ export default {
|
||||
gotoKefu() {
|
||||
window.open('https://work.weixin.qq.com/kfid/kfcaa4208f661131eba', '_blank')
|
||||
},
|
||||
closeSheinAlert() {
|
||||
this.$store.commit('setSheinAlertShow', false)
|
||||
},
|
||||
closeTemuAlert() {
|
||||
this.$store.commit('setTemuAlertShow', false)
|
||||
},
|
||||
getAliexpressGoodsList() {
|
||||
let url = "https://seller-acs.aliexpress.com/h5/mtop.global.merchant.self.product.manager.render.list/1.0/?jsv=2.7.2&appKey=30267743&t=1713978403051&sign=ba2bda69b4a2695c7279d4bc05f51741&v=1.0&timeout=15000&H5Request=true&url=mtop.global.merchant.self.product.manager.render.list&__channel-id__=701301&api=mtop.global.merchant.self.product.manager.render.list&type=originaljson&dataType=json&valueType=original&x-i18n-regionID=AE"
|
||||
url = url + "&data=" + encodeURIComponent(
|
||||
@@ -322,7 +366,7 @@ export default {
|
||||
}).then(res => {
|
||||
//console.log(res)
|
||||
})
|
||||
},
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
// this.getAliexpressGoodsList()
|
||||
|
||||
@@ -106,6 +106,7 @@
|
||||
productName: item.productName,
|
||||
skcId: item.skcId,
|
||||
popUpType: 1,
|
||||
versionId: res.result.popUpAutoPass12.versionId,
|
||||
newSupplyPrice: item.newSupplyPrice / 100,
|
||||
}
|
||||
item.skuInfoItemList.map(item1 => {
|
||||
@@ -118,6 +119,7 @@
|
||||
productName: item.productName,
|
||||
skcId: item.skcId,
|
||||
popUpType: 2,
|
||||
versionId: res.result.popUpAutoPass24.versionId,
|
||||
newSupplyPrice: item.newSupplyPrice / 100,
|
||||
}
|
||||
item.skuInfoItemList.map(item1 => {
|
||||
@@ -130,6 +132,7 @@
|
||||
productName: item.productName,
|
||||
skcId: item.skcId,
|
||||
popUpType: 3,
|
||||
versionId: res.result.popUpOthers.versionId,
|
||||
newSupplyPrice: item.newSupplyPrice / 100,
|
||||
}
|
||||
item.skuInfoItemList.map(item1 => {
|
||||
@@ -160,11 +163,14 @@
|
||||
Message.success("该店铺无调价通知,无需处理")
|
||||
return
|
||||
}
|
||||
let maxOrderId = 0
|
||||
let ids = this.priceList.map(item => {
|
||||
let popUpType1VersionId = ''
|
||||
let popUpType2VersionId = ''
|
||||
let popUpType3VersionId = ''
|
||||
let ids = []
|
||||
this.priceList.map(item => {
|
||||
if (item.popUpType == 1) {
|
||||
if (maxOrderId < item.id) maxOrderId = item.id
|
||||
return item.id
|
||||
popUpType1VersionId = item.versionId
|
||||
ids.push(item.id)
|
||||
}
|
||||
})
|
||||
let res = null
|
||||
@@ -175,16 +181,16 @@
|
||||
mallId: this.currentMallId,
|
||||
data: {
|
||||
"rejectOrderIdList": ids,
|
||||
"maxOrderId": maxOrderId,
|
||||
"maxOrderId": popUpType1VersionId,
|
||||
"popUpType": 1,
|
||||
"createTime": new Date().getTime() * 1000
|
||||
"createTime": new Date().getTime()
|
||||
}})
|
||||
}
|
||||
maxOrderId = 0
|
||||
ids = this.priceList.map(item => {
|
||||
ids = []
|
||||
this.priceList.map(item => {
|
||||
if (item.popUpType == 2) {
|
||||
if (maxOrderId < item.id) maxOrderId = item.id
|
||||
return item.id
|
||||
popUpType2VersionId = item.versionId
|
||||
ids.push(item.id)
|
||||
}
|
||||
})
|
||||
if (ids.length > 0) {
|
||||
@@ -194,16 +200,16 @@
|
||||
mallId: this.currentMallId,
|
||||
data: {
|
||||
"rejectOrderIdList": ids,
|
||||
"maxOrderId": maxOrderId,
|
||||
"maxOrderId": popUpType2VersionId,
|
||||
"popUpType": 2,
|
||||
"createTime": new Date().getTime() * 1000
|
||||
"createTime": new Date().getTime()
|
||||
}})
|
||||
}
|
||||
maxOrderId = 0
|
||||
ids = this.priceList.map(item => {
|
||||
ids = []
|
||||
this.priceList.map(item => {
|
||||
if (item.popUpType == 3) {
|
||||
if (maxOrderId < item.id) maxOrderId = item.id
|
||||
return item.id
|
||||
popUpType3VersionId = item.versionId
|
||||
ids.push(item.id)
|
||||
}
|
||||
})
|
||||
if (ids.length > 0) {
|
||||
@@ -213,9 +219,9 @@
|
||||
mallId: this.currentMallId,
|
||||
data: {
|
||||
"rejectOrderIdList": ids,
|
||||
"maxOrderId": maxOrderId,
|
||||
"maxOrderId": popUpType3VersionId,
|
||||
"popUpType": 3,
|
||||
"createTime": new Date().getTime() * 1000
|
||||
"createTime": new Date().getTime()
|
||||
}})
|
||||
}
|
||||
if (res.success && res.errorCode == 1000000) {
|
||||
|
||||
@@ -18,6 +18,15 @@
|
||||
:value="item.mallId">
|
||||
</el-option>
|
||||
</el-select>
|
||||
<label style="width:90px">站点:</label>
|
||||
<el-select v-model="siteId" placeholder="请选择" size="small">
|
||||
<el-option
|
||||
v-for="item in siteList"
|
||||
:key="item.siteId"
|
||||
:label="item.siteName"
|
||||
:value="item.siteId">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -29,6 +38,10 @@
|
||||
<el-button v-if="$store.state.mallName" type="button" :class="'el-button el-button--primary'" @click="batchSubmitConfig()">批量提交</el-button>
|
||||
</template>
|
||||
<template #right>
|
||||
<label style="width:140px; text-align: right;">起始页:</label>
|
||||
<el-input size="small" placeholder="请输入起始页" style="width: 100px; display: inline" type="number" v-model="search.startPage"></el-input>
|
||||
<label style="width:140px; text-align: right;">结束页:</label>
|
||||
<el-input size="small" placeholder="请输入起始页" style="width: 100px; display: inline" type="number" v-model="search.endPage"></el-input>
|
||||
<label style="width:120px">商品名称:</label>
|
||||
<el-input clearable size="small" style="display: inline" placeholder="请输入商品名称" v-model="search.productName"></el-input>
|
||||
<el-button type="primary" @click="toLoad">查询</el-button>
|
||||
@@ -37,7 +50,6 @@
|
||||
<ai-table
|
||||
:tableData="tableData"
|
||||
:col-configs="colConfigs"
|
||||
:total="total"
|
||||
style="margin-top: 8px;"
|
||||
@selection-change="handleSelectionChange"
|
||||
:isShowPagination="false">
|
||||
@@ -52,7 +64,12 @@
|
||||
:close-on-click-modal="false"
|
||||
width="790px"
|
||||
customFooter
|
||||
@close="handleClose">
|
||||
@close="dlgShow = false">
|
||||
<el-alert
|
||||
title="默认“承诺发货时效”为“2个工作日内发货”"
|
||||
type="success"
|
||||
:closable="false">
|
||||
</el-alert>
|
||||
<el-form class="ai-form" :model="configForm" label-width="160px" ref="configForm">
|
||||
<el-form-item label="运费模板" style="width: 100%;" prop="freightTemplateId" :rules="[{ required: true, message: '请选择运费模板', trigger: 'blur' }]">
|
||||
<el-select style="width: 380px" v-model="configForm.freightTemplateId" placeholder="请选择运费模板">
|
||||
@@ -64,12 +81,6 @@
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
prop="stockNumber"
|
||||
label="库存数量:"
|
||||
:rules="[{ required: true, message: '请输入库存数量', trigger: 'blur' }]">
|
||||
<el-input size="small" placeholder="请输入库存数量" type="number" v-model="configForm.stockNumber"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="发货仓" style="width: 100%;" prop="wareHouseList" :rules="[{ required: true, message: '请选择发货仓', trigger: 'blur' }]">
|
||||
<el-select style="width: 380px" multiple v-model="configForm.wareHouseList" placeholder="请选择发货仓">
|
||||
<el-option
|
||||
@@ -80,6 +91,30 @@
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
prop="stockNumber"
|
||||
label="库存数量:"
|
||||
:rules="[{ required: true, message: '请输入库存数量', trigger: 'blur' }]">
|
||||
<el-input size="small" placeholder="请输入库存数量" type="number" v-model="configForm.stockNumber"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
prop="upMoney"
|
||||
label="上浮金额:"
|
||||
:rules="[{ required: true, message: '请输入上浮金额', trigger: 'blur' }]">
|
||||
<el-input size="small" placeholder="请输入上浮金额" type="number" v-model="configForm.upMoney"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
prop="brand"
|
||||
label="品牌:">
|
||||
<el-select style="width: 380px" clearable v-model="configForm.brandId" placeholder="请选择品牌">
|
||||
<el-option
|
||||
v-for="item in brandList"
|
||||
:key="item.vid"
|
||||
:label="item.brandNameEn"
|
||||
:value="item.vid">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div class="dialog-footer" slot="footer">
|
||||
<el-button @click="dlgShow = false">取 消</el-button>
|
||||
@@ -92,15 +127,19 @@
|
||||
<script>
|
||||
import {sendChromeAPIMessage} from '@/api/chromeApi'
|
||||
import {timestampToTime} from '@/utils/date'
|
||||
import {transform, transformSubmitForHalf} from '@/utils/product'
|
||||
import { Message } from 'element-ui'
|
||||
import {transformSubmitForHalf} from '@/utils/product'
|
||||
import { Message, MessageBox } from 'element-ui'
|
||||
|
||||
export default {
|
||||
name: 'CopyProduct',
|
||||
name: 'Draft',
|
||||
data () {
|
||||
return {
|
||||
mallId: '',
|
||||
siteId: '',
|
||||
siteList: [],
|
||||
search: {
|
||||
startPage: 1,
|
||||
endPage: 10,
|
||||
productName: ''
|
||||
},
|
||||
colConfigs: [
|
||||
@@ -115,7 +154,6 @@ import { Message } from 'element-ui'
|
||||
page: 1,
|
||||
pageSize: 100,
|
||||
tableData: [],
|
||||
total: 0,
|
||||
|
||||
dlgShow: false,
|
||||
|
||||
@@ -124,7 +162,10 @@ import { Message } from 'element-ui'
|
||||
freightTemplateId: '',
|
||||
stockNumber: 5,
|
||||
siteList: [],
|
||||
wareHouseList: []
|
||||
upMoney: 0.0,
|
||||
wareHouseList: [],
|
||||
brandId: '',
|
||||
brandName: ''
|
||||
},
|
||||
|
||||
wareHouseList: [],
|
||||
@@ -133,11 +174,16 @@ import { Message } from 'element-ui'
|
||||
ids: [],
|
||||
|
||||
sites: [],
|
||||
loadingText: '拼命加载中……'
|
||||
loadingText: '拼命加载中……',
|
||||
|
||||
successNumber: 0,
|
||||
errorNumber: 0,
|
||||
brandList: [],
|
||||
selectBrand: {}
|
||||
}
|
||||
},
|
||||
created () {
|
||||
// this.getDraftList()
|
||||
this.getSiteList()
|
||||
},
|
||||
|
||||
methods: {
|
||||
@@ -146,11 +192,33 @@ import { Message } from 'element-ui'
|
||||
Message.error("请选择店铺")
|
||||
return
|
||||
}
|
||||
if (!this.siteId) {
|
||||
Message.error("请选择站点")
|
||||
return
|
||||
}
|
||||
if (!this.search.startPage || (this.search.startPage < 1)) {
|
||||
Message.error("起始页不能为空,且不能小于1")
|
||||
return
|
||||
}
|
||||
if (!this.search.endPage || (this.search.startPage < 1)) {
|
||||
Message.error("结束页不能为空")
|
||||
return
|
||||
}
|
||||
if (this.search.startPage > this.search.endPage) {
|
||||
Message.error("起始页不能大于结束页")
|
||||
return
|
||||
}
|
||||
this.isLoading = true
|
||||
this.loadingText = '拼命加载中……'
|
||||
this.tableData = []
|
||||
this.page = this.search.startPage
|
||||
this.getDraftList()
|
||||
},
|
||||
async getDraftList () {
|
||||
let sites = []
|
||||
if (this.siteId) {
|
||||
sites.push(this.siteId)
|
||||
}
|
||||
let res = await sendChromeAPIMessage({
|
||||
url: 'bg-visage-mms/product/draft/pageQuery',
|
||||
needMallId: true,
|
||||
@@ -158,7 +226,8 @@ import { Message } from 'element-ui'
|
||||
data: {
|
||||
page: this.page,
|
||||
pageSize: this.pageSize,
|
||||
...this.search
|
||||
...this.search,
|
||||
bindSiteIds: sites
|
||||
}})
|
||||
|
||||
if (res.success && res.errorCode == 1000000) {
|
||||
@@ -191,7 +260,7 @@ import { Message } from 'element-ui'
|
||||
if (this.page == 1 && res.result.pageItems.length == 0) {
|
||||
this.isLoading = false
|
||||
}
|
||||
else if (res.result.pageItems.length == this.pageSize) {
|
||||
else if (res.result.pageItems.length == this.pageSize && this.page < this.search.endPage) {
|
||||
this.page ++
|
||||
this.getDraftList()
|
||||
} else {
|
||||
@@ -205,32 +274,51 @@ import { Message } from 'element-ui'
|
||||
return;
|
||||
}
|
||||
|
||||
let id = this.ids[0]
|
||||
this.sites = []
|
||||
for (let i = 0; i < this.tableData.length; i++) {
|
||||
if (this.tableData[i].spuId == id) {
|
||||
this.sites = this.tableData[i].bindSiteIds.split(',')
|
||||
}
|
||||
}
|
||||
this.sites.push(this.siteId)
|
||||
|
||||
this.configForm.siteList = this.sites
|
||||
this.freightTmplList = []
|
||||
this.wareHouseList = []
|
||||
this.configForm.freightTemplateId = ''
|
||||
this.configForm.wareHouseList = []
|
||||
await this.getFreightTmplList(this.sites)
|
||||
await this.getWareahouseList(this.sites)
|
||||
await this.getBrandList()
|
||||
this.dlgShow = true
|
||||
},
|
||||
async toBtachSubmit() {
|
||||
this.$refs.configForm.validate((valid) => {
|
||||
if (valid) {
|
||||
if (this.configForm.brandId) {
|
||||
this.brandList.map(item => {
|
||||
if (item.vid == this.configForm.brandId) {
|
||||
this.selectBrand = item
|
||||
}
|
||||
})
|
||||
}
|
||||
this.isLoading = true
|
||||
this.dlgShow = false
|
||||
for(let i = 0; i < this.ids.length; i++) {
|
||||
this.loadingText = '正在提交第' + (i+1) + '/' + this.ids.length + '个商品'
|
||||
this.submitSpu(this.ids[i])
|
||||
}
|
||||
this.isLoading = false
|
||||
this.successNumber = 0
|
||||
this.errorNumber = 0
|
||||
this.submitSpu(0)
|
||||
}
|
||||
})
|
||||
},
|
||||
async submitSpu(spuId) {
|
||||
async submitSpu(idx) {
|
||||
if (idx == this.ids.length) {
|
||||
this.isLoading = false
|
||||
MessageBox.alert('总共提交' + this.ids.length + '个商品,成功' + this.successNumber + '个,失败' + this.errorNumber + '个', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
callback: action => {
|
||||
this.toLoad()
|
||||
}
|
||||
})
|
||||
return
|
||||
} else {
|
||||
this.loadingText = '正在提交第' + (idx+1) + '/' + this.ids.length + '个商品,成功' + this.successNumber + '个,失败' + this.errorNumber + '个'
|
||||
}
|
||||
let spuId = this.ids[idx]
|
||||
let res = await sendChromeAPIMessage({
|
||||
url: 'bg-visage-mms/product/draft/query',
|
||||
needMallId: true,
|
||||
@@ -239,15 +327,53 @@ import { Message } from 'element-ui'
|
||||
productDraftId: spuId
|
||||
}})
|
||||
if (res.success && res.errorCode == 1000000) {
|
||||
let catId = this.getCategoryId(res.result)
|
||||
let brandProperty = await this.queryProperty(catId)
|
||||
|
||||
let content = transformSubmitForHalf(res.result, this.configForm, spuId)
|
||||
|
||||
if (this.configForm.brandId && brandProperty) {
|
||||
let flag = false
|
||||
content.productPropertyReqs.map(item => {
|
||||
if (item.propName == '品牌名') {
|
||||
flag = true
|
||||
item.pid = brandProperty.pid
|
||||
item.refPid = brandProperty.refPid
|
||||
item.templatePid = brandProperty.templatePid
|
||||
item.propValue = this.selectBrand.brandNameEn
|
||||
item.vid = this.selectBrand.vid
|
||||
}
|
||||
})
|
||||
if (!flag) {
|
||||
content.productPropertyReqs.push({
|
||||
"templatePid": brandProperty.templatePid,
|
||||
"pid": brandProperty.pid,
|
||||
"refPid": brandProperty.refPid,
|
||||
"propName": "品牌名",
|
||||
"vid": this.selectBrand.vid,
|
||||
"propValue": this.selectBrand.brandNameEn,
|
||||
"valueUnit": "",
|
||||
"valueExtendInfo": "",
|
||||
"numberInputValue": ""
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
let res1 = await sendChromeAPIMessage({
|
||||
url: 'bg-visage-mms/product/add',
|
||||
needMallId: true,
|
||||
mallId: this.mallId,
|
||||
data: content})
|
||||
|
||||
console.log(res1)
|
||||
if (res1.success && res1.errorCode == 1000000) {
|
||||
this.successNumber += 1
|
||||
} else {
|
||||
this.errorNumber += 1
|
||||
}
|
||||
setTimeout(() => {
|
||||
idx ++
|
||||
this.submitSpu(idx)
|
||||
}, 1000)
|
||||
}
|
||||
},
|
||||
async getFreightTmplList(siteId) {
|
||||
@@ -294,39 +420,6 @@ import { Message } from 'element-ui'
|
||||
this.ids.push(e.spuId);
|
||||
});
|
||||
},
|
||||
saveDraftTemplate(spu, index) {
|
||||
sendChromeAPIMessage({
|
||||
url: 'bg-visage-mms/product/draft/query',
|
||||
needMallId: true,
|
||||
mallId: this.productPage.mallId,
|
||||
data: {
|
||||
productDraftId: spu
|
||||
}}).then((res) => {
|
||||
if (res.errorCode == 1000000) {
|
||||
let content = transform(res.result)
|
||||
let mallInfo = this.$store.state.mallList.filter(item => {
|
||||
return item.mallId == this.productPage.mallId
|
||||
})
|
||||
this.$http.post('/api/product/add', {
|
||||
mallId: mallInfo[0].mallId,
|
||||
mallName: mallInfo[0].mallName,
|
||||
productSpu: spu,
|
||||
productName: res.result.productName,
|
||||
type: 0,
|
||||
content: content
|
||||
}).then(res1 => {
|
||||
if (res1.code == 0) {
|
||||
Message.success("商品【" + res.result.productName + "】成功添加为商品模板")
|
||||
if (index == this.productIds.length - 1) {
|
||||
this.getList()
|
||||
}
|
||||
}
|
||||
})
|
||||
} else {
|
||||
this.saveDraftTemplate(spu, index)
|
||||
}
|
||||
})
|
||||
},
|
||||
async getSiteList() {
|
||||
let res = await sendChromeAPIMessage({
|
||||
url: 'bg-visage-mms/config/common/site/query',
|
||||
@@ -339,6 +432,52 @@ import { Message } from 'element-ui'
|
||||
})
|
||||
}
|
||||
},
|
||||
async getBrandList() {
|
||||
let res = await sendChromeAPIMessage({
|
||||
url: 'bg-anniston-mms/category/brand/property/value/pageQuery',
|
||||
needMallId: true,
|
||||
mallId: this.mallId,
|
||||
data: {
|
||||
"page": 1,
|
||||
"pageSize": 50
|
||||
}})
|
||||
if (res.success && res.errorCode == 1000000) {
|
||||
this.brandList = res.result.pageItems
|
||||
}
|
||||
},
|
||||
async queryProperty(catId) {
|
||||
let res = await sendChromeAPIMessage({
|
||||
url: 'bg-anniston-mms/category/template/query',
|
||||
needMallId: true,
|
||||
mallId: this.mallId,
|
||||
data: {
|
||||
"catId": catId,
|
||||
"productCreateTime": null,
|
||||
"langList": [
|
||||
"en"
|
||||
]
|
||||
}})
|
||||
if (res.success && res.errorCode == 1000000) {
|
||||
let properties = res.result.properties.filter(item => {
|
||||
return item.name == '品牌名'
|
||||
})
|
||||
if (properties && properties.length > 0) {
|
||||
return properties[0]
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
}
|
||||
},
|
||||
getCategoryId(obj) {
|
||||
let i = 1
|
||||
while(true) {
|
||||
if (!obj.categories['cat'+i].catId) {
|
||||
break
|
||||
}
|
||||
i++
|
||||
}
|
||||
return obj.categories['cat'+(i-1)].catId
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
118
src/view/product/FindSeller.vue
Normal file
118
src/view/product/FindSeller.vue
Normal file
@@ -0,0 +1,118 @@
|
||||
<template>
|
||||
<ai-list class="list" v-loading="isLoading" element-loading-text="拼命加载中" element-loading-spinner="el-icon-loading">
|
||||
<ai-title
|
||||
slot="title"
|
||||
title="查找买手"
|
||||
isShowBottomBorder>
|
||||
</ai-title>
|
||||
<template slot="content">
|
||||
<div class="content">
|
||||
<ai-card title="查找买手" style="padding-bottom: 40px;">
|
||||
<div style="text-align: center; display: flex; flex-wrap: nowrap;justify-content: center;">
|
||||
<label style="width:90px; height: 25px; font-size: 25px">店铺:</label>
|
||||
<el-select style="width:180px;" v-model="form.mallId" placeholder="请选择" clearable size="small">
|
||||
<el-option
|
||||
v-for="item in $store.state.mallList"
|
||||
:key="item.mallId"
|
||||
:label="item.mallName"
|
||||
:value="item.mallId">
|
||||
</el-option>
|
||||
</el-select>
|
||||
<label style="width:120px; height: 25px; font-size: 25px">SKC ID:</label>
|
||||
<el-input style="width:250px; " clearable size="small" placeholder="请输入SKC ID" v-model="form.skc"></el-input>
|
||||
<el-button style="margin-left: 5px" type="primary" @click="beforeFind">查找</el-button>
|
||||
</div>
|
||||
</ai-card>
|
||||
</div>
|
||||
</template>
|
||||
</ai-list>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Message } from 'element-ui'
|
||||
import {sendChromeAPIMessage} from '@/api/chromeApi'
|
||||
|
||||
export default {
|
||||
name: 'FindSeller',
|
||||
|
||||
data () {
|
||||
return {
|
||||
form: {
|
||||
mallId: '',
|
||||
skc: ''
|
||||
},
|
||||
isLoading: false,
|
||||
}
|
||||
},
|
||||
created () {
|
||||
},
|
||||
methods: {
|
||||
beforeFind() {
|
||||
this.$userCheck(this.form.mallId).then(() => {
|
||||
this.toFind()
|
||||
}).catch((err) => {
|
||||
this.form.mallId = ''
|
||||
})
|
||||
},
|
||||
async toFind() {
|
||||
if (!this.form.mallId) {
|
||||
Message.error("请选择店铺")
|
||||
return
|
||||
}
|
||||
if (!this.form.skc || (this.form.skc < 1)) {
|
||||
Message.error("请输入SKC")
|
||||
return
|
||||
}
|
||||
|
||||
this.isLoading = true
|
||||
|
||||
let res = await sendChromeAPIMessage({
|
||||
url: 'marvel-mms/cn/api/kiana/venom/sales/management/listWarehouse',
|
||||
needMallId: true,
|
||||
mallId: this.form.mallId,
|
||||
data: {
|
||||
pageNo: 1,
|
||||
pageSize: 10,
|
||||
isLack: 0,
|
||||
priceAdjustRecentDays: 7,
|
||||
productSkcIdList: [this.form.skc]
|
||||
}})
|
||||
if (res.errorCode == 1000000) {
|
||||
if (res.result.subOrderList.length == 0) {
|
||||
Message.error("没有查询结果,请检查店铺和SKC是否正确")
|
||||
} else {
|
||||
this.$confirm(res.result.subOrderList[0].buyerName, '查询结果', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
center: true
|
||||
}).then(() => {
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
this.isLoading = false
|
||||
}
|
||||
}
|
||||
}
|
||||
</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>
|
||||
@@ -3,12 +3,13 @@
|
||||
<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" @change="beforeGetList" placeholder="请选择" size="small">
|
||||
<el-select v-model="form.mallId" placeholder="请选择" size="small">
|
||||
<el-option
|
||||
v-for="item in $store.state.mallList"
|
||||
:key="item.mallId"
|
||||
@@ -21,47 +22,108 @@
|
||||
</template>
|
||||
</ai-title>
|
||||
<template slot="content">
|
||||
<ai-card title="数据明细" style="padding-bottom: 40px;">
|
||||
<template #right>
|
||||
<label style="width:140px">是否在售:</label>
|
||||
<el-select clearable v-model="reqData.skcSiteStatus" placeholder="请选择">
|
||||
<el-option
|
||||
v-for="item in options"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value">
|
||||
</el-option>
|
||||
</el-select>
|
||||
<label style="width:140px">商品名称:</label>
|
||||
<el-input clearable size="small" style="display: inline" placeholder="请输入商品名称" v-model="reqData.productName"></el-input>
|
||||
<el-button type="primary" @click="toLoad">加载</el-button>
|
||||
<json-excel
|
||||
:data="tableData"
|
||||
:fields="jsonFields"
|
||||
name="商品列表.xls"
|
||||
worksheet="商品列表">
|
||||
<el-button type="primary" :disabled="tableData.length == 0">下载数据</el-button>
|
||||
</json-excel>
|
||||
</template>
|
||||
<ai-table
|
||||
:isShowPagination="false"
|
||||
:tableData="tableData"
|
||||
:col-configs="colConfigs"
|
||||
:total="tableData.length"
|
||||
height="500"
|
||||
style="margin-top: 8px;"
|
||||
@getList="() => {}">
|
||||
<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>
|
||||
<div class="search-item">
|
||||
<label>是否在售:</label>
|
||||
<el-select clearable v-model="reqData.skcSiteStatus" 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>站点:</label>
|
||||
<el-select v-model="reqData.bindSiteId" placeholder="请选择" size="small">
|
||||
<el-option
|
||||
v-for="item in siteList"
|
||||
:key="item.siteId"
|
||||
:label="item.siteName"
|
||||
:value="item.siteId">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
<div class="search-item">
|
||||
<label>合规下架风险:</label>
|
||||
<el-select v-model="reqData.certPunishTypes" multiple placeholder="请选择" size="small">
|
||||
<el-option
|
||||
v-for="item in certPunishTypes"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:value="item.id">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
<div class="search-item">
|
||||
<label>资质上传状态:</label>
|
||||
<el-select v-model="reqData.productCertAuditStatuses" multiple placeholder="请选择" size="small">
|
||||
<el-option
|
||||
v-for="item in productCertAuditStatusList"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:value="item.id">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
<div class="search-item">
|
||||
<label>商品名称:</label>
|
||||
<el-input clearable size="small" placeholder="请输入商品名称" v-model="reqData.productName"></el-input>
|
||||
</div>
|
||||
<div class="search-item">
|
||||
<label>库存起始值:</label>
|
||||
<el-input size="small" placeholder="请输入库存起始值" type="number" v-model="reqData.jitStockQuantitySection.leftValue"></el-input>
|
||||
</div>
|
||||
<div class="search-item">
|
||||
<label>库存结束值:</label>
|
||||
<el-input size="small" placeholder="请输入库存结束值" type="number" v-model="reqData.jitStockQuantitySection.rightValue"></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>
|
||||
<json-excel
|
||||
:data="tableData"
|
||||
:fields="jsonFields"
|
||||
name="商品列表.xls"
|
||||
worksheet="商品列表">
|
||||
<el-button type="primary" :disabled="tableData.length == 0">下载数据</el-button>
|
||||
</json-excel>
|
||||
</template>
|
||||
<ai-table
|
||||
:isShowPagination="false"
|
||||
:tableData="tableData"
|
||||
:col-configs="colConfigs"
|
||||
:total="tableData.length"
|
||||
height="500"
|
||||
style="margin-top: 8px;"
|
||||
@getList="() => {}">
|
||||
|
||||
<el-table-column slot="productName" width="200px" :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>
|
||||
<el-table-column slot="productName" width="200px" :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>
|
||||
@@ -80,11 +142,20 @@ import JsonExcel from 'vue-json-excel'
|
||||
form: {
|
||||
mallId: ''
|
||||
},
|
||||
startPage: 1,
|
||||
endPage: 10,
|
||||
reqData: {
|
||||
productName: '',
|
||||
page: 1,
|
||||
pageSize: 100,
|
||||
skcSiteStatus: ''
|
||||
skcSiteStatus: '',
|
||||
bindSiteId: '',
|
||||
certPunishTypes: [],
|
||||
productCertAuditStatuses: [],
|
||||
jitStockQuantitySection: {
|
||||
leftValue: '',
|
||||
rightValue: ''
|
||||
}
|
||||
},
|
||||
options: [
|
||||
{label: '是', value: 1},
|
||||
@@ -100,6 +171,9 @@ import JsonExcel from 'vue-json-excel'
|
||||
{ prop: 'extCode', label: 'SKC货号', width: '100px', align: 'left' },
|
||||
{ prop: 'skuExtCode', label: 'SKU货号', width: '160px', align: 'left' },
|
||||
{ prop: 'specName', label: 'SKU属性', width: '100px', align: 'left' },
|
||||
{ prop: 'skuStockQuantity', label: '库存', width: '100px', align: 'left' },
|
||||
{ prop: 'productCertAuditStatus', label: '资质上传状态', width: '120px', align: 'left' },
|
||||
{ prop: 'certPunishType', label: '合规下架风险', width: '120px', align: 'left' },
|
||||
{ prop: 'supplierPrice', label: '申报价格(CNY)', width: '180px', align: 'left' },
|
||||
{ prop: 'todaySalesVolume', label: '今日销量', width: '100px', align: 'left' },
|
||||
{ prop: 'createdAt', label: '上架时间', width: '160px', align: 'left' }
|
||||
@@ -117,17 +191,47 @@ import JsonExcel from 'vue-json-excel'
|
||||
"SKC货号": "extCode",
|
||||
"SKU货号": "skuExtCode",
|
||||
"SKU属性": "specName",
|
||||
"库存": "skuStockQuantity",
|
||||
"资质上传状态": "productCertAuditStatus",
|
||||
"合规下架风险": "certPunishType",
|
||||
"申报价格(CNY)": "supplierPrice",
|
||||
"今日销量": "todaySalesVolume",
|
||||
"上架时间": "createdAt"
|
||||
},
|
||||
currentIndex: 0
|
||||
certPunishTypes: [
|
||||
{id: 1, name: '已经处罚'},
|
||||
{id: 2, name: '即将下架'},
|
||||
{id: 3, name: '下架风险预警'},
|
||||
],
|
||||
productCertAuditStatusList: [
|
||||
{id: 1, name: '待上传'},
|
||||
{id: 2, name: '上传中'},
|
||||
{id: 3, name: '上传失败'},
|
||||
{id: 4, name: '上传成功'},
|
||||
],
|
||||
currentIndex: 0,
|
||||
siteList: []
|
||||
}
|
||||
},
|
||||
components: {
|
||||
JsonExcel
|
||||
},
|
||||
created () {
|
||||
this.getSiteList()
|
||||
},
|
||||
methods: {
|
||||
async getSiteList() {
|
||||
let res = await sendChromeAPIMessage({
|
||||
url: 'bg-visage-mms/config/common/site/query',
|
||||
needMallId: true,
|
||||
mallId: this.$store.state.mallList[0].mallId,
|
||||
data: {}})
|
||||
if (res.success && res.errorCode == 1000000) {
|
||||
this.siteList = res.result.siteBaseList.filter(item => {
|
||||
return item.matchSemiManaged
|
||||
})
|
||||
}
|
||||
},
|
||||
beforeGetList() {
|
||||
this.$userCheck(this.form.mallId).then(() => {
|
||||
this.toLoad()
|
||||
@@ -140,7 +244,19 @@ import JsonExcel from 'vue-json-excel'
|
||||
Message.error("请选择店铺")
|
||||
return
|
||||
}
|
||||
this.reqData.page = 1
|
||||
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.reqData.page = this.startPage
|
||||
this.tableData = []
|
||||
this.currentIndex = 0
|
||||
this.isLoading = true
|
||||
@@ -164,6 +280,24 @@ import JsonExcel from 'vue-json-excel'
|
||||
data.skcSiteStatus = item.skcSiteStatus == '1'? '在售': ''
|
||||
data.createdAt = timestampToTime(item.createdAt)
|
||||
data.extCode = item.extCode
|
||||
data.productCertAuditStatus = '-'
|
||||
if (item.productCertAuditStatus == 1) {
|
||||
data.productCertAuditStatus = '待上传'
|
||||
} else if (item.productCertAuditStatus == 2) {
|
||||
data.productCertAuditStatus = '上传中'
|
||||
} else if (item.productCertAuditStatus == 3) {
|
||||
data.productCertAuditStatus = '上传失败'
|
||||
} else if (item.productCertAuditStatus == 4) {
|
||||
data.productCertAuditStatus = '上传成功'
|
||||
}
|
||||
data.certPunishType = '-'
|
||||
if (item.productCertPunish?.certPunishType == 1) {
|
||||
data.certPunishType = '已经处罚'
|
||||
} else if (item.productCertPunish?.certPunishType == 2) {
|
||||
data.certPunishType = '即将下架'
|
||||
} else if (item.productCertPunish?.certPunishType == 3) {
|
||||
data.certPunishType = '下架风险预警'
|
||||
}
|
||||
|
||||
data.category = ''
|
||||
for (let i = 1; i < 11; i++) {
|
||||
@@ -179,21 +313,23 @@ import JsonExcel from 'vue-json-excel'
|
||||
let temp = item.productSkuSummaries[k].productSkuSpecList.map(item2 => {
|
||||
return item2.parentSpecName + ":" + item2.specName
|
||||
})
|
||||
let skuStockQuantity = '-'
|
||||
if (item.productSkuSummaries[k].productSkuSemiManagedStock) {
|
||||
skuStockQuantity = item.productSkuSummaries[k].productSkuSemiManagedStock.skuStockQuantity
|
||||
}
|
||||
data = {...data,
|
||||
productSkuId: item.productSkuSummaries[k].productSkuId,
|
||||
skuExtCode: item.productSkuSummaries[k].extCode,
|
||||
supplierPrice: item.productSkuSummaries[k].supplierPrice / 100,
|
||||
specName: temp.join(","),
|
||||
skuStockQuantity,
|
||||
todaySalesVolume: item.productSkuSummaries[k].todaySalesVolume}
|
||||
|
||||
this.tableData.push(data)
|
||||
}
|
||||
|
||||
}
|
||||
if (this.reqData.page == 1 && res.result.pageItems.length == 0) {
|
||||
this.isLoading = false
|
||||
}
|
||||
else if (res.result.pageItems.length == 100) {
|
||||
if (res.result.pageItems.length == this.reqData.pageSize && this.reqData.page < this.endPage) {
|
||||
this.reqData.page ++
|
||||
this.load()
|
||||
} else {
|
||||
|
||||
272
src/view/product/SellerSelect.vue
Normal file
272
src/view/product/SellerSelect.vue
Normal file
@@ -0,0 +1,272 @@
|
||||
<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>
|
||||
<div class="search-item">
|
||||
<label>状态:</label>
|
||||
<el-select v-model="status" placeholder="请选择" size="small">
|
||||
<el-option
|
||||
v-for="item in statusList"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:value="item.id">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
<div class="search-item">
|
||||
<label>是否合规待办:</label>
|
||||
<el-select v-model="isViolationInfo" placeholder="请选择" size="small">
|
||||
<el-option
|
||||
v-for="item in options"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</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>
|
||||
<json-excel
|
||||
:data="tableData"
|
||||
:fields="jsonFields"
|
||||
name="商品列表.xls"
|
||||
worksheet="商品列表">
|
||||
<el-button type="primary" :disabled="tableData.length == 0">下载数据</el-button>
|
||||
</json-excel>
|
||||
</template>
|
||||
<ai-table
|
||||
:isShowPagination="false"
|
||||
:tableData="tableData"
|
||||
:col-configs="colConfigs"
|
||||
:total="tableData.length"
|
||||
height="800"
|
||||
style="margin-top: 8px;"
|
||||
@getList="() => {}">
|
||||
|
||||
<el-table-column slot="productName" width="200px" :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 JsonExcel from 'vue-json-excel'
|
||||
|
||||
export default {
|
||||
name: 'SellerSelect',
|
||||
|
||||
data () {
|
||||
return {
|
||||
form: {
|
||||
mallId: ''
|
||||
},
|
||||
startPage: 1,
|
||||
endPage: 10,
|
||||
reqData: {
|
||||
pageNum: 1,
|
||||
pageSize: 100,
|
||||
secondarySelectStatusList: []
|
||||
},
|
||||
colConfigs: [
|
||||
{ slot: 'productName', label: '商品名称', width: '180px', align: 'left', fixed: 'left' },
|
||||
{ prop: 'category', label: '分类', width: '220px', align: 'left', fixed: 'left' },
|
||||
{ prop: 'siteName', label: '站点', width: '140px', align: 'left', fixed: 'left' },
|
||||
{ prop: 'productId', label: 'SPU ID', width: '120px', align: 'left' },
|
||||
{ prop: 'productSkcId', label: 'SKC ID', width: '120px', align: 'left' },
|
||||
{ prop: 'extCode', label: 'SKC货号', width: '120px', align: 'left' },
|
||||
{ prop: 'punishInfo', label: '违规信息', width: '120px', align: 'left' },
|
||||
{ prop: 'violationInfo', label: '合规待办项', width: '200px', align: 'left' },
|
||||
{ prop: 'supplierPrice', label: '申报价格(CNY)', width: '180px', align: 'left' },
|
||||
{ prop: 'createdAt', label: '创建时间', width: '160px', align: 'left' }
|
||||
],
|
||||
isLoading: false,
|
||||
tableData: [],
|
||||
jsonFields: {
|
||||
"商品名称": "productName",
|
||||
"图片": "mainImageUrl",
|
||||
"分类": "category",
|
||||
"站点": "siteName",
|
||||
"SPU ID": "productId",
|
||||
"SKC ID": "productSkcId",
|
||||
"SKC货号": "extCode",
|
||||
"违规信息": "punishInfo",
|
||||
"合规待办项": "violationInfo",
|
||||
"申报价格(CNY)": "supplierPrice",
|
||||
"创建时间": "createdAt"
|
||||
},
|
||||
statusList: [
|
||||
{id: 1, name: '未发布到站点'},
|
||||
{id: 2, name: '已下架/终止'}
|
||||
],
|
||||
options: [
|
||||
{label: '是', value: 1},
|
||||
{label: '否', value: 0}
|
||||
],
|
||||
status: 1,
|
||||
isViolationInfo: ''
|
||||
}
|
||||
},
|
||||
components: {
|
||||
JsonExcel
|
||||
},
|
||||
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
|
||||
}
|
||||
if (this.status == 1) {
|
||||
this.reqData.secondarySelectStatusList = [10, 11]
|
||||
} else if (this.status == 2) {
|
||||
this.reqData.secondarySelectStatusList = [13]
|
||||
}
|
||||
if (this.isViolationInfo == 0) {
|
||||
this.reqData.supplierTodoTypeList = []
|
||||
} else if (this.isViolationInfo == 1) {
|
||||
this.reqData.supplierTodoTypeList = [7]
|
||||
}
|
||||
this.reqData.pageNum = this.startPage
|
||||
this.tableData = []
|
||||
this.isLoading = true
|
||||
this.load()
|
||||
},
|
||||
load() {
|
||||
sendChromeAPIMessage({
|
||||
url: 'marvel-supplier/api/xmen/select/search',
|
||||
needMallId: true,
|
||||
mallId: this.form.mallId,
|
||||
anti: true,
|
||||
data: this.reqData}).then((res) => {
|
||||
if (res.errorCode == 1000000) {
|
||||
for(let i = 0;i < res.result.dataList.length; i++) {
|
||||
let item = res.result.dataList[i];
|
||||
let data = {};
|
||||
data.productName = item.productName
|
||||
data.mainImageUrl = item.carouselImageUrlList[0]
|
||||
data.productId = item.productId
|
||||
data.productSkcId = item.productSkcId
|
||||
data.siteName = item.siteName
|
||||
data.createdAt = timestampToTime(item.productCreatedAt)
|
||||
|
||||
data.category = item.fullCategoryName.join('->')
|
||||
|
||||
for (let k = 0; k < item.skcList.length; k++) {
|
||||
data = {...data, productSkcId: item.skcList[k].skcId, punishInfo: item.skcList[k].punishInfo, extCode: item.skcList[k].extCode, supplierPrice: item.skcList[k].supplierPrice}
|
||||
|
||||
if (item.skcList[k].addSiteViolationInfoVO && item.skcList[k].addSiteViolationInfoVO.violationCodeList?.length > 0) {
|
||||
let temp = ''
|
||||
for (let j = 0; j < item.skcList[k].addSiteViolationInfoVO.violationCodeList.length; j++) {
|
||||
if (item.skcList[k].addSiteViolationInfoVO.violationCodeList[j] == 1) {
|
||||
temp += ',商品资质'
|
||||
}
|
||||
if (item.skcList[k].addSiteViolationInfoVO.violationCodeList[j] == 2) {
|
||||
temp += ',商品标签实拍图'
|
||||
}
|
||||
}
|
||||
temp = temp.substring(1)
|
||||
data.violationInfo = temp
|
||||
}
|
||||
|
||||
this.tableData.push(data)
|
||||
}
|
||||
|
||||
}
|
||||
if (res.result.dataList.length == this.reqData.pageSize && this.reqData.pageNum < this.endPage) {
|
||||
this.reqData.pageNum ++
|
||||
this.load()
|
||||
} else {
|
||||
this.isLoading = false
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</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>
|
||||
270
src/view/sale/AfterSaleDeductStat.vue
Normal file
270
src/view/sale/AfterSaleDeductStat.vue
Normal file
@@ -0,0 +1,270 @@
|
||||
<template>
|
||||
<ai-list class="list" v-loading="isLoading" element-loading-text="拼命加载中" element-loading-spinner="el-icon-loading">
|
||||
<ai-title
|
||||
slot="title"
|
||||
title="售后赔付统计"
|
||||
isShowBottomBorder>
|
||||
<template #rightBtn>
|
||||
<div class="title-right">
|
||||
<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>
|
||||
</div>
|
||||
</template>
|
||||
</ai-title>
|
||||
<template slot="content">
|
||||
<div class="content">
|
||||
<ai-search-bar>
|
||||
<template #left>
|
||||
<div class="search-item">
|
||||
<label>账务时间:</label>
|
||||
<el-date-picker
|
||||
v-model="searchDate"
|
||||
type="daterange"
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期">
|
||||
</el-date-picker>
|
||||
</div>
|
||||
</template>
|
||||
<template #right>
|
||||
<el-button type="primary" @click="beforeGetList">加载</el-button>
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-card title="数据明细" style="padding-bottom: 40px;">
|
||||
<template #right>
|
||||
<json-excel
|
||||
:data="tableData"
|
||||
:fields="jsonFields"
|
||||
name="售后赔付统计列表.xls"
|
||||
worksheet="售后赔付统计列表">
|
||||
<el-button type="primary" :disabled="tableData.length == 0">下载数据</el-button>
|
||||
</json-excel>
|
||||
</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="400px" :show-overflow-tooltip='true' label="商品名称" fixed="left">
|
||||
<template slot-scope="scope">
|
||||
<div>
|
||||
<el-image :src="scope.row.productUrl" style="width: 40px; height: 40px" class="image" :preview-src-list="[scope.row.productUrl]" />
|
||||
{{ 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 JsonExcel from 'vue-json-excel'
|
||||
|
||||
export default {
|
||||
name: 'AfterSaleStat',
|
||||
|
||||
data () {
|
||||
return {
|
||||
mallId: '',
|
||||
searchDate: [],
|
||||
reqData: {
|
||||
pageNum: 1,
|
||||
pageSize: 100
|
||||
},
|
||||
colConfigs: [
|
||||
{ prop: 'productName', label: '商品名称', width: '400px', align: 'left', fixed: 'left' },
|
||||
{ prop: 'productSkuId', label: 'SKU ID', align: 'left' },
|
||||
{ prop: 'skuCode', label: 'SKU货号', align: 'left' },
|
||||
{ prop: 'deductionAmount', label: '扣款总金额', align: 'left', sortable: true, 'sort-method': (a, b) => a.deductionAmount - b.deductionAmount },
|
||||
{ prop: 'times', label: '扣款次数', align: 'left', sortable: true, 'sort-method': (a, b) => a.times - b.times },
|
||||
/*{ prop: 'supplierPrice', label: '供货价', align: 'left', sortable: true, 'sort-method': (a, b) => a.supplierPrice - b.supplierPrice },
|
||||
{ prop: 'cost', label: '成本', align: 'left', sortable: true, 'sort-method': (a, b) => a.cost - b.cost },
|
||||
{ prop: 'profitTimes', label: '相当于X件白卖', align: 'left', sortable: true, 'sort-method': (a, b) => a.profitTimes - b.profitTimes }*/
|
||||
],
|
||||
isLoading: false,
|
||||
tableData: [],
|
||||
jsonFields: {
|
||||
"商品名称": "productName",
|
||||
"SKU ID": "productSkuId",
|
||||
"SKU货号": "skuCode",
|
||||
"扣款总金额": "deductionAmount",
|
||||
"扣款次数": "times"
|
||||
},
|
||||
costList: []
|
||||
}
|
||||
},
|
||||
components: {
|
||||
JsonExcel
|
||||
},
|
||||
methods: {
|
||||
beforeGetList() {
|
||||
this.$userCheck(this.mallId).then(() => {
|
||||
this.toLoad()
|
||||
}).catch((err) => {
|
||||
this.mallId = ''
|
||||
})
|
||||
},
|
||||
async toLoad() {
|
||||
if (!this.mallId) {
|
||||
Message.error("请选择店铺")
|
||||
return
|
||||
}
|
||||
if (!this.searchDate) {
|
||||
Message.error("请选择时间范围")
|
||||
return
|
||||
}
|
||||
this.reqData.pageNum = 1
|
||||
this.tableData = []
|
||||
this.isLoading = true
|
||||
|
||||
let startTime = this.searchDate[0].getTime()
|
||||
let endTime = this.searchDate[1].getTime()
|
||||
while(true) {
|
||||
if ((endTime - startTime) > 2592000000) {
|
||||
this.reqData.pageNum = 1
|
||||
await this.getAfterSaleDeductList(startTime, startTime + 2592000000)
|
||||
startTime = startTime + 2592000000
|
||||
} else {
|
||||
this.reqData.pageNum = 1
|
||||
await this.getAfterSaleDeductList(startTime, endTime)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
this.isLoading = false
|
||||
|
||||
},
|
||||
async getAfterSaleDeductList(startTime, endTime) {
|
||||
let res = await sendChromeAPIMessage({
|
||||
url: `api/merchant/fund/deduction/after-sales-compensation/query`,
|
||||
needMallId: true,
|
||||
mallId: this.mallId,
|
||||
data: {
|
||||
...this.reqData,
|
||||
beginFundTime: startTime,
|
||||
endFundTime: endTime
|
||||
}})
|
||||
if (res.errorCode == 1000000) {
|
||||
for (let i = 0; i < res.result.resultList.length; i++) {
|
||||
let item = res.result.resultList[i]
|
||||
let flag = false
|
||||
for (let j = 0; j < item.productSkuIdList.length; j++) {
|
||||
for ( let k = 0; k < this.tableData.length; k++) {
|
||||
if (item.productSkuIdList[j] == this.tableData[k].productSkuId) {
|
||||
flag = true
|
||||
this.tableData[k].times++
|
||||
this.tableData[k].deductionAmount = Math.round((this.tableData[k].deductionAmount + new Number(item.deductionAmount.digitalText))*100)/100
|
||||
if (!this.tableData[k].skuCode) {
|
||||
this.tableData[k].skuCode = item.skuExtCodeList[j]
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
if (!flag) {
|
||||
this.tableData.push({
|
||||
productName: item.goodsNameList[j],
|
||||
productSkuId: item.productSkuIdList[j],
|
||||
deductionAmount: new Number(item.deductionAmount.digitalText),
|
||||
skuCode: item.skuExtCodeList[j],
|
||||
times: 1,
|
||||
supplierPrice: ''
|
||||
})
|
||||
flag = true
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((this.reqData.pageSize * this.reqData.pageNum) < res.result.total) {
|
||||
this.reqData.pageNum ++
|
||||
await this.getAfterSaleDeductList(startTime, endTime)
|
||||
}
|
||||
}
|
||||
},
|
||||
async getProductList(params) {
|
||||
let res = await sendChromeAPIMessage({
|
||||
url: 'bg-visage-mms/product/skc/pageQuery',
|
||||
needMallId: true,
|
||||
mallId: this.mallId,
|
||||
data: {
|
||||
...params
|
||||
}})
|
||||
if (res.errorCode == 1000000) {
|
||||
res.result.pageItems.map((item) => {
|
||||
item.productSkuSummaries.map(item1 => {
|
||||
for (let i = 0; i < this.tableData.length; i++) {
|
||||
if (this.tableData[i].productSkuId == item1.productSkuId) {
|
||||
this.tableData[i].supplierPrice = item1.supplierPrice / 100
|
||||
this.tableData[i].productUrl = item1.thumbUrl
|
||||
this.tableData[i].skcCode = item.extCode
|
||||
this.tableData[i].skuCode = item1.extCode
|
||||
break
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
if ((params.page * params.pageSize) < res.result.total) {
|
||||
params.page ++
|
||||
await this.getProductList(params)
|
||||
}
|
||||
}
|
||||
},
|
||||
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>
|
||||
|
||||
<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>
|
||||
301
src/view/sale/AfterSaleStat.vue
Normal file
301
src/view/sale/AfterSaleStat.vue
Normal file
@@ -0,0 +1,301 @@
|
||||
<template>
|
||||
<ai-list class="list" v-loading="isLoading" element-loading-text="拼命加载中" element-loading-spinner="el-icon-loading">
|
||||
<ai-title
|
||||
slot="title"
|
||||
title="售后统计"
|
||||
isShowBottomBorder>
|
||||
<template #rightBtn>
|
||||
<div class="title-right">
|
||||
<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>
|
||||
</div>
|
||||
</template>
|
||||
</ai-title>
|
||||
<template slot="content">
|
||||
<div class="content">
|
||||
<ai-search-bar>
|
||||
<template #left>
|
||||
<div class="search-item">
|
||||
<label>售后申请年份:</label>
|
||||
<el-date-picker
|
||||
v-model="reqData.afsApplyYear"
|
||||
type="year"
|
||||
value-format='yyyy'
|
||||
placeholder="选择年">
|
||||
</el-date-picker>
|
||||
</div>
|
||||
<div class="search-item">
|
||||
<label>扣罚倍数:</label>
|
||||
<el-select v-model="reqData.punishRatioList" multiple placeholder="请选择" size="small">
|
||||
<el-option
|
||||
v-for="item in punishRatioOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
</template>
|
||||
<template #right>
|
||||
<el-button type="primary" @click="beforeGetList">加载</el-button>
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-card title="数据明细" style="padding-bottom: 40px;">
|
||||
<template #right>
|
||||
<json-excel
|
||||
:data="tableData"
|
||||
:fields="jsonFields"
|
||||
name="售后统计列表.xls"
|
||||
worksheet="售后统计列表">
|
||||
<el-button type="primary" :disabled="tableData.length == 0">下载数据</el-button>
|
||||
</json-excel>
|
||||
</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="400px" :show-overflow-tooltip='true' label="商品名称" fixed="left">
|
||||
<template slot-scope="scope">
|
||||
<div>
|
||||
<el-image :src="scope.row.productUrl" style="width: 40px; height: 40px" class="image" :preview-src-list="[scope.row.productUrl]" />
|
||||
{{ 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, sendTemuSellerAgentMessage } from '@/api/chromeApi'
|
||||
import {timestampToTime} from '@/utils/date'
|
||||
import JsonExcel from 'vue-json-excel'
|
||||
|
||||
export default {
|
||||
name: 'AfterSaleStat',
|
||||
|
||||
data () {
|
||||
return {
|
||||
mallId: '',
|
||||
reqData: {
|
||||
pageNo: 1,
|
||||
pageSize: 100,
|
||||
afsApplyYear: '2024',
|
||||
punishRatioList: []
|
||||
},
|
||||
punishRatioOptions: [
|
||||
{label: '0', value: '0'},
|
||||
{label: '1', value: '1'},
|
||||
{label: '1.5', value: '1.5'},
|
||||
{label: '2.5', value: '2.5'},
|
||||
{label: '5', value: '5'},
|
||||
],
|
||||
colConfigs: [
|
||||
{ slot: 'productName', label: '商品名称', width: '400px', align: 'left', fixed: 'left' },
|
||||
{ prop: 'skcCode', label: 'SKC货号', align: 'left', height: '40px', fixed: 'left' },
|
||||
{ prop: 'productSkuId', label: 'SKU ID', align: 'left' },
|
||||
{ prop: 'skuCode', label: 'SKU货号', align: 'left' },
|
||||
{ prop: 'rawQualityScore', label: '品质分', align: 'left', sortable: true, 'sort-method': (a, b) => a.rawQualityScore - b.rawQualityScore },
|
||||
{ prop: 'punishRatio', label: '扣罚总倍数', align: 'left', sortable: true, 'sort-method': (a, b) => a.punishRatio - b.punishRatio },
|
||||
{ prop: 'times', label: '扣罚次数', align: 'left', sortable: true, 'sort-method': (a, b) => a.times - b.times },
|
||||
{ prop: 'supplierPrice', label: '供货价', align: 'left', sortable: true, 'sort-method': (a, b) => a.supplierPrice - b.supplierPrice },
|
||||
{ prop: 'deductionAmount', label: '预计扣款', align: 'left', sortable: true, 'sort-method': (a, b) => a.deductionAmount - b.deductionAmount },
|
||||
{ prop: 'cost', label: '成本', align: 'left', sortable: true, 'sort-method': (a, b) => a.cost - b.cost },
|
||||
{ prop: 'profitTimes', label: '相当于X件白卖', align: 'left', sortable: true, 'sort-method': (a, b) => a.profitTimes - b.profitTimes }
|
||||
],
|
||||
isLoading: false,
|
||||
tableData: [],
|
||||
jsonFields: {
|
||||
"商品名称": "productName",
|
||||
"图片URL": "productUrl",
|
||||
"SKC货号": "skcCode",
|
||||
"SKU ID": "productSkuId",
|
||||
"SKU货号": "skuCode",
|
||||
"品质分": "rawQualityScore",
|
||||
"扣罚总倍数": "punishRatio",
|
||||
"扣罚次数": "times",
|
||||
"供货价": "supplierPrice",
|
||||
"预计扣款": "deductionAmount",
|
||||
"成本": "cost",
|
||||
"相当于X件白卖": "profitTimes"
|
||||
},
|
||||
costList: []
|
||||
}
|
||||
},
|
||||
components: {
|
||||
JsonExcel
|
||||
},
|
||||
methods: {
|
||||
beforeGetList() {
|
||||
this.$userCheck(this.mallId).then(() => {
|
||||
this.toLoad()
|
||||
}).catch((err) => {
|
||||
this.mallId = ''
|
||||
})
|
||||
},
|
||||
async toLoad() {
|
||||
if (!this.mallId) {
|
||||
Message.error("请选择店铺")
|
||||
return
|
||||
}
|
||||
this.reqData.pageNo = 1
|
||||
this.tableData = []
|
||||
this.currentIndex = 0
|
||||
this.isLoading = true
|
||||
await this.getAfterSalesList('101')
|
||||
this.reqData.pageNo = 1
|
||||
await this.getAfterSalesList('202')
|
||||
this.reqData.pageNo = 1
|
||||
await this.getAfterSalesList('102')
|
||||
|
||||
let skuIds = []
|
||||
this.tableData.map(item => {
|
||||
skuIds.push(item.productSkuId)
|
||||
})
|
||||
this.reqData.pageNo = 1
|
||||
|
||||
await this.getProductList({page: this.reqData.pageNo,
|
||||
pageSize: this.reqData.pageSize,
|
||||
productSkuIds: skuIds})
|
||||
|
||||
this.costList = []
|
||||
await this.getSkuCostList()
|
||||
this.isLoading = false
|
||||
},
|
||||
async getAfterSalesList(zone) {
|
||||
this.reqData.bizDrType = zone
|
||||
let res = await sendTemuSellerAgentMessage({
|
||||
url: `mms/api/appalachian/afs/queryPageV2`,
|
||||
needMallId: true,
|
||||
mallId: this.mallId,
|
||||
data: this.reqData})
|
||||
if (res.errorCode == 1000000) {
|
||||
for (let i = 0; i < res.result.list.length; i++) {
|
||||
let item = res.result.list[i]
|
||||
let flag = false
|
||||
for (let j = 0; j < item.productSkuId.length; j++) {
|
||||
for ( let k = 0; k < this.tableData.length; k++) {
|
||||
if (item.productSkuId[j] == this.tableData[k].productSkuId) {
|
||||
flag = true
|
||||
this.tableData[k].times++
|
||||
this.tableData[k].punishRatio = this.tableData[k].punishRatio + new Number(item.punishRatio)
|
||||
break
|
||||
}
|
||||
}
|
||||
if (!flag) {
|
||||
this.tableData.push({
|
||||
productName: item.goodsName,
|
||||
productUrl: '',
|
||||
skcCode: '',
|
||||
productSkuId: item.productSkuId[j],
|
||||
punishRatio: new Number(item.punishRatio),
|
||||
rawQualityScore: item.rawQualityScore,
|
||||
skuCode: '',
|
||||
times: 1,
|
||||
cost: '',
|
||||
supplierPrice: '',
|
||||
deductionAmount: null,
|
||||
profitTimes: ''
|
||||
})
|
||||
flag = true
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((this.reqData.pageSize * this.reqData.pageNo) < res.result.total) {
|
||||
this.reqData.pageNo ++
|
||||
await this.getAfterSalesList(zone)
|
||||
}
|
||||
} else if (res.error_code == 40001) {
|
||||
this.isLoading = false
|
||||
this.$store.commit("setTemuAlertShow", true)
|
||||
}
|
||||
},
|
||||
async getProductList(params) {
|
||||
let res = await sendChromeAPIMessage({
|
||||
url: 'bg-visage-mms/product/skc/pageQuery',
|
||||
needMallId: true,
|
||||
mallId: this.mallId,
|
||||
data: {
|
||||
...params
|
||||
}})
|
||||
if (res.errorCode == 1000000) {
|
||||
res.result.pageItems.map((item) => {
|
||||
item.productSkuSummaries.map(item1 => {
|
||||
for (let i = 0; i < this.tableData.length; i++) {
|
||||
if (this.tableData[i].productSkuId == item1.productSkuId) {
|
||||
this.tableData[i].supplierPrice = item1.supplierPrice / 100
|
||||
this.tableData[i].deductionAmount = Math.round((item1.supplierPrice / 100 * this.tableData[i].punishRatio) * 100)/ 100
|
||||
this.tableData[i].productUrl = item1.thumbUrl
|
||||
this.tableData[i].skcCode = item.extCode
|
||||
this.tableData[i].skuCode = item1.extCode
|
||||
break
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
if ((params.page * params.pageSize) < res.result.total) {
|
||||
params.page ++
|
||||
await this.getProductList(params)
|
||||
}
|
||||
}
|
||||
},
|
||||
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>
|
||||
|
||||
<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>
|
||||
361
src/view/sale/CostManageTemu.vue
Normal file
361
src/view/sale/CostManageTemu.vue
Normal file
@@ -0,0 +1,361 @@
|
||||
<template>
|
||||
<ai-list class="list" v-loading="isLoading" element-loading-text="拼命加载中" element-loading-spinner="el-icon-loading">
|
||||
<ai-title
|
||||
slot="title"
|
||||
title="成本管理"
|
||||
isShowBottomBorder>
|
||||
<template #rightBtn>
|
||||
<div class="title-right">
|
||||
<div>
|
||||
<label style="width:90px">店铺:</label>
|
||||
<el-select v-model="mallId" @change="beforeGetList" 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 style="margin-bottom: 5px">
|
||||
<el-alert
|
||||
title="郑重承诺:由于业务逻辑需要,TEMU助手将会以最小范围内存储SKU成本信息,平台将会做好保密,不泄露、不出售任何数据。使用与成本管理以及利润计算等相关功能,将视为授权TEMU助手存储相关信息。"
|
||||
type="error"
|
||||
:closable="false">
|
||||
</el-alert>
|
||||
</div>
|
||||
<ai-search-bar>
|
||||
<template #left>
|
||||
<div class="search-item">
|
||||
<el-checkbox v-model="search.unSet">只显示未填写</el-checkbox>
|
||||
</div>
|
||||
<div class="search-item">
|
||||
<label>SKC ID:</label>
|
||||
<el-input size="small" clearable placeholder="请输入SKC ID" v-model="search.skc"></el-input>
|
||||
</div>
|
||||
<div class="search-item">
|
||||
<label>SKU ID:</label>
|
||||
<el-input size="small" clearable placeholder="请输入SKU ID" v-model="search.sku"></el-input>
|
||||
</div>
|
||||
<div class="search-item">
|
||||
<label>SKC货号:</label>
|
||||
<el-input size="small" clearable placeholder="请输入SKC货号" v-model="search.skcCode"></el-input>
|
||||
</div>
|
||||
</template>
|
||||
<template #right>
|
||||
<!--<el-button type="primary" @click="toLoad">加载</el-button>-->
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-card title="SKU明细" style="padding-bottom: 40px;">
|
||||
<template #right>
|
||||
<el-button type="primary" @click="exportToExcel">导出</el-button>
|
||||
<el-button type="primary" @click="toUpload">导入</el-button>
|
||||
</template>
|
||||
<ai-table
|
||||
:isShowPagination="false"
|
||||
:tableData="filteredData"
|
||||
:col-configs="colConfigs"
|
||||
height="600"
|
||||
style="margin-top: 8px;"
|
||||
@getList="() => {}">
|
||||
<el-table-column slot="costPrice" label="成本价格" :sortable="true" :sort-method="(a, b) => a.costPrice - b.costPrice">
|
||||
<template slot-scope="{ row }">
|
||||
<el-input
|
||||
v-if="row.edit"
|
||||
v-model="row.editValue"
|
||||
type="number"
|
||||
size="small"
|
||||
></el-input>
|
||||
<span v-else>{{ row.costPrice }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column slot="options" label="操作" width="80px" show-overflow-tooltip align="center" fixed="right">
|
||||
<template slot-scope="{ row }">
|
||||
<el-button
|
||||
v-if="!row.edit"
|
||||
size="small"
|
||||
icon="el-icon-edit"
|
||||
@click="row.edit = true"
|
||||
></el-button>
|
||||
<el-button
|
||||
v-if="row.edit"
|
||||
size="small"
|
||||
type="success"
|
||||
icon="el-icon-circle-check"
|
||||
@click="handleSave(row)"
|
||||
></el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
</ai-card>
|
||||
|
||||
<AiDialog
|
||||
title="成本导入"
|
||||
:visible.sync="costDlgShow"
|
||||
:close-on-click-modal="false"
|
||||
customFooter
|
||||
width="1290px">
|
||||
<el-form :model="costForm" ref="costForm" label-width="180px" class="form">
|
||||
<el-form-item label="上传excel" prop="file" :rules="[{ required: true, message: '请上传文件', trigger: 'blur' }]" style="width: 100%;">
|
||||
<ai-uploader isImport v-model="costForm.file" fileType="file" :limit="1"
|
||||
acceptType=".xlsx," :clearable="false">
|
||||
<template #trigger>
|
||||
<el-button icon="iconfont iconfangda">选择文件</el-button>
|
||||
</template>
|
||||
<template #tips>最多上传1个文件,单个文件最大10MB,仅支持Excel格式</template>
|
||||
</ai-uploader>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="costDlgShow = false">关 闭</el-button>
|
||||
<el-button type="primary" @click="importConfirm">确 定</el-button>
|
||||
</span>
|
||||
</AiDialog>
|
||||
</template>
|
||||
</ai-list>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {sendChromeAPIMessage} from '@/api/chromeApi'
|
||||
import {timestampToTime} from '@/utils/date'
|
||||
import { Message } from 'element-ui'
|
||||
import * as XLSX from 'xlsx'
|
||||
import { saveAs } from 'file-saver'
|
||||
|
||||
export default {
|
||||
name: 'CostManageTemu',
|
||||
|
||||
data () {
|
||||
return {
|
||||
isLoading: false,
|
||||
list: [],
|
||||
mallId: '',
|
||||
colConfigs: [
|
||||
{ prop: 'skc', label: 'SKC ID', align: 'left' },
|
||||
{ prop: 'skcCode', label: 'SKC货号', align: 'left' },
|
||||
{ prop: 'sku', label: 'SKU ID', align: 'left' },
|
||||
{ prop: 'skuCode', label: 'SKU货号', align: 'left' },
|
||||
{ prop: 'price', label: '申报价格', align: 'left', sortable: true, 'sort-method': (a, b) => a.price - b.price },
|
||||
{ slot: 'costPrice', label: '成本价格', align: 'left' },
|
||||
{ prop: 'profitPercent', label: '利润率(%)', align: 'left', sortable: true, 'sort-method': (a, b) => a.profitPercent - b.profitPercent }
|
||||
],
|
||||
search: {
|
||||
unSet: false,
|
||||
skc: '',
|
||||
sku: '',
|
||||
skcCode: ''
|
||||
},
|
||||
|
||||
tableData: [],
|
||||
currentPage: 1,
|
||||
|
||||
costList: [],
|
||||
|
||||
costDlgShow: false,
|
||||
costForm: {
|
||||
file: null
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
filteredData() {
|
||||
const filteredData = this.list.filter(item => {
|
||||
let flag1 = true, flag2 = true, flag3 = true, flag4 = true
|
||||
if (this.search.unSet) {
|
||||
if (item.costPrice) flag1 = false
|
||||
}
|
||||
if (this.search.skc) {
|
||||
if (!(item.skc == this.search.skc)) {
|
||||
flag2 = false
|
||||
}
|
||||
}
|
||||
if (this.search.sku) {
|
||||
if (!(item.sku == this.search.sku)) {
|
||||
flag3 = false
|
||||
}
|
||||
}
|
||||
if (this.search.skcCode) {
|
||||
if (!(item.skcCode == this.search.skcCode)) {
|
||||
flag5 = false
|
||||
}
|
||||
}
|
||||
|
||||
return flag1 && flag2 && flag3 && flag4
|
||||
})
|
||||
|
||||
return filteredData
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
beforeGetList() {
|
||||
this.list = []
|
||||
this.currentPage = 1
|
||||
this.costList = []
|
||||
if (!this.mallId) {
|
||||
Message.error("请先选择店铺")
|
||||
return
|
||||
}
|
||||
|
||||
this.$userCheck(this.mallId).then(() => {
|
||||
this.isLoading = true
|
||||
this.getList()
|
||||
}).catch((err) => {
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
async getList () {
|
||||
let res = await sendChromeAPIMessage({
|
||||
url: `bg-visage-mms/product/skc/pageQuery`,
|
||||
needMallId: true,
|
||||
mallId: this.mallId,
|
||||
data: {
|
||||
page: this.currentPage,
|
||||
pageSize: 100
|
||||
}})
|
||||
if (res.errorCode == 1000000) {
|
||||
for(let i = 0;i < res.result.pageItems.length; i++) {
|
||||
let item = res.result.pageItems[i];
|
||||
let data = {skc: item.productSkcId,
|
||||
skcCode: item.extCode
|
||||
}
|
||||
|
||||
for (let j = 0; j < item.productSkuSummaries.length; j++) {
|
||||
let sku = item.productSkuSummaries[j]
|
||||
data = {...data, sku: sku.productSkuId,
|
||||
skuAttr: null,
|
||||
skuCode: sku.extCode,
|
||||
price: sku.supplierPrice / 100,
|
||||
costPrice: '',
|
||||
profitPercent: null,
|
||||
edit: false,
|
||||
editValue: null
|
||||
}
|
||||
|
||||
this.list.push(data)
|
||||
}
|
||||
}
|
||||
if (res.result.pageItems.length == 100 && (res.result.total > 100*this.currentPage)) {
|
||||
this.currentPage++
|
||||
await this.sleepSync(200)
|
||||
await this.getList()
|
||||
} else {
|
||||
this.getSkuCostList()
|
||||
}
|
||||
}
|
||||
},
|
||||
sleepSync(milliseconds) {
|
||||
return new Promise(resolve => setTimeout(resolve, milliseconds));
|
||||
},
|
||||
getSkuCostList() {
|
||||
this.$http.post(`/api/skuCost/listAll`, null, {
|
||||
params: {
|
||||
mallId: this.mallId
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.costList = res.data
|
||||
for (let i = 0; i < this.costList.length; i++) {
|
||||
for (let j = 0; j < this.list.length; j++) {
|
||||
if (this.costList[i].sku == this.list[j].sku) {
|
||||
this.list[j].costPrice = this.costList[i].costPrice
|
||||
this.list[j].editValue = this.costList[i].costPrice
|
||||
this.list[j].profitPercent = Math.round((this.list[j].price - this.list[j].costPrice) / this.list[j].price * 10000) /100
|
||||
}
|
||||
}
|
||||
}
|
||||
this.isLoading = false
|
||||
} else {
|
||||
this.isLoading = false
|
||||
}
|
||||
})
|
||||
},
|
||||
handleSave(row) {
|
||||
this.$http.post(`/api/skuCost/addOrUpdate`, [{
|
||||
mallId: this.mallId,
|
||||
costPrice: row.editValue,
|
||||
skc: row.skc,
|
||||
sku: row.sku
|
||||
}]).then((res) => {
|
||||
if (res.code == 0) {
|
||||
row.edit = false
|
||||
row.costPrice = row.editValue
|
||||
row.profitPercent = Math.round((row.price - row.costPrice) / row.price * 10000) / 100
|
||||
Message.success("修改成功")
|
||||
}
|
||||
})
|
||||
},
|
||||
toUpload() {
|
||||
this.costDlgShow = true
|
||||
},
|
||||
importConfirm() {
|
||||
this.$refs.costForm.validate((valid) => {
|
||||
const data = new FormData()
|
||||
data.append('file', this.costForm.file[0].raw);
|
||||
this.$http.post(`/api/skuCost/importStock`, data).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.costDlgShow = false
|
||||
this.$message.success('导入成功')
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
exportToExcel() {
|
||||
// 假设你有一个表格数据的数组
|
||||
const data = [
|
||||
["店铺ID", "SKC ID", "SKC货号", "SKU ID", "属性集", "SKU货号", "申报价格", "成本价格"]
|
||||
]
|
||||
|
||||
this.filteredData.map(item => {
|
||||
data.push([this.mallId, item.skc, item.skcCode, item.sku, item.skuAttr, item.skuCode, item.price, item.costPrice])
|
||||
})
|
||||
|
||||
// 将数据转换为工作表
|
||||
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, 'SKU列表.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>
|
||||
@@ -68,12 +68,12 @@
|
||||
<template slot="content" v-if="type === '0'">
|
||||
<div class="top">
|
||||
<div class="item">
|
||||
<h2>今日销量</h2>
|
||||
<p>{{ todayTotal }}</p>
|
||||
<h2>今日销量/销售额</h2>
|
||||
<p>{{ todayTotal }}/{{ todayMoney }}</p>
|
||||
</div>
|
||||
<div class="item">
|
||||
<h2>今日销售额</h2>
|
||||
<p>{{ todayMoney }}</p>
|
||||
<h2>今日利润/利润率</h2>
|
||||
<p>{{ profitMoney }}/{{ profitPercent }}</p>
|
||||
</div>
|
||||
<div class="item">
|
||||
<h2>可用库存总量(件)</h2>
|
||||
@@ -103,17 +103,12 @@
|
||||
</el-tooltip></span></h2>
|
||||
<p>{{ inroadTotalMoney }}</p>
|
||||
</div>
|
||||
<div class="item">
|
||||
<h2>已收货总量(件)</h2>
|
||||
<p>{{ deliveryTotal }}</p>
|
||||
</div>
|
||||
<div class="item">
|
||||
<h2>已收货总货值</h2>
|
||||
<p>{{ deliveryMoney }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<ai-card title="数据明细" style="padding-bottom: 40px;">
|
||||
<template #right>
|
||||
<div class="search-item" style="width: 160px;">
|
||||
<el-checkbox v-model="showTodaySale">只显示今日有销量</el-checkbox>
|
||||
</div>
|
||||
<json-excel
|
||||
:data="list"
|
||||
v-if="type === '0'"
|
||||
@@ -137,10 +132,10 @@
|
||||
<ai-table
|
||||
ref="table0"
|
||||
:isShowPagination="false"
|
||||
:tableData="list"
|
||||
:tableData="filteredData"
|
||||
height="500"
|
||||
:col-configs="colConfigs"
|
||||
:total="list.length"
|
||||
:total="filteredData.length"
|
||||
style="margin-top: 8px;"
|
||||
@getList="() => {}">
|
||||
</ai-table>
|
||||
@@ -224,13 +219,13 @@ import { Message } from 'element-ui'
|
||||
currentPage: 1,
|
||||
todayTotal: 0,
|
||||
todayMoney: 0.0,
|
||||
profitMoney: 0.0,
|
||||
profitPercent: 0,
|
||||
inventoryTotal: 0,
|
||||
inventoryMoney: 0.0,
|
||||
inroadTotal: 0,
|
||||
inroadTotalMoney: 0.0,
|
||||
deliveryTotal: 0,
|
||||
deliveryMoney: 0.0,
|
||||
allProductList: [],
|
||||
costList: [],
|
||||
startDate: '',
|
||||
endDate: '',
|
||||
skuIds: [],
|
||||
@@ -264,6 +259,9 @@ import { Message } from 'element-ui'
|
||||
"用户累计加购数量": "inCardNumber",
|
||||
"已订阅待提醒到货": "nomsgSubsCntCntSth",
|
||||
"销售数据 - 今日": "todaySaleVolume",
|
||||
"销售数据 - 今日销售额": "saleMoney",
|
||||
"销售数据 - 利润": "profitMoney",
|
||||
"销售数据 - 利润率": "profitPercent",
|
||||
"销售数据 - 近7日": "lastSevenDaysSaleVolume",
|
||||
"销售数据 - 近30天": "lastThirtyDaysSaleVolume",
|
||||
"库存数据 - 仓内可用库存": "inventoryNumInfo.warehouseInventoryNum",
|
||||
@@ -296,11 +294,22 @@ import { Message } from 'element-ui'
|
||||
skuDownloadForm: {
|
||||
date: ''
|
||||
},
|
||||
showTodaySale: false
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapState(['mallList']),
|
||||
filteredData() {
|
||||
const filteredData = this.list.filter(item => {
|
||||
if (this.showTodaySale) {
|
||||
return item.todaySaleVolume > 0
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
return filteredData
|
||||
},
|
||||
colConfigs () {
|
||||
return [
|
||||
{
|
||||
@@ -362,6 +371,38 @@ import { Message } from 'element-ui'
|
||||
width: '120px',
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
prop: 'todaySaleVolume',
|
||||
label: '今日销量',
|
||||
width: '120px',
|
||||
align: 'center',
|
||||
sortable: true,
|
||||
'sort-method': (a, b) => {
|
||||
return a.todaySaleVolume - b.todaySaleVolume
|
||||
}
|
||||
},
|
||||
{
|
||||
prop: 'saleMoney',
|
||||
label: '销售额',
|
||||
width: '120px',
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
prop: 'profitMoney',
|
||||
label: '利润',
|
||||
width: '120px',
|
||||
align: 'center',
|
||||
sortable: true,
|
||||
'sort-method': (a, b) => {
|
||||
return a.profitMoney - b.profitMoney
|
||||
}
|
||||
},
|
||||
{
|
||||
prop: 'profitPercent',
|
||||
label: '利润率(%)',
|
||||
width: '120px',
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
prop: 'onSalesDurationOffline',
|
||||
label: '加入站点时长',
|
||||
@@ -388,7 +429,6 @@ import { Message } from 'element-ui'
|
||||
label: '仓内可用库存',
|
||||
width: '160px',
|
||||
align: 'center',
|
||||
fixed: "right",
|
||||
sortable: true,
|
||||
'sort-method': (a, b) => {
|
||||
return a.warehouseInventoryNum - b.warehouseInventoryNum
|
||||
@@ -550,6 +590,13 @@ import { Message } from 'element-ui'
|
||||
align: 'center',
|
||||
fixed: 'left'
|
||||
},
|
||||
{
|
||||
prop: 'supplierPrice',
|
||||
label: '申报价格',
|
||||
width: '120px',
|
||||
align: 'center',
|
||||
fixed: 'left'
|
||||
},
|
||||
{
|
||||
prop: 'productSkuId',
|
||||
label: 'SKU ID',
|
||||
@@ -599,6 +646,7 @@ import { Message } from 'element-ui'
|
||||
"SKC货号": "skcExtCode",
|
||||
"SKU ID": "productSkuId",
|
||||
"SKU货号": "skuExtCode",
|
||||
"申报价格": "supplierPrice",
|
||||
"图片链接": "productSkcPicture"
|
||||
}
|
||||
|
||||
@@ -637,15 +685,13 @@ import { Message } from 'element-ui'
|
||||
this.currentPage = 1
|
||||
this.todayMoney = 0.0
|
||||
this.todayTotal = 0
|
||||
this.profitMoney = 0.0
|
||||
this.profitPercent = 0
|
||||
this.inventoryMoney = 0.0
|
||||
this.inventoryTotal = 0
|
||||
this.inroadTotalMoney = 0.0
|
||||
this.inroadTotal = 0
|
||||
this.deliveryTotal = 0
|
||||
this.deliveryMoney = 0.0
|
||||
this.allProductList = []
|
||||
if (!this.mallId) {
|
||||
|
||||
Message.error("请先选择店铺")
|
||||
return
|
||||
}
|
||||
@@ -657,33 +703,27 @@ import { Message } from 'element-ui'
|
||||
this.isLoading = true
|
||||
this.$userCheck(this.mallId).then(() => {
|
||||
this.last30DaySkcList = []
|
||||
this.getAllProductList()
|
||||
this.getSkuCostList()
|
||||
this.getList()
|
||||
}).catch((err) => {
|
||||
console.log(err)
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
getAllProductList() {
|
||||
this.$http.post('/api/deliveryOrder/totalDelivery',null, {
|
||||
params: {mallId: this.mallId}
|
||||
}).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.deliveryTotal = res.data
|
||||
getSkuCostList() {
|
||||
this.$http.post(`/api/skuCost/listAll`, null, {
|
||||
params: {
|
||||
mallId: this.mallId
|
||||
}
|
||||
})
|
||||
|
||||
this.$http.post('/api/deliveryOrder/getAllProductList', null, {
|
||||
params: {mallId: this.mallId}
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.allProductList = res.data
|
||||
this.costList = res.data
|
||||
}
|
||||
})
|
||||
},
|
||||
getList () {
|
||||
sendChromeAPIMessage({
|
||||
url: 'marvel-mms/cn/api/kiana/venom/sales/management/list',
|
||||
url: 'marvel-mms/cn/api/kiana/venom/sales/management/listWarehouse',
|
||||
needMallId: true,
|
||||
mallId: this.mallId,
|
||||
data: {
|
||||
@@ -724,32 +764,30 @@ import { Message } from 'element-ui'
|
||||
|
||||
|
||||
for(let j = 0;j < item.skuQuantityDetailList.length; j++) {
|
||||
let costPrice = this.getCostPrice(item.skuQuantityDetailList[j].productSkuId)
|
||||
let saleMoney = Math.round(item.skuQuantityDetailList[j].todaySaleVolume * item.skuQuantityDetailList[j].supplierPrice) /100
|
||||
let profitMoney = Math.round(item.skuQuantityDetailList[j].todaySaleVolume * (item.skuQuantityDetailList[j].supplierPrice / 100 - costPrice) * 100) /100
|
||||
let profitPercent = Math.round(profitMoney / saleMoney * 10000) /100
|
||||
data = {...data, ...item.skuQuantityDetailList[j],
|
||||
saleMoney: saleMoney,
|
||||
profitMoney: profitMoney,
|
||||
profitPercent: profitPercent,
|
||||
productTotalPrice: ((item.skuQuantityDetailList[j].supplierPrice / 100) * item.skuQuantityDetailList[j].inventoryNumInfo.warehouseInventoryNum).toFixed(2),
|
||||
inroadTotalPrice: ((item.skuQuantityDetailList[j].supplierPrice / 100) * (item.skuQuantityDetailList[j].inventoryNumInfo.waitOnShelfNum + item.skuQuantityDetailList[j].inventoryNumInfo.waitReceiveNum)).toFixed(2),
|
||||
warehouseInventoryNum: item.skuQuantityDetailList[j].inventoryNumInfo.warehouseInventoryNum}
|
||||
|
||||
this.todayTotal += item.skuQuantityDetailList[j].todaySaleVolume
|
||||
this.todayMoney += new Number(((item.skuQuantityDetailList[j].supplierPrice / 100) * item.skuQuantityDetailList[j].todaySaleVolume).toFixed(2))
|
||||
this.todayMoney = new Number(this.todayMoney.toFixed(2))
|
||||
this.inventoryTotal += item.skuQuantityDetailList[j].inventoryNumInfo.warehouseInventoryNum
|
||||
this.inventoryMoney += new Number(((item.skuQuantityDetailList[j].supplierPrice / 100) * item.skuQuantityDetailList[j].inventoryNumInfo.warehouseInventoryNum).toFixed(2))
|
||||
this.inventoryMoney = new Number(this.inventoryMoney.toFixed(2))
|
||||
this.inroadTotal += (item.skuQuantityDetailList[j].inventoryNumInfo.waitOnShelfNum + item.skuQuantityDetailList[j].inventoryNumInfo.waitReceiveNum)
|
||||
this.inroadTotalMoney += new Number(((item.skuQuantityDetailList[j].supplierPrice / 100) * (item.skuQuantityDetailList[j].inventoryNumInfo.waitOnShelfNum + item.skuQuantityDetailList[j].inventoryNumInfo.waitReceiveNum)).toFixed(2))
|
||||
this.inroadTotalMoney = new Number(this.inroadTotalMoney.toFixed(2))
|
||||
this.adviceProduceNum = item.skuQuantityDetailList[j].adviceProduceNum || '-'
|
||||
this.availableProduceNum = item.skuQuantityDetailList[j].availableProduceNum || '-'
|
||||
this.list.push(data);
|
||||
|
||||
// 计算已发货货值
|
||||
for(let k = 0; k < this.allProductList.length; k++) {
|
||||
if (this.allProductList[k].product_sku_id == data.productSkuId) {
|
||||
this.deliveryMoney += (item.skuQuantityDetailList[j].supplierPrice / 100) * this.allProductList[k].product_sku_number
|
||||
this.deliveryMoney = new Number(this.deliveryMoney.toFixed(2))
|
||||
}
|
||||
}
|
||||
|
||||
this.todayTotal += item.skuQuantityDetailList[j].todaySaleVolume
|
||||
this.profitMoney += item.skuQuantityDetailList[j].todaySaleVolume * (item.skuQuantityDetailList[j].supplierPrice / 100 - costPrice)
|
||||
this.todayMoney += (item.skuQuantityDetailList[j].supplierPrice / 100) * item.skuQuantityDetailList[j].todaySaleVolume
|
||||
this.inventoryTotal += item.skuQuantityDetailList[j].inventoryNumInfo.warehouseInventoryNum
|
||||
this.inventoryMoney += (item.skuQuantityDetailList[j].supplierPrice / 100) * item.skuQuantityDetailList[j].inventoryNumInfo.warehouseInventoryNum
|
||||
this.inroadTotal += (item.skuQuantityDetailList[j].inventoryNumInfo.waitOnShelfNum + item.skuQuantityDetailList[j].inventoryNumInfo.waitReceiveNum)
|
||||
this.inroadTotalMoney += (item.skuQuantityDetailList[j].supplierPrice / 100) * (item.skuQuantityDetailList[j].inventoryNumInfo.waitOnShelfNum + item.skuQuantityDetailList[j].inventoryNumInfo.waitReceiveNum)
|
||||
this.adviceProduceNum = item.skuQuantityDetailList[j].adviceProduceNum || '-'
|
||||
this.availableProduceNum = item.skuQuantityDetailList[j].availableProduceNum || '-'
|
||||
this.list.push(data);
|
||||
}
|
||||
|
||||
}
|
||||
if (this.pageSize == res.result.subOrderList.length) {
|
||||
this.currentPage ++
|
||||
@@ -757,6 +795,12 @@ import { Message } from 'element-ui'
|
||||
this.getList()
|
||||
}, 1500)
|
||||
} else {
|
||||
this.profitMoney = Math.round(this.profitMoney * 100) / 100
|
||||
this.todayMoney = Math.round(this.todayMoney * 100) / 100
|
||||
this.profitPercent = Math.round((this.profitMoney / this.todayMoney) * 10000) /100 + '%'
|
||||
this.inventoryMoney = Math.round(this.inventoryMoney * 100) / 100
|
||||
this.inroadTotalMoney = Math.round(this.inroadTotalMoney * 100) / 100
|
||||
|
||||
this.isLoading = false
|
||||
Message.success('销售数据加载完成,可进行导出')
|
||||
|
||||
@@ -782,7 +826,8 @@ import { Message } from 'element-ui'
|
||||
productSkuId: item.productSkuId,
|
||||
skuExtCode: item.skuExtCode,
|
||||
skcExtCode: item.skcExtCode,
|
||||
productSkcPicture: item.productSkcPicture
|
||||
productSkcPicture: item.productSkcPicture,
|
||||
supplierPrice: this.getSupplierPrice(item.productSkuId)
|
||||
}
|
||||
let date = new Date()
|
||||
date.setDate(date.getDate() - 31)
|
||||
@@ -888,7 +933,8 @@ import { Message } from 'element-ui'
|
||||
temp = {
|
||||
'SKC': 'skc',
|
||||
'SKU': 'sku',
|
||||
'SKU货号': 'skuExtCode'
|
||||
'SKU货号': 'skuExtCode',
|
||||
'申报价格': 'supplierPrice'
|
||||
}
|
||||
let beginTime = new Date(this.skuDownloadForm.date[0])
|
||||
let endTime = new Date(this.skuDownloadForm.date[1])
|
||||
@@ -914,7 +960,8 @@ import { Message } from 'element-ui'
|
||||
let temp = {
|
||||
sku: item.productSkuId,
|
||||
skc: item.productSkcId,
|
||||
skuExtCode: item.skuExtCode
|
||||
skuExtCode: item.skuExtCode,
|
||||
supplierPrice: this.getSupplierPrice(item.productSkuId)
|
||||
}
|
||||
beginTime = new Date(this.skuDownloadForm.date[0])
|
||||
endTime = new Date(this.skuDownloadForm.date[1])
|
||||
@@ -966,6 +1013,22 @@ import { Message } from 'element-ui'
|
||||
reqSkusIds = []
|
||||
}
|
||||
}
|
||||
},
|
||||
getSupplierPrice(productSkuId) {
|
||||
for (let i = 0; i < this.list.length; i++) {
|
||||
if (this.list[i].productSkuId == productSkuId) {
|
||||
return this.list[i].supplierPrice / 100
|
||||
}
|
||||
}
|
||||
return 0
|
||||
},
|
||||
getCostPrice(productSkuId) {
|
||||
for (let i = 0; i < this.costList.length; i++) {
|
||||
if (this.costList[i].sku == productSkuId) {
|
||||
return this.costList[i].costPrice
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
156
src/view/shein/CertCenterShein.vue
Normal file
156
src/view/shein/CertCenterShein.vue
Normal file
@@ -0,0 +1,156 @@
|
||||
<template>
|
||||
<ai-list class="list" v-loading="isLoading" element-loading-text="拼命加载中" element-loading-spinner="el-icon-loading">
|
||||
<ai-title
|
||||
slot="title"
|
||||
title="证书中心"
|
||||
isShowBottomBorder>
|
||||
</ai-title>
|
||||
<template slot="content">
|
||||
<ai-card title="待补充证书列表" style="padding-bottom: 40px;">
|
||||
<template #right>
|
||||
<el-button type="primary" @click="exportToExcel">导出</el-button>
|
||||
</template>
|
||||
<ai-table
|
||||
:isShowPagination="false"
|
||||
:tableData="list"
|
||||
:col-configs="colConfigs"
|
||||
height="600"
|
||||
style="margin-top: 8px;"
|
||||
@getList="() => {}">
|
||||
</ai-table>
|
||||
</ai-card>
|
||||
</template>
|
||||
</ai-list>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {sendGeiwohuoAPIMessage} from '@/api/chromeApi'
|
||||
import {timestampToTime} from '@/utils/date'
|
||||
import { Message } from 'element-ui'
|
||||
import * as XLSX from 'xlsx'
|
||||
import { saveAs } from 'file-saver'
|
||||
|
||||
export default {
|
||||
name: 'CertCenterShein',
|
||||
|
||||
data () {
|
||||
return {
|
||||
isLoading: false,
|
||||
list: [],
|
||||
mallId: '',
|
||||
colConfigs: [
|
||||
{ prop: 'spu', label: 'SPU', align: 'left' },
|
||||
{ prop: 'productName', label: '商品标题', align: 'left' },
|
||||
{ prop: 'skc', label: 'SKC ID', align: 'left' },
|
||||
{ prop: 'mainAttrName', label: '主规格', align: 'left' },
|
||||
{ prop: 'certificateTypeName', label: '证书类型', align: 'left' },
|
||||
{ prop: 'mergeSiteName', label: '管控地区', align: 'left' },
|
||||
{ prop: 'subSite', label: '管控子站点', align: 'left' },
|
||||
{ slot: 'uploadEndTime', label: '上传截止时间', align: 'left' }
|
||||
],
|
||||
|
||||
tableData: [],
|
||||
currentPage: 1,
|
||||
}
|
||||
},
|
||||
|
||||
mounted () {
|
||||
this.isLoading = true
|
||||
this.getList()
|
||||
},
|
||||
|
||||
methods: {
|
||||
async getList () {
|
||||
let res = await sendGeiwohuoAPIMessage({
|
||||
url: `spmp-api-prefix/spmp/certificate/get_skc_certificate_miss_list?page_num=${this.currentPage}&page_size=200`,
|
||||
method: 'POST',
|
||||
data: {}})
|
||||
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 = {spu: item.spu_name,
|
||||
productName: item.skc_name_cn,
|
||||
skc: item.skc_name,
|
||||
mainAttrName: item.main_attribute_name,
|
||||
uploadEndTime: item.upload_end_time,
|
||||
mergeSiteName: mainSite.join(','),
|
||||
certificateTypeName: item.certificate_type_name,
|
||||
subSite: subSite.join(',')
|
||||
}
|
||||
|
||||
this.list.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
|
||||
}
|
||||
} else if (res.code == 100004 || res.code == 20302) {
|
||||
this.isLoading = false
|
||||
this.$store.commit("setSheinAlertShow", true)
|
||||
}
|
||||
},
|
||||
sleepSync(milliseconds) {
|
||||
return new Promise(resolve => setTimeout(resolve, milliseconds));
|
||||
},
|
||||
exportToExcel() {
|
||||
// 假设你有一个表格数据的数组
|
||||
const data = [
|
||||
["SPU", "商品标题", "SKC ID", "主规格", "证书类型", "管控地区", "管控子站点", "上传截止时间"]
|
||||
]
|
||||
|
||||
this.list.map(item => {
|
||||
data.push([item.spu, item.productName, item.skc, item.mainAttrName, item.certificateTypeName, item.mergeSiteName, item.subSite, item.uploadEndTime])
|
||||
})
|
||||
|
||||
// 将数据转换为工作表
|
||||
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>
|
||||
@@ -51,11 +51,11 @@
|
||||
label="商品列表"
|
||||
value="0">
|
||||
</el-option>
|
||||
<el-option
|
||||
<!--<el-option
|
||||
key="1"
|
||||
label="草稿箱列表"
|
||||
value="1">
|
||||
</el-option>
|
||||
</el-option>-->
|
||||
</el-select>
|
||||
</div>
|
||||
<div class="search-item">
|
||||
@@ -256,6 +256,9 @@ import { Message } from 'element-ui'
|
||||
createTime: item.create_time
|
||||
};
|
||||
})
|
||||
} else if (res.code == 100004 || res.code == 20302) {
|
||||
this.isLoading = false
|
||||
this.$store.commit("setSheinAlertShow", true)
|
||||
}
|
||||
},
|
||||
productHandleSelectionChange(val) {
|
||||
354
src/view/shein/CostManageShein.vue
Normal file
354
src/view/shein/CostManageShein.vue
Normal file
@@ -0,0 +1,354 @@
|
||||
<template>
|
||||
<ai-list class="list" v-loading="isLoading" element-loading-text="拼命加载中" element-loading-spinner="el-icon-loading">
|
||||
<ai-title
|
||||
slot="title"
|
||||
title="成本管理"
|
||||
isShowBottomBorder>
|
||||
</ai-title>
|
||||
<template slot="content">
|
||||
<div style="margin-bottom: 5px">
|
||||
<el-alert
|
||||
title="郑重承诺:由于业务逻辑需要,TEMU助手将会以最小范围内存储SKU成本信息,平台将会做好保密,不泄露、不出售任何数据。使用与成本管理以及利润计算等相关功能,将视为授权TEMU助手存储相关信息。"
|
||||
type="error"
|
||||
:closable="false">
|
||||
</el-alert>
|
||||
</div>
|
||||
<ai-search-bar>
|
||||
<template #left>
|
||||
<div class="search-item">
|
||||
<el-checkbox v-model="search.unSet">只显示未填写</el-checkbox>
|
||||
</div>
|
||||
<div class="search-item">
|
||||
<label>SKC ID:</label>
|
||||
<el-input size="small" clearable placeholder="请输入SKC ID" v-model="search.skc"></el-input>
|
||||
</div>
|
||||
<div class="search-item">
|
||||
<label>SKU ID:</label>
|
||||
<el-input size="small" clearable placeholder="请输入SKU ID" v-model="search.sku"></el-input>
|
||||
</div>
|
||||
<div class="search-item">
|
||||
<label>SKC货号:</label>
|
||||
<el-input size="small" clearable placeholder="请输入SKC货号" v-model="search.skcCode"></el-input>
|
||||
</div>
|
||||
</template>
|
||||
<template #right>
|
||||
<!--<el-button type="primary" @click="toLoad">加载</el-button>-->
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-card title="SKU明细" style="padding-bottom: 40px;">
|
||||
<template #right>
|
||||
<el-button type="primary" @click="exportToExcel">导出</el-button>
|
||||
<el-button type="primary" @click="toUpload">导入</el-button>
|
||||
</template>
|
||||
<ai-table
|
||||
:isShowPagination="false"
|
||||
:tableData="filteredData"
|
||||
:col-configs="colConfigs"
|
||||
height="600"
|
||||
style="margin-top: 8px;"
|
||||
@getList="() => {}">
|
||||
<el-table-column slot="costPrice" label="成本价格" :sortable="true" :sort-method="(a, b) => a.costPrice - b.costPrice">
|
||||
<template slot-scope="{ row }">
|
||||
<el-input
|
||||
v-if="row.edit"
|
||||
v-model="row.editValue"
|
||||
type="number"
|
||||
size="small"
|
||||
></el-input>
|
||||
<span v-else>{{ row.costPrice }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column slot="options" label="操作" width="80px" show-overflow-tooltip align="center" fixed="right">
|
||||
<template slot-scope="{ row }">
|
||||
<el-button
|
||||
v-if="!row.edit"
|
||||
size="small"
|
||||
icon="el-icon-edit"
|
||||
@click="row.edit = true"
|
||||
></el-button>
|
||||
<el-button
|
||||
v-if="row.edit"
|
||||
size="small"
|
||||
type="success"
|
||||
icon="el-icon-circle-check"
|
||||
@click="handleSave(row)"
|
||||
></el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
</ai-card>
|
||||
|
||||
<AiDialog
|
||||
title="成本导入"
|
||||
:visible.sync="costDlgShow"
|
||||
:close-on-click-modal="false"
|
||||
customFooter
|
||||
width="1290px">
|
||||
<el-form :model="costForm" ref="costForm" label-width="180px" class="form">
|
||||
<el-form-item label="上传excel" prop="file" :rules="[{ required: true, message: '请上传文件', trigger: 'blur' }]" style="width: 100%;">
|
||||
<ai-uploader isImport v-model="costForm.file" fileType="file" :limit="1"
|
||||
acceptType=".xlsx," :clearable="false">
|
||||
<template #trigger>
|
||||
<el-button icon="iconfont iconfangda">选择文件</el-button>
|
||||
</template>
|
||||
<template #tips>最多上传1个文件,单个文件最大10MB,仅支持Excel格式</template>
|
||||
</ai-uploader>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="costDlgShow = false">关 闭</el-button>
|
||||
<el-button type="primary" @click="importConfirm">确 定</el-button>
|
||||
</span>
|
||||
</AiDialog>
|
||||
</template>
|
||||
</ai-list>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {sendGeiwohuoAPIMessage} from '@/api/chromeApi'
|
||||
import {timestampToTime} from '@/utils/date'
|
||||
import { Message } from 'element-ui'
|
||||
import * as XLSX from 'xlsx'
|
||||
import { saveAs } from 'file-saver'
|
||||
|
||||
export default {
|
||||
name: 'CostManageShein',
|
||||
|
||||
data () {
|
||||
return {
|
||||
isLoading: false,
|
||||
list: [],
|
||||
mallId: '',
|
||||
colConfigs: [
|
||||
{ prop: 'skc', label: 'SKC ID', align: 'left' },
|
||||
{ prop: 'skcCode', label: 'SKC货号', align: 'left' },
|
||||
{ prop: 'sku', label: 'SKU ID', align: 'left' },
|
||||
{ prop: 'skuAttr', label: '属性集', align: 'left' },
|
||||
{ prop: 'skuCode', label: 'SKU货号', align: 'left' },
|
||||
{ prop: 'price', label: '申报价格', align: 'left', sortable: true, 'sort-method': (a, b) => a.price - b.price },
|
||||
{ slot: 'costPrice', label: '成本价格', align: 'left' },
|
||||
{ prop: 'profitPercent', label: '利润率(%)', align: 'left', sortable: true, 'sort-method': (a, b) => a.profitPercent - b.profitPercent }
|
||||
],
|
||||
search: {
|
||||
unSet: false,
|
||||
skc: '',
|
||||
sku: '',
|
||||
skcCode: ''
|
||||
},
|
||||
|
||||
tableData: [],
|
||||
currentPage: 1,
|
||||
|
||||
costList: [],
|
||||
|
||||
costDlgShow: false,
|
||||
costForm: {
|
||||
file: null
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
filteredData() {
|
||||
const filteredData = this.list.filter(item => {
|
||||
let flag1 = true, flag2 = true, flag3 = true, flag4 = true
|
||||
if (this.search.unSet) {
|
||||
if (item.costPrice) flag1 = false
|
||||
}
|
||||
if (this.search.skc) {
|
||||
if (!item.skc.toLowerCase().includes(this.search.skc.toLowerCase())) {
|
||||
flag2 = false
|
||||
}
|
||||
}
|
||||
if (this.search.sku) {
|
||||
if (!item.sku.toLowerCase().includes(this.search.sku.toLowerCase())) {
|
||||
flag3 = false
|
||||
}
|
||||
}
|
||||
if (this.search.skcCode) {
|
||||
if (!item.skcCode.toLowerCase().includes(this.search.skcCode.toLowerCase())) {
|
||||
flag4 = false
|
||||
}
|
||||
}
|
||||
|
||||
return flag1 && flag2 && flag3 && flag4
|
||||
})
|
||||
|
||||
return filteredData
|
||||
}
|
||||
},
|
||||
|
||||
mounted () {
|
||||
this.getUserInfo()
|
||||
this.isLoading = true
|
||||
this.getList()
|
||||
},
|
||||
|
||||
methods: {
|
||||
async getUserInfo() {
|
||||
let res = await sendGeiwohuoAPIMessage({
|
||||
url: 'sso-prefix/auth/getUser?uuid=' + Date.now(),
|
||||
method: 'GET'
|
||||
})
|
||||
if (res.code == '0' && res.msg == "OK") {
|
||||
this.mallId = res.info.merchantCode
|
||||
} else if (res.code == 100004 || res.code == 20302) {
|
||||
this.isLoading = false
|
||||
this.$store.commit("setSheinAlertShow", true)
|
||||
}
|
||||
},
|
||||
async getList () {
|
||||
let res = await sendGeiwohuoAPIMessage({
|
||||
url: `idms/goods-skc/list`,
|
||||
method: 'POST',
|
||||
data: {
|
||||
pageNumber: this.currentPage,
|
||||
pageSize: 100,
|
||||
sortBy7dSaleCnt: 2
|
||||
}})
|
||||
if (res.code == '0') {
|
||||
for(let i = 0;i < res.info.list.length; i++) {
|
||||
let item = res.info.list[i];
|
||||
let data = {skc: item.skc,
|
||||
skcCode: item.supplierCode
|
||||
}
|
||||
|
||||
for (let j = 0; j < item.skuList.length; j++) {
|
||||
let sku = item.skuList[j]
|
||||
if (sku.attr == '合计') continue
|
||||
data = {...data, sku: sku.skuCode,
|
||||
skuAttr: sku.attr,
|
||||
skuCode: sku.supplierSku,
|
||||
price: sku.price,
|
||||
costPrice: '',
|
||||
profitPercent: null,
|
||||
edit: false,
|
||||
editValue: null
|
||||
}
|
||||
|
||||
this.list.push(data)
|
||||
}
|
||||
}
|
||||
if (res.info.list.length == 100 && (res.info.count > 100*this.currentPage)) {
|
||||
this.currentPage++
|
||||
await this.sleepSync(200)
|
||||
await this.getList()
|
||||
} else {
|
||||
this.getSkuCostList()
|
||||
}
|
||||
} else if (res.code == 100004 || res.code == 20302) {
|
||||
this.isLoading = false
|
||||
this.$store.commit("setSheinAlertShow", true)
|
||||
}
|
||||
},
|
||||
sleepSync(milliseconds) {
|
||||
return new Promise(resolve => setTimeout(resolve, milliseconds));
|
||||
},
|
||||
getSkuCostList() {
|
||||
this.$http.post(`/api/skuCost/listAll`, null, {
|
||||
params: {
|
||||
mallId: this.mallId
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.costList = res.data
|
||||
for (let i = 0; i < this.costList.length; i++) {
|
||||
for (let j = 0; j < this.list.length; j++) {
|
||||
if (this.costList[i].sku == this.list[j].sku) {
|
||||
this.list[j].costPrice = this.costList[i].costPrice
|
||||
this.list[j].editValue = this.costList[i].costPrice
|
||||
this.list[j].profitPercent = Math.round((this.list[j].price - this.list[j].costPrice) / this.list[j].price * 10000) /100
|
||||
}
|
||||
}
|
||||
}
|
||||
this.isLoading = false
|
||||
}
|
||||
})
|
||||
},
|
||||
handleSave(row) {
|
||||
this.$http.post(`/api/skuCost/addOrUpdate`, [{
|
||||
mallId: this.mallId,
|
||||
costPrice: row.editValue,
|
||||
skc: row.skc,
|
||||
sku: row.sku
|
||||
}]).then((res) => {
|
||||
if (res.code == 0) {
|
||||
row.edit = false
|
||||
row.costPrice = row.editValue
|
||||
row.profitPercent = Math.round((row.price - row.costPrice) / row.price * 10000) / 100
|
||||
Message.success("修改成功")
|
||||
}
|
||||
})
|
||||
},
|
||||
toUpload() {
|
||||
this.costDlgShow = true
|
||||
},
|
||||
importConfirm() {
|
||||
this.$refs.costForm.validate((valid) => {
|
||||
const data = new FormData()
|
||||
data.append('file', this.costForm.file[0].raw);
|
||||
this.$http.post(`/api/skuCost/importStock`, data).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.costDlgShow = false
|
||||
this.$message.success('导入成功')
|
||||
this.currentPage = 1
|
||||
this.list = []
|
||||
this.isLoading = true
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
exportToExcel() {
|
||||
// 假设你有一个表格数据的数组
|
||||
const data = [
|
||||
["店铺ID", "SKC ID", "SKC货号", "SKU ID", "属性集", "SKU货号", "申报价格", "成本价格"]
|
||||
]
|
||||
|
||||
this.filteredData.map(item => {
|
||||
data.push([this.mallId, item.skc, item.skcCode, item.sku, item.skuAttr, item.skuCode, item.price, item.costPrice])
|
||||
})
|
||||
|
||||
// 将数据转换为工作表
|
||||
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, 'SKU列表.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>
|
||||
@@ -2,7 +2,7 @@
|
||||
<ai-list class="list" v-loading="isLoading" element-loading-text="拼命加载中" element-loading-spinner="el-icon-loading">
|
||||
<ai-title
|
||||
slot="title"
|
||||
title="销售数据(希音)"
|
||||
title="销售数据"
|
||||
isShowBottomBorder>
|
||||
</ai-title>
|
||||
<template slot="content">
|
||||
@@ -46,22 +46,17 @@
|
||||
</div>
|
||||
<ai-card title="数据明细" style="padding-bottom: 40px;">
|
||||
<template #right>
|
||||
<json-excel
|
||||
:data="list"
|
||||
:fields="jsonFields"
|
||||
:before-generate = "startDownload"
|
||||
name="销售数据.xls"
|
||||
worksheet="销售统计">
|
||||
<el-button type="primary">导出数据</el-button>
|
||||
</json-excel>
|
||||
<div class="search-item" style="width: 160px;">
|
||||
<el-checkbox v-model="showTodaySale">只显示今日有销量</el-checkbox>
|
||||
</div>
|
||||
</template>
|
||||
<ai-table
|
||||
ref="table0"
|
||||
:isShowPagination="false"
|
||||
:tableData="list"
|
||||
:tableData="filteredData"
|
||||
height="500"
|
||||
:col-configs="colConfigs"
|
||||
:total="list.length"
|
||||
:total="filteredData.length"
|
||||
style="margin-top: 8px;"
|
||||
@getList="() => {}">
|
||||
<el-table-column slot="goodsThumb" width="120px" label="商品图片" fixed="left">
|
||||
@@ -90,6 +85,7 @@ import { Message } from 'element-ui'
|
||||
data () {
|
||||
return {
|
||||
list: [],
|
||||
mallId: '',
|
||||
isLoading: false,
|
||||
pageSize: 100,
|
||||
currentPage: 1,
|
||||
@@ -104,61 +100,7 @@ import { Message } from 'element-ui'
|
||||
startDate: '',
|
||||
endDate: '',
|
||||
skuIds: [],
|
||||
jsonFields: {
|
||||
"商品名称": "productName",
|
||||
"SPU": "productId",
|
||||
"SKC": "productSkcId",
|
||||
"SKU ID": "productSkuId",
|
||||
"SKU属性": "className",
|
||||
"SKU货号": "skuExtCode",
|
||||
"加入站点时长": "onSalesDurationOffline",
|
||||
"图片链接": "productSkcPicture",
|
||||
"申报价格(CNY)": {
|
||||
"field": "supplierPrice",
|
||||
callback: (value) => {
|
||||
return value /100;
|
||||
}
|
||||
},
|
||||
"开款核价状态": {
|
||||
"field": "isVerifyPrice",
|
||||
callback: (value) => {
|
||||
return value ? '核价通过': '核价未通过 / 无法备货';
|
||||
}
|
||||
},
|
||||
"缺货数量": "lackQuantity",
|
||||
"建议备货量": "adviceQuantity",
|
||||
"可售天数": "availableSaleDays",
|
||||
"库存可售天数": "availableSaleDaysFromInventory",
|
||||
"仓内库存可售天数": "warehouseAvailableSaleDays",
|
||||
"近7日用户加购数量": "inCartNumber7d",
|
||||
"用户累计加购数量": "inCardNumber",
|
||||
"已订阅待提醒到货": "nomsgSubsCntCntSth",
|
||||
"销售数据 - 今日": "todaySaleVolume",
|
||||
"销售数据 - 近7日": "lastSevenDaysSaleVolume",
|
||||
"销售数据 - 近30天": "lastThirtyDaysSaleVolume",
|
||||
"库存数据 - 仓内可用库存": "inventoryNumInfo.warehouseInventoryNum",
|
||||
"库存数据 - 仓内暂不可用库存": "inventoryNumInfo.waitOnShelfNum",
|
||||
"库存数据 - 已发货库存": "inventoryNumInfo.waitReceiveNum",
|
||||
"库存数据 - 已下单待发货库存": "inventoryNumInfo.waitDeliveryInventoryNum",
|
||||
"库存数据 - 待审核备货库存": "inventoryNumInfo.waitApproveInventoryNum",
|
||||
"VMI备货单数 - 待发货": "vmiOrderInfo.waitDeliveryNum",
|
||||
"VMI备货单数 - 在途单数": "vmiOrderInfo.transportationNum",
|
||||
"VMI备货单数 - 发货延迟": "vmiOrderInfo.deliveryDelayNum",
|
||||
"VMI备货单数 - 到货延迟": "vmiOrderInfo.arrivalDelayNum",
|
||||
"非VMI备货单数 - 待发货": "notVmiOrderInfo.waitDeliveryNum",
|
||||
"非VMI备货单数 - 在途单数": "notVmiOrderInfo.transportationNum",
|
||||
"非VMI备货单数 - 发货延迟": "notVmiOrderInfo.deliveryDelayNum",
|
||||
"非VMI备货单数 - 到货延迟": "notVmiOrderInfo.arrivalDelayNum",
|
||||
"备货逻辑": "purchaseConfig",
|
||||
"可用库存货值(CNY)": "productTotalPrice",
|
||||
"在途库存货值(CNY)": "inroadTotalPrice",
|
||||
"店铺名称": "mallName",
|
||||
"评分": "mark",
|
||||
"是否热销": 'hotTag',
|
||||
"生产建议信息 - 建议生产数": 'adviceProduceNum',
|
||||
"生产建议信息 - 剩余件数": 'availableProduceNum',
|
||||
"类目": 'category'
|
||||
},
|
||||
showTodaySale: false,
|
||||
|
||||
skuSaleNumberFields: {},
|
||||
skuSaleNumberList: [],
|
||||
@@ -166,134 +108,52 @@ import { Message } from 'element-ui'
|
||||
skuDownloadForm: {
|
||||
date: ''
|
||||
},
|
||||
costList: []
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
filteredData() {
|
||||
const filteredData = this.list.filter(item => {
|
||||
if (this.showTodaySale) {
|
||||
return item.todaySale > 0
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
return filteredData
|
||||
},
|
||||
colConfigs () {
|
||||
return [
|
||||
{
|
||||
slot: 'goodsThumb',
|
||||
label: '图片'
|
||||
},
|
||||
{
|
||||
prop: 'supplierCode',
|
||||
label: '货号',
|
||||
width: '120px',
|
||||
align: 'center',
|
||||
fixed: 'left'
|
||||
},
|
||||
{
|
||||
prop: 'suffixZh',
|
||||
label: '规格',
|
||||
width: '160px',
|
||||
align: 'center',
|
||||
fixed: 'left'
|
||||
},
|
||||
{
|
||||
prop: 'categoryName',
|
||||
label: '分类',
|
||||
"show-overflow-tooltip": true,
|
||||
width: '100px'
|
||||
},
|
||||
|
||||
{
|
||||
prop: 'mallStatusName',
|
||||
label: '状态',
|
||||
width: '120px',
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
prop: 'skc',
|
||||
label: 'SKC',
|
||||
width: '160px',
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
prop: 'ableSaleDays',
|
||||
label: '可售天数',
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
prop: 'cost',
|
||||
label: '价格',
|
||||
width: '120px',
|
||||
align: 'center'
|
||||
},
|
||||
|
||||
{
|
||||
prop: 'todaySale',
|
||||
label: '今日销量',
|
||||
width: '120px',
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
prop: 'saleInfoWeek',
|
||||
label: '近7天销量',
|
||||
width: '120px',
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
prop: 'saleInfoMonth',
|
||||
label: '本月销量',
|
||||
width: '120px',
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
prop: 'saleInfoPreMonth',
|
||||
label: '上月销量',
|
||||
width: '120px',
|
||||
align: 'center'
|
||||
},
|
||||
|
||||
{
|
||||
prop: 'purchaseConfig',
|
||||
label: '备货逻辑',
|
||||
width: '160px',
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
prop: 'onWayNum',
|
||||
label: '在途数量',
|
||||
width: '160px',
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
prop: 'ivtNum',
|
||||
label: '库存数量',
|
||||
width: '160px',
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
prop: 'productTotalPrice',
|
||||
label: '库存货值(CNY)',
|
||||
width: '180px',
|
||||
align: 'center',
|
||||
fixed: "right",
|
||||
sortable: true,
|
||||
'sort-method': (a, b) => {
|
||||
{slot: 'goodsThumb',label: '图片'},
|
||||
{prop: 'supplierCode',label: '货号',width: '120px',align: 'center',fixed: 'left'},
|
||||
{prop: 'suffixZh',label: '规格',width: '160px',align: 'center',fixed: 'left'},
|
||||
{prop: 'categoryName',label: '分类',"show-overflow-tooltip": true,width: '100px'},
|
||||
{prop: 'mallStatusName',label: '状态',width: '120px',align: 'center'},
|
||||
{prop: 'skc',label: 'SKC',width: '160px',align: 'center'},
|
||||
{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: 'todayProfit',label: '利润',width: '120px',align: 'center',sortable: true,'sort-method': (a, b) => {
|
||||
return a.todayProfit - b.todayProfit
|
||||
}},
|
||||
{prop: 'saleInfoWeek',label: '近7天销量',width: '120px',align: 'center'},
|
||||
{prop: 'saleInfoMonth',label: '本月销量',width: '120px',align: 'center'},
|
||||
{prop: 'saleInfoPreMonth',label: '上月销量',width: '120px',align: 'center'},
|
||||
{prop: 'purchaseConfig',label: '备货逻辑',width: '160px',align: 'center'},
|
||||
{prop: 'onWayNum',label: '在途数量',width: '160px',align: 'center'},
|
||||
{prop: 'ivtNum',label: '库存数量',width: '160px',align: 'center'},
|
||||
{prop: 'productTotalPrice',label: '库存货值(CNY)',width: '180px',align: 'center',fixed: "right",sortable: true,'sort-method': (a, b) => {
|
||||
return a.productTotalPrice - b.productTotalPrice
|
||||
}
|
||||
},
|
||||
{
|
||||
prop: 'inroadTotalPrice',
|
||||
label: '在途货值(CNY)',
|
||||
width: '180px',
|
||||
align: 'center',
|
||||
fixed: "right",
|
||||
sortable: true,
|
||||
'sort-method': (a, b) => {
|
||||
{prop: 'inroadTotalPrice',label: '在途货值(CNY)',width: '180px',align: 'center',fixed: "right",sortable: true,'sort-method': (a, b) => {
|
||||
return a.inroadTotalPrice - b.inroadTotalPrice
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
prop: 'purchaseConfig',
|
||||
label: '备货逻辑',
|
||||
align: 'center',
|
||||
width: '120px',
|
||||
fixed: "right",
|
||||
sortable: true,
|
||||
{prop: 'purchaseConfig',
|
||||
label: '备货逻辑',align: 'center',width: '120px',fixed: "right",sortable: true,
|
||||
'sort-method': (a, b) => {
|
||||
if (a.purchaseConfig > b.purchaseConfig) {
|
||||
return 1
|
||||
@@ -304,8 +164,6 @@ import { Message } from 'element-ui'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
]
|
||||
}
|
||||
},
|
||||
@@ -329,7 +187,20 @@ import { Message } from 'element-ui'
|
||||
},
|
||||
|
||||
methods: {
|
||||
beforeGetList() {
|
||||
async getUserInfo() {
|
||||
let res = await sendGeiwohuoAPIMessage({
|
||||
url: 'sso-prefix/auth/getUser?uuid=' + Date.now(),
|
||||
method: 'GET'
|
||||
})
|
||||
if (res.code == '0' && res.msg == "OK") {
|
||||
this.mallId = res.info.merchantCode
|
||||
} else if (res.code == 100004 || res.code == 20302) {
|
||||
this.isLoading = false
|
||||
this.$store.commit("setSheinAlertShow", true)
|
||||
}
|
||||
},
|
||||
async beforeGetList() {
|
||||
await this.getUserInfo()
|
||||
this.list = []
|
||||
this.currentPage = 1
|
||||
this.todayMoney = 0.0
|
||||
@@ -339,6 +210,7 @@ import { Message } from 'element-ui'
|
||||
this.inroadTotalMoney = 0.0
|
||||
this.inroadTotal = 0
|
||||
|
||||
await this.getSkuCostList()
|
||||
this.isLoading = true
|
||||
this.getList()
|
||||
},
|
||||
@@ -368,6 +240,7 @@ import { Message } from 'element-ui'
|
||||
data = {...data,
|
||||
ableSaleDays: sku.ableSaleDays,
|
||||
cost: sku.cost,
|
||||
skuCode: sku.skuCode,
|
||||
purchaseConfig: (sku.operateTime?sku.operateTime:'/') + '+' + (sku.prepareDay?sku.prepareDay:'/'),
|
||||
saleInfoMonth: sku.saleInfoMonth,
|
||||
saleInfoPreMonth: sku.saleInfoPreMonth,
|
||||
@@ -376,18 +249,20 @@ import { Message } from 'element-ui'
|
||||
todaySale: sku.todaySale,
|
||||
onWayNum: sku.onWayNum,
|
||||
ivtNum: sku.ivtNum,
|
||||
productTotalPrice: (sku.cost * sku.ivtNum).toFixed(2),
|
||||
inroadTotalPrice: (sku.cost * sku.onWayNum).toFixed(2)}
|
||||
costPrice: null,
|
||||
todayProfit: null,
|
||||
productTotalPrice: Math.round((sku.cost * sku.ivtNum)*100)/100,
|
||||
inroadTotalPrice: Math.round((sku.cost * sku.onWayNum)*100)/100}
|
||||
|
||||
this.todayTotal += sku.todaySale
|
||||
this.todayMoney += new Number((sku.cost * sku.todaySale).toFixed(2))
|
||||
this.todayMoney = new Number(this.todayMoney.toFixed(2))
|
||||
this.todayMoney += Math.round((sku.cost * sku.todaySale)*100)/100
|
||||
this.todayMoney = Math.round(this.todayMoney * 100) / 100
|
||||
this.inventoryTotal += sku.ivtNum
|
||||
this.inventoryMoney += new Number((sku.cost * sku.ivtNum).toFixed(2))
|
||||
this.inventoryMoney = new Number(this.inventoryMoney.toFixed(2))
|
||||
this.inventoryMoney += Math.round((sku.cost * sku.ivtNum)*100)/100
|
||||
this.inventoryMoney = Math.round(this.inventoryMoney*100)/100
|
||||
this.inroadTotal += sku.onWayNum
|
||||
this.inroadTotalMoney += new Number((sku.cost * sku.onWayNum).toFixed(2))
|
||||
this.inroadTotalMoney = new Number(this.inroadTotalMoney.toFixed(2))
|
||||
this.inroadTotalMoney += Math.round((sku.cost * sku.onWayNum)*100)/100
|
||||
this.inroadTotalMoney = Math.round(this.inroadTotalMoney*100)/100
|
||||
this.list.push(data);
|
||||
}
|
||||
}
|
||||
@@ -398,12 +273,24 @@ import { Message } from 'element-ui'
|
||||
this.getList()
|
||||
}, 1500)
|
||||
} else {
|
||||
for (let i = 0; i < this.list.length; i++) {
|
||||
for (let j = 0; j < this.costList.length; j++) {
|
||||
if (this.list[i].skuCode == this.costList[j].sku) {
|
||||
this.list[i].costPrice = this.costList[j].costPrice
|
||||
this.list[i].todayProfit = Math.round((this.list[i].cost - this.costList[j].costPrice) * this.list[i].todaySale * 100) / 100
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
this.isLoading = false
|
||||
Message.success('销售数据加载完成,可进行导出')
|
||||
this.$nextTick(() => { //在数据加载完,重新渲染表格
|
||||
this.$refs['table0'].doLayout();
|
||||
})
|
||||
}
|
||||
} else if (res.code == 100004 || res.code == 20302) {
|
||||
this.isLoading = false
|
||||
this.$store.commit("setSheinAlertShow", true)
|
||||
} else {
|
||||
setTimeout(() => {
|
||||
this.getList()
|
||||
@@ -413,18 +300,16 @@ import { Message } from 'element-ui'
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
startDownload() {
|
||||
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;
|
||||
}
|
||||
async getSkuCostList() {
|
||||
let res = await this.$http.post(`/api/skuCost/listAll`, null, {
|
||||
params: {
|
||||
mallId: this.mallId
|
||||
}
|
||||
})
|
||||
}
|
||||
if (res.code == 0) {
|
||||
this.costList = res.data
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
905
src/view/shein/ExportSaleStatShein.vue
Normal file
905
src/view/shein/ExportSaleStatShein.vue
Normal file
@@ -0,0 +1,905 @@
|
||||
<template>
|
||||
<ai-list class="list" v-loading="isLoading" element-loading-text="拼命加载中" element-loading-spinner="el-icon-loading">
|
||||
<ai-title
|
||||
slot="title"
|
||||
title="商家账单统计"
|
||||
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 HH:mm:ss"
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
:default-time="['00:00:00', '23:59:59']">
|
||||
</el-date-picker>
|
||||
</div>
|
||||
<el-button type="button" :class="'el-button el-button--primary'" @click="beginStat">开始统计</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="SKC账单数据.xls"
|
||||
worksheet="SKC账单数据">
|
||||
<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
|
||||
title="销售额/单数"
|
||||
>
|
||||
<template slot="formatter">
|
||||
{{ saleAmount }}/{{ saleCount }}
|
||||
</template>
|
||||
</el-statistic>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="5">
|
||||
<div>
|
||||
<el-statistic
|
||||
group-separator=","
|
||||
:precision="2"
|
||||
:value="deductionAmount"
|
||||
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="amount" label="销售额">
|
||||
<template slot-scope="scope">
|
||||
<div style="color: red">{{ scope.row.amount }}</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="profitPercent" label="利润率">
|
||||
<template slot-scope="scope">
|
||||
<div>{{ scope.row.profitPercent + '%' }}</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="amount" label="销售额">
|
||||
<template slot-scope="scope">
|
||||
<div>{{ scope.row.amount }}</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="profitPercent" label="利润率">
|
||||
<template slot-scope="scope">
|
||||
<div>{{ scope.row.profitPercent + '%' }}</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="topProfitPercentSkcList"
|
||||
:col-configs="skcColConfigs"
|
||||
style="margin-top: 8px;">
|
||||
<el-table-column slot="amount" label="销售额">
|
||||
<template slot-scope="scope">
|
||||
<div>{{ scope.row.amount }}</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="profitPercent" label="利润率">
|
||||
<template slot-scope="scope">
|
||||
<div style="color: red">{{ scope.row.profitPercent + '%' }}</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="amount" label="销售额">
|
||||
<template slot-scope="scope">
|
||||
<div style="color: red">{{ scope.row.amount }}</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="profitPercent" label="利润率">
|
||||
<template slot-scope="scope">
|
||||
<div>{{ scope.row.profitPercent + '%' }}</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="amount" label="销售额">
|
||||
<template slot-scope="scope">
|
||||
<div>{{ scope.row.amount }}</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="profitPercent" label="利润率">
|
||||
<template slot-scope="scope">
|
||||
<div>{{ scope.row.profitPercent + '%' }}</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="topProfitPercentSkuList"
|
||||
:col-configs="skuColConfigs"
|
||||
style="margin-top: 8px;">
|
||||
<el-table-column slot="amount" label="销售额">
|
||||
<template slot-scope="scope">
|
||||
<div>{{ scope.row.amount }}</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="profitPercent" label="利润率">
|
||||
<template slot-scope="scope">
|
||||
<div style="color: red">{{ scope.row.profitPercent + '%' }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
</ai-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
</ai-list>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {sendGeiwohuoAPIMessage} from '@/api/chromeApi'
|
||||
import JsonExcel from 'vue-json-excel'
|
||||
import { Message } from 'element-ui'
|
||||
import html2canvas from 'html2canvas'
|
||||
import { DualAxes } from '@antv/g2plot'
|
||||
|
||||
export default {
|
||||
name: 'ExportSaleStatShein',
|
||||
|
||||
data () {
|
||||
return {
|
||||
storeCode: '',
|
||||
productList: [],
|
||||
|
||||
dateRange: [],
|
||||
|
||||
page: 1,
|
||||
perPage: 100,
|
||||
orderList: [],
|
||||
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: 'skcCode', label: '货号', width: '180px' },
|
||||
{ slot: 'amount', label: '销售额', align: 'center' },
|
||||
{ prop: 'quantity', label: '单数', align: 'center' },
|
||||
{ prop: 'cost', label: '成本', align: 'center'},
|
||||
{ slot: 'profitAmount', label: '利润', align: 'center' },
|
||||
{ slot: 'profitPercent', label: '利润率', align: 'center'},
|
||||
],
|
||||
skcJsonFields: {
|
||||
"SKC": "skc",
|
||||
"货号": "skcCode",
|
||||
"销售额": "amount",
|
||||
"单数": "quantity",
|
||||
"成本": "cost",
|
||||
"利润": "profitAmount",
|
||||
"利润率": "profitPercent",
|
||||
},
|
||||
skuColConfigs: [
|
||||
{ prop: 'skuCode', label: '属性集', width: '220px' },
|
||||
{ slot: 'amount', label: '销售额', align: 'center' },
|
||||
{ prop: 'quantity', label: '单数', align: 'center' },
|
||||
{ prop: 'cost', label: '成本', align: 'center'},
|
||||
{ slot: 'profitAmount', label: '利润', align: 'center' },
|
||||
{ slot: 'profitPercent', label: '利润率', align: 'center'},
|
||||
],
|
||||
skuJsonFields: {
|
||||
"SKC": "skc",
|
||||
"SKU": "sku",
|
||||
"属性集": "skuCode",
|
||||
"销售额": "amount",
|
||||
"单数": "quantity",
|
||||
"成本": "cost",
|
||||
"利润": "profitAmount",
|
||||
"利润率": "profitPercent",
|
||||
},
|
||||
|
||||
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)
|
||||
},
|
||||
topProfitPercentSkcList() {
|
||||
const list = Object.assign([], this.skcList)
|
||||
list.sort((a, b) => b.profitPercent - a.profitPercent)
|
||||
return list.slice(0, 10)
|
||||
},
|
||||
topSaleAmountSkuList() {
|
||||
const list = Object.assign([], this.skuList)
|
||||
list.sort((a, b) => b.amount - a.amount)
|
||||
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)
|
||||
},
|
||||
topProfitPercentSkuList() {
|
||||
const list = Object.assign([], this.skuList)
|
||||
list.sort((a, b) => b.profitPercent - a.profitPercent)
|
||||
return list.slice(0, 10)
|
||||
}
|
||||
},
|
||||
|
||||
components: {
|
||||
JsonExcel
|
||||
},
|
||||
mounted () {
|
||||
this.$nextTick(() => {
|
||||
this.initChart1()
|
||||
})
|
||||
},
|
||||
created () {
|
||||
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.getStoreCode()
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
methods: {
|
||||
initChart1 () {
|
||||
/*const data = [
|
||||
{ year: '1991', value: 3, count: 11, type: '销售额' },
|
||||
{ year: '1992', value: 4, count: 143, type: '销售额' },
|
||||
{ year: '1993', value: 3.5, count: 143, type: '销售额' },
|
||||
{ year: '1991', value: 5, count: 11, type: '利润' },
|
||||
{ year: '1992', value: 4.9, count: 17, type: '利润' },
|
||||
{ year: '1993', value: 6, count: 143, type: '利润' }
|
||||
]
|
||||
|
||||
const data1 = [
|
||||
{ year: '1991', value1: 30.1, count: 11, type: '利润率' },
|
||||
{ year: '1992', value1: 32.1, count: 143, type: '利润率' },
|
||||
{ year: '1993', value1: 44.1, count: 143, type: '利润率' }
|
||||
]*/
|
||||
|
||||
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();
|
||||
},
|
||||
async beginStat() {
|
||||
if (!this.dateRange) {
|
||||
Message.error("请选择统计时间范围")
|
||||
return
|
||||
}
|
||||
this.page = 1
|
||||
this.isLoading = true
|
||||
this.saleAmount = 0.0
|
||||
this.saleCount = 0
|
||||
this.costAmount = 0.0
|
||||
this.profitAmount = 0.0
|
||||
this.profitPercent = 0.0
|
||||
this.deductionAmount = 0.0
|
||||
this.orderList = []
|
||||
this.skcList = []
|
||||
this.skuList = []
|
||||
this.leftChartData = []
|
||||
this.rightChartData = []
|
||||
this.chartObj.changeData([this.leftChartData, this.rightChartData])
|
||||
this.getOrderList()
|
||||
},
|
||||
async getStoreCode() {
|
||||
let res = await sendGeiwohuoAPIMessage({
|
||||
url: 'sso-prefix/auth/getUser?uuid=' + Date.now(),
|
||||
method: 'GET'
|
||||
})
|
||||
if (res.code == '0' && res.msg == "OK") {
|
||||
this.storeCode = res.info.merchantCode
|
||||
this.getPorductList()
|
||||
} else if (res.code == 100004 || res.code == 20302) {
|
||||
this.isLoading = false
|
||||
this.$store.commit("setSheinAlertShow", true)
|
||||
}
|
||||
},
|
||||
getPorductList() {
|
||||
this.$http.post(`/api/skuCost/listAll`, null, {
|
||||
params: {
|
||||
mallId: this.storeCode
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.productList = res.data
|
||||
}
|
||||
})
|
||||
},
|
||||
async getOrderList() {
|
||||
let res = await sendGeiwohuoAPIMessage({
|
||||
url: 'gsfs/finance/reportOrder/dualMode/reportOrderList',
|
||||
method: 'POST',
|
||||
data: {
|
||||
"page": this.page,
|
||||
"perPage": this.perPage,
|
||||
"addTimeStart": this.dateRange[0],
|
||||
"addTimeEnd": this.dateRange[1]
|
||||
}
|
||||
})
|
||||
if (res.code == '0' && res.msg == "OK") {
|
||||
for (let i = 0; i < res.info.data.length; i++) {
|
||||
this.orderList.push(res.info.data[i])
|
||||
}
|
||||
if (res.info.data.length == this.perPage && (res.info.meta.count > this.perPage*this.page)) {
|
||||
this.page++
|
||||
await this.sleepSync(200)
|
||||
await this.getOrderList()
|
||||
} else {
|
||||
this.page = 1
|
||||
await this.getDetail()
|
||||
// 计算SKC维度利润
|
||||
for (let i = 0; i < this.skcList.length; i++) {
|
||||
this.skcList[i].amount = Math.round(this.skcList[i].amount * 100)/100
|
||||
this.skcList[i].cost = Math.round(this.skcList[i].cost * 100)/100
|
||||
this.skcList[i].profitAmount = Math.round((this.skcList[i].amount - this.skcList[i].cost)*100)/100
|
||||
this.skcList[i].profitPercent = Math.round((this.skcList[i].profitAmount / this.skcList[i].amount)*10000)/100
|
||||
|
||||
this.saleAmount += this.skcList[i].amount
|
||||
this.costAmount += this.skcList[i].cost
|
||||
this.saleCount += this.skcList[i].quantity
|
||||
}
|
||||
this.saleAmount = Math.round(this.saleAmount*100)/100
|
||||
this.profitAmount = this.saleAmount - this.costAmount
|
||||
for (let i = 0; i < this.orderList.length; i++) {
|
||||
let item = this.orderList[i]
|
||||
let saleAmount = 0
|
||||
for (let j = 0; j < item.details.length; j++) {
|
||||
// this.saleAmount -= (item.details[j].deduction.funds ? item.details[j].deduction.funds: 0)
|
||||
this.deductionAmount += (item.details[j].deduction.funds ? item.details[j].deduction.funds: 0)
|
||||
saleAmount += item.details[j].income
|
||||
}
|
||||
this.leftChartData.push({day: item.addTime, value: Math.round(saleAmount*100)/100, type: '销售额'})
|
||||
}
|
||||
this.profitPercent = Math.round((this.profitAmount / this.saleAmount)*10000)/100
|
||||
|
||||
// 计算SKU维度利润
|
||||
for (let i = 0; i < this.skuList.length; i++) {
|
||||
this.skuList[i].amount = Math.round(this.skuList[i].amount * 100)/100
|
||||
this.skuList[i].cost = Math.round(this.skuList[i].cost * 100)/100
|
||||
this.skuList[i].profitAmount = Math.round((this.skuList[i].amount - this.skuList[i].cost)*100)/100
|
||||
this.skuList[i].profitPercent = Math.round(((this.skuList[i].profitAmount / this.skuList[i].amount)*10000))/100
|
||||
}
|
||||
|
||||
// 计算每天利润和利润率
|
||||
const tempData = Object.assign([], this.leftChartData)
|
||||
for (let i = 0; i < this.orderList.length; i++) {
|
||||
for (let j = 0; j < tempData.length; j++) {
|
||||
if ((tempData[j].type == '销售额') && (tempData[j].day == this.orderList[i].addTime)) {
|
||||
for (let m = 0; m < tempData.length; m++) {
|
||||
if ((tempData[m].type == '成本') && (tempData[m].day == this.orderList[i].addTime)) {
|
||||
this.leftChartData.push({
|
||||
day: this.orderList[i].addTime,
|
||||
value: Math.round((tempData[j].value - tempData[m].value)*100)/100,
|
||||
type: '利润'
|
||||
})
|
||||
|
||||
this.rightChartData.push({
|
||||
day: this.orderList[i].addTime,
|
||||
value1: Math.round(((tempData[j].value - tempData[m].value)/tempData[j].value)*10000)/100,
|
||||
type: '利润率'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
console.log(this.leftChartData)
|
||||
this.chartObj.changeData([this.leftChartData, this.rightChartData])
|
||||
this.isLoading = false
|
||||
}
|
||||
} else if (res.code == 100004 || res.code == 20302) {
|
||||
this.isLoading = false
|
||||
this.$store.commit("setSheinAlertShow", true)
|
||||
}
|
||||
},
|
||||
async getDetail() {
|
||||
for (let i = 0; i < this.orderList.length; i++) {
|
||||
let item = this.orderList[i]
|
||||
for (let j = 0; j < item.details.length; j++) {
|
||||
if (item.details[j].sourceSystem == "GSFS") {
|
||||
let currentPage = 1
|
||||
while(true) {
|
||||
await this.sleepSync(200)
|
||||
let res = await sendGeiwohuoAPIMessage({
|
||||
url: 'gsfs/finance/reportOrder/dualMode/checkOrderList/item',
|
||||
method: 'POST',
|
||||
data: {
|
||||
"page": currentPage,
|
||||
"perPage": this.perPage,
|
||||
"reportOrderNo": item.details[j].reportOrderNo,
|
||||
"secondOrderTypes": [1,2,41,42]
|
||||
}
|
||||
})
|
||||
if (res.code == '0' && res.msg == "OK") {
|
||||
// calc
|
||||
this.calculate(res.info.data, item.addTime)
|
||||
if (res.info.data.length == this.perPage && (res.info.meta.count > this.perPage*currentPage)) {
|
||||
currentPage ++
|
||||
} else {
|
||||
break
|
||||
}
|
||||
} else if (res.code == 100004 || res.code == 20302) {
|
||||
this.isLoading = false
|
||||
this.$store.commit("setSheinAlertShow", true)
|
||||
}
|
||||
}
|
||||
} else if (item.details[j].sourceSystem == "PMS") {
|
||||
let currentPage = 1
|
||||
while(true) {
|
||||
await this.sleepSync(200)
|
||||
let res2 = await sendGeiwohuoAPIMessage({
|
||||
url: 'gmpj/finance/incomeAndExpensesDetail',
|
||||
isWWW: true,
|
||||
method: 'POST',
|
||||
data: {
|
||||
"page": currentPage,
|
||||
"perPage": this.perPage,
|
||||
"reportOrderNo": item.details[j].reportOrderNo
|
||||
}
|
||||
})
|
||||
|
||||
if (res2.code == '0' && res2.msg == "OK") {
|
||||
// calc
|
||||
this.calculate(res2.info.checkDetailList, item.addTime)
|
||||
if (res2.info.checkDetailList.length == this.perPage && (res2.info.count > this.perPage*currentPage)) {
|
||||
currentPage ++
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
calculate(data, addTime) {
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
let exist = false
|
||||
let cost = this.getCost(data[i].skuCode) * (data[i].goodsCount || data[i].quantity)
|
||||
|
||||
// 按SKC维度统计
|
||||
for (let j = 0; j < this.skcList.length; j++) {
|
||||
if (this.skcList[j].skc == (data[i].skc || data[i].skcName)) {
|
||||
exist = true
|
||||
if (data[i].incomeAndExpensesTypeName == '支出' || data[i].inAndOutName == '支出') {
|
||||
this.skcList[j].amount -= data[i].amount || data[i].income
|
||||
} else if (data[i].incomeAndExpensesTypeName == '收入' || data[i].inAndOutName == '收入') {
|
||||
this.skcList[j].quantity += data[i].goodsCount || data[i].quantity
|
||||
this.skcList[j].amount += data[i].amount || data[i].income
|
||||
this.skcList[j].cost += cost
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
if (!exist) {
|
||||
if (data[i].incomeAndExpensesTypeName == '支出' || data[i].inAndOutName == '支出') {
|
||||
this.skcList.push({
|
||||
skc: (data[i].skc || data[i].skcName),
|
||||
skcCode: (data[i].goodsSn || data[i].supplierCode),
|
||||
amount: -(data[i].amount || data[i].income),
|
||||
quantity: 0,
|
||||
cost: 0,
|
||||
profitPercent: 0.0,
|
||||
profitAmount: 0.0
|
||||
})
|
||||
} else if (data[i].incomeAndExpensesTypeName == '收入' || data[i].inAndOutName == '收入') {
|
||||
this.skcList.push({
|
||||
skc: (data[i].skc || data[i].skcName),
|
||||
skcCode: (data[i].goodsSn || data[i].supplierCode),
|
||||
amount: data[i].amount || data[i].income,
|
||||
quantity: data[i].goodsCount || data[i].quantity,
|
||||
cost: cost,
|
||||
profitPercent: 0.0,
|
||||
profitAmount: 0.0
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 按SKU维度统计
|
||||
exist = false
|
||||
for (let j = 0; j < this.skuList.length; j++) {
|
||||
if (this.skuList[j].sku == data[i].skuCode) {
|
||||
exist = true
|
||||
if (data[i].incomeAndExpensesTypeName == '支出' || data[i].inAndOutName == '支出') {
|
||||
this.skuList[j].amount -= data[i].amount || data[i].income
|
||||
} else if (data[i].incomeAndExpensesTypeName == '收入' || data[i].inAndOutName == '收入') {
|
||||
this.skuList[j].quantity += data[i].goodsCount || data[i].quantity
|
||||
this.skuList[j].amount += data[i].amount || data[i].income
|
||||
this.skuList[j].cost += cost
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
if (!exist) {
|
||||
if (data[i].incomeAndExpensesTypeName == '支出' || data[i].inAndOutName == '支出') {
|
||||
this.skuList.push({
|
||||
skc: (data[i].skc || data[i].skcName),
|
||||
sku: data[i].skuCode,
|
||||
skuCode: (data[i].goodsSn || data[i].supplierCode) + '/' + (data[i].suffix || data[i].suffixZh),
|
||||
amount: -(data[i].amount || data[i].income),
|
||||
quantity: 0,
|
||||
cost: 0,
|
||||
profitPercent: 0.0,
|
||||
profitAmount: 0.0
|
||||
})
|
||||
} else if (data[i].incomeAndExpensesTypeName == '收入' || data[i].inAndOutName == '收入') {
|
||||
this.skuList.push({
|
||||
skc: (data[i].skc || data[i].skcName),
|
||||
sku: data[i].skuCode,
|
||||
skuCode: (data[i].goodsSn || data[i].supplierCode) + '/' + (data[i].suffix || data[i].suffixZh),
|
||||
amount: data[i].amount || data[i].income,
|
||||
quantity: data[i].goodsCount || data[i].quantity,
|
||||
cost: cost,
|
||||
profitPercent: 0.0,
|
||||
profitAmount: 0.0
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 计算每天的成本
|
||||
exist = false
|
||||
for (let x = 0; x < this.leftChartData.length; x++) {
|
||||
if ((this.leftChartData[x].day == addTime) && (this.leftChartData[x].type == '成本')) {
|
||||
exist = true
|
||||
if (data[i].incomeAndExpensesTypeName == '收入' || data[i].inAndOutName == '收入') {
|
||||
this.leftChartData[x].value = Math.round((this.leftChartData[x].value + cost)*100)/100
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
if (!exist) {
|
||||
if (data[i].incomeAndExpensesTypeName == '收入' || data[i].inAndOutName == '收入') {
|
||||
this.leftChartData.push({
|
||||
day: addTime,
|
||||
type: '成本',
|
||||
value: cost
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 计算每天的单数
|
||||
exist = false
|
||||
for (let x = 0; x < this.leftChartData.length; x++) {
|
||||
if ((this.leftChartData[x].day == addTime) && (this.leftChartData[x].type == '单数')) {
|
||||
exist = true
|
||||
if (data[i].incomeAndExpensesTypeName == '收入' || data[i].inAndOutName == '收入') {
|
||||
this.leftChartData[x].value += (data[i].goodsCount || data[i].quantity)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
if (!exist) {
|
||||
if (data[i].incomeAndExpensesTypeName == '收入' || data[i].inAndOutName == '收入') {
|
||||
this.leftChartData.push({
|
||||
day: addTime,
|
||||
type: '单数',
|
||||
value: (data[i].goodsCount || data[i].quantity)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
getCost(sku) {
|
||||
for (let i = 0; i < this.productList.length; i++) {
|
||||
if (sku == this.productList[i].sku) {
|
||||
return this.productList[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 = '账单统计(希音).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>
|
||||
@@ -19,8 +19,7 @@
|
||||
<!--<el-button type="primary" :disabled="isBegin" @click="isShow = true">添加备货单</el-button>
|
||||
<el-button type="primary" :disabled="isBegin" @click="loadAll">一键加载全部</el-button>-->
|
||||
</el-dropdown>
|
||||
<el-button v-if="!isBegin" type="button" :class="'el-button el-button--primary'" @click="beginCreate">开始创建</el-button>
|
||||
<el-button v-else type="button" :icon="isBegin? 'el-icon-loading': ''" :class="isBegin ? 'el-button el-button--danger': 'el-button el-button--primary'" @click="beginCreate()">{{ `结束创建(${choosedList.length}/${createTotal})` }}</el-button>
|
||||
<el-button type="button" :class="'el-button el-button--primary'" @click="beginCreate">开始创建</el-button>
|
||||
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
@@ -225,12 +224,10 @@
|
||||
Message.error("请选择待创建备货单")
|
||||
return
|
||||
}
|
||||
console.log(this.arr)
|
||||
this.arr.map(item => {
|
||||
let temp = this.choosedList.filter(i => {
|
||||
return i.subPurchaseOrderSn == item.subPurchaseOrderSn
|
||||
})
|
||||
console.log(temp)
|
||||
if (temp.length == 0) {
|
||||
this.choosedList.push(item)
|
||||
console.log(this.choosedList)
|
||||
@@ -261,20 +258,12 @@
|
||||
this.loadAll()
|
||||
}
|
||||
},
|
||||
beginCreateConfirm() {
|
||||
beforeBegin() {
|
||||
if (this.choosedList.length <= 0) {
|
||||
Message.error('请先添加备货单');
|
||||
return;
|
||||
}
|
||||
this.createDlgShow = true
|
||||
},
|
||||
beforeBegin() {
|
||||
this.$refs.robForm.validate((valid) => {
|
||||
if (valid) {
|
||||
this.createDlgShow = false
|
||||
this.beginCreate()
|
||||
}
|
||||
})
|
||||
this.beginCreate()
|
||||
},
|
||||
getList (data, mallId, mallName, currentPage) {
|
||||
sendChromeAPIMessage({
|
||||
@@ -334,74 +323,43 @@
|
||||
getStyle(url) {
|
||||
return "background-image: url(" + url + "); width: 72px; height: 72px; cursor: pointer; border-radius: 6px; border: 1px solid rgba(0, 0, 0, 0.14);";
|
||||
},
|
||||
beginCreate() {
|
||||
if (this.isBegin) {
|
||||
this.isBegin = false;
|
||||
return;
|
||||
async beginCreate() {
|
||||
let waitCreateList = []
|
||||
for (let i = 0; i < this.mallList.length; i++) {
|
||||
let subPurchaseOrderSnList = []
|
||||
this.choosedList.map(item => {
|
||||
if (item.mallId == this.mallList[i].mallId) {
|
||||
subPurchaseOrderSnList.push(item.subPurchaseOrderSn)
|
||||
}
|
||||
})
|
||||
if (subPurchaseOrderSnList.length > 0) {
|
||||
waitCreateList.push({
|
||||
mallId: this.mallList[i].mallId,
|
||||
subPurchaseOrderSnList: subPurchaseOrderSnList
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
this.createTotal = this.choosedList.length
|
||||
this.isBegin = true;
|
||||
for (let j = 0; j < waitCreateList.length; j++) {
|
||||
let res = await sendChromeAPIMessage({
|
||||
url: 'oms/bg/venom/api/supplier/purchase/manager/batchAcceptSubPurchaseOrder',
|
||||
needMallId: true,
|
||||
anti: true,
|
||||
mallId: waitCreateList[j].mallId,
|
||||
data: {
|
||||
subPurchaseOrderSnList: waitCreateList[j].subPurchaseOrderSnList,
|
||||
confirmFulfilment: false
|
||||
}})
|
||||
|
||||
this.choosedList.map((data, index) => {
|
||||
let deliverOrderDetailInfos = data.skuQuantityDetailList.map(item => {
|
||||
if (this.robForm.isModifyMaxNum) {
|
||||
return {
|
||||
productSkuId: item.productSkuId,
|
||||
deliverSkuNum: item.skuDeliveryQuantityMaxLimit
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
productSkuId: item.productSkuId,
|
||||
deliverSkuNum: item.productSkuPurchaseQuantity
|
||||
if (res.success && res.errorCode == 1000000) {
|
||||
if (res.result.isSuccess) {
|
||||
for (let n = 0; n < waitCreateList[j].subPurchaseOrderSnList.length; n++) {
|
||||
this.remove(waitCreateList[j].subPurchaseOrderSnList[n])
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
let packageInfos = []
|
||||
data.orderDetailVOList.map(item => {
|
||||
let packageDetailSaveInfos = []
|
||||
if (this.robForm.isModifyMaxNum) {
|
||||
packageDetailSaveInfos.push({
|
||||
productSkuId: item.productSkuId,
|
||||
skuNum: item.skuDeliveryQuantityMaxLimit
|
||||
})
|
||||
|
||||
} else {
|
||||
packageDetailSaveInfos.push({
|
||||
productSkuId: item.productSkuId,
|
||||
skuNum: item.productSkuPurchaseQuantity
|
||||
})
|
||||
}
|
||||
packageInfos.push({packageDetailSaveInfos: packageDetailSaveInfos})
|
||||
})
|
||||
|
||||
let addressInfo = this.addressList.filter(k => {
|
||||
return k.mallId == data.mallId
|
||||
})
|
||||
|
||||
let deliveryOrderCreateInfos = []
|
||||
deliveryOrderCreateInfos.push({
|
||||
deliverOrderDetailInfos: deliverOrderDetailInfos,
|
||||
subPurchaseOrderSn: data.subPurchaseOrderSn,
|
||||
deliveryAddressId: addressInfo[0].addressId,
|
||||
packageInfos: packageInfos
|
||||
})
|
||||
|
||||
let deliveryOrderCreateGroupList = []
|
||||
deliveryOrderCreateGroupList.push({
|
||||
deliveryOrderCreateInfos: deliveryOrderCreateInfos,
|
||||
receiveAddressInfo: data.receiveAddressInfo,
|
||||
subWarehouseId: data.subWarehouseId
|
||||
})
|
||||
})
|
||||
|
||||
let _this = this;
|
||||
let tt = setInterval(function() {
|
||||
if (_this.choosedList.length == 0) {
|
||||
_this.isBegin = false;
|
||||
clearInterval(tt);
|
||||
}
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
},
|
||||
formatTime(time) {
|
||||
return timestampToTime(time)
|
||||
|
||||
97
yarn.lock
97
yarn.lock
@@ -2054,6 +2054,11 @@ address@^1.1.2:
|
||||
resolved "https://registry.npmmirror.com/address/-/address-1.2.2.tgz"
|
||||
integrity sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==
|
||||
|
||||
adler-32@~1.3.0:
|
||||
version "1.3.1"
|
||||
resolved "https://registry.npmmirror.com/adler-32/-/adler-32-1.3.1.tgz#1dbf0b36dda0012189a32b3679061932df1821e2"
|
||||
integrity sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==
|
||||
|
||||
aggregate-error@^3.0.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.npmmirror.com/aggregate-error/-/aggregate-error-3.1.0.tgz"
|
||||
@@ -2358,6 +2363,11 @@ balanced-match@^1.0.0:
|
||||
resolved "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz"
|
||||
integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
|
||||
|
||||
base64-arraybuffer@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz"
|
||||
integrity sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==
|
||||
|
||||
base64-js@^1.3.1:
|
||||
version "1.5.1"
|
||||
resolved "https://registry.npmmirror.com/base64-js/-/base64-js-1.5.1.tgz"
|
||||
@@ -2568,6 +2578,14 @@ center-align@^0.1.1:
|
||||
align-text "^0.1.3"
|
||||
lazy-cache "^1.0.3"
|
||||
|
||||
cfb@~1.2.1:
|
||||
version "1.2.2"
|
||||
resolved "https://registry.npmmirror.com/cfb/-/cfb-1.2.2.tgz#94e687628c700e5155436dac05f74e08df23bc44"
|
||||
integrity sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==
|
||||
dependencies:
|
||||
adler-32 "~1.3.0"
|
||||
crc-32 "~1.2.0"
|
||||
|
||||
chalk@4.1.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.npmmirror.com/chalk/-/chalk-4.1.0.tgz"
|
||||
@@ -2751,6 +2769,11 @@ clone@^1.0.2:
|
||||
resolved "https://registry.npmmirror.com/clone/-/clone-1.0.4.tgz"
|
||||
integrity sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==
|
||||
|
||||
codepage@~1.15.0:
|
||||
version "1.15.0"
|
||||
resolved "https://registry.npmmirror.com/codepage/-/codepage-1.15.0.tgz#2e00519024b39424ec66eeb3ec07227e692618ab"
|
||||
integrity sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==
|
||||
|
||||
color-convert@^1.9.0:
|
||||
version "1.9.3"
|
||||
resolved "https://registry.npmmirror.com/color-convert/-/color-convert-1.9.3.tgz"
|
||||
@@ -2953,6 +2976,11 @@ cosmiconfig@^7.0.0:
|
||||
path-type "^4.0.0"
|
||||
yaml "^1.10.0"
|
||||
|
||||
crc-32@~1.2.0, crc-32@~1.2.1:
|
||||
version "1.2.2"
|
||||
resolved "https://registry.npmmirror.com/crc-32/-/crc-32-1.2.2.tgz#3cad35a934b8bf71f25ca524b6da51fb7eace2ff"
|
||||
integrity sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==
|
||||
|
||||
cross-spawn@^5.0.1:
|
||||
version "5.1.0"
|
||||
resolved "https://registry.npmmirror.com/cross-spawn/-/cross-spawn-5.1.0.tgz"
|
||||
@@ -2997,6 +3025,13 @@ css-declaration-sorter@^6.3.1:
|
||||
resolved "https://registry.npmmirror.com/css-declaration-sorter/-/css-declaration-sorter-6.4.1.tgz"
|
||||
integrity sha512-rtdthzxKuyq6IzqX6jEcIzQF/YqccluefyCYheovBOLhFT/drQA9zj/UbRAa9J7C0o6EG6u3E6g+vKkay7/k3g==
|
||||
|
||||
css-line-break@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz"
|
||||
integrity sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==
|
||||
dependencies:
|
||||
utrie "^1.0.2"
|
||||
|
||||
css-loader@^6.5.0:
|
||||
version "6.8.1"
|
||||
resolved "https://registry.npmmirror.com/css-loader/-/css-loader-6.8.1.tgz"
|
||||
@@ -3897,6 +3932,11 @@ file-entry-cache@^6.0.1:
|
||||
dependencies:
|
||||
flat-cache "^3.0.4"
|
||||
|
||||
file-saver@^2.0.5:
|
||||
version "2.0.5"
|
||||
resolved "https://registry.npmmirror.com/file-saver/-/file-saver-2.0.5.tgz#d61cfe2ce059f414d899e9dd6d4107ee25670c38"
|
||||
integrity sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==
|
||||
|
||||
fill-range@^7.0.1:
|
||||
version "7.0.1"
|
||||
resolved "https://registry.npmmirror.com/fill-range/-/fill-range-7.0.1.tgz"
|
||||
@@ -3989,6 +4029,11 @@ forwarded@0.2.0:
|
||||
resolved "https://registry.npmmirror.com/forwarded/-/forwarded-0.2.0.tgz"
|
||||
integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==
|
||||
|
||||
frac@~1.1.2:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.npmmirror.com/frac/-/frac-1.1.2.tgz#3d74f7f6478c88a1b5020306d747dc6313c74d0b"
|
||||
integrity sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==
|
||||
|
||||
fraction.js@^4.2.0:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.npmmirror.com/fraction.js/-/fraction.js-4.2.0.tgz"
|
||||
@@ -4335,6 +4380,14 @@ html-webpack-plugin@^5.1.0:
|
||||
pretty-error "^4.0.0"
|
||||
tapable "^2.0.0"
|
||||
|
||||
html2canvas@^1.4.1:
|
||||
version "1.4.1"
|
||||
resolved "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz"
|
||||
integrity sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==
|
||||
dependencies:
|
||||
css-line-break "^2.1.0"
|
||||
text-segmentation "^1.0.3"
|
||||
|
||||
htmlparser2@^6.1.0:
|
||||
version "6.1.0"
|
||||
resolved "https://registry.npmmirror.com/htmlparser2/-/htmlparser2-6.1.0.tgz"
|
||||
@@ -6788,6 +6841,13 @@ sprintf-js@~1.0.2:
|
||||
resolved "https://registry.npmmirror.com/sprintf-js/-/sprintf-js-1.0.3.tgz"
|
||||
integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==
|
||||
|
||||
ssf@~0.11.2:
|
||||
version "0.11.2"
|
||||
resolved "https://registry.npmmirror.com/ssf/-/ssf-0.11.2.tgz#0b99698b237548d088fc43cdf2b70c1a7512c06c"
|
||||
integrity sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==
|
||||
dependencies:
|
||||
frac "~1.1.2"
|
||||
|
||||
ssri@^8.0.1:
|
||||
version "8.0.1"
|
||||
resolved "https://registry.npmmirror.com/ssri/-/ssri-8.0.1.tgz"
|
||||
@@ -7060,6 +7120,13 @@ terser@^5.10.0, terser@^5.16.8:
|
||||
commander "^2.20.0"
|
||||
source-map-support "~0.5.20"
|
||||
|
||||
text-segmentation@^1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz"
|
||||
integrity sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==
|
||||
dependencies:
|
||||
utrie "^1.0.2"
|
||||
|
||||
text-table@^0.2.0:
|
||||
version "0.2.0"
|
||||
resolved "https://registry.npmmirror.com/text-table/-/text-table-0.2.0.tgz"
|
||||
@@ -7341,6 +7408,13 @@ utils-merge@1.0.1:
|
||||
resolved "https://registry.npmmirror.com/utils-merge/-/utils-merge-1.0.1.tgz"
|
||||
integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==
|
||||
|
||||
utrie@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz"
|
||||
integrity sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==
|
||||
dependencies:
|
||||
base64-arraybuffer "^1.0.2"
|
||||
|
||||
uuid@^8.3.2:
|
||||
version "8.3.2"
|
||||
resolved "https://registry.npmmirror.com/uuid/-/uuid-8.3.2.tgz"
|
||||
@@ -7722,11 +7796,21 @@ window-size@0.1.0:
|
||||
resolved "https://registry.npmmirror.com/window-size/-/window-size-0.1.0.tgz"
|
||||
integrity sha512-1pTPQDKTdd61ozlKGNCjhNRd+KPmgLSGa3mZTHoOliaGcESD8G1PXhh7c1fgiPjVbNVfgy2Faw4BI8/m0cC8Mg==
|
||||
|
||||
wmf@~1.0.1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.npmmirror.com/wmf/-/wmf-1.0.2.tgz#7d19d621071a08c2bdc6b7e688a9c435298cc2da"
|
||||
integrity sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==
|
||||
|
||||
word-wrap@~1.2.3:
|
||||
version "1.2.5"
|
||||
resolved "https://registry.npmmirror.com/word-wrap/-/word-wrap-1.2.5.tgz"
|
||||
integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==
|
||||
|
||||
word@~0.3.0:
|
||||
version "0.3.0"
|
||||
resolved "https://registry.npmmirror.com/word/-/word-0.3.0.tgz#8542157e4f8e849f4a363a288992d47612db9961"
|
||||
integrity sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==
|
||||
|
||||
wordwrap@0.0.2:
|
||||
version "0.0.2"
|
||||
resolved "https://registry.npmmirror.com/wordwrap/-/wordwrap-0.0.2.tgz"
|
||||
@@ -7764,6 +7848,19 @@ ws@^8.13.0:
|
||||
resolved "https://registry.npmmirror.com/ws/-/ws-8.13.0.tgz"
|
||||
integrity sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==
|
||||
|
||||
xlsx@^0.18.5:
|
||||
version "0.18.5"
|
||||
resolved "https://registry.npmmirror.com/xlsx/-/xlsx-0.18.5.tgz#16711b9113c848076b8a177022799ad356eba7d0"
|
||||
integrity sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==
|
||||
dependencies:
|
||||
adler-32 "~1.3.0"
|
||||
cfb "~1.2.1"
|
||||
codepage "~1.15.0"
|
||||
crc-32 "~1.2.1"
|
||||
ssf "~0.11.2"
|
||||
wmf "~1.0.1"
|
||||
word "~0.3.0"
|
||||
|
||||
y18n@^5.0.5:
|
||||
version "5.0.8"
|
||||
resolved "https://registry.npmmirror.com/y18n/-/y18n-5.0.8.tgz"
|
||||
|
||||
Reference in New Issue
Block a user