Compare commits
125 Commits
ai-rob
...
b1d1f60f96
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b1d1f60f96 | ||
|
|
191edd1eb4 | ||
|
|
0cbe017a95 | ||
|
|
b1abecfb29 | ||
|
|
2511778c9f | ||
|
|
fea7848653 | ||
|
|
3cdaba63b7 | ||
|
|
5ece8b562f | ||
|
|
15614d9489 | ||
|
|
7b43c97f5f | ||
|
|
74043c55ae | ||
|
|
f69c86f92b | ||
|
|
c7cb7c103d | ||
|
|
1285b0644c | ||
|
|
b6e721826f | ||
|
|
0f6f894f84 | ||
|
|
0baccbf650 | ||
|
|
ffcebb2913 | ||
|
|
a2bbe798b8 | ||
|
|
57d58cdad3 | ||
|
|
b3c7dde44f | ||
|
|
3574f8ce83 | ||
|
|
11a9972329 | ||
|
|
56ee90ed30 | ||
|
|
e920251718 | ||
|
|
d38206a1a0 | ||
|
|
4bfb4c2d1a | ||
|
|
aa36ce497a | ||
|
|
81d4f10c14 | ||
|
|
fdac7fc7d3 | ||
|
|
bbde4e3f3f | ||
|
|
4b6e221369 | ||
|
|
b4c3e3796f | ||
|
|
6618242f7f | ||
|
|
8225f21d14 | ||
|
|
86f4256eb4 | ||
|
|
5a74b0d382 | ||
|
|
6261be7807 | ||
|
|
275f5f6abd | ||
|
|
244d84d45d | ||
|
|
8900853066 | ||
|
|
4f4f303867 | ||
|
|
05f63c7af5 | ||
|
|
49b9b2c280 | ||
|
|
d6e3d7bbe1 | ||
|
|
a51a0d49bc | ||
|
|
4d0cc14001 | ||
|
|
d763045c94 | ||
|
|
b4cbdce74a | ||
|
|
9d7ed6f701 | ||
|
|
f7530ed1f5 | ||
|
|
28264e43b5 | ||
|
|
432d4351d3 | ||
|
|
d9fe8dea7b | ||
|
|
441510a4e4 | ||
|
|
5a7058c036 | ||
|
|
5157d601cc | ||
|
|
649ddc2504 | ||
|
|
006f84ccbb | ||
|
|
2d14cb7c6d | ||
|
|
1ecf85475d | ||
|
|
9c2b6c434c | ||
|
|
90a3e60e76 | ||
|
|
4d8b597abf | ||
|
|
4a90536696 | ||
|
|
5e8b1ea682 | ||
|
|
25ba3eb387 | ||
|
|
0808f42ce7 | ||
|
|
6356004d74 | ||
|
|
9253427bcc | ||
|
|
10c5bce468 | ||
|
|
2c2538c828 | ||
|
|
2e1a84681d | ||
|
|
360803de94 | ||
|
|
5fb4a5fb6b | ||
| 98fa8fc150 | |||
|
|
c3ef37e184 | ||
|
|
f5c64d0800 | ||
|
|
fa9eba44cf | ||
|
|
45f727ed7e | ||
|
|
482391d6d3 | ||
|
|
845ceae3cd | ||
|
|
f7af9b6b25 | ||
|
|
a0cd09e6ed | ||
|
|
bc2403bea6 | ||
|
|
218f382c4a | ||
|
|
60c4b0d9c0 | ||
|
|
be762a6f23 | ||
|
|
81c81b3c2a | ||
|
|
66624fc77a | ||
|
|
d1c746be14 | ||
|
|
8e87162e94 | ||
|
|
cd08530b62 | ||
|
|
7eec4b50ce | ||
|
|
0047e3dbe7 | ||
|
|
21b754497b | ||
|
|
492e6b83ea | ||
|
|
eaea055f6c | ||
|
|
53e8d2da74 | ||
|
|
fc6cec2eca | ||
|
|
b304fb53a0 | ||
| f9d84526a2 | |||
|
|
4863fcb199 | ||
|
|
3db7e387f1 | ||
|
|
2e957ac485 | ||
|
|
0a7f8eb036 | ||
|
|
fa57f0fa99 | ||
|
|
3921daba27 | ||
|
|
15cd54a44e | ||
|
|
fe6fd6cfdc | ||
|
|
0016f7e5bc | ||
|
|
0e9d59b1eb | ||
|
|
66c89f71e1 | ||
|
|
9909a938ca | ||
|
|
eb518c412f | ||
|
|
af109bf3ad | ||
|
|
9c644627bc | ||
|
|
0522cadeee | ||
|
|
e52e62c1d5 | ||
|
|
17986a574b | ||
|
|
de0229419b | ||
|
|
af84e9fca6 | ||
|
|
0a1f6f1105 | ||
|
|
0076b54016 | ||
|
|
a26050de73 |
1
.gitignore
vendored
@@ -3,6 +3,7 @@ node_modules
|
||||
/dist
|
||||
/artifacts
|
||||
package-lock.json
|
||||
/node_modules
|
||||
|
||||
# local env files
|
||||
.env.local
|
||||
|
||||
62364
node_modules/vue-plugin-hiprint/dist/vue-plugin-hiprint.js
generated
vendored
Normal file
19
package.json
@@ -3,23 +3,34 @@
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "vue-cli-service --env.NODE_ENV=development build-watch --mode development",
|
||||
"dev": "vue-cli-service --env.NODE_ENV=development build-watch --mode development",
|
||||
"build": "vue-cli-service build"
|
||||
},
|
||||
"dependencies": {
|
||||
"@antv/g2plot": "^2.4.31",
|
||||
"@antv/g2plot": "^2.4.25",
|
||||
"@babel/standalone": "^7.25.8",
|
||||
"axios": "^1.4.0",
|
||||
"bi-vue-mindmap": "^0.6.12",
|
||||
"core-js": "^3.8.3",
|
||||
"crypto-js": "^4.0.0",
|
||||
"dayjs": "^1.11.9",
|
||||
"element-ui": "^2.15.13",
|
||||
"eval5": "^1.4.8",
|
||||
"file-saver": "^2.0.5",
|
||||
"html2canvas": "^1.4.1",
|
||||
"jsbarcode": "^3.11.6",
|
||||
"query-string": "^9.0.0",
|
||||
"spark-md5": "^3.0.2",
|
||||
"v-viewer": "^1.6.4",
|
||||
"vue": "^2.6.14",
|
||||
"vue-cropper": "^0.6.4",
|
||||
"vue-json-excel": "^0.3.0",
|
||||
"vue-plugin-hiprint": "^0.0.56",
|
||||
"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",
|
||||
@@ -31,7 +42,7 @@
|
||||
"eslint": "^7.32.0",
|
||||
"eslint-plugin-vue": "^8.0.3",
|
||||
"javascript-obfuscator": "2.6.0",
|
||||
"sass": "^1.68.0",
|
||||
"sass": "1.32.13",
|
||||
"sass-loader": "^7.3.1",
|
||||
"vue-cli-plugin-chrome-extension-cli": "~1.1.4",
|
||||
"vue-template-compiler": "^2.6.14",
|
||||
|
||||
383
public/css/print-lock.css
Normal file
@@ -0,0 +1,383 @@
|
||||
@media print {
|
||||
body {
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
}
|
||||
}
|
||||
|
||||
@page {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.hiprint-printPaper * {
|
||||
box-sizing: border-box;
|
||||
-moz-box-sizing: border-box; /* Firefox */
|
||||
-webkit-box-sizing: border-box; /* Safari */
|
||||
}
|
||||
|
||||
.hiprint-printPaper *:focus {
|
||||
outline: -webkit-focus-ring-color auto 0px;
|
||||
}
|
||||
|
||||
.hiprint-printPaper {
|
||||
position: relative;
|
||||
padding: 0 0 0 0;
|
||||
page-break-after: always;
|
||||
-webkit-user-select: none; /* Chrome/Safari/Opera */
|
||||
-moz-user-select: none; /* Firefox */
|
||||
user-select: none;
|
||||
overflow-x: hidden;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.hiprint-printPaper .hiprint-printPaper-content {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* 火狐浏览器打印 第一页过后 重叠问题 */
|
||||
@-moz-document url-prefix() {
|
||||
.hiprint-printPaper .hiprint-printPaper-content {
|
||||
position: relative;
|
||||
margin-top: 20px;
|
||||
top: -20px
|
||||
}
|
||||
}
|
||||
|
||||
.hiprint-printPaper.design {
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
|
||||
.hiprint-printTemplate .hiprint-printPanel {
|
||||
page-break-after: always;
|
||||
}
|
||||
|
||||
.hiprint-printPaper, hiprint-printPanel {
|
||||
box-sizing: border-box;
|
||||
border: 0px;
|
||||
}
|
||||
|
||||
.hiprint-printPanel .hiprint-printPaper:last-child {
|
||||
page-break-after: avoid;
|
||||
}
|
||||
|
||||
.hiprint-printTemplate .hiprint-printPanel:last-child {
|
||||
page-break-after: avoid;
|
||||
}
|
||||
|
||||
.hiprint-printPaper .hideheaderLinetarget {
|
||||
border-top: 0px dashed rgb(201, 190, 190) !important;
|
||||
}
|
||||
|
||||
.hiprint-printPaper .hidefooterLinetarget {
|
||||
border-top: 0px dashed rgb(201, 190, 190) !important;
|
||||
}
|
||||
|
||||
.hiprint-printPaper.design {
|
||||
border: 1px dashed rgba(170, 170, 170, 0.7);
|
||||
}
|
||||
|
||||
.design .hiprint-printElement-table-content, .design .hiprint-printElement-longText-content {
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.design .resize-panel {
|
||||
box-sizing: border-box;
|
||||
border: 1px dotted;
|
||||
}
|
||||
|
||||
.hiprint-printElement-text {
|
||||
background-color: transparent;
|
||||
background-repeat: repeat;
|
||||
padding: 0 0 0 0;
|
||||
border: 0.75pt none rgb(0, 0, 0);
|
||||
direction: ltr;
|
||||
font-family: 'SimSun';
|
||||
font-size: 9pt;
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
padding-bottom: 0pt;
|
||||
padding-left: 0pt;
|
||||
padding-right: 0pt;
|
||||
padding-top: 0pt;
|
||||
text-align: left;
|
||||
text-decoration: none;
|
||||
line-height: 9.75pt;
|
||||
box-sizing: border-box;
|
||||
word-wrap: break-word;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.design .hiprint-printElement-text-content {
|
||||
border: 1px dashed rgb(206, 188, 188);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.hiprint-printElement-longText {
|
||||
background-color: transparent;
|
||||
background-repeat: repeat;
|
||||
border: 0.75pt none rgb(0, 0, 0);
|
||||
direction: ltr;
|
||||
font-family: 'SimSun';
|
||||
font-size: 9pt;
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
padding-bottom: 0pt;
|
||||
padding-left: 0pt;
|
||||
padding-right: 0pt;
|
||||
padding-top: 0pt;
|
||||
text-align: left;
|
||||
text-decoration: none;
|
||||
line-height: 9.75pt;
|
||||
box-sizing: border-box;
|
||||
word-wrap: break-word;
|
||||
word-break: break-all;
|
||||
/*white-space: pre-wrap*/
|
||||
}
|
||||
|
||||
|
||||
.hiprint-printElement-table {
|
||||
background-color: transparent;
|
||||
background-repeat: repeat;
|
||||
color: rgb(0, 0, 0);
|
||||
border-color: rgb(0, 0, 0);
|
||||
border-style: none;
|
||||
direction: ltr;
|
||||
font-family: 'SimSun';
|
||||
font-size: 9pt;
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
padding-bottom: 0pt;
|
||||
padding-left: 0pt;
|
||||
padding-right: 0pt;
|
||||
padding-top: 0pt;
|
||||
text-align: left;
|
||||
text-decoration: none;
|
||||
padding: 0 0 0 0;
|
||||
box-sizing: border-box;
|
||||
line-height: 9.75pt;
|
||||
}
|
||||
|
||||
.hiprint-printElement-table thead {
|
||||
background: #e8e8e8;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
table.hiprint-printElement-tableTarget {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.hiprint-printElement-tableTarget, .hiprint-printElement-tableTarget tr, .hiprint-printElement-tableTarget td {
|
||||
border-color: rgb(0, 0, 0);
|
||||
/*border-style: none;*/
|
||||
/*border: 1px solid rgb(0, 0, 0);*/
|
||||
font-weight: normal;
|
||||
direction: ltr;
|
||||
padding-bottom: 0pt;
|
||||
padding-left: 4pt;
|
||||
padding-right: 4pt;
|
||||
padding-top: 0pt;
|
||||
text-decoration: none;
|
||||
vertical-align: middle;
|
||||
box-sizing: border-box;
|
||||
word-wrap: break-word;
|
||||
word-break: break-all;
|
||||
/*line-height: 9.75pt;
|
||||
font-size: 9pt;*/
|
||||
}
|
||||
|
||||
.hiprint-printElement-tableTarget-border-all {
|
||||
border: 1px solid;
|
||||
}
|
||||
.hiprint-printElement-tableTarget-border-none {
|
||||
border: 0px solid;
|
||||
}
|
||||
.hiprint-printElement-tableTarget-border-lr {
|
||||
border-left: 1px solid;
|
||||
border-right: 1px solid;
|
||||
}
|
||||
.hiprint-printElement-tableTarget-border-left {
|
||||
border-left: 1px solid;
|
||||
}
|
||||
.hiprint-printElement-tableTarget-border-right {
|
||||
border-right: 1px solid;
|
||||
}
|
||||
.hiprint-printElement-tableTarget-border-tb {
|
||||
border-top: 1px solid;
|
||||
border-bottom: 1px solid;
|
||||
}
|
||||
.hiprint-printElement-tableTarget-border-top {
|
||||
border-top: 1px solid;
|
||||
}
|
||||
.hiprint-printElement-tableTarget-border-bottom {
|
||||
border-bottom: 1px solid;
|
||||
}
|
||||
|
||||
.hiprint-printElement-tableTarget-border-td-none td {
|
||||
border: 0px solid;
|
||||
}
|
||||
.hiprint-printElement-tableTarget-border-td-all td:not(:nth-last-child(-n+2)) {
|
||||
border-right: 1px solid;
|
||||
}
|
||||
.hiprint-printElement-tableTarget-border-td-all td:last-child {
|
||||
border-left: 1px solid;
|
||||
}
|
||||
.hiprint-printElement-tableTarget-border-td-all td:last-child:first-child {
|
||||
border-left: none;
|
||||
}
|
||||
|
||||
/*.hiprint-printElement-tableTarget tr,*/
|
||||
.hiprint-printElement-tableTarget td {
|
||||
height: 18pt;
|
||||
}
|
||||
|
||||
.hiprint-printPaper .hiprint-paperNumber {
|
||||
font-size: 9pt;
|
||||
}
|
||||
|
||||
.design .hiprint-printElement-table-handle {
|
||||
position: absolute;
|
||||
height: 21pt;
|
||||
width: 21pt;
|
||||
background: red;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.hiprint-printPaper .hiprint-paperNumber-disabled {
|
||||
float: right !important;
|
||||
right: 0 !important;
|
||||
color: gainsboro !important;
|
||||
}
|
||||
|
||||
.hiprint-printElement-vline, .hiprint-printElement-hline {
|
||||
border: 0px none rgb(0, 0, 0);
|
||||
|
||||
}
|
||||
|
||||
.hiprint-printElement-vline {
|
||||
border-left: 0.75pt solid #000;
|
||||
border-right: 0px none rgb(0, 0, 0) !important;
|
||||
border-bottom: 0px none rgb(0, 0, 0) !important;
|
||||
border-top: 0px none rgb(0, 0, 0) !important;
|
||||
}
|
||||
|
||||
.hiprint-printElement-hline {
|
||||
border-top: 0.75pt solid #000;
|
||||
border-right: 0px none rgb(0, 0, 0) !important;
|
||||
border-bottom: 0px none rgb(0, 0, 0) !important;
|
||||
border-left: 0px none rgb(0, 0, 0) !important;
|
||||
}
|
||||
|
||||
.hiprint-printElement-oval, .hiprint-printElement-rect {
|
||||
border: 0.75pt solid #000;
|
||||
}
|
||||
|
||||
.hiprint-text-content-middle {
|
||||
}
|
||||
|
||||
.hiprint-text-content-middle > div {
|
||||
display: grid;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.hiprint-text-content-bottom {
|
||||
}
|
||||
|
||||
.hiprint-text-content-bottom > div {
|
||||
display: grid;
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
.hiprint-text-content-wrap {
|
||||
}
|
||||
|
||||
.hiprint-text-content-wrap .hiprint-text-content-wrap-nowrap {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.hiprint-text-content-wrap .hiprint-text-content-wrap-clip {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: clip;
|
||||
}
|
||||
|
||||
.hiprint-text-content-wrap .hiprint-text-content-wrap-ellipsis {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
/*hi-grid-row */
|
||||
.hi-grid-row {
|
||||
position: relative;
|
||||
height: auto;
|
||||
margin-right: 0;
|
||||
margin-left: 0;
|
||||
zoom: 1;
|
||||
display: block;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.hi-grid-row::after, .hi-grid-row::before {
|
||||
display: table;
|
||||
content: '';
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.hi-grid-col {
|
||||
display: block;
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
float: left;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.table-grid-row {
|
||||
margin-left: -0pt;
|
||||
margin-right: -0pt;
|
||||
}
|
||||
|
||||
.tableGridColumnsGutterRow {
|
||||
padding-left: 0pt;
|
||||
padding-right: 0pt;
|
||||
}
|
||||
|
||||
.hiprint-gridColumnsFooter {
|
||||
text-align: left;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.temuBarCode {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 10pt 10pt;
|
||||
border: 2pt solid #000;
|
||||
}
|
||||
|
||||
.temuBarCode-code {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.temuBarCode-code svg {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.temuBarCode-top,
|
||||
.temuBarCode-bottom {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 94%;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.temuBarCode-middle {
|
||||
width: 88%;
|
||||
height: 60%;
|
||||
}
|
||||
@@ -1,17 +1,57 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
||||
<title>TEMU助手</title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>
|
||||
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
|
||||
</noscript>
|
||||
<div id="app"></div>
|
||||
<!-- built files will be auto injected -->
|
||||
</body>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
||||
<link rel="stylesheet" type="text/css" media="print" href="<%= BASE_URL %>css/print-lock.css">
|
||||
<title>TEMU助手</title>
|
||||
<style>
|
||||
.temuBarCode {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 10pt 10pt;
|
||||
border: 2pt solid #000;
|
||||
}
|
||||
|
||||
.temuBarCode-code {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.temuBarCode-code svg {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.temuBarCode-top,
|
||||
.temuBarCode-bottom {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 94%;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.temuBarCode-middle {
|
||||
width: 88%;
|
||||
height: 60%;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<noscript>
|
||||
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled.
|
||||
Please enable it to continue.</strong>
|
||||
</noscript>
|
||||
<div id="app"></div>
|
||||
<!-- built files will be auto injected -->
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
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.us/item/')) {
|
||||
if (window.location.href.startsWith('https://www.aliexpress.com/item/')) {
|
||||
const popup = document.createElement("div")
|
||||
popup.innerText = "下载图片"
|
||||
const styles = {
|
||||
@@ -148,7 +153,7 @@ function init() {
|
||||
|
||||
var imgObjList = document.querySelectorAll('div.aplus-v2 img')
|
||||
for (var i = 0; i < imgObjList.length; i++) {
|
||||
baseList.push({type: 0, index: i+1, src: imgObjList[i].getAttribute('data-src'), folder: imgsDetail})
|
||||
baseList.push({type: 0, index: i+1, src: imgObjList[i].getAttribute('data-src') || imgObjList[i].src, folder: imgsDetail})
|
||||
}
|
||||
|
||||
for (var k = 0; k < baseList.length; k++) {
|
||||
@@ -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)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
390
public/js/temuSeller.js
Normal file
@@ -0,0 +1,390 @@
|
||||
function matchTemuDomain(url) {
|
||||
const urlPattern = /https:\/\/([\da-z\.-]+)\.kuajingmaihuo\.com\//
|
||||
return urlPattern.test(url);
|
||||
}
|
||||
|
||||
function init() {
|
||||
if (matchTemuDomain(window.location.href)) {
|
||||
let j = 0
|
||||
let timer = setInterval(() => {
|
||||
let models = document.querySelectorAll('div[class^="MDL_header"]')
|
||||
let flag = false
|
||||
for (let i = 0; i < models.length; i++) {
|
||||
if (models[i].textContent.includes("商品降价提醒") || models[i].textContent.includes("降价,提升竞争力,避免限制备货")) {
|
||||
const popup = document.createElement("div")
|
||||
popup.innerText = "拒绝调价"
|
||||
const styles = {
|
||||
padding: "8px",
|
||||
background: "#fb7701",
|
||||
color: "#fff",
|
||||
display: 'inline',
|
||||
borderRadius: "8px",
|
||||
cursor: "pointer"
|
||||
}
|
||||
for (const e in styles) {
|
||||
popup.style[e] = styles[e]
|
||||
}
|
||||
models[i].appendChild(popup)
|
||||
popup.addEventListener('click', async () => {
|
||||
let tbodyObj = models[i].parentElement.querySelector('tbody')
|
||||
let trList = tbodyObj.querySelectorAll('tr')
|
||||
for (let i = 0; i < trList.length; i++) {
|
||||
let tdObj = trList[i].querySelector('td:last-child')
|
||||
let firstLabelObj = tdObj.querySelector('div label:first-child')
|
||||
if (firstLabelObj.getAttribute("data-checked")) {
|
||||
let labelObj = tdObj.querySelector('div label:nth-child(2)')
|
||||
let radioObj = labelObj.querySelector('div[class^="RD_radioWrapper"]')
|
||||
// await sleepSync(50)
|
||||
radioObj.click()
|
||||
}
|
||||
}
|
||||
})
|
||||
flag = true
|
||||
}
|
||||
}
|
||||
|
||||
const regex = /price-adjust-confirm[^\n]+content/
|
||||
let modelsAll = document.querySelectorAll('div[class*="price-adjust-confirm"]')
|
||||
const results = Array.from(modelsAll).filter(item => regex.test(item.getAttribute('class')))
|
||||
|
||||
for (let i = 0; i < results.length; i++) {
|
||||
let tipsObj = results[i].querySelector('div[class*="_tips"]')
|
||||
let spanObj = tipsObj.querySelector('div span:last-child')
|
||||
if (spanObj) {
|
||||
const popup = document.createElement("div")
|
||||
popup.innerText = "拒绝调价"
|
||||
const styles = {
|
||||
padding: "8px",
|
||||
background: "#fb7701",
|
||||
color: "#fff",
|
||||
display: 'inline',
|
||||
borderRadius: "8px",
|
||||
cursor: "pointer"
|
||||
}
|
||||
for (const e in styles) {
|
||||
popup.style[e] = styles[e]
|
||||
}
|
||||
spanObj.appendChild(popup)
|
||||
|
||||
popup.addEventListener('click', async () => {
|
||||
let tbodyObj = results[i].querySelector('tbody')
|
||||
let trList = tbodyObj.querySelectorAll('tr')
|
||||
for (let i = 0; i < trList.length; i++) {
|
||||
let tdObj = trList[i].querySelector('td:last-child')
|
||||
let firstLabelObj = tdObj.querySelector('div label:first-child')
|
||||
if (firstLabelObj.getAttribute("data-checked")) {
|
||||
let labelObj = tdObj.querySelector('div label:nth-child(2)')
|
||||
let radioObj = labelObj.querySelector('div[class^="RD_radioWrapper"]')
|
||||
// await sleepSync(50)
|
||||
radioObj.click()
|
||||
}
|
||||
}
|
||||
})
|
||||
flag = true
|
||||
}
|
||||
}
|
||||
|
||||
let models2 = document.querySelectorAll('div[class^="modal-content_platBanner"]')
|
||||
for (let i = 0; i < models2.length; i++) {
|
||||
let tipsObj = models2[i].parentElement.querySelector('div[class^="modal-content_content"]')
|
||||
let spanObj = tipsObj.querySelector('div span:last-child')
|
||||
if (spanObj) {
|
||||
const popup = document.createElement("div")
|
||||
popup.innerText = "拒绝调价"
|
||||
const styles = {
|
||||
padding: "8px",
|
||||
background: "#fb7701",
|
||||
color: "#fff",
|
||||
display: 'inline',
|
||||
borderRadius: "8px",
|
||||
cursor: "pointer"
|
||||
}
|
||||
for (const e in styles) {
|
||||
popup.style[e] = styles[e]
|
||||
}
|
||||
spanObj.appendChild(popup)
|
||||
|
||||
popup.addEventListener('click', async () => {
|
||||
let tbodyObj = models2[i].parentElement.querySelector('tbody')
|
||||
let trList = tbodyObj.querySelectorAll('tr')
|
||||
for (let i = 0; i < trList.length; i++) {
|
||||
let tdObj = trList[i].querySelector('td:last-child')
|
||||
let firstLabelObj = tdObj.querySelector('div label:first-child')
|
||||
if (firstLabelObj && firstLabelObj.getAttribute("data-checked")) {
|
||||
let labelObj = tdObj.querySelector('div label:nth-child(2)')
|
||||
let radioObj = labelObj.querySelector('div[class^="RD_radioWrapper"]')
|
||||
// await sleepSync(50)
|
||||
radioObj.click()
|
||||
}
|
||||
}
|
||||
})
|
||||
flag = true
|
||||
}
|
||||
}
|
||||
|
||||
let models3 = document.querySelectorAll('div[class^="modal-content_content"]')
|
||||
for (let i = 0; i < models3.length; i++) {
|
||||
let tipsObj = models3[i].parentElement.querySelector('div[class^="modal-content_content"]')
|
||||
let spanObj = tipsObj.querySelector('div span:last-child')
|
||||
if (spanObj) {
|
||||
const popup = document.createElement("div")
|
||||
popup.innerText = "拒绝调价"
|
||||
const styles = {
|
||||
padding: "8px",
|
||||
background: "#fb7701",
|
||||
color: "#fff",
|
||||
display: 'inline',
|
||||
borderRadius: "8px",
|
||||
cursor: "pointer"
|
||||
}
|
||||
for (const e in styles) {
|
||||
popup.style[e] = styles[e]
|
||||
}
|
||||
spanObj.appendChild(popup)
|
||||
|
||||
popup.addEventListener('click', async () => {
|
||||
let tbodyObj = models3[i].parentElement.querySelector('tbody')
|
||||
let trList = tbodyObj.querySelectorAll('tr')
|
||||
for (let i = 0; i < trList.length; i++) {
|
||||
let tdObj = trList[i].querySelector('td:last-child')
|
||||
let firstLabelObj = tdObj.querySelector('div label:first-child')
|
||||
if (firstLabelObj && firstLabelObj.getAttribute("data-checked")) {
|
||||
let labelObj = tdObj.querySelector('div label:nth-child(2)')
|
||||
let radioObj = labelObj.querySelector('div[class^="RD_radioWrapper"]')
|
||||
// await sleepSync(50)
|
||||
radioObj.click()
|
||||
}
|
||||
}
|
||||
})
|
||||
flag = true
|
||||
}
|
||||
}
|
||||
|
||||
/*let models3 = document.querySelectorAll('div[class^="price-adjust-confirm-new_content"]')
|
||||
for (let i = 0; i < models3.length; i++) {
|
||||
let tipsObj = models3[i].querySelector('div[class^="price-adjust-confirm-new_tips"]')
|
||||
let spanObj = tipsObj.querySelector('div span:last-child')
|
||||
if (spanObj) {
|
||||
const popup = document.createElement("div")
|
||||
popup.innerText = "拒绝调价"
|
||||
const styles = {
|
||||
padding: "8px",
|
||||
background: "#fb7701",
|
||||
color: "#fff",
|
||||
display: 'inline',
|
||||
borderRadius: "8px",
|
||||
cursor: "pointer"
|
||||
}
|
||||
for (const e in styles) {
|
||||
popup.style[e] = styles[e]
|
||||
}
|
||||
spanObj.appendChild(popup)
|
||||
|
||||
popup.addEventListener('click', async () => {
|
||||
let tbodyObj = models3[i].querySelector('tbody')
|
||||
let trList = tbodyObj.querySelectorAll('tr')
|
||||
for (let i = 0; i < trList.length; i++) {
|
||||
let tdObj = trList[i].querySelector('td:last-child')
|
||||
let firstLabelObj = tdObj.querySelector('div label:first-child')
|
||||
if (firstLabelObj.getAttribute("data-checked")) {
|
||||
let labelObj = tdObj.querySelector('div label:nth-child(2)')
|
||||
let radioObj = labelObj.querySelector('div[class^="RD_radioWrapper"]')
|
||||
// await sleepSync(50)
|
||||
radioObj.click()
|
||||
}
|
||||
}
|
||||
})
|
||||
flag = true
|
||||
}
|
||||
}
|
||||
|
||||
let models4 = document.querySelectorAll('div[class^="price-adjust-confirm-system-old_contentWrp"]')
|
||||
for (let i = 0; i < models4.length; i++) {
|
||||
let tipsObj = models4[i].querySelector('div[class^="price-adjust-confirm-system-old_tips"]')
|
||||
let spanObj = tipsObj.querySelector('div span:last-child')
|
||||
if (spanObj) {
|
||||
const popup = document.createElement("div")
|
||||
popup.innerText = "拒绝调价"
|
||||
const styles = {
|
||||
padding: "8px",
|
||||
background: "#fb7701",
|
||||
color: "#fff",
|
||||
display: 'inline',
|
||||
borderRadius: "8px",
|
||||
cursor: "pointer"
|
||||
}
|
||||
for (const e in styles) {
|
||||
popup.style[e] = styles[e]
|
||||
}
|
||||
spanObj.appendChild(popup)
|
||||
|
||||
popup.addEventListener('click', async () => {
|
||||
let tbodyObj = models4[i].querySelector('tbody')
|
||||
let trList = tbodyObj.querySelectorAll('tr')
|
||||
for (let i = 0; i < trList.length; i++) {
|
||||
let tdObj = trList[i].querySelector('td:last-child')
|
||||
let firstLabelObj = tdObj.querySelector('div label:first-child')
|
||||
if (firstLabelObj.getAttribute("data-checked")) {
|
||||
let labelObj = tdObj.querySelector('div label:nth-child(2)')
|
||||
let radioObj = labelObj.querySelector('div[class^="RD_radioWrapper"]')
|
||||
// await sleepSync(50)
|
||||
radioObj.click()
|
||||
}
|
||||
}
|
||||
})
|
||||
flag = true
|
||||
}
|
||||
}
|
||||
|
||||
let models5 = document.querySelectorAll('div[class^="new-price-adjust-confirm_content"]')
|
||||
for (let i = 0; i < models5.length; i++) {
|
||||
let tipsObj = models5[i].querySelector('div[class^="new-price-adjust-confirm_tips"]')
|
||||
let spanObj = tipsObj.querySelector('div span:last-child')
|
||||
if (spanObj) {
|
||||
const popup = document.createElement("div")
|
||||
popup.innerText = "拒绝调价"
|
||||
const styles = {
|
||||
padding: "8px",
|
||||
background: "#fb7701",
|
||||
color: "#fff",
|
||||
display: 'inline',
|
||||
borderRadius: "8px",
|
||||
cursor: "pointer"
|
||||
}
|
||||
for (const e in styles) {
|
||||
popup.style[e] = styles[e]
|
||||
}
|
||||
spanObj.appendChild(popup)
|
||||
|
||||
popup.addEventListener('click', async () => {
|
||||
let tbodyObj = models5[i].querySelector('tbody')
|
||||
let trList = tbodyObj.querySelectorAll('tr')
|
||||
for (let i = 0; i < trList.length; i++) {
|
||||
let tdObj = trList[i].querySelector('td:last-child')
|
||||
let firstLabelObj = tdObj.querySelector('div label:first-child')
|
||||
if (firstLabelObj.getAttribute("data-checked")) {
|
||||
let labelObj = tdObj.querySelector('div label:nth-child(2)')
|
||||
let radioObj = labelObj.querySelector('div[class^="RD_radioWrapper"]')
|
||||
// await sleepSync(50)
|
||||
radioObj.click()
|
||||
}
|
||||
}
|
||||
})
|
||||
flag = true
|
||||
}
|
||||
}
|
||||
let models6 = document.querySelectorAll('div[class^="grape-price-adjust-confirm_content"]')
|
||||
for (let i = 0; i < models6.length; i++) {
|
||||
let tipsObj = models6[i].querySelector('div[class^="grape-price-adjust-confirm_tips"]')
|
||||
let spanObj = tipsObj.querySelector('div span:last-child')
|
||||
if (spanObj) {
|
||||
const popup = document.createElement("div")
|
||||
popup.innerText = "拒绝调价"
|
||||
const styles = {
|
||||
padding: "8px",
|
||||
background: "#fb7701",
|
||||
color: "#fff",
|
||||
display: 'inline',
|
||||
borderRadius: "8px",
|
||||
cursor: "pointer"
|
||||
}
|
||||
for (const e in styles) {
|
||||
popup.style[e] = styles[e]
|
||||
}
|
||||
spanObj.appendChild(popup)
|
||||
|
||||
popup.addEventListener('click', async () => {
|
||||
let tbodyObj = models6[i].querySelector('tbody')
|
||||
let trList = tbodyObj.querySelectorAll('tr')
|
||||
for (let i = 0; i < trList.length; i++) {
|
||||
let tdObj = trList[i].querySelector('td:last-child')
|
||||
let firstLabelObj = tdObj.querySelector('div label:first-child')
|
||||
if (firstLabelObj.getAttribute("data-checked")) {
|
||||
let labelObj = tdObj.querySelector('div label:nth-child(2)')
|
||||
let radioObj = labelObj.querySelector('div[class^="RD_radioWrapper"]')
|
||||
// await sleepSync(50)
|
||||
radioObj.click()
|
||||
}
|
||||
}
|
||||
})
|
||||
flag = true
|
||||
}
|
||||
}*/
|
||||
if (flag) {
|
||||
clearInterval(timer)
|
||||
} else {
|
||||
j++
|
||||
if (j == 10) {
|
||||
clearInterval(timer)
|
||||
}
|
||||
}
|
||||
}, 3000)
|
||||
|
||||
// document.body.appendChild(popup)
|
||||
}
|
||||
}
|
||||
/*
|
||||
function createElement() {
|
||||
const popup = document.createElement("div")
|
||||
popup.innerText = "拒绝调价"
|
||||
const styles = {
|
||||
position: "fixed",
|
||||
right: '10px',
|
||||
top: '60px',
|
||||
zIndex: 999999,
|
||||
padding: "8px",
|
||||
background: "#409EFF",
|
||||
color: "#fff",
|
||||
borderRadius: "8px",
|
||||
cursor: "pointer"
|
||||
}
|
||||
for (const e in styles) {
|
||||
popup.style[e] = styles[e]
|
||||
}
|
||||
popup.addEventListener('click', async () => {
|
||||
let divObj1 = document.querySelector('div[class^="price-adjust-confirm-system_contentWrp"]')
|
||||
if (divObj1) {
|
||||
let tbodyObj = divObj1.querySelector('tbody')
|
||||
let trList = tbodyObj.querySelectorAll('tr')
|
||||
for (let i = 0; i < trList.length; i++) {
|
||||
let tdObj = trList[i].querySelector('td:last-child')
|
||||
let labelObj = tdObj.querySelector('div label:last-child')
|
||||
let radioObj = labelObj.querySelector('div[class^="RD_radioWrapper"]')
|
||||
// await sleepSync(50)
|
||||
radioObj.click()
|
||||
}
|
||||
}
|
||||
let divObj2 = document.querySelector('div[class^="price-adjust-confirm_header"]')
|
||||
if (divObj2) {
|
||||
let divObj = divObj2.nextElementSibling
|
||||
let tbodyObj = divObj.querySelector('tbody')
|
||||
let trList = tbodyObj.querySelectorAll('tr')
|
||||
for (let i = 0; i < trList.length; i++) {
|
||||
let tdObj = trList[i].querySelector('td:last-child')
|
||||
let labelObj = tdObj.querySelector('div label:last-child')
|
||||
//let radioObj = labelObj.querySelector("[type='radio']")
|
||||
// await sleepSync(50)
|
||||
let radioObj = labelObj.querySelector('div[class^="RD_radioWrapper"]')
|
||||
radioObj.click()
|
||||
}
|
||||
}
|
||||
let divObj3 = document.querySelector('div[class^="price-adjust-confirm-new_banner"]')
|
||||
if (divObj3) {
|
||||
let divObj = divObj3.nextElementSibling
|
||||
let tbodyObj = divObj.querySelector('tbody')
|
||||
let trList = tbodyObj.querySelectorAll('tr')
|
||||
for (let i = 0; i < trList.length; i++) {
|
||||
let tdObj = trList[i].querySelector('td:last-child')
|
||||
let labelObj = tdObj.querySelector('div label:last-child')
|
||||
//let radioObj = labelObj.querySelector("[type='radio']")
|
||||
// await sleepSync(50)
|
||||
let radioObj = labelObj.querySelector('div[class^="RD_radioWrapper"]')
|
||||
radioObj.click()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return popup
|
||||
}
|
||||
*/
|
||||
init()
|
||||
8
public/js/temuSellerContent.js
Normal file
@@ -0,0 +1,8 @@
|
||||
function injectScript(file, node) {
|
||||
var th = document.getElementsByTagName(node)[0];
|
||||
var s = document.createElement('script');
|
||||
s.setAttribute('type', 'text/javascript');
|
||||
s.setAttribute('src', file);
|
||||
th.appendChild(s);
|
||||
}
|
||||
injectScript( chrome.runtime.getURL('/js/temuSeller.js'), 'body');
|
||||
@@ -8,17 +8,17 @@
|
||||
{
|
||||
"header": "Origin",
|
||||
"operation": "set",
|
||||
"value": "https://kuajing.pinduoduo.com"
|
||||
"value": "https://seller.kuajingmaihuo.com"
|
||||
},
|
||||
{
|
||||
"header": "Referer",
|
||||
"operation": "set",
|
||||
"value": "https://kuajing.pinduoduo.com/main/order-manage"
|
||||
"value": "https://seller.kuajingmaihuo.com/main/order-manage"
|
||||
}
|
||||
]
|
||||
},
|
||||
"condition": {
|
||||
"urlFilter": "||kuajing.pinduoduo.com"
|
||||
"urlFilter": "||seller.kuajingmaihuo.com"
|
||||
}
|
||||
}
|
||||
]
|
||||
24
public/rules_10.json
Normal file
@@ -0,0 +1,24 @@
|
||||
[
|
||||
{
|
||||
"id": 21,
|
||||
"priority": 1,
|
||||
"action": {
|
||||
"type": "modifyHeaders",
|
||||
"requestHeaders": [
|
||||
{
|
||||
"header": "Origin",
|
||||
"operation": "set",
|
||||
"value": "https://oms.goodcang.com/"
|
||||
},
|
||||
{
|
||||
"header": "Referer",
|
||||
"operation": "set",
|
||||
"value": "https://oms.goodcang.com/"
|
||||
}
|
||||
]
|
||||
},
|
||||
"condition": {
|
||||
"urlFilter": "||oms.goodcang.com"
|
||||
}
|
||||
}
|
||||
]
|
||||
24
public/rules_11.json
Normal file
@@ -0,0 +1,24 @@
|
||||
[
|
||||
{
|
||||
"id": 22,
|
||||
"priority": 1,
|
||||
"action": {
|
||||
"type": "modifyHeaders",
|
||||
"requestHeaders": [
|
||||
{
|
||||
"header": "Origin",
|
||||
"operation": "set",
|
||||
"value": "https://sellerhub.shein.com/"
|
||||
},
|
||||
{
|
||||
"header": "Referer",
|
||||
"operation": "set",
|
||||
"value": "https://sellerhub.shein.com/"
|
||||
}
|
||||
]
|
||||
},
|
||||
"condition": {
|
||||
"urlFilter": "||sellerhub.shein.com"
|
||||
}
|
||||
}
|
||||
]
|
||||
24
public/rules_12.json
Normal file
@@ -0,0 +1,24 @@
|
||||
[
|
||||
{
|
||||
"id": 23,
|
||||
"priority": 1,
|
||||
"action": {
|
||||
"type": "modifyHeaders",
|
||||
"requestHeaders": [
|
||||
{
|
||||
"header": "Origin",
|
||||
"operation": "set",
|
||||
"value": "http://xc.rqlis.com:888"
|
||||
},
|
||||
{
|
||||
"header": "Host",
|
||||
"operation": "set",
|
||||
"value": "xc.rqlis.com:888"
|
||||
}
|
||||
]
|
||||
},
|
||||
"condition": {
|
||||
"urlFilter": "||xc.rqlis.com"
|
||||
}
|
||||
}
|
||||
]
|
||||
24
public/rules_2.json
Normal file
@@ -0,0 +1,24 @@
|
||||
[
|
||||
{
|
||||
"id": 13,
|
||||
"priority": 1,
|
||||
"action": {
|
||||
"type": "modifyHeaders",
|
||||
"requestHeaders": [
|
||||
{
|
||||
"header": "Origin",
|
||||
"operation": "set",
|
||||
"value": "https://www.temu.com"
|
||||
},
|
||||
{
|
||||
"header": "Referer",
|
||||
"operation": "set",
|
||||
"value": "https://www.temu.com"
|
||||
}
|
||||
]
|
||||
},
|
||||
"condition": {
|
||||
"urlFilter": "||www.temu.com"
|
||||
}
|
||||
}
|
||||
]
|
||||
24
public/rules_3.json
Normal file
@@ -0,0 +1,24 @@
|
||||
[
|
||||
{
|
||||
"id": 14,
|
||||
"priority": 1,
|
||||
"action": {
|
||||
"type": "modifyHeaders",
|
||||
"requestHeaders": [
|
||||
{
|
||||
"header": "Origin",
|
||||
"operation": "set",
|
||||
"value": "https://www.aliexpress.com"
|
||||
},
|
||||
{
|
||||
"header": "Referer",
|
||||
"operation": "set",
|
||||
"value": "https://www.aliexpress.com"
|
||||
}
|
||||
]
|
||||
},
|
||||
"condition": {
|
||||
"urlFilter": "||aeproductsourcesite.alicdn.com"
|
||||
}
|
||||
}
|
||||
]
|
||||
24
public/rules_4.json
Normal file
@@ -0,0 +1,24 @@
|
||||
[
|
||||
{
|
||||
"id": 15,
|
||||
"priority": 1,
|
||||
"action": {
|
||||
"type": "modifyHeaders",
|
||||
"requestHeaders": [
|
||||
{
|
||||
"header": "Origin",
|
||||
"operation": "set",
|
||||
"value": "https://seller.kuajingmaihuo.com"
|
||||
},
|
||||
{
|
||||
"header": "Referer",
|
||||
"operation": "set",
|
||||
"value": "https://seller.kuajingmaihuo.com"
|
||||
}
|
||||
]
|
||||
},
|
||||
"condition": {
|
||||
"urlFilter": "||file.kuajingmaihuo.com"
|
||||
}
|
||||
}
|
||||
]
|
||||
24
public/rules_5.json
Normal file
@@ -0,0 +1,24 @@
|
||||
[
|
||||
{
|
||||
"id": 16,
|
||||
"priority": 1,
|
||||
"action": {
|
||||
"type": "modifyHeaders",
|
||||
"requestHeaders": [
|
||||
{
|
||||
"header": "Origin",
|
||||
"operation": "set",
|
||||
"value": "https://sso.geiwohuo.com/"
|
||||
},
|
||||
{
|
||||
"header": "Referer",
|
||||
"operation": "set",
|
||||
"value": "https://sso.geiwohuo.com/"
|
||||
}
|
||||
]
|
||||
},
|
||||
"condition": {
|
||||
"urlFilter": "||sso.geiwohuo.com"
|
||||
}
|
||||
}
|
||||
]
|
||||
29
public/rules_6.json
Normal file
@@ -0,0 +1,29 @@
|
||||
[
|
||||
{
|
||||
"id": 17,
|
||||
"priority": 1,
|
||||
"action": {
|
||||
"type": "modifyHeaders",
|
||||
"requestHeaders": [
|
||||
{
|
||||
"header": "Origin",
|
||||
"operation": "set",
|
||||
"value": "https://csp.aliexpress.com"
|
||||
},
|
||||
{
|
||||
"header": "Referer",
|
||||
"operation": "set",
|
||||
"value": "https://csp.aliexpress.com/"
|
||||
},
|
||||
{
|
||||
"header": "Sec-Fetch-Site",
|
||||
"operation": "set",
|
||||
"value": "same-site"
|
||||
}
|
||||
]
|
||||
},
|
||||
"condition": {
|
||||
"urlFilter": "||aliexpress.com"
|
||||
}
|
||||
}
|
||||
]
|
||||
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
@@ -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
@@ -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"
|
||||
}
|
||||
}
|
||||
]
|
||||
162
src/api/aliExpress.js
Normal file
@@ -0,0 +1,162 @@
|
||||
/**
|
||||
*
|
||||
* @param token 从cookie中获取,判断从[_m_h5_c,_m_h5_tk]中取值,优先判断第一个
|
||||
* @param appKey 取值window.mtopConfig
|
||||
* @param formData formData中的data
|
||||
* @param t 时间戳
|
||||
* @returns {*}
|
||||
*/
|
||||
|
||||
export const getSign = (token, appKey, formData, t = (new Date()).getTime()) => {
|
||||
token = token?.split("_")[0]
|
||||
console.log("获取sign的参数:", token, appKey, formData, t)
|
||||
return {
|
||||
t, sign: function (e) {
|
||||
function t(e, t) {
|
||||
return e << t | e >>> 32 - t
|
||||
}
|
||||
|
||||
function n(e, t) {
|
||||
var n, i, r, o, a;
|
||||
return r = 2147483648 & e,
|
||||
o = 2147483648 & t,
|
||||
a = (1073741823 & e) + (1073741823 & t),
|
||||
(n = 1073741824 & e) & (i = 1073741824 & t) ? 2147483648 ^ a ^ r ^ o : n | i ? 1073741824 & a ? 3221225472 ^ a ^ r ^ o : 1073741824 ^ a ^ r ^ o : a ^ r ^ o
|
||||
}
|
||||
|
||||
function i(e, i, r, o, a, s, l) {
|
||||
return e = n(e, n(n(function (e, t, n) {
|
||||
return e & t | ~e & n
|
||||
}(i, r, o), a), l)),
|
||||
n(t(e, s), i)
|
||||
}
|
||||
|
||||
function r(e, i, r, o, a, s, l) {
|
||||
return e = n(e, n(n(function (e, t, n) {
|
||||
return e & n | t & ~n
|
||||
}(i, r, o), a), l)),
|
||||
n(t(e, s), i)
|
||||
}
|
||||
|
||||
function o(e, i, r, o, a, s, l) {
|
||||
return e = n(e, n(n(function (e, t, n) {
|
||||
return e ^ t ^ n
|
||||
}(i, r, o), a), l)),
|
||||
n(t(e, s), i)
|
||||
}
|
||||
|
||||
function a(e, i, r, o, a, s, l) {
|
||||
return e = n(e, n(n(function (e, t, n) {
|
||||
return t ^ (e | ~n)
|
||||
}(i, r, o), a), l)),
|
||||
n(t(e, s), i)
|
||||
}
|
||||
|
||||
function s(e) {
|
||||
var t, n = "", i = "";
|
||||
for (t = 0; 3 >= t; t++)
|
||||
n += (i = "0" + (e >>> 8 * t & 255).toString(16)).substr(i.length - 2, 2);
|
||||
return n
|
||||
}
|
||||
|
||||
var l, u, c, d, p, f, h, g, m, v;
|
||||
for (v = function (e) {
|
||||
for (var t, n = e.length, i = n + 8, r = 16 * ((i - i % 64) / 64 + 1), o = new Array(r - 1), a = 0, s = 0; n > s;)
|
||||
a = s % 4 * 8,
|
||||
o[t = (s - s % 4) / 4] = o[t] | e.charCodeAt(s) << a,
|
||||
s++;
|
||||
return a = s % 4 * 8,
|
||||
o[t = (s - s % 4) / 4] = o[t] | 128 << a,
|
||||
o[r - 2] = n << 3,
|
||||
o[r - 1] = n >>> 29,
|
||||
o
|
||||
}(e = function (e) {
|
||||
e = e.replace(/\r\n/g, "\n");
|
||||
for (var t = "", n = 0; n < e.length; n++) {
|
||||
var i = e.charCodeAt(n);
|
||||
128 > i ? t += String.fromCharCode(i) : i > 127 && 2048 > i ? (t += String.fromCharCode(i >> 6 | 192),
|
||||
t += String.fromCharCode(63 & i | 128)) : (t += String.fromCharCode(i >> 12 | 224),
|
||||
t += String.fromCharCode(i >> 6 & 63 | 128),
|
||||
t += String.fromCharCode(63 & i | 128))
|
||||
}
|
||||
return t
|
||||
}(e)),
|
||||
f = 1732584193,
|
||||
h = 4023233417,
|
||||
g = 2562383102,
|
||||
m = 271733878,
|
||||
l = 0; l < v.length; l += 16)
|
||||
u = f,
|
||||
c = h,
|
||||
d = g,
|
||||
p = m,
|
||||
f = i(f, h, g, m, v[l], 7, 3614090360),
|
||||
m = i(m, f, h, g, v[l + 1], 12, 3905402710),
|
||||
g = i(g, m, f, h, v[l + 2], 17, 606105819),
|
||||
h = i(h, g, m, f, v[l + 3], 22, 3250441966),
|
||||
f = i(f, h, g, m, v[l + 4], 7, 4118548399),
|
||||
m = i(m, f, h, g, v[l + 5], 12, 1200080426),
|
||||
g = i(g, m, f, h, v[l + 6], 17, 2821735955),
|
||||
h = i(h, g, m, f, v[l + 7], 22, 4249261313),
|
||||
f = i(f, h, g, m, v[l + 8], 7, 1770035416),
|
||||
m = i(m, f, h, g, v[l + 9], 12, 2336552879),
|
||||
g = i(g, m, f, h, v[l + 10], 17, 4294925233),
|
||||
h = i(h, g, m, f, v[l + 11], 22, 2304563134),
|
||||
f = i(f, h, g, m, v[l + 12], 7, 1804603682),
|
||||
m = i(m, f, h, g, v[l + 13], 12, 4254626195),
|
||||
g = i(g, m, f, h, v[l + 14], 17, 2792965006),
|
||||
f = r(f, h = i(h, g, m, f, v[l + 15], 22, 1236535329), g, m, v[l + 1], 5, 4129170786),
|
||||
m = r(m, f, h, g, v[l + 6], 9, 3225465664),
|
||||
g = r(g, m, f, h, v[l + 11], 14, 643717713),
|
||||
h = r(h, g, m, f, v[l], 20, 3921069994),
|
||||
f = r(f, h, g, m, v[l + 5], 5, 3593408605),
|
||||
m = r(m, f, h, g, v[l + 10], 9, 38016083),
|
||||
g = r(g, m, f, h, v[l + 15], 14, 3634488961),
|
||||
h = r(h, g, m, f, v[l + 4], 20, 3889429448),
|
||||
f = r(f, h, g, m, v[l + 9], 5, 568446438),
|
||||
m = r(m, f, h, g, v[l + 14], 9, 3275163606),
|
||||
g = r(g, m, f, h, v[l + 3], 14, 4107603335),
|
||||
h = r(h, g, m, f, v[l + 8], 20, 1163531501),
|
||||
f = r(f, h, g, m, v[l + 13], 5, 2850285829),
|
||||
m = r(m, f, h, g, v[l + 2], 9, 4243563512),
|
||||
g = r(g, m, f, h, v[l + 7], 14, 1735328473),
|
||||
f = o(f, h = r(h, g, m, f, v[l + 12], 20, 2368359562), g, m, v[l + 5], 4, 4294588738),
|
||||
m = o(m, f, h, g, v[l + 8], 11, 2272392833),
|
||||
g = o(g, m, f, h, v[l + 11], 16, 1839030562),
|
||||
h = o(h, g, m, f, v[l + 14], 23, 4259657740),
|
||||
f = o(f, h, g, m, v[l + 1], 4, 2763975236),
|
||||
m = o(m, f, h, g, v[l + 4], 11, 1272893353),
|
||||
g = o(g, m, f, h, v[l + 7], 16, 4139469664),
|
||||
h = o(h, g, m, f, v[l + 10], 23, 3200236656),
|
||||
f = o(f, h, g, m, v[l + 13], 4, 681279174),
|
||||
m = o(m, f, h, g, v[l], 11, 3936430074),
|
||||
g = o(g, m, f, h, v[l + 3], 16, 3572445317),
|
||||
h = o(h, g, m, f, v[l + 6], 23, 76029189),
|
||||
f = o(f, h, g, m, v[l + 9], 4, 3654602809),
|
||||
m = o(m, f, h, g, v[l + 12], 11, 3873151461),
|
||||
g = o(g, m, f, h, v[l + 15], 16, 530742520),
|
||||
f = a(f, h = o(h, g, m, f, v[l + 2], 23, 3299628645), g, m, v[l], 6, 4096336452),
|
||||
m = a(m, f, h, g, v[l + 7], 10, 1126891415),
|
||||
g = a(g, m, f, h, v[l + 14], 15, 2878612391),
|
||||
h = a(h, g, m, f, v[l + 5], 21, 4237533241),
|
||||
f = a(f, h, g, m, v[l + 12], 6, 1700485571),
|
||||
m = a(m, f, h, g, v[l + 3], 10, 2399980690),
|
||||
g = a(g, m, f, h, v[l + 10], 15, 4293915773),
|
||||
h = a(h, g, m, f, v[l + 1], 21, 2240044497),
|
||||
f = a(f, h, g, m, v[l + 8], 6, 1873313359),
|
||||
m = a(m, f, h, g, v[l + 15], 10, 4264355552),
|
||||
g = a(g, m, f, h, v[l + 6], 15, 2734768916),
|
||||
h = a(h, g, m, f, v[l + 13], 21, 1309151649),
|
||||
f = a(f, h, g, m, v[l + 4], 6, 4149444226),
|
||||
m = a(m, f, h, g, v[l + 11], 10, 3174756917),
|
||||
g = a(g, m, f, h, v[l + 2], 15, 718787259),
|
||||
h = a(h, g, m, f, v[l + 9], 21, 3951481745),
|
||||
f = n(f, u),
|
||||
h = n(h, c),
|
||||
g = n(g, d),
|
||||
m = n(m, p);
|
||||
return (s(f) + s(h) + s(g) + s(m)).toLowerCase()
|
||||
}(token + "&" + t + "&" + appKey + "&" + formData)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,27 +1,63 @@
|
||||
import store from '@/store'
|
||||
import {genAnti} from "@/api/genAnti";
|
||||
import { genAnti } from "@/api/genAnti";
|
||||
import { Message } from 'element-ui'
|
||||
|
||||
/**
|
||||
* 向Chrome发送消息
|
||||
* @param message 消息
|
||||
*/
|
||||
export async function sendChromeAPIMessage(message) {
|
||||
message.type = 'api'
|
||||
message.url = "https://kuajing.pinduoduo.com/" + message.url;
|
||||
message.anti = message.anti || false
|
||||
if (message.needMallId) {
|
||||
// 如果参数中没有携带MallId,则从state中获取
|
||||
if (!message.mallId) {
|
||||
message.mallId = store.state.mallId;
|
||||
}
|
||||
message.type = 'api'
|
||||
if (!message.url.startsWith('http')) {
|
||||
message.url = "https://seller.kuajingmaihuo.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)
|
||||
}
|
||||
if (message.anti) {
|
||||
message.anti = await genAnti.a()
|
||||
}
|
||||
|
||||
return new Promise((resolve) => {
|
||||
// @ts-ignore
|
||||
// chrome.runtime.sendMessage(message, resolve)
|
||||
chrome.runtime.sendMessage(message, res => {
|
||||
if (res.error_code === 40001) {
|
||||
Message.error('请先登录拼多多跨境卖家中心')
|
||||
}
|
||||
resolve(res)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 向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)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -29,16 +65,17 @@ export async function sendChromeAPIMessage(message) {
|
||||
* @param message 消息
|
||||
*/
|
||||
export async function sendTemuAPIMessage(message) {
|
||||
message.type = 'temuApi'
|
||||
message.url = "https://www.temu.com/" + message.url;
|
||||
message.anti = message.anti || false
|
||||
if (message.anti) {
|
||||
message.anti = await genAnti.a()
|
||||
}
|
||||
return new Promise((resolve) => {
|
||||
// @ts-ignore
|
||||
chrome.runtime.sendMessage(message, resolve)
|
||||
})
|
||||
message.type = 'temuApi'
|
||||
message.url = "https://www.temu.com/" + message.url;
|
||||
message.anti = message.anti || false
|
||||
if (message.anti) {
|
||||
message.anti = await genAnti.a()
|
||||
message.data.anti_content = message.anti
|
||||
}
|
||||
return new Promise((resolve) => {
|
||||
// @ts-ignore
|
||||
chrome.runtime.sendMessage(message, resolve)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -46,10 +83,40 @@ export async function sendTemuAPIMessage(message) {
|
||||
* @param message 消息
|
||||
*/
|
||||
export async function sendChromeWebReqMessage(message) {
|
||||
return new Promise((resolve) => {
|
||||
// @ts-ignore
|
||||
chrome.runtime.sendMessage(message, resolve)
|
||||
})
|
||||
return new Promise((resolve) => {
|
||||
// @ts-ignore
|
||||
chrome.runtime.sendMessage(message, resolve)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 向Chrome发送消息
|
||||
* @param message 消息
|
||||
*/
|
||||
export async function sendSheinAPIMessage(message) {
|
||||
message.type = 'sheinApi'
|
||||
message.url = "https://www.shein.com/" + message.url;
|
||||
return new Promise((resolve) => {
|
||||
// @ts-ignore
|
||||
chrome.runtime.sendMessage(message, resolve)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 向Chrome发送消息
|
||||
* @param message 消息
|
||||
*/
|
||||
export async function sendGeiwohuoAPIMessage(message) {
|
||||
message.type = 'geiwohuoApi'
|
||||
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)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -57,9 +124,52 @@ export async function sendChromeWebReqMessage(message) {
|
||||
* @param message 消息
|
||||
*/
|
||||
export function sendChromeNotification(message) {
|
||||
message.type = 'notify'
|
||||
return new Promise((resolve) => {
|
||||
// @ts-ignore
|
||||
chrome.runtime.sendMessage(message, resolve)
|
||||
})
|
||||
message.type = 'notify'
|
||||
return new Promise((resolve) => {
|
||||
// @ts-ignore
|
||||
chrome.runtime.sendMessage(message, resolve)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 向Chrome发送消息
|
||||
* @param message 消息
|
||||
*/
|
||||
export function sendAliexpressAPIMessage(message) {
|
||||
message.type = 'aliexpress'
|
||||
if (!message.url.startsWith('http')) {
|
||||
message.url = "https://seller-acs.aliexpress.com/" + message.url;
|
||||
}
|
||||
const {mtopConfig = {appKey: "12574478"}} = window
|
||||
message.appKey = message.appKey || mtopConfig.appKey
|
||||
return new Promise((resolve) => {
|
||||
chrome.runtime.sendMessage(message, resolve)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 向Chrome发送消息
|
||||
* @param message 消息
|
||||
*/
|
||||
export function sendGoodcangAPIMessage(message) {
|
||||
message.type = 'goodcangApi'
|
||||
if (!message.url.startsWith('http')) {
|
||||
message.url = "https://oms.goodcang.com/" + message.url;
|
||||
}
|
||||
return new Promise((resolve) => {
|
||||
chrome.runtime.sendMessage(message, resolve)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 向Chrome发送消息
|
||||
* @param message 消息
|
||||
*/
|
||||
export async function sendXcAPIMessage(message) {
|
||||
message.type = 'xcApi'
|
||||
message.url = "http://xc.rqlis.com:888/" + message.url;
|
||||
return new Promise((resolve) => {
|
||||
// @ts-ignore
|
||||
chrome.runtime.sendMessage(message, resolve)
|
||||
})
|
||||
}
|
||||
|
||||
2874
src/api/cnPdd.js
@@ -4,7 +4,7 @@ import store from '@/store'
|
||||
|
||||
|
||||
var instance = axios.create({
|
||||
baseURL: process.env.NODE_ENV === 'production' ? 'http://temu.jjcp52.com' : 'http://temu.jjcp52.com',
|
||||
baseURL: process.env.NODE_ENV === 'production' ? 'http://temu.jjcp52.com' : 'http://124.71.2.127:10248',
|
||||
timeout: 50000,
|
||||
validateStatus: function (status) {
|
||||
return status < 500
|
||||
|
||||
@@ -53133,7 +53133,7 @@ export default[function(e, t, r) {
|
||||
))
|
||||
}
|
||||
, r = new XMLHttpRequest;
|
||||
r.open("GET", "https://kuajing.pinduoduo.com/api/server/_stm", !0),
|
||||
r.open("GET", "https://seller.kuajingmaihuo.com/api/server/_stm", !0),
|
||||
r.setRequestHeader("Content-type", "application/json; charset=utf-8"),
|
||||
r.withCredentials = !0,
|
||||
r.onreadystatechange = function() {
|
||||
|
||||
BIN
src/assets/code.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
@@ -1,13 +1,22 @@
|
||||
@import "./styles.scss";
|
||||
|
||||
@font-face {
|
||||
font-family: 'iconfont'; /* project id 1995974 */
|
||||
font-family: 'iconfont';
|
||||
/* project id 1995974 */
|
||||
src: url('https://at.alicdn.com/t/font_1995974_ihzpmuv4lpk.eot');
|
||||
src: url('https://at.alicdn.com/t/font_1995974_ihzpmuv4lpk.eot?#iefix') format('embedded-opentype'),
|
||||
url('https://at.alicdn.com/t/font_1995974_ihzpmuv4lpk.woff2') format('woff2'),
|
||||
url('https://at.alicdn.com/t/font_1995974_ihzpmuv4lpk.woff') format('woff'),
|
||||
url('https://at.alicdn.com/t/font_1995974_ihzpmuv4lpk.ttf') format('truetype'),
|
||||
url('https://at.alicdn.com/t/font_1995974_ihzpmuv4lpk.svg#iconfont') format('svg');
|
||||
url('https://at.alicdn.com/t/font_1995974_ihzpmuv4lpk.woff2') format('woff2'),
|
||||
url('https://at.alicdn.com/t/font_1995974_ihzpmuv4lpk.woff') format('woff'),
|
||||
url('https://at.alicdn.com/t/font_1995974_ihzpmuv4lpk.ttf') format('truetype'),
|
||||
url('https://at.alicdn.com/t/font_1995974_ihzpmuv4lpk.svg#iconfont') format('svg');
|
||||
}
|
||||
|
||||
|
||||
@font-face {
|
||||
font-family: "iconfont";
|
||||
src: url('https://at.alicdn.com/t/c/font_4680344_rxl7gevvsys.woff2?t=1725970465332') format('woff2'),
|
||||
url('https://at.alicdn.com/t/c/font_4680344_rxl7gevvsys.woff?t=1725970465332') format('woff'),
|
||||
url('https://at.alicdn.com/t/c/font_4680344_rxl7gevvsys.ttf?t=1725970465332') format('truetype');
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
@@ -20,12 +29,15 @@
|
||||
}
|
||||
|
||||
html {
|
||||
line-height: 1; /* 1 */
|
||||
-webkit-text-size-adjust: 100%; /* 2 */
|
||||
line-height: 1;
|
||||
/* 1 */
|
||||
-webkit-text-size-adjust: 100%;
|
||||
/* 2 */
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
h1 {
|
||||
@@ -35,14 +47,19 @@ h1 {
|
||||
|
||||
hr {
|
||||
-webkit-box-sizing: content-box;
|
||||
box-sizing: content-box; /* 1 */
|
||||
height: 0; /* 1 */
|
||||
overflow: visible; /* 2 */
|
||||
box-sizing: content-box;
|
||||
/* 1 */
|
||||
height: 0;
|
||||
/* 1 */
|
||||
overflow: visible;
|
||||
/* 2 */
|
||||
}
|
||||
|
||||
pre {
|
||||
font-family: monospace, monospace; /* 1 */
|
||||
font-size: 1em; /* 2 */
|
||||
font-family: monospace, monospace;
|
||||
/* 1 */
|
||||
font-size: 1em;
|
||||
/* 2 */
|
||||
}
|
||||
|
||||
a {
|
||||
@@ -50,10 +67,13 @@ a {
|
||||
}
|
||||
|
||||
abbr[title] {
|
||||
border-bottom: none; /* 1 */
|
||||
text-decoration: underline; /* 2 */
|
||||
border-bottom: none;
|
||||
/* 1 */
|
||||
text-decoration: underline;
|
||||
/* 2 */
|
||||
-webkit-text-decoration: underline dotted;
|
||||
text-decoration: underline dotted; /* 2 */
|
||||
text-decoration: underline dotted;
|
||||
/* 2 */
|
||||
}
|
||||
|
||||
b,
|
||||
@@ -64,8 +84,10 @@ strong {
|
||||
code,
|
||||
kbd,
|
||||
samp {
|
||||
font-family: monospace, monospace; /* 1 */
|
||||
font-size: 1em; /* 2 */
|
||||
font-family: monospace, monospace;
|
||||
/* 1 */
|
||||
font-size: 1em;
|
||||
/* 2 */
|
||||
}
|
||||
|
||||
small {
|
||||
@@ -97,14 +119,19 @@ input,
|
||||
optgroup,
|
||||
select,
|
||||
textarea {
|
||||
font-family: inherit; /* 1 */
|
||||
font-size: 100%; /* 1 */
|
||||
line-height: 1.15; /* 1 */
|
||||
margin: 0; /* 2 */
|
||||
font-family: inherit;
|
||||
/* 1 */
|
||||
font-size: 100%;
|
||||
/* 1 */
|
||||
line-height: 1.15;
|
||||
/* 1 */
|
||||
margin: 0;
|
||||
/* 2 */
|
||||
}
|
||||
|
||||
button,
|
||||
input { /* 1 */
|
||||
input {
|
||||
/* 1 */
|
||||
overflow: visible;
|
||||
font-family: SJsuqian;
|
||||
}
|
||||
@@ -116,7 +143,8 @@ input::placeholder {
|
||||
}
|
||||
|
||||
button,
|
||||
select { /* 1 */
|
||||
select {
|
||||
/* 1 */
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
@@ -148,12 +176,18 @@ fieldset {
|
||||
|
||||
legend {
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box; /* 1 */
|
||||
color: inherit; /* 2 */
|
||||
display: table; /* 1 */
|
||||
max-width: 100%; /* 1 */
|
||||
padding: 0; /* 3 */
|
||||
white-space: normal; /* 1 */
|
||||
box-sizing: border-box;
|
||||
/* 1 */
|
||||
color: inherit;
|
||||
/* 2 */
|
||||
display: table;
|
||||
/* 1 */
|
||||
max-width: 100%;
|
||||
/* 1 */
|
||||
padding: 0;
|
||||
/* 3 */
|
||||
white-space: normal;
|
||||
/* 1 */
|
||||
}
|
||||
|
||||
progress {
|
||||
@@ -167,8 +201,10 @@ textarea {
|
||||
[type="checkbox"],
|
||||
[type="radio"] {
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box; /* 1 */
|
||||
padding: 0; /* 2 */
|
||||
box-sizing: border-box;
|
||||
/* 1 */
|
||||
padding: 0;
|
||||
/* 2 */
|
||||
}
|
||||
|
||||
[type="number"]::-webkit-inner-spin-button,
|
||||
@@ -177,8 +213,10 @@ textarea {
|
||||
}
|
||||
|
||||
[type="search"] {
|
||||
-webkit-appearance: textfield; /* 1 */
|
||||
outline-offset: -2px; /* 2 */
|
||||
-webkit-appearance: textfield;
|
||||
/* 1 */
|
||||
outline-offset: -2px;
|
||||
/* 2 */
|
||||
}
|
||||
|
||||
[type="search"]::-webkit-search-decoration {
|
||||
@@ -186,8 +224,10 @@ textarea {
|
||||
}
|
||||
|
||||
::-webkit-file-upload-button {
|
||||
-webkit-appearance: button; /* 1 */
|
||||
font: inherit; /* 2 */
|
||||
-webkit-appearance: button;
|
||||
/* 1 */
|
||||
font: inherit;
|
||||
/* 2 */
|
||||
}
|
||||
|
||||
details {
|
||||
@@ -206,7 +246,10 @@ template {
|
||||
display: none;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4 {
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4 {
|
||||
font-weight: normal;
|
||||
font-size: 14px;
|
||||
padding: 0;
|
||||
@@ -224,7 +267,8 @@ a {
|
||||
transition: all .3s ease;
|
||||
}
|
||||
|
||||
ul, li {
|
||||
ul,
|
||||
li {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
@@ -238,7 +282,8 @@ img {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
html, body {
|
||||
html,
|
||||
body {
|
||||
width: 100%;
|
||||
min-height: 100vh;
|
||||
}
|
||||
@@ -268,7 +313,8 @@ img {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.flex-align, .flex-center {
|
||||
.flex-align,
|
||||
.flex-center {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
@@ -304,11 +350,13 @@ img {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.fade-enter-active, .fade-leave-active {
|
||||
transition: opacity .3s ease-in-out;
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
transition: opacity .2s ease-in-out;
|
||||
}
|
||||
|
||||
.fade-enter, .fade-leave-to {
|
||||
.fade-enter,
|
||||
.fade-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
@@ -379,7 +427,8 @@ img {
|
||||
line-height: 17px;
|
||||
margin-bottom: 14px;
|
||||
font-size: 14px;
|
||||
font-family: SJsuqian;;
|
||||
font-family: SJsuqian;
|
||||
;
|
||||
|
||||
label {
|
||||
margin-right: 6px;
|
||||
@@ -393,7 +442,7 @@ img {
|
||||
}
|
||||
|
||||
.el-pagination {
|
||||
margin-top: 40px;
|
||||
margin-top: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@@ -429,7 +478,8 @@ img {
|
||||
background-color: #1FBAD6;
|
||||
}
|
||||
|
||||
.el-button--danger:focus, .el-button.el-button--danger.is-link:not(.is-disabled):hover {
|
||||
.el-button--danger:focus,
|
||||
.el-button.el-button--danger.is-link:not(.is-disabled):hover {
|
||||
color: #fff !important;
|
||||
border-color: #FA5555;
|
||||
background-color: #FA5555;
|
||||
@@ -470,16 +520,60 @@ img {
|
||||
.search-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 0 16px 12px;
|
||||
margin: 0 25px 10px 0;
|
||||
|
||||
label {
|
||||
&>label {
|
||||
width: 80px;
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
font-weight: 500;
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
input {
|
||||
width: 240px;
|
||||
// width: 240px;
|
||||
}
|
||||
}
|
||||
|
||||
.el-table__fixed-body-wrapper .el-table__body {
|
||||
padding-bottom: 6px; // 6px为横向滚动条高度
|
||||
}
|
||||
|
||||
.hiprint_rul_wrapper {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.hiprint-printPanel {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
|
||||
.print-images {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
width: 420px;
|
||||
max-height: 400px;
|
||||
padding: 0 10px;
|
||||
overflow-y: auto;
|
||||
|
||||
img {
|
||||
width: 180px;
|
||||
height: 80px;
|
||||
margin-bottom: 10px;
|
||||
cursor: pointer;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
p {
|
||||
width: 100%;
|
||||
line-height: 1.3;
|
||||
margin-bottom: 10px;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
349
src/assets/css/print-lock.css
Normal file
@@ -0,0 +1,349 @@
|
||||
@media print {
|
||||
body {
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
}
|
||||
}
|
||||
|
||||
@page {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.hiprint-printPaper * {
|
||||
box-sizing: border-box;
|
||||
-moz-box-sizing: border-box; /* Firefox */
|
||||
-webkit-box-sizing: border-box; /* Safari */
|
||||
}
|
||||
|
||||
.hiprint-printPaper *:focus {
|
||||
outline: -webkit-focus-ring-color auto 0px;
|
||||
}
|
||||
|
||||
.hiprint-printPaper {
|
||||
position: relative;
|
||||
padding: 0 0 0 0;
|
||||
page-break-after: always;
|
||||
-webkit-user-select: none; /* Chrome/Safari/Opera */
|
||||
-moz-user-select: none; /* Firefox */
|
||||
user-select: none;
|
||||
overflow-x: hidden;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.hiprint-printPaper .hiprint-printPaper-content {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* 火狐浏览器打印 第一页过后 重叠问题 */
|
||||
@-moz-document url-prefix() {
|
||||
.hiprint-printPaper .hiprint-printPaper-content {
|
||||
position: relative;
|
||||
margin-top: 20px;
|
||||
top: -20px
|
||||
}
|
||||
}
|
||||
|
||||
.hiprint-printPaper.design {
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
|
||||
.hiprint-printTemplate .hiprint-printPanel {
|
||||
page-break-after: always;
|
||||
}
|
||||
|
||||
.hiprint-printPaper, hiprint-printPanel {
|
||||
box-sizing: border-box;
|
||||
border: 0px;
|
||||
}
|
||||
|
||||
.hiprint-printPanel .hiprint-printPaper:last-child {
|
||||
page-break-after: avoid;
|
||||
}
|
||||
|
||||
.hiprint-printTemplate .hiprint-printPanel:last-child {
|
||||
page-break-after: avoid;
|
||||
}
|
||||
|
||||
.hiprint-printPaper .hideheaderLinetarget {
|
||||
border-top: 0px dashed rgb(201, 190, 190) !important;
|
||||
}
|
||||
|
||||
.hiprint-printPaper .hidefooterLinetarget {
|
||||
border-top: 0px dashed rgb(201, 190, 190) !important;
|
||||
}
|
||||
|
||||
.hiprint-printPaper.design {
|
||||
border: 1px dashed rgba(170, 170, 170, 0.7);
|
||||
}
|
||||
|
||||
.design .hiprint-printElement-table-content, .design .hiprint-printElement-longText-content {
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.design .resize-panel {
|
||||
box-sizing: border-box;
|
||||
border: 1px dotted;
|
||||
}
|
||||
|
||||
.hiprint-printElement-text {
|
||||
background-color: transparent;
|
||||
background-repeat: repeat;
|
||||
padding: 0 0 0 0;
|
||||
border: 0.75pt none rgb(0, 0, 0);
|
||||
direction: ltr;
|
||||
font-family: 'SimSun';
|
||||
font-size: 9pt;
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
padding-bottom: 0pt;
|
||||
padding-left: 0pt;
|
||||
padding-right: 0pt;
|
||||
padding-top: 0pt;
|
||||
text-align: left;
|
||||
text-decoration: none;
|
||||
line-height: 9.75pt;
|
||||
box-sizing: border-box;
|
||||
word-wrap: break-word;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.design .hiprint-printElement-text-content {
|
||||
border: 1px dashed rgb(206, 188, 188);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.hiprint-printElement-longText {
|
||||
background-color: transparent;
|
||||
background-repeat: repeat;
|
||||
border: 0.75pt none rgb(0, 0, 0);
|
||||
direction: ltr;
|
||||
font-family: 'SimSun';
|
||||
font-size: 9pt;
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
padding-bottom: 0pt;
|
||||
padding-left: 0pt;
|
||||
padding-right: 0pt;
|
||||
padding-top: 0pt;
|
||||
text-align: left;
|
||||
text-decoration: none;
|
||||
line-height: 9.75pt;
|
||||
box-sizing: border-box;
|
||||
word-wrap: break-word;
|
||||
word-break: break-all;
|
||||
/*white-space: pre-wrap*/
|
||||
}
|
||||
|
||||
|
||||
.hiprint-printElement-table {
|
||||
background-color: transparent;
|
||||
background-repeat: repeat;
|
||||
color: rgb(0, 0, 0);
|
||||
border-color: rgb(0, 0, 0);
|
||||
border-style: none;
|
||||
direction: ltr;
|
||||
font-family: 'SimSun';
|
||||
font-size: 9pt;
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
padding-bottom: 0pt;
|
||||
padding-left: 0pt;
|
||||
padding-right: 0pt;
|
||||
padding-top: 0pt;
|
||||
text-align: left;
|
||||
text-decoration: none;
|
||||
padding: 0 0 0 0;
|
||||
box-sizing: border-box;
|
||||
line-height: 9.75pt;
|
||||
}
|
||||
|
||||
.hiprint-printElement-table thead {
|
||||
background: #e8e8e8;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
table.hiprint-printElement-tableTarget {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.hiprint-printElement-tableTarget, .hiprint-printElement-tableTarget tr, .hiprint-printElement-tableTarget td {
|
||||
border-color: rgb(0, 0, 0);
|
||||
/*border-style: none;*/
|
||||
/*border: 1px solid rgb(0, 0, 0);*/
|
||||
font-weight: normal;
|
||||
direction: ltr;
|
||||
padding-bottom: 0pt;
|
||||
padding-left: 4pt;
|
||||
padding-right: 4pt;
|
||||
padding-top: 0pt;
|
||||
text-decoration: none;
|
||||
vertical-align: middle;
|
||||
box-sizing: border-box;
|
||||
word-wrap: break-word;
|
||||
word-break: break-all;
|
||||
/*line-height: 9.75pt;
|
||||
font-size: 9pt;*/
|
||||
}
|
||||
|
||||
.hiprint-printElement-tableTarget-border-all {
|
||||
border: 1px solid;
|
||||
}
|
||||
.hiprint-printElement-tableTarget-border-none {
|
||||
border: 0px solid;
|
||||
}
|
||||
.hiprint-printElement-tableTarget-border-lr {
|
||||
border-left: 1px solid;
|
||||
border-right: 1px solid;
|
||||
}
|
||||
.hiprint-printElement-tableTarget-border-left {
|
||||
border-left: 1px solid;
|
||||
}
|
||||
.hiprint-printElement-tableTarget-border-right {
|
||||
border-right: 1px solid;
|
||||
}
|
||||
.hiprint-printElement-tableTarget-border-tb {
|
||||
border-top: 1px solid;
|
||||
border-bottom: 1px solid;
|
||||
}
|
||||
.hiprint-printElement-tableTarget-border-top {
|
||||
border-top: 1px solid;
|
||||
}
|
||||
.hiprint-printElement-tableTarget-border-bottom {
|
||||
border-bottom: 1px solid;
|
||||
}
|
||||
|
||||
.hiprint-printElement-tableTarget-border-td-none td {
|
||||
border: 0px solid;
|
||||
}
|
||||
.hiprint-printElement-tableTarget-border-td-all td:not(:nth-last-child(-n+2)) {
|
||||
border-right: 1px solid;
|
||||
}
|
||||
.hiprint-printElement-tableTarget-border-td-all td:last-child {
|
||||
border-left: 1px solid;
|
||||
}
|
||||
.hiprint-printElement-tableTarget-border-td-all td:last-child:first-child {
|
||||
border-left: none;
|
||||
}
|
||||
|
||||
/*.hiprint-printElement-tableTarget tr,*/
|
||||
.hiprint-printElement-tableTarget td {
|
||||
height: 18pt;
|
||||
}
|
||||
|
||||
.hiprint-printPaper .hiprint-paperNumber {
|
||||
font-size: 9pt;
|
||||
}
|
||||
|
||||
.design .hiprint-printElement-table-handle {
|
||||
position: absolute;
|
||||
height: 21pt;
|
||||
width: 21pt;
|
||||
background: red;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.hiprint-printPaper .hiprint-paperNumber-disabled {
|
||||
float: right !important;
|
||||
right: 0 !important;
|
||||
color: gainsboro !important;
|
||||
}
|
||||
|
||||
.hiprint-printElement-vline, .hiprint-printElement-hline {
|
||||
border: 0px none rgb(0, 0, 0);
|
||||
|
||||
}
|
||||
|
||||
.hiprint-printElement-vline {
|
||||
border-left: 0.75pt solid #000;
|
||||
border-right: 0px none rgb(0, 0, 0) !important;
|
||||
border-bottom: 0px none rgb(0, 0, 0) !important;
|
||||
border-top: 0px none rgb(0, 0, 0) !important;
|
||||
}
|
||||
|
||||
.hiprint-printElement-hline {
|
||||
border-top: 0.75pt solid #000;
|
||||
border-right: 0px none rgb(0, 0, 0) !important;
|
||||
border-bottom: 0px none rgb(0, 0, 0) !important;
|
||||
border-left: 0px none rgb(0, 0, 0) !important;
|
||||
}
|
||||
|
||||
.hiprint-printElement-oval, .hiprint-printElement-rect {
|
||||
border: 0.75pt solid #000;
|
||||
}
|
||||
|
||||
.hiprint-text-content-middle {
|
||||
}
|
||||
|
||||
.hiprint-text-content-middle > div {
|
||||
display: grid;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.hiprint-text-content-bottom {
|
||||
}
|
||||
|
||||
.hiprint-text-content-bottom > div {
|
||||
display: grid;
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
.hiprint-text-content-wrap {
|
||||
}
|
||||
|
||||
.hiprint-text-content-wrap .hiprint-text-content-wrap-nowrap {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.hiprint-text-content-wrap .hiprint-text-content-wrap-clip {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: clip;
|
||||
}
|
||||
|
||||
.hiprint-text-content-wrap .hiprint-text-content-wrap-ellipsis {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
/*hi-grid-row */
|
||||
.hi-grid-row {
|
||||
position: relative;
|
||||
height: auto;
|
||||
margin-right: 0;
|
||||
margin-left: 0;
|
||||
zoom: 1;
|
||||
display: block;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.hi-grid-row::after, .hi-grid-row::before {
|
||||
display: table;
|
||||
content: '';
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.hi-grid-col {
|
||||
display: block;
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
float: left;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.table-grid-row {
|
||||
margin-left: -0pt;
|
||||
margin-right: -0pt;
|
||||
}
|
||||
|
||||
.tableGridColumnsGutterRow {
|
||||
padding-left: 0pt;
|
||||
padding-right: 0pt;
|
||||
}
|
||||
|
||||
.hiprint-gridColumnsFooter {
|
||||
text-align: left;
|
||||
clear: both;
|
||||
}
|
||||
BIN
src/assets/free.png
Normal file
|
After Width: | Height: | Size: 9.0 KiB |
BIN
src/assets/images/avatar.png
Normal file
|
After Width: | Height: | Size: 964 B |
BIN
src/assets/images/triman1.png
Normal file
|
After Width: | Height: | Size: 185 KiB |
BIN
src/assets/off.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
src/assets/right.png
Normal file
|
After Width: | Height: | Size: 5.6 KiB |
BIN
src/assets/tab_middle.png
Normal file
|
After Width: | Height: | Size: 8.1 KiB |
@@ -37,7 +37,7 @@
|
||||
margin-bottom: 20px;
|
||||
padding-bottom: 20px;
|
||||
background: #FFFFFF;
|
||||
overflow: hidden;
|
||||
overflow: auto;
|
||||
box-shadow: 0 4px 6px -2px rgba(15, 15, 21, 0.15);
|
||||
border-radius: 2px;
|
||||
|
||||
|
||||
294
src/components/AiCopyFromAliExpress.vue
Normal file
@@ -0,0 +1,294 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-alert
|
||||
title="采集一个商品添加进草稿箱,将消耗20金币"
|
||||
type="success"
|
||||
:closable="false" style="margin-bottom: 10px;">
|
||||
</el-alert>
|
||||
<el-form class="ai-form" :model="form" label-width="150px" ref="form">
|
||||
<el-form-item v-if="!isMultiCopy" label="商品地址:" style="width: 100%;" prop="url" :rules="[{ required: true, message: '请输入商品地址', trigger: 'blur' }]">
|
||||
<el-input type="textarea" :rows="5" v-model="form.url"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="店铺:" style="width: 100%;" prop="targetMallId" :rules="[{ required: true, message: '请选择店铺', trigger: 'blur' }]">
|
||||
<el-select style="width: 380px" v-model="form.targetMallId" placeholder="请选择">
|
||||
<el-option
|
||||
v-for="item in $store.state.mallList"
|
||||
:key="item.mallId"
|
||||
:label="item.mallName"
|
||||
:value="item.mallId">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="商品分类:" style="width: 100%;" prop="targetCatId" :rules="[{ required: true, message: '请选择商品分类', trigger: 'blur' }]">
|
||||
<ai-lazy-cascader
|
||||
style="width: 380px"
|
||||
v-model="form.targetCatId"
|
||||
filterable
|
||||
:props="props"></ai-lazy-cascader>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div class="bottom flex-center">
|
||||
<el-button @click="$emit('onClose')">取 消</el-button>
|
||||
<el-button type="primary" @click="toAddToDraft" :loading="isCopying">确定</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {sendChromeAPIMessage, sendChromeWebReqMessage} from '@/api/chromeApi'
|
||||
import AiLazyCascader from "@/components/AiLazyCascader.vue"
|
||||
import { getImageMd5, uploadImage } from "@/utils/image.js"
|
||||
import { extractImagesAndText } from "@/utils/html.js"
|
||||
import { transformAliExpress } from "@/utils/product.js"
|
||||
import { formatDate } from "@/utils/date.js"
|
||||
import { createFolderApi } from "@/utils/folder.js"
|
||||
import { Message } from 'element-ui'
|
||||
import { MessageBox } from 'element-ui';
|
||||
|
||||
export default {
|
||||
name: 'AiCopyFromTemu',
|
||||
props: ['params', 'isMultiCopy'],
|
||||
components: {AiLazyCascader},
|
||||
data() {
|
||||
return {
|
||||
props: {
|
||||
value: 'catId',
|
||||
label: 'catName',
|
||||
lazy: true,
|
||||
lazyLoad (value, resolve) {
|
||||
sendChromeAPIMessage({
|
||||
url: 'bg-anniston-mms/category/children/list',
|
||||
needMallId: true,
|
||||
data: {
|
||||
parentCatId: value || ''
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.errorCode === 1000000) {
|
||||
resolve(res.result.categoryNodeVOS.map(v => {
|
||||
return {
|
||||
...v,
|
||||
leaf: v.isLeaf
|
||||
}
|
||||
}))
|
||||
}
|
||||
})
|
||||
},
|
||||
lazySearch(queryString, resolve) {
|
||||
sendChromeAPIMessage({
|
||||
url: 'bg-anniston-mms/category/search',
|
||||
needMallId: true,
|
||||
data: {
|
||||
searchText: queryString || ''
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.errorCode === 1000000) {
|
||||
resolve(res.result.categoryPaths.map(v => {
|
||||
let value = []
|
||||
let label = []
|
||||
for (let i = 1; i <= 10; i++ ) {
|
||||
if (v['cat'+i+'NodeVO']) {
|
||||
value.push(v['cat'+i+'NodeVO'].catId)
|
||||
label.push(v['cat'+i+'NodeVO'].catName)
|
||||
}
|
||||
}
|
||||
return {
|
||||
catId: value,
|
||||
catName: label
|
||||
}
|
||||
}))
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
form: {
|
||||
url: '',
|
||||
type: 2, // 默认从temu复制
|
||||
targetMallId: '',
|
||||
targetCatId: []
|
||||
},
|
||||
goods: {},
|
||||
sku: {},
|
||||
productDetail: {},
|
||||
isCopying: false,
|
||||
goodsId: '',
|
||||
currentUrl: '',
|
||||
goodsProperty: [],
|
||||
catId: null,
|
||||
currentIndex: 0,
|
||||
successList: []
|
||||
}
|
||||
},
|
||||
created () {
|
||||
if (this.params?.url) {
|
||||
this.form.url = this.params.url
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toAddToDraft() {
|
||||
this.$refs.form.validate((valid) => {
|
||||
if (valid) {
|
||||
this.currentUrl = this.form.url
|
||||
this.addToDraft()
|
||||
}
|
||||
})
|
||||
},
|
||||
async addToDraft() {
|
||||
// let test = await createFolderApi(formatDate(new Date()).split('-'),this.form.targetMallId)
|
||||
this.isCopying = true
|
||||
let res = await sendChromeWebReqMessage({
|
||||
type: 'aliexpress',
|
||||
url: this.currentUrl,
|
||||
})
|
||||
if (res.indexOf("runParams") == -1) {
|
||||
Message.error("请检查地址是否正确,或者“速卖通”网站是否出现滑动条")
|
||||
return
|
||||
}
|
||||
let str = res.substring(res.indexOf("runParams"))
|
||||
str = str.substring(0, str.indexOf("<\/script>"))
|
||||
str = str.substring(str.indexOf("{"))
|
||||
str = str.substring(0, str.lastIndexOf("}"))
|
||||
str = str.substring(str.indexOf('data'))
|
||||
str = str.substring(5)
|
||||
|
||||
let obj = JSON.parse(str)
|
||||
|
||||
let folderId = await createFolderApi(formatDate(new Date()).split('-'),this.form.targetMallId)
|
||||
|
||||
let carouselImageUrls = [], detailImageUrls = []
|
||||
let imageConponent = obj.imageComponent
|
||||
for (let i = 0; i < imageConponent.imagePathList.length; i++) {
|
||||
let img = await uploadImage(folderId, imageConponent.imagePathList[i], this.form.targetMallId)
|
||||
carouselImageUrls.push(img)
|
||||
}
|
||||
|
||||
let res1 = await sendChromeWebReqMessage({
|
||||
type: 'aliexpress',
|
||||
url: obj.productDescComponent.descriptionUrl,
|
||||
})
|
||||
|
||||
res1 = res1.substring(0, res1.indexOf("<script>"))
|
||||
|
||||
res1 = extractImagesAndText(res1)
|
||||
res1 = JSON.parse(res1)
|
||||
console.log(res1)
|
||||
for (let i = 0; i < res1.images.length; i++) {
|
||||
let img = await uploadImage(folderId, res1.images[i], this.form.targetMallId)
|
||||
detailImageUrls.push(img)
|
||||
}
|
||||
|
||||
this.createDraft(transformAliExpress({
|
||||
title: obj.productInfoComponent.subject,
|
||||
carouselImageUrls,
|
||||
detailImageList: detailImageUrls,
|
||||
text: res1.text
|
||||
}))
|
||||
},
|
||||
async createDraft(data) {
|
||||
let catId = this.form.targetCatId[this.form.targetCatId.length - 1]
|
||||
let res = await sendChromeAPIMessage({
|
||||
url: 'bg-visage-mms/product/draft/add',
|
||||
needMallId: true,
|
||||
mallId: this.form.targetMallId,
|
||||
data: {
|
||||
catId: catId
|
||||
}})
|
||||
|
||||
if (res.errorCode == 1000000) {
|
||||
let draftId = res.result.productDraftId
|
||||
let content = data
|
||||
let i = 0
|
||||
for (; i < this.form.targetCatId.length; i++) {
|
||||
content['cat' + (i+1) + 'Id'] = this.form.targetCatId[i]
|
||||
}
|
||||
for (; i < 10; i++) {
|
||||
content['cat' + (i+1) + 'Id'] = ''
|
||||
}
|
||||
|
||||
content.productDraftId = draftId
|
||||
|
||||
this.createProduct(content)
|
||||
} else {
|
||||
setTimeout(() => {
|
||||
this.createDraft(data)
|
||||
}, 500)
|
||||
}
|
||||
},
|
||||
createProduct(content) {
|
||||
sendChromeAPIMessage({
|
||||
url: 'bg-visage-mms/product/draft/save',
|
||||
needMallId: true,
|
||||
mallId: this.form.targetMallId,
|
||||
data: content
|
||||
}).then((res) => {
|
||||
if (res.errorCode == 1000000) {
|
||||
this.successList.push(this.currentUrl)
|
||||
this.saveInfo()
|
||||
this.isCopying = false
|
||||
Message.success("成功添加到草稿箱")
|
||||
|
||||
} else {
|
||||
setTimeout(() => {
|
||||
this.createProduct(content)
|
||||
}, 500)
|
||||
}
|
||||
})
|
||||
},
|
||||
getSpecIdNew(data) {
|
||||
return sendChromeAPIMessage({
|
||||
url: 'bg-anniston-mms/sku/spec/byName/queryOrAdd',
|
||||
needMallId: true,
|
||||
mallId: this.form.targetMallId,
|
||||
data: {
|
||||
parentSpecId: data.spec_key_id,
|
||||
specName: data.spec_value
|
||||
}}).then((res) => {
|
||||
if (res.errorCode == 1000000) {
|
||||
return res
|
||||
} else {
|
||||
this.getSpecIdNew(data)
|
||||
}
|
||||
})
|
||||
},
|
||||
getSpecId(data) {
|
||||
return sendChromeAPIMessage({
|
||||
url: 'bg-anniston-mms/sku/spec/byName/queryOrAdd',
|
||||
needMallId: true,
|
||||
mallId: this.form.targetMallId,
|
||||
data: {
|
||||
parentSpecId: data.specKeyId,
|
||||
specName: data.specValue
|
||||
}}).then((res) => {
|
||||
if (res.errorCode == 1000000) {
|
||||
return res
|
||||
} else {
|
||||
this.getSpecId(data)
|
||||
}
|
||||
})
|
||||
},
|
||||
saveInfo() {
|
||||
let mallInfo = this.$store.state.mallList.filter(item => {
|
||||
return item.mallId == this.form.targetMallId
|
||||
})
|
||||
this.$http.post('/api/copyProduct/add', {
|
||||
mallId: mallInfo[0].mallId,
|
||||
mallName: mallInfo[0].mallName,
|
||||
url: this.currentUrl,
|
||||
type: this.form.type
|
||||
}).then(res1 => {
|
||||
if (res1.code == 0) {
|
||||
this.$store.dispatch('getUserInfo')
|
||||
if (!this.isMultiCopy) {
|
||||
this.$emit('onSuccess')
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.bottom {
|
||||
justify-content: center;
|
||||
}
|
||||
</style>
|
||||
@@ -1,55 +1,89 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-form class="ai-form" :model="form" label-width="140px" ref="form">
|
||||
<el-form-item label="来源:" style="width: 100%;" prop="type" :rules="[{ required: true, message: '请选择来源', trigger: 'blur' }]">
|
||||
<el-radio-group v-model="form.type" size="medium">
|
||||
<el-radio :label="1">TEMU</el-radio>
|
||||
<!--<el-radio :label="2">速卖通</el-radio>-->
|
||||
</el-radio-group>
|
||||
<el-alert
|
||||
title="采集一个商品添加进草稿箱,将消耗20金币"
|
||||
type="success"
|
||||
:closable="false" style="margin-bottom: 10px;">
|
||||
</el-alert>
|
||||
<el-form class="ai-form" :model="form" label-width="150px" ref="form">
|
||||
<el-form-item v-if="!isMultiCopy" label="商品地址:" style="width: 100%;" prop="url" :rules="[{ required: true, message: '请输入商品地址', trigger: 'blur' }]">
|
||||
<el-input type="textarea" :rows="5" v-model="form.url"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="商品地址:" style="width: 100%;" prop="url" :rules="[{ required: true, message: '请输入商品地址', trigger: 'blur' }]">
|
||||
<el-input type="textarea" :rows="5" v-model="form.url"></el-input>
|
||||
<el-form-item
|
||||
prop="isSemi"
|
||||
label="是否半托管:"
|
||||
:rules="[{ required: true, message: '请选择是否半托管', trigger: 'blur' }]">
|
||||
<el-radio-group v-model="form.isSemi" size="medium">
|
||||
<el-radio :label="false">否</el-radio>
|
||||
<el-radio :label="true">是</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="店铺:" style="width: 100%;" prop="targetMallId" :rules="[{ required: true, message: '请选择店铺', trigger: 'blur' }]">
|
||||
<el-select style="width: 380px" v-model="form.targetMallId" placeholder="请选择">
|
||||
<el-select style="width: 380px" multiple v-model="form.targetMallId" placeholder="请选择">
|
||||
<el-option
|
||||
v-for="item in $store.state.mallList"
|
||||
v-for="item in mallList"
|
||||
:key="item.mallId"
|
||||
:label="item.mallName"
|
||||
:value="item.mallId">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="商品分类:" style="width: 100%;" prop="targetCatId" :rules="[{ required: true, message: '请选择商品分类', trigger: 'blur' }]">
|
||||
<el-cascader style="width: 380px" v-model="form.targetCatId" :props="props"></el-cascader>
|
||||
<el-form-item v-if="form.isSemi" label="经营站点" style="width: 100%;" prop="siteId" :rules="[{ required: true, message: '请选择经营站点', trigger: 'blur' }]">
|
||||
<el-select style="width: 380px" multiple v-model="form.siteId" placeholder="请选择">
|
||||
<el-option
|
||||
v-for="item in siteList"
|
||||
:key="item.siteId"
|
||||
:label="item.siteName"
|
||||
:value="item.siteId">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
prop="isSameCategory"
|
||||
label="是否保持相同类目:"
|
||||
:rules="[{ required: true, message: '请选择是否保持相同类目', trigger: 'blur' }]">
|
||||
<el-radio-group v-model="form.isSameCategory" size="medium">
|
||||
<el-radio :label="false">否</el-radio>
|
||||
<el-radio :label="true">是</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="!form.isSameCategory" label="商品分类:" style="width: 100%;" prop="targetCatId" :rules="[{ required: true, message: '请选择商品分类', trigger: 'blur' }]">
|
||||
<ai-lazy-cascader
|
||||
style="width: 380px"
|
||||
v-model="form.targetCatId"
|
||||
filterable
|
||||
:props="props"></ai-lazy-cascader>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div class="bottom flex-center">
|
||||
<el-button @click="$emit('onClose')">取 消</el-button>
|
||||
<el-button type="primary" @click="addToDraft">确定</el-button>
|
||||
<el-button type="primary" @click="toAddToDraft" :loading="isCopying">确定</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {sendChromeAPIMessage, sendChromeWebReqMessage} from '@/api/chromeApi'
|
||||
import {sendChromeAPIMessage, sendTemuAPIMessage, sendChromeWebReqMessage} from '@/api/chromeApi'
|
||||
import AiLazyCascader from "@/components/AiLazyCascader.vue"
|
||||
import { Message } from 'element-ui'
|
||||
import { MessageBox } from 'element-ui';
|
||||
|
||||
export default {
|
||||
name: 'AiCopyFromTemu',
|
||||
props: ['params'],
|
||||
props: ['params', 'isMultiCopy'],
|
||||
components: {AiLazyCascader},
|
||||
data() {
|
||||
return {
|
||||
props: {
|
||||
value: 'catId',
|
||||
label: 'catName',
|
||||
lazy: true,
|
||||
lazyLoad (node, resolve) {
|
||||
lazyLoad (value, resolve) {
|
||||
sendChromeAPIMessage({
|
||||
url: 'bg-anniston-mms/category/children/list',
|
||||
needMallId: true,
|
||||
data: {
|
||||
parentCatId: node.value || ''
|
||||
parentCatId: value || ''
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.errorCode === 1000000) {
|
||||
@@ -61,171 +95,449 @@ export default {
|
||||
}))
|
||||
}
|
||||
})
|
||||
},
|
||||
lazySearch(queryString, resolve) {
|
||||
sendChromeAPIMessage({
|
||||
url: 'bg-anniston-mms/category/search',
|
||||
needMallId: true,
|
||||
data: {
|
||||
searchText: queryString || ''
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.errorCode === 1000000) {
|
||||
resolve(res.result.categoryPaths.map(v => {
|
||||
let value = []
|
||||
let label = []
|
||||
for (let i = 1; i <= 10; i++ ) {
|
||||
if (v['cat'+i+'NodeVO']) {
|
||||
value.push(v['cat'+i+'NodeVO'].catId)
|
||||
label.push(v['cat'+i+'NodeVO'].catName)
|
||||
}
|
||||
}
|
||||
return {
|
||||
catId: value,
|
||||
catName: label
|
||||
}
|
||||
}))
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
form: {
|
||||
url: '',
|
||||
type: 1, // 默认从temu复制
|
||||
targetMallId: '',
|
||||
targetCatId: []
|
||||
targetCatId: [],
|
||||
isSameCategory: true,
|
||||
isSemi: false,
|
||||
siteId: []
|
||||
},
|
||||
goods: {},
|
||||
sku: {},
|
||||
productDetail: {}
|
||||
productDetail: {},
|
||||
isCopying: false,
|
||||
goodsId: '',
|
||||
currentUrl: '',
|
||||
goodsProperty: [],
|
||||
catId: null,
|
||||
currentIndex: 0,
|
||||
successList: [],
|
||||
siteList: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
mallList () {
|
||||
const filteredData = this.$store.state.mallList.filter(item => {
|
||||
return item.isSemiManagedMall == this.form.isSemi
|
||||
})
|
||||
|
||||
return filteredData
|
||||
}
|
||||
},
|
||||
created () {
|
||||
console.log(this.params?.url)
|
||||
if (this.params?.url) {
|
||||
this.form.url = this.params.url
|
||||
}
|
||||
this.getSiteList()
|
||||
if (this.params?.url) {
|
||||
this.form.url = this.params.url
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async addToDraft() {
|
||||
this.$refs.form.validate((valid) => {
|
||||
if (valid) {
|
||||
this.$http.post('/api/copyProduct/check',null, {params: {type: 0}}).then(res => {
|
||||
if (res.code == 0) {
|
||||
let source
|
||||
if (this.form.type == '1') {
|
||||
source = 'temu'
|
||||
} else if (this.form.type == '2') {
|
||||
source = 'aliexpress'
|
||||
}
|
||||
sendChromeWebReqMessage({
|
||||
type: source,
|
||||
url: this.form.url,
|
||||
}).then((res) => {
|
||||
if (this.form.type == '1') {
|
||||
if (res.indexOf("rawData") == -1) {
|
||||
Message.error("请检查地址是否正确,或者“TEMU”网站是否出现图形验证码")
|
||||
return
|
||||
}
|
||||
let str = res.substring(res.indexOf("rawData"))
|
||||
str = str.substring(0, str.indexOf("<\/script>"))
|
||||
str = str.substring(str.indexOf("{"))
|
||||
str = str.substring(0, str.lastIndexOf("}"))
|
||||
str = str + "}"
|
||||
|
||||
let goodsObj = JSON.parse(str)
|
||||
this.goods = goodsObj.store.goods
|
||||
this.sku = goodsObj.store.sku
|
||||
this.productDetail = goodsObj.store.productDetail
|
||||
|
||||
let specIds = []
|
||||
this.sku.forEach(item => {
|
||||
item.specs.forEach(item1 => {
|
||||
let flag = false
|
||||
specIds.forEach(item2 => {
|
||||
if (item2.specValue == item1.specValue) {
|
||||
flag = true
|
||||
}
|
||||
})
|
||||
if (!flag) {
|
||||
specIds.push({specKeyId: item1.specKeyId, specValue: item1.specValue})
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
Promise.all(specIds.map(item => this.getSpecId(item).then(res => {
|
||||
this.sku.forEach(item1 => {
|
||||
item1.specs.forEach(item2 => {
|
||||
if (item2.specValue == item.specValue) {
|
||||
item2.specValueId = res.result.specId
|
||||
}
|
||||
})
|
||||
})
|
||||
return 0
|
||||
}))).then(() => {
|
||||
this.$http.post('/api/copyProduct/translate',{type: 1, goods: this.goods, sku: this.sku, productDetail: this.productDetail}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.createDraft(res.data)
|
||||
}
|
||||
})
|
||||
})
|
||||
} else if (this.form.type == '2') {
|
||||
/*if (res.indexOf("runParams") == -1) {
|
||||
Message.error("请检查地址是否正确,或者“速卖通”网站是否出现滑动条")
|
||||
return
|
||||
}
|
||||
let str = res.substring(res.indexOf("runParams"))
|
||||
str = str.substring(0, str.indexOf("<\/script>"))
|
||||
str = str.substring(str.indexOf("{"))
|
||||
str = str.substring(0, str.lastIndexOf("}"))
|
||||
str = str.substring(str.indexOf('data'))
|
||||
str = str.substring(5)
|
||||
|
||||
let obj = JSON.parse(str)
|
||||
|
||||
sendChromeWebReqMessage({
|
||||
type: source,
|
||||
url: obj.productDescComponent.descriptionUrl,
|
||||
}).then((res1) => {
|
||||
res1 = res1.substring(0, res1.indexOf("<script>"))
|
||||
let str = res1.replace(/<img[^>]+src="([^">]+)"[^>]+>/g, '$1\n').replace(/<.*?>/g, '[||]')
|
||||
let arr = str.split('[||]')
|
||||
for (let i = 0; i < arr.length; i++) {
|
||||
console.log(arr[i])
|
||||
}
|
||||
})*/
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
getSiteList() {
|
||||
sendChromeAPIMessage({
|
||||
url: 'bg-visage-mms/config/common/site/query',
|
||||
needMallId: true,
|
||||
mallId: this.$store.state.mallList[0].mallId,
|
||||
data: {}}).then((res) => {
|
||||
if (res.success) {
|
||||
this.siteList = res.result.siteBaseList.filter(item => {
|
||||
return item.matchSemiManaged
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
createDraft(data) {
|
||||
sendChromeAPIMessage({
|
||||
toAddToDraft() {
|
||||
this.$refs.form.validate((valid) => {
|
||||
if (valid) {
|
||||
if (this.isMultiCopy) {
|
||||
this.successList = []
|
||||
this.currentIndex = 0
|
||||
this.currentUrl = this.params.urlList[this.currentIndex]
|
||||
this.execAddToDraft()
|
||||
} else {
|
||||
this.currentUrl = this.form.url
|
||||
this.execAddToDraft()
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
execAddToDraft() {
|
||||
if (!this.currentUrl.startsWith("http")) {
|
||||
this.goodsId = this.currentUrl
|
||||
this.addToDraftNew()
|
||||
} else {
|
||||
let t = this.currentUrl
|
||||
let urlParams = this.parseURL(t)
|
||||
t = t.substring(0,t.indexOf(".html"))
|
||||
if (t.lastIndexOf("-g-") > 0) {
|
||||
t = t.substring(t.lastIndexOf("-g-"), t.length);
|
||||
t = t.substring(3, t.length);
|
||||
this.goodsId = t
|
||||
this.addToDraftNew()
|
||||
} else if(urlParams.params) {
|
||||
let goodsId = urlParams.params.goods_id
|
||||
if (!goodsId) {
|
||||
this.addToDraft()
|
||||
} else {
|
||||
this.goodsId = goodsId
|
||||
this.addToDraftNew()
|
||||
}
|
||||
} else {
|
||||
this.addToDraft()
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
async addToDraftNew() {
|
||||
this.isCopying = true
|
||||
sendTemuAPIMessage({
|
||||
url: 'api/oak/integration/render',
|
||||
anti: true,
|
||||
data: {
|
||||
goods_id: this.goodsId
|
||||
}}).then((res) => {
|
||||
if (!res.goods || !res.goods.productName) {
|
||||
//this.isCopying = false
|
||||
//Message.error("获取商品信息失败,采集失败")
|
||||
this.addToDraft()
|
||||
return
|
||||
}
|
||||
this.goods = res.goods
|
||||
this.sku = res.sku
|
||||
this.productDetail = res.product_detail
|
||||
this.catId = this.goods.cat_id
|
||||
this.goodsProperty = this.goods.goods_property
|
||||
let specIds = []
|
||||
this.sku.forEach(item => {
|
||||
item.specs.forEach(item1 => {
|
||||
let flag = false
|
||||
specIds.forEach(item2 => {
|
||||
if (item2.spec_value == item1.spec_value) {
|
||||
flag = true
|
||||
}
|
||||
})
|
||||
/*if (!flag && (item1.specKeyId != 1001 && item1.specKeyId != 43404162)) {
|
||||
specIds.push({spec_key_id: item1.spec_key_id, spec_value: item1.spec_value})
|
||||
}*/
|
||||
if (!flag) {
|
||||
specIds.push({spec_key_id: item1.spec_key_id, spec_value: item1.spec_value})
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
/*Promise.all(specIds.map(item => this.getSpecIdNew(item).then(res => {
|
||||
this.sku.forEach(item1 => {
|
||||
item1.specs.forEach(item2 => {
|
||||
if (item2.spec_value == item.spec_value) {
|
||||
item2.spec_value_id = res.result.specId
|
||||
}
|
||||
})
|
||||
})
|
||||
return 0
|
||||
}))).then(() => {
|
||||
this.$http.post('/api/copyProduct/translateNew',{type: 1, goods: this.goods, sku: this.sku, productDetail: this.productDetail}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.createDraft(res.data)
|
||||
}
|
||||
})
|
||||
})*/
|
||||
this.toCreateDraftNew(specIds)
|
||||
})
|
||||
},
|
||||
async addToDraft() {
|
||||
this.isCopying = true
|
||||
this.$http.post('/api/copyProduct/check',null, {params: {type: 0}}).then(res => {
|
||||
if (res.code == 0) {
|
||||
let source
|
||||
if (this.form.type == '1') {
|
||||
source = 'temu'
|
||||
} else if (this.form.type == '2') {
|
||||
source = 'aliexpress'
|
||||
}
|
||||
sendChromeWebReqMessage({
|
||||
type: source,
|
||||
url: this.currentUrl,
|
||||
}).then((res) => {
|
||||
if (this.form.type == '1') {
|
||||
if (res.indexOf("window.rawData") == -1) {
|
||||
this.isCopying = false
|
||||
Message.error("请检查地址是否正确,或者“TEMU”网站是否出现图形验证码")
|
||||
return
|
||||
}
|
||||
let str = res.substring(res.indexOf("window.rawData"))
|
||||
str = str.substring(0, str.indexOf("<\/script>"))
|
||||
str = str.substring(str.indexOf("{"))
|
||||
str = str.substring(0, str.lastIndexOf("}"))
|
||||
str = str + "}"
|
||||
|
||||
let goodsObj = JSON.parse(str)
|
||||
this.goods = goodsObj.store.goods
|
||||
this.sku = goodsObj.store.sku
|
||||
this.catId = this.goods.catId
|
||||
this.goodsProperty = this.goods.goodsProperty
|
||||
this.productDetail = goodsObj.store.productDetail
|
||||
|
||||
let specIds = []
|
||||
this.sku.forEach(item => {
|
||||
item.specs.forEach(item1 => {
|
||||
let flag = false
|
||||
specIds.forEach(item2 => {
|
||||
if (item2.specValue == item1.specValue) {
|
||||
flag = true
|
||||
}
|
||||
})
|
||||
/*if (!flag && (item1.specKeyId != 1001 && item1.specKeyId != 43404162)) {
|
||||
specIds.push({specKeyId: item1.specKeyId, specValue: item1.specValue})
|
||||
}*/
|
||||
if (!flag) {
|
||||
specIds.push({specKeyId: item1.specKeyId, specValue: item1.specValue})
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
/*Promise.all(specIds.map(item => this.getSpecId(item).then(res => {
|
||||
this.sku.forEach(item1 => {
|
||||
item1.specs.forEach(item2 => {
|
||||
if (item2.specValue == item.specValue) {
|
||||
item2.specValueId = res.result.specId
|
||||
}
|
||||
})
|
||||
})
|
||||
return 0
|
||||
}))).then(() => {
|
||||
this.$http.post('/api/copyProduct/translate',{type: 1, goods: this.goods, sku: this.sku, productDetail: this.productDetail}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.createDraft(res.data)
|
||||
}
|
||||
})
|
||||
})*/
|
||||
this.toCreateDraft(specIds)
|
||||
} else if (this.form.type == '2') {
|
||||
}
|
||||
})
|
||||
} else {
|
||||
this.isCopying = false
|
||||
}
|
||||
})
|
||||
},
|
||||
async toCreateDraft(specIds) {
|
||||
for (let kk = 0; kk < this.form.targetMallId.length; kk++) {
|
||||
await Promise.all(specIds.map(item => this.getSpecId(item, this.form.targetMallId[kk]).then(res => {
|
||||
this.sku.forEach(item1 => {
|
||||
item1.specs.forEach(item2 => {
|
||||
if (item2.specValue == item.specValue) {
|
||||
item2.specValueId = res.result.specId
|
||||
}
|
||||
})
|
||||
})
|
||||
return 0
|
||||
})))
|
||||
let res = await this.$http.post('/api/copyProduct/translate',{type: 1, goods: this.goods, sku: this.sku, productDetail: this.productDetail})
|
||||
if (res.code == 0) {
|
||||
await this.createDraft(res.data, this.form.targetMallId[kk])
|
||||
}
|
||||
await this.$sleepSync(500)
|
||||
}
|
||||
},
|
||||
async toCreateDraftNew(specIds) {
|
||||
for (let kk = 0; kk < this.form.targetMallId.length; kk++) {
|
||||
await Promise.all(specIds.map(item => this.getSpecIdNew(item, this.form.targetMallId[kk]).then(res => {
|
||||
this.sku.forEach(item1 => {
|
||||
item1.specs.forEach(item2 => {
|
||||
if (item2.spec_value == item.spec_value) {
|
||||
item2.spec_value_id = res.result.specId
|
||||
}
|
||||
})
|
||||
})
|
||||
return 0
|
||||
})))
|
||||
let res = await this.$http.post('/api/copyProduct/translateNew',{type: 1, goods: this.goods, sku: this.sku, productDetail: this.productDetail})
|
||||
if (res.code == 0) {
|
||||
await this.createDraft(res.data, this.form.targetMallId[kk])
|
||||
}
|
||||
await this.$sleepSync(500)
|
||||
}
|
||||
},
|
||||
async createDraft(data, mallId) {
|
||||
let reqData = {}
|
||||
let catId = null;
|
||||
if (this.form.isSameCategory) {
|
||||
reqData.catId = this.catId;
|
||||
} else {
|
||||
reqData.catId = this.form.targetCatId[this.form.targetCatId.length - 1]
|
||||
}
|
||||
if (this.form.isSemi) {
|
||||
reqData.productSemiManagedReq = {
|
||||
bindSiteIds: this.form.siteId
|
||||
}
|
||||
}
|
||||
let res = await sendChromeAPIMessage({
|
||||
url: 'bg-visage-mms/product/draft/add',
|
||||
needMallId: true,
|
||||
mallId: this.form.targetMallId,
|
||||
data: {
|
||||
catId: this.form.targetCatId[this.form.targetCatId.length - 1]
|
||||
}}).then((res) => {
|
||||
if (res.errorCode == 1000000) {
|
||||
let draftId = res.result.productDraftId
|
||||
let content = data
|
||||
let i = 0
|
||||
mallId: mallId,
|
||||
data: reqData})
|
||||
|
||||
if (res.errorCode == 1000000) {
|
||||
let draftId = res.result.productDraftId
|
||||
let content = data
|
||||
let i = 0
|
||||
if (this.form.isSameCategory) {
|
||||
/*let res2 = await this.$http.post('/api/innerCategory/fullById',null , {
|
||||
params: {
|
||||
id: reqData.catId
|
||||
}
|
||||
})*/
|
||||
for (; i < 10; i++) {
|
||||
if (content['cat' + (i+1) + 'Id']) {
|
||||
continue
|
||||
}else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
let res3 = await sendChromeAPIMessage({
|
||||
url: 'bg-anniston-mms/category/template/query',
|
||||
needMallId: true,
|
||||
mallId: mallId,
|
||||
data: {
|
||||
catId: reqData.catId,
|
||||
productCreateTime: null,
|
||||
langList: [
|
||||
"en"
|
||||
]
|
||||
}})
|
||||
content.productPropertyReqs = []
|
||||
for (let j = 0; j < this.goodsProperty.length; j++) {
|
||||
let temp = {}
|
||||
|
||||
for (let k = 0; k < res3.result.properties.length; k++) {
|
||||
if (this.goodsProperty[j].key == res3.result.properties[k].lang2Name.en) {
|
||||
temp.templatePid = res3.result.properties[k].templatePid
|
||||
temp.pid = res3.result.properties[k].pid
|
||||
temp.refPid = res3.result.properties[k].refPid
|
||||
temp.propName = res3.result.properties[k].name
|
||||
for (let x = 0; x < this.goodsProperty[j].values.length; x++) {
|
||||
if (null == res3.result.properties[k].values) break
|
||||
for (let l = 0; l < res3.result.properties[k].values.length; l++) {
|
||||
if (res3.result.properties[k].values[l].lang2Value.en == this.goodsProperty[j].values[x]) {
|
||||
temp.vid = res3.result.properties[k].values[l].vid
|
||||
temp.propValue = res3.result.properties[k].values[l].value
|
||||
temp.valueUnit = ''
|
||||
temp.valueExtendInfo = ''
|
||||
temp.controlType = res3.result.properties[k].values[l].controlType
|
||||
|
||||
content.productPropertyReqs.push({...temp})
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (; i < this.form.targetCatId.length; i++) {
|
||||
content['cat' + (i+1) + 'Id'] = this.form.targetCatId[i]
|
||||
}
|
||||
for (; i < 10; i++) {
|
||||
content['cat' + (i+1) + 'Id'] = ''
|
||||
}
|
||||
content.productDraftId = draftId
|
||||
|
||||
this.createProduct(content)
|
||||
} else {
|
||||
setTimeout(() => {
|
||||
this.createDraft(data)
|
||||
}, 500)
|
||||
}
|
||||
})
|
||||
if (content['cat'+(i)+'Id'] != reqData.catId) {
|
||||
content['cat'+(++i)+'Id'] = reqData.catId
|
||||
}
|
||||
for (; i < 10; i++) {
|
||||
content['cat' + (i+1) + 'Id'] = ''
|
||||
}
|
||||
|
||||
content.personalizationSwitch = 0
|
||||
content.productDraftId = draftId
|
||||
|
||||
await this.createProduct(content, mallId)
|
||||
}
|
||||
},
|
||||
createProduct(content) {
|
||||
sendChromeAPIMessage({
|
||||
async createProduct(content, mallId) {
|
||||
if (this.form.isSemi) {
|
||||
content.productSemiManagedReq = {
|
||||
bindSiteIds: this.form.siteId
|
||||
}
|
||||
}
|
||||
let res = await sendChromeAPIMessage({
|
||||
url: 'bg-visage-mms/product/draft/save',
|
||||
needMallId: true,
|
||||
mallId: this.form.targetMallId,
|
||||
mallId: mallId,
|
||||
data: {
|
||||
...content
|
||||
}}).then((res) => {
|
||||
if (res.errorCode == 1000000) {
|
||||
Message.success("成功添加到草稿箱")
|
||||
this.saveInfo()
|
||||
}})
|
||||
if (res.errorCode == 1000000) {
|
||||
this.successList.push(this.currentUrl)
|
||||
this.saveInfo(mallId)
|
||||
if (this.isMultiCopy) {
|
||||
this.currentIndex ++
|
||||
if (this.currentIndex == this.params.urlList.length) {
|
||||
this.isCopying = false
|
||||
this.$emit('onSuccess')
|
||||
MessageBox.alert(`成功添加${this.successList.length}个商品进入草稿箱`)
|
||||
} else {
|
||||
this.currentUrl = this.params.urlList[this.currentIndex]
|
||||
this.execAddToDraft()
|
||||
}
|
||||
} else {
|
||||
setTimeout(() => {
|
||||
this.createProduct(content)
|
||||
}, 500)
|
||||
this.isCopying = false
|
||||
Message.success("成功添加到草稿箱")
|
||||
}
|
||||
})
|
||||
|
||||
} else {
|
||||
await this.$sleepSync(1000)
|
||||
this.createProduct(content)
|
||||
}
|
||||
},
|
||||
getSpecId(data) {
|
||||
getSpecIdNew(data) {
|
||||
return sendChromeAPIMessage({
|
||||
url: 'bg-anniston-mms/sku/spec/byName/queryOrAdd',
|
||||
needMallId: true,
|
||||
mallId: this.form.targetMallId,
|
||||
data: {
|
||||
parentSpecId: data.spec_key_id,
|
||||
specName: data.spec_value
|
||||
}}).then((res) => {
|
||||
if (res.errorCode == 1000000) {
|
||||
return res
|
||||
} else {
|
||||
this.getSpecIdNew(data)
|
||||
}
|
||||
})
|
||||
},
|
||||
getSpecId(data, mallId) {
|
||||
return sendChromeAPIMessage({
|
||||
url: 'bg-anniston-mms/sku/spec/byName/queryOrAdd',
|
||||
needMallId: true,
|
||||
mallId: mallId,
|
||||
data: {
|
||||
parentSpecId: data.specKeyId,
|
||||
specName: data.specValue
|
||||
@@ -233,25 +545,54 @@ export default {
|
||||
if (res.errorCode == 1000000) {
|
||||
return res
|
||||
} else {
|
||||
this.getSpecId(data)
|
||||
this.getSpecId(data, mallId)
|
||||
}
|
||||
})
|
||||
},
|
||||
saveInfo() {
|
||||
saveInfo(mallId) {
|
||||
let mallInfo = this.$store.state.mallList.filter(item => {
|
||||
return item.mallId == this.form.targetMallId
|
||||
return item.mallId == mallId
|
||||
})
|
||||
this.$http.post('/api/copyProduct/add', {
|
||||
mallId: mallInfo[0].mallId,
|
||||
mallName: mallInfo[0].mallName,
|
||||
url: this.form.url,
|
||||
url: this.currentUrl,
|
||||
type: this.form.type
|
||||
}).then(res1 => {
|
||||
if (res1.code == 0) {
|
||||
this.$store.dispatch('getUserInfo')
|
||||
this.$emit('onSuccess')
|
||||
if (!this.isMultiCopy) {
|
||||
this.$emit('onSuccess')
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
parseURL(url) {
|
||||
let a = document.createElement('a');
|
||||
a.href = url;
|
||||
return {
|
||||
source: url,
|
||||
protocol: a.protocol.replace(':',''),
|
||||
host: a.hostname,
|
||||
port: a.port,
|
||||
query: a.search,
|
||||
params: (function(){
|
||||
var ret = {},
|
||||
seg = a.search.replace(/^\?/,'').split('&'),
|
||||
len = seg.length, i = 0, s;
|
||||
for (;i<len;i++) {
|
||||
if (!seg[i]) { continue; }
|
||||
s = seg[i].split('=');
|
||||
ret[s[0]] = s[1];
|
||||
}
|
||||
return ret;
|
||||
})(),
|
||||
file: (a.pathname.match(/\/([^\/?#]+)$/i) || [,''])[1],
|
||||
hash: a.hash.replace('#',''),
|
||||
path: a.pathname.replace(/^([^\/])/,'/$1'),
|
||||
relative: (a.href.match(/tps?:\/\/[^\/]+(.+)/) || [,''])[1],
|
||||
segments: a.pathname.replace(/^\//,'').split('/')
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<template>
|
||||
<section class="ai-dialog__wrapper">
|
||||
<el-dialog custom-class="ai-dialog" v-on="$listeners" v-bind="$attrs" :visible.sync="dialog">
|
||||
<el-dialog custom-class="ai-dialog" v-on="$listeners" v-bind="$attrs" :visible.sync="dialog" :close-on-click-modal="false">
|
||||
<div class="ai-dialog__header fill" slot="title" v-text="title"/>
|
||||
<div class="ai-dialog__content">
|
||||
<div class="ai-dialog__content--wrapper pad-r8">
|
||||
<div class="ai-dialog__content--wrapper">
|
||||
<slot/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -69,13 +69,13 @@ export default {
|
||||
|
||||
.ai-dialog__content {
|
||||
overflow-y: auto;
|
||||
padding-bottom: 4px;
|
||||
max-height: 500px;
|
||||
padding-bottom: 0px;
|
||||
max-height: 550px;
|
||||
|
||||
.ai-dialog__content--wrapper {
|
||||
height: 100%;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
93
src/components/AiDownload.vue
Normal file
@@ -0,0 +1,93 @@
|
||||
<template>
|
||||
<div class="ai-download">
|
||||
<a @click="onExport">
|
||||
<slot slot v-if="isHasSlot"></slot>
|
||||
</a>
|
||||
<template v-if="!isHasSlot">
|
||||
<el-button :disabled="disabled" type="primary" @click="onExport">导出</el-button>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'AiDownload',
|
||||
|
||||
props: {
|
||||
url: {
|
||||
type: String,
|
||||
default: '',
|
||||
required: true
|
||||
},
|
||||
|
||||
timeout: {
|
||||
type: Number,
|
||||
default: 80000
|
||||
},
|
||||
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
|
||||
params: {
|
||||
type: Object
|
||||
},
|
||||
|
||||
fileName: {
|
||||
type: String,
|
||||
default: '文件'
|
||||
},
|
||||
|
||||
suffixName: {
|
||||
type: String,
|
||||
default: 'xls'
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
isHasSlot() {
|
||||
return this.$slots.default
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
onExport() {
|
||||
if (this.disabled) {
|
||||
return this.$message.error('暂无数据')
|
||||
}
|
||||
this.$http.post(this.url, this.params, {
|
||||
responseType: 'blob',
|
||||
params: this.params,
|
||||
timeout: this.timeout
|
||||
}).then(res => {
|
||||
if (res?.type == "application/json") {
|
||||
let reader = new FileReader()
|
||||
reader.readAsText(res, "utf-8")
|
||||
reader.onload = e => {
|
||||
if (e.target.readyState === 2) {
|
||||
let ret = JSON.parse(e.target.result)
|
||||
if (ret?.code == 0) {
|
||||
this.$message.success(ret.msg)
|
||||
} else this.$message.error(ret.msg)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const link = document.createElement('a')
|
||||
let blob = new Blob([res], {type: res.type})
|
||||
link.style.display = 'none'
|
||||
link.href = URL.createObjectURL(blob)
|
||||
link.setAttribute('download', this.fileName + '.' + this.suffixName)
|
||||
document.body.appendChild(link)
|
||||
link.click()
|
||||
document.body.removeChild(link)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
</style>
|
||||
@@ -28,7 +28,8 @@
|
||||
background: url("../assets/images/empty.svg") no-repeat center;
|
||||
background-size: 120px 120px;
|
||||
height: 120px;
|
||||
margin: 48px auto 0;
|
||||
margin: 0 auto;
|
||||
padding-top: 40px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
466
src/components/AiLazyCascader.vue
Normal file
@@ -0,0 +1,466 @@
|
||||
<template>
|
||||
<div class="lazy-cascader" :style="{ width: width }">
|
||||
<!-- 禁用状态 -->
|
||||
<div
|
||||
v-if="disabled"
|
||||
class="el-input__inner lazy-cascader-input lazy-cascader-input-disabled"
|
||||
>
|
||||
<span class="lazy-cascader-placeholder" v-show="placeholderVisible">
|
||||
{{ placeholder }}
|
||||
</span>
|
||||
<div class="lazy-cascader-tags" v-if="props.multiple">
|
||||
<el-tag
|
||||
class="lazy-cascader-tag"
|
||||
type="info"
|
||||
disable-transitions
|
||||
v-for="(item, index) in labelArray"
|
||||
:key="index"
|
||||
closable
|
||||
>
|
||||
<span> {{ item.label.join(separator) }}</span>
|
||||
</el-tag>
|
||||
</div>
|
||||
<div class="lazy-cascader-label" v-else>
|
||||
<el-tooltip
|
||||
placement="top-start"
|
||||
:content="labelObject.label.join(separator)"
|
||||
>
|
||||
<span>{{ labelObject.label.join(separator) }}</span>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 禁用状态 -->
|
||||
<!-- 可选状态 -->
|
||||
<el-popover v-else trigger="click" placement="bottom-start" ref="popover">
|
||||
<!-- 搜索 -->
|
||||
<div class="lazy-cascader-search">
|
||||
<el-autocomplete
|
||||
:style="{ width: searchWidth || '100%' }"
|
||||
:popper-class="suggestionsPopperClass"
|
||||
v-if="filterable"
|
||||
class="inline-input"
|
||||
prefix-icon="el-icon-search"
|
||||
label="name"
|
||||
v-model="keyword"
|
||||
:fetch-suggestions="querySearch"
|
||||
:trigger-on-focus="false"
|
||||
placeholder="请输入"
|
||||
@select="handleSelect"
|
||||
@blur="isSearchEmpty = false"
|
||||
>
|
||||
<template slot-scope="{ item }">
|
||||
<div class="name" :class="isChecked(item[props.value])">
|
||||
{{ item[props.label].join(separator) }}
|
||||
</div>
|
||||
</template>
|
||||
</el-autocomplete>
|
||||
<div class="empty" v-show="isSearchEmpty">{{ searchEmptyText }}</div>
|
||||
</div>
|
||||
<!-- 搜索 -->
|
||||
<!-- 级联面板 -->
|
||||
<div class="lazy-cascader-panel">
|
||||
<el-cascader-panel
|
||||
ref="panel"
|
||||
v-model="current"
|
||||
:options="options"
|
||||
:props="currentProps"
|
||||
@change="change"
|
||||
></el-cascader-panel>
|
||||
</div>
|
||||
<!-- 级联面板 -->
|
||||
<!--内容区域-->
|
||||
<div
|
||||
class="el-input__inner lazy-cascader-input"
|
||||
:class="disabled ? 'lazy-cascader-input-disabled' : ''"
|
||||
slot="reference"
|
||||
>
|
||||
<span class="lazy-cascader-placeholder" v-show="placeholderVisible">
|
||||
{{ placeholder }}
|
||||
</span>
|
||||
<div class="lazy-cascader-tags" v-if="props.multiple">
|
||||
<el-tag
|
||||
class="lazy-cascader-tag"
|
||||
type="info"
|
||||
size="small"
|
||||
disable-transitions
|
||||
v-for="(item, index) in labelArray"
|
||||
:key="index"
|
||||
closable
|
||||
@close="handleClose(item)"
|
||||
>
|
||||
<span> {{ item.label.join(separator) }}</span>
|
||||
</el-tag>
|
||||
</div>
|
||||
<div class="lazy-cascader-label" v-else>
|
||||
<el-tooltip
|
||||
placement="top-start"
|
||||
:content="labelObject.label.join(separator)"
|
||||
>
|
||||
<span>{{ labelObject.label.join(separator) }}</span>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<span
|
||||
class="lazy-cascader-clear"
|
||||
v-if="clearable && current.length > 0"
|
||||
@click.stop="clearBtnClick"
|
||||
>
|
||||
<i class="el-icon-close"></i>
|
||||
</span>
|
||||
</div>
|
||||
<!--内容区域-->
|
||||
</el-popover>
|
||||
<!-- 可选状态 -->
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
value: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
separator: {
|
||||
type: String,
|
||||
default: " > "
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: "请选择"
|
||||
},
|
||||
|
||||
width: {
|
||||
type: String,
|
||||
default: "400px"
|
||||
},
|
||||
filterable: Boolean,
|
||||
clearable: Boolean,
|
||||
disabled: Boolean,
|
||||
props: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {};
|
||||
}
|
||||
},
|
||||
suggestionsPopperClass: {
|
||||
type: String,
|
||||
default: "suggestions-popper-class"
|
||||
},
|
||||
searchWidth: {
|
||||
type: String
|
||||
},
|
||||
searchEmptyText: {
|
||||
type: String,
|
||||
default: "暂无数据"
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isSearchEmpty: false,
|
||||
keyword: "",
|
||||
options: [],
|
||||
current: [],
|
||||
labelObject: { label: [], value: [] },
|
||||
labelArray: [],
|
||||
currentProps: {
|
||||
multiple: this.props.multiple,
|
||||
checkStrictly: this.props.checkStrictly,
|
||||
value: this.props.value,
|
||||
label: this.props.label,
|
||||
leaf: this.props.leaf,
|
||||
lazy: true,
|
||||
lazyLoad: this.lazyLoad
|
||||
}
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
placeholderVisible() {
|
||||
if (this.current) {
|
||||
return this.current.length == 0;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
current() {
|
||||
this.getLabelArray();
|
||||
},
|
||||
value(v) {
|
||||
this.current = v;
|
||||
},
|
||||
keyword() {
|
||||
this.isSearchEmpty = false;
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.initOptions();
|
||||
},
|
||||
methods: {
|
||||
//搜索是否选中
|
||||
isChecked(value) {
|
||||
//多选
|
||||
if (this.props.multiple) {
|
||||
let index = this.current.findIndex(item => {
|
||||
return item.join() == value.join();
|
||||
});
|
||||
if (index > -1) {
|
||||
return "el-link el-link--primary";
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
} else {
|
||||
if (value.join() == this.current.join()) {
|
||||
return "el-link el-link--primary";
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
},
|
||||
//搜索
|
||||
querySearch(query, callback) {
|
||||
this.props.lazySearch(query, list => {
|
||||
callback(list);
|
||||
if (!list || !list.length) this.isSearchEmpty = true;
|
||||
});
|
||||
},
|
||||
//选中搜索下拉搜索项
|
||||
handleSelect(item) {
|
||||
if (this.props.multiple) {
|
||||
let index = this.current.findIndex(obj => {
|
||||
return obj.join() == item[this.props.value].join();
|
||||
});
|
||||
if (index == -1) {
|
||||
this.$refs.panel.clearCheckedNodes();
|
||||
this.current.push(item[this.props.value]);
|
||||
this.$emit("change", this.current);
|
||||
}
|
||||
} else {
|
||||
//选中下拉选变更值
|
||||
if (
|
||||
this.current == null ||
|
||||
item[this.props.value].join() !== this.current.join()
|
||||
) {
|
||||
this.$refs.panel.activePath = [];
|
||||
this.current = item[this.props.value];
|
||||
this.$emit("change", this.current);
|
||||
}
|
||||
}
|
||||
this.keyword = "";
|
||||
},
|
||||
//初始化数据
|
||||
async initOptions() {
|
||||
this.props.lazyLoad(0, list => {
|
||||
this.$set(this, "options", list);
|
||||
if (this.props.multiple) {
|
||||
this.current = [...this.value];
|
||||
} else {
|
||||
this.current = this.value;
|
||||
}
|
||||
});
|
||||
},
|
||||
async getLabelArray() {
|
||||
if (this.props.multiple) {
|
||||
let array = [];
|
||||
for (let i = 0; i < this.current.length; i++) {
|
||||
let obj = await this.getObject(this.current[i]);
|
||||
array.push(obj);
|
||||
}
|
||||
this.labelArray = array;
|
||||
this.$emit("input", this.current);
|
||||
if (!this.disabled) {
|
||||
this.$nextTick(() => {
|
||||
this.$refs.popover.updatePopper();
|
||||
});
|
||||
}
|
||||
} else {
|
||||
this.labelObject = await this.getObject(this.current || []);
|
||||
this.$emit("input", this.current);
|
||||
}
|
||||
},
|
||||
/**格式化id=>object */
|
||||
async getObject(id) {
|
||||
try {
|
||||
let options = this.options;
|
||||
let nameArray = [];
|
||||
for (let i = 0; i < id.length; i++) {
|
||||
let index = options.findIndex(item => {
|
||||
return item[this.props.value] == id[i];
|
||||
});
|
||||
nameArray.push(options[index][this.props.label]);
|
||||
if (i < id.length - 1 && options[index].children == undefined) {
|
||||
let list = new Promise(resolve => {
|
||||
this.props.lazyLoad(id[i], list => {
|
||||
resolve(list);
|
||||
});
|
||||
});
|
||||
this.$set(options[index], "children", await list);
|
||||
options = options[index].children;
|
||||
} else {
|
||||
options = options[index].children;
|
||||
}
|
||||
}
|
||||
return { value: id, label: nameArray };
|
||||
} catch (e) {
|
||||
this.current = [];
|
||||
return { value: [], label: [] };
|
||||
}
|
||||
},
|
||||
//懒加载数据
|
||||
async lazyLoad(node, resolve) {
|
||||
let current = this.current;
|
||||
if (this.props.multiple) {
|
||||
current = [...this.current];
|
||||
}
|
||||
if (node.root) {
|
||||
resolve();
|
||||
} else if (node.data[this.props.leaf]) {
|
||||
resolve();
|
||||
} else if (node.data.children) {
|
||||
if (this.props.multiple) {
|
||||
this.current = current;
|
||||
}
|
||||
resolve();
|
||||
} else {
|
||||
this.props.lazyLoad(node.value, list => {
|
||||
node.data.children = list;
|
||||
if (this.props.multiple) {
|
||||
this.current = current;
|
||||
}
|
||||
resolve(list);
|
||||
});
|
||||
}
|
||||
},
|
||||
//删除多选值
|
||||
/**删除**/
|
||||
handleClose(item) {
|
||||
let index = this.current.findIndex(obj => {
|
||||
return obj.join() == item.value.join();
|
||||
});
|
||||
if (index > -1) {
|
||||
this.$refs.panel.clearCheckedNodes();
|
||||
this.current.splice(index, 1);
|
||||
this.$emit("change", this.current);
|
||||
}
|
||||
},
|
||||
//点击清空按钮
|
||||
clearBtnClick() {
|
||||
this.$refs.panel.clearCheckedNodes();
|
||||
this.current = [];
|
||||
this.$emit("change", this.current);
|
||||
},
|
||||
change() {
|
||||
this.$emit("change", this.current);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.lazy-cascader {
|
||||
display: inline-block;
|
||||
width: 300px;
|
||||
.lazy-cascader-input {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
background: #fff;
|
||||
height: auto;
|
||||
min-height: 36px;
|
||||
padding: 5px;
|
||||
line-height: 1;
|
||||
cursor: pointer;
|
||||
.lazy-cascader-placeholder {
|
||||
padding: 0 2px;
|
||||
line-height: 28px;
|
||||
color: #999;
|
||||
font-size: 14px;
|
||||
}
|
||||
.lazy-cascader-label {
|
||||
padding: 0 2px;
|
||||
line-height: 28px;
|
||||
color: #606266;
|
||||
font-size: 14px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.lazy-cascader-clear {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
display: inline-block;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
text-align: center;
|
||||
line-height: 40px;
|
||||
}
|
||||
}
|
||||
.lazy-cascader-input-disabled {
|
||||
background-color: #f5f7fa;
|
||||
border-color: #e4e7ed;
|
||||
color: #c0c4cc;
|
||||
cursor: not-allowed;
|
||||
.lazy-cascader-label {
|
||||
color: #c0c4cc;
|
||||
}
|
||||
.lazy-cascader-placeholder {
|
||||
color: #c0c4cc;
|
||||
}
|
||||
}
|
||||
}
|
||||
.lazy-cascader-tag {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
max-width: 100%;
|
||||
margin: 2px;
|
||||
text-overflow: ellipsis;
|
||||
background: #f0f2f5;
|
||||
span {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.el-icon-close {
|
||||
-webkit-box-flex: 0;
|
||||
-ms-flex: none;
|
||||
flex: none;
|
||||
background-color: #c0c4cc;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
.lazy-cascader-panel {
|
||||
margin-top: 10px;
|
||||
display: inline-block;
|
||||
}
|
||||
.suggestions-popper-class {
|
||||
width: auto !important;
|
||||
min-width: 200px;
|
||||
}
|
||||
.lazy-cascader-search {
|
||||
.empty {
|
||||
width: calc(100% - 24px);
|
||||
box-sizing: border-box;
|
||||
background-color: #fff;
|
||||
color: #999;
|
||||
text-align: center;
|
||||
position: absolute;
|
||||
z-index: 999;
|
||||
padding: 12px 0;
|
||||
margin-top: 12px;
|
||||
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
||||
&:before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: -12px;
|
||||
left: 36px;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-left: 6px solid transparent;
|
||||
border-right: 6px solid transparent;
|
||||
border-top: 6px solid transparent;
|
||||
border-bottom: 6px solid #fff;
|
||||
filter: drop-shadow(0 -1px 2px rgba(0, 0, 0, 0.02));
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -2,7 +2,7 @@
|
||||
<section class="AiPayment">
|
||||
<el-tabs type="card" stretch v-model="search.module" @tab-click="getPayments">
|
||||
<el-tab-pane label="激活码兑换" name="2"/>
|
||||
<el-tab-pane label="基础会员" name="0"/>
|
||||
<el-tab-pane label="年度会员" name="0"/>
|
||||
<el-tab-pane label="金币充值" name="1"/>
|
||||
</el-tabs>
|
||||
<div class="content">
|
||||
@@ -46,8 +46,8 @@
|
||||
<el-form-item
|
||||
prop="mallId"
|
||||
v-show="false"
|
||||
:rules="[{ message: '请输入商城ID', trigger: 'blur' }]">
|
||||
<el-input placeholder="请输入商城ID" v-model="form.mallId"></el-input>
|
||||
:rules="[{ message: '请输入店铺ID', trigger: 'blur' }]">
|
||||
<el-input placeholder="请输入店铺ID" v-model="form.mallId"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
prop="code"
|
||||
@@ -108,12 +108,12 @@ export default {
|
||||
mallId: this.$store.state.mallId,
|
||||
mallName: this.$store.state.mallName
|
||||
},
|
||||
vipType: ["体验会员","年会员","年会员多店通用"],
|
||||
vipType: ["体验会员","单店年会员","年会员多店通用"],
|
||||
|
||||
search: {module: "0"},
|
||||
show: true,
|
||||
descriptionsModule0: ["抢仓发货", "数据下载", "复制商品", "会员服务"],
|
||||
descriptionsModule1: ["智能复制"],
|
||||
descriptionsModule1: ["商品采集", "店铺跟踪", "关键字跟踪", "单品跟踪", "新品跟踪"],
|
||||
payments: [],
|
||||
qrcode: "",
|
||||
amount: 0,
|
||||
@@ -134,6 +134,9 @@ export default {
|
||||
}
|
||||
})
|
||||
},
|
||||
getMessage(type) {
|
||||
return `你使用的是“${this.vipType[type]}”兑换券,确定兑换?`;
|
||||
},
|
||||
getQrcode(item) {
|
||||
if (item.module == '0' && !this.vipForm.mallId) {
|
||||
Message.error("请先登录拼多多垮境卖家中心")
|
||||
@@ -141,7 +144,11 @@ export default {
|
||||
}
|
||||
this.selected = item
|
||||
this.$http.post("/api/order/createOrder", null, {
|
||||
params: {priceConfigId: item.id}
|
||||
params: {
|
||||
priceConfigId: item.id,
|
||||
mallName: this.vipForm.mallName,
|
||||
mallId: this.vipForm.mallId
|
||||
}
|
||||
}).then(res => {
|
||||
if (res?.data?.id) {
|
||||
return res.data.id
|
||||
|
||||
@@ -9,14 +9,14 @@
|
||||
<ai-wrapper
|
||||
label-width="120px" class="fill">
|
||||
<ai-info-item label="价格:" :value="'$' + info.price"></ai-info-item>
|
||||
<ai-info-item label="销量:" :value="info.saleTotal"></ai-info-item>
|
||||
<ai-info-item label="销量/评论数:" :value="info.saleTotal"></ai-info-item>
|
||||
</ai-wrapper>
|
||||
</div>
|
||||
</template>
|
||||
</ai-card>
|
||||
<ai-card title="趋势信息">
|
||||
<template #content>
|
||||
<div id="chart"></div>
|
||||
<div id="dataChart"></div>
|
||||
</template>
|
||||
</ai-card>
|
||||
</template>
|
||||
@@ -28,7 +28,7 @@ import { DualAxes } from '@antv/g2plot'
|
||||
|
||||
export default {
|
||||
name: "AiProductDetail",
|
||||
props: ['params'],
|
||||
props: ['params', 'url'],
|
||||
components: {
|
||||
AiProductDropDown
|
||||
},
|
||||
@@ -39,19 +39,23 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
},
|
||||
created() {
|
||||
this.getInfo()
|
||||
mounted() {
|
||||
// this.info = this.params
|
||||
this.$nextTick(() => {
|
||||
this.init()
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
getInfo() {
|
||||
this.$http.post('/api/monitorDetail/queryDetail',null,{
|
||||
init() {
|
||||
this.$http.post(this.url ? this.url: '/api/monitorDetail/queryProductDetail',null,{
|
||||
params: {
|
||||
goodsId: this.params.goodsId
|
||||
goodsId: this.params.goodsId,
|
||||
monitorId: this.params.monitorId
|
||||
}
|
||||
}).then(res => {
|
||||
this.info = res.data
|
||||
|
||||
const dualAxes = new DualAxes('chart', {
|
||||
|
||||
const dualAxes = new DualAxes('dataChart', {
|
||||
data: [this.info.priceAndSale, this.info.priceAndSale],
|
||||
xField: '日期',
|
||||
yField: ['价格', '销量'],
|
||||
@@ -65,14 +69,6 @@ export default {
|
||||
color: '#5AD8A6',
|
||||
}
|
||||
],
|
||||
smooth: true,
|
||||
// @TODO 后续会换一种动画方式
|
||||
animation: {
|
||||
appear: {
|
||||
animation: 'path-in',
|
||||
duration: 5000,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
dualAxes.render();
|
||||
|
||||
@@ -6,14 +6,17 @@
|
||||
</span>
|
||||
<el-dropdown-menu slot="dropdown">
|
||||
<el-dropdown-item v-if="isShowDetail" :command="beforeGoDetail(params.goodsId)">查看详情</el-dropdown-item>
|
||||
<el-dropdown-item divided :command="beforeCopy(params.url)">复制商品</el-dropdown-item>
|
||||
<el-dropdown-item v-if="isShowAddFavorite" :command="beforeAddFavorite(params.goodsId, params.monitorId)">加入收藏</el-dropdown-item>
|
||||
<el-dropdown-item v-if="isShowDelFavorite" :command="beforeDelFavorite(params.id)">取消收藏</el-dropdown-item>
|
||||
<el-dropdown-item divided v-if="isShowGroup" :command="beforeAddGroup(params.goodsId)">加入分组</el-dropdown-item>
|
||||
<el-dropdown-item divided v-if="!isHideCopy" :command="beforeCopy(params.url)">商品采集</el-dropdown-item>
|
||||
<el-dropdown-item divided :command="beforeGoWeb(params.url)">访问商品</el-dropdown-item>
|
||||
<el-dropdown-item :command="beforeGoMal(params.mallId)">访问店铺</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
|
||||
<ai-dialog
|
||||
title="复制"
|
||||
title="商品采集"
|
||||
:visible.sync="copyFromDlgShow"
|
||||
:close-on-click-modal="false"
|
||||
width="790px"
|
||||
@@ -22,19 +25,53 @@
|
||||
@close="handleClose">
|
||||
<ai-copy-from-temu v-if="copyFromDlgShow" :params="temuParams" @onClose="handleClose" @onSuccess="handleSuccess"></ai-copy-from-temu>
|
||||
</ai-dialog>
|
||||
|
||||
<ai-dialog
|
||||
title="添加到分组"
|
||||
:visible.sync="addGroupDlgShow"
|
||||
:close-on-click-modal="false"
|
||||
width="790px"
|
||||
customFooter
|
||||
:append-to-body="true"
|
||||
@close="handleClose">
|
||||
<el-form class="ai-form" :model="addGroupForm" label-width="120px" ref="addGroupForm">
|
||||
<el-form-item label="分组" style="width: 100%;" prop="groupId" :rules="[{ required: true, message: '请选择分组', trigger: 'blur' }]">
|
||||
<el-select style="width: 380px" v-model="addGroupForm.groupId" placeholder="请选择分组">
|
||||
<el-option
|
||||
v-for="item in groupList"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:value="item.id">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div class="dialog-footer" slot="footer">
|
||||
<el-button @click="addGroupDlgShow = false">取消</el-button>
|
||||
<el-button type="primary" @click="addToGroup">确定</el-button>
|
||||
</div>
|
||||
</ai-dialog>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import AiCopyFromTemu from "./AiCopyFromTemu.vue";
|
||||
import { Message } from 'element-ui'
|
||||
|
||||
export default {
|
||||
name: "AiProductDropDown",
|
||||
components: {AiCopyFromTemu},
|
||||
props: ['params', 'isShowDetail'],
|
||||
props: ['params', 'source', 'isShowDetail', 'isShowAddFavorite', 'isShowDelFavorite', 'isShowGroup', 'isHideCopy'],
|
||||
data() {
|
||||
return {
|
||||
info: {},
|
||||
copyFromDlgShow: false,
|
||||
temuParams: {}
|
||||
addGroupDlgShow: false,
|
||||
temuParams: {},
|
||||
addGroupForm: {
|
||||
groupId: '',
|
||||
goodsId: ''
|
||||
},
|
||||
groupList: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -46,18 +83,59 @@ export default {
|
||||
if (e.type == 'detail') {
|
||||
this.$emit('onGoDetail')
|
||||
} else if (e.type == 'copy') {
|
||||
this.temuParams = {url: 'https://www.temu.com/' + e.url}
|
||||
if (e.url.startsWith('http')) {
|
||||
this.temuParams = {url: e.url}
|
||||
} else {
|
||||
this.temuParams = {url: 'https://www.temu.com/' + e.url}
|
||||
}
|
||||
this.copyFromDlgShow = true
|
||||
} else if (e.type == 'addFavorite') {
|
||||
this.$http.post('/api/monitorFavorite/add',{goodsId: e.goodsId, monitorId: e.monitorId}).then(res => {
|
||||
if (res.code == 0) {
|
||||
Message.success('收藏成功')
|
||||
}
|
||||
})
|
||||
} else if (e.type == 'delFavorite') {
|
||||
this.$http.post('/api/monitorFavorite/del?id=' + e.id).then(res => {
|
||||
if (res.code == 0) {
|
||||
Message.success('删除收藏成功')
|
||||
this.$emit('onDelFavoriteSuccess')
|
||||
}
|
||||
})
|
||||
} else if (e.type == 'addGroup') {
|
||||
this.addGroupForm.goodsId = e.goodsId
|
||||
this.$http.post('/api/newProductGroup/myPage?size=1000').then(res => {
|
||||
if (res.code == 0) {
|
||||
this.addGroupDlgShow = true
|
||||
this.groupList = res.data.records
|
||||
}
|
||||
})
|
||||
} else if (e.type == 'goMall') {
|
||||
window.open('https://www.temu.com/mall.html?mall_id=' + e.mallId, '_blank');
|
||||
if (e.mallId.startsWith('http')) {
|
||||
window.open(e.mallId, '_blank');
|
||||
} else {
|
||||
window.open('https://www.temu.com/mall.html?mall_id=' + e.mallId, '_blank');
|
||||
}
|
||||
} else if (e.type == 'goWeb') {
|
||||
console.log(e.url)
|
||||
window.open('https://www.temu.com/' + e.url, '_blank');
|
||||
if (e.url.startsWith('http')) {
|
||||
window.open(e.url, '_blank');
|
||||
} else {
|
||||
window.open('https://www.temu.com/' + e.url, '_blank');
|
||||
}
|
||||
}
|
||||
},
|
||||
beforeGoDetail(goodsId) {
|
||||
return {type: 'detail', goodsId: goodsId}
|
||||
},
|
||||
beforeAddFavorite(goodsId, monitorId) {
|
||||
return {type: 'addFavorite', goodsId: goodsId, monitorId: monitorId}
|
||||
},
|
||||
beforeDelFavorite(id) {
|
||||
return {type: 'delFavorite', id: id}
|
||||
},
|
||||
beforeAddGroup(goodsId) {
|
||||
return {type: 'addGroup', goodsId: goodsId}
|
||||
},
|
||||
beforeCopy(url) {
|
||||
return {type: 'copy', url: url}
|
||||
},
|
||||
@@ -69,9 +147,22 @@ export default {
|
||||
},
|
||||
handleClose() {
|
||||
this.copyFromDlgShow = false
|
||||
this.addGroupDlgShow = false
|
||||
},
|
||||
handleSuccess() {
|
||||
this.copyFromDlgShow = false
|
||||
},
|
||||
addToGroup() {
|
||||
this.$refs.addGroupForm.validate((valid) => {
|
||||
if (valid) {
|
||||
this.$http.post('/api/newProductGroupDetail/add', {...this.addGroupForm}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.addGroupDlgShow = false
|
||||
Message.success("商品成功添加到分组")
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
81
src/components/AiSingleProductDetail.vue
Normal file
@@ -0,0 +1,81 @@
|
||||
<template>
|
||||
<ai-detail class="audit">
|
||||
<template slot="content">
|
||||
<ai-card title="基本信息">
|
||||
<ai-product-drop-down v-if="info" :params="info" slot="right"></ai-product-drop-down>
|
||||
<template #content>
|
||||
<div class="flex">
|
||||
<ai-avatar v-model="info.imgUrl" :editable="false" :preview="true"/>
|
||||
<ai-wrapper
|
||||
label-width="120px" class="fill">
|
||||
<ai-info-item label="价格:" :value="'$' + info.price"></ai-info-item>
|
||||
<ai-info-item label="销量:" :value="info.saleTotal"></ai-info-item>
|
||||
</ai-wrapper>
|
||||
</div>
|
||||
</template>
|
||||
</ai-card>
|
||||
<ai-card title="趋势信息">
|
||||
<template #content>
|
||||
<div id="dataChart"></div>
|
||||
</template>
|
||||
</ai-card>
|
||||
</template>
|
||||
</ai-detail>
|
||||
</template>
|
||||
<script>
|
||||
import AiProductDropDown from './AiProductDropDown.vue'
|
||||
import { DualAxes } from '@antv/g2plot'
|
||||
|
||||
export default {
|
||||
name: "AiSingleProductDetail",
|
||||
props: ['params', 'url'],
|
||||
components: {
|
||||
AiProductDropDown
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
info: {}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
},
|
||||
mounted() {
|
||||
// this.info = this.params
|
||||
this.$nextTick(() => {
|
||||
this.init()
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
this.$http.post(this.url ? this.url: '/api/singleGoodsDetail/queryDetail',null,{
|
||||
params: {
|
||||
goodsId: this.params.goodsId,
|
||||
groupId: this.params.groupId
|
||||
}
|
||||
}).then(res => {
|
||||
this.info = res.data
|
||||
|
||||
const dualAxes = new DualAxes('dataChart', {
|
||||
data: [this.info.priceAndSale, this.info.priceAndSale],
|
||||
xField: '日期',
|
||||
yField: ['价格', '销量'],
|
||||
geometryOptions: [
|
||||
{
|
||||
geometry: 'line',
|
||||
color: '#5B8FF9',
|
||||
},
|
||||
{
|
||||
geometry: 'line',
|
||||
color: '#5AD8A6',
|
||||
}
|
||||
],
|
||||
});
|
||||
|
||||
dualAxes.render();
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
</style>
|
||||
81
src/components/AiSpecialProductDetail.vue
Normal file
@@ -0,0 +1,81 @@
|
||||
<template>
|
||||
<ai-detail class="audit">
|
||||
<template slot="content">
|
||||
<ai-card title="基本信息">
|
||||
<ai-product-drop-down v-if="info" :params="info" slot="right"></ai-product-drop-down>
|
||||
<template #content>
|
||||
<div class="flex">
|
||||
<ai-avatar v-model="info.imgUrl" :editable="false" :preview="true"/>
|
||||
<ai-wrapper
|
||||
label-width="120px" class="fill">
|
||||
<ai-info-item label="价格:" :value="'$' + info.price"></ai-info-item>
|
||||
<ai-info-item label="销量:" :value="info.saleTotal"></ai-info-item>
|
||||
</ai-wrapper>
|
||||
</div>
|
||||
</template>
|
||||
</ai-card>
|
||||
<ai-card title="趋势信息">
|
||||
<template #content>
|
||||
<div id="dataChart"></div>
|
||||
</template>
|
||||
</ai-card>
|
||||
</template>
|
||||
</ai-detail>
|
||||
</template>
|
||||
<script>
|
||||
import AiProductDropDown from './AiProductDropDown.vue'
|
||||
import { DualAxes } from '@antv/g2plot'
|
||||
|
||||
export default {
|
||||
name: "AiProductDetail",
|
||||
props: ['params'],
|
||||
components: {
|
||||
AiProductDropDown
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
info: {}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
},
|
||||
mounted() {
|
||||
// this.info = this.params
|
||||
this.$nextTick(() => {
|
||||
this.init()
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
this.$http.post('/api/specialDetail/queryProductDetail',null,{
|
||||
params: {
|
||||
goodsId: this.params.goodsId,
|
||||
categoryId: this.params.categoryId
|
||||
}
|
||||
}).then(res => {
|
||||
this.info = res.data
|
||||
|
||||
const dualAxes = new DualAxes('dataChart', {
|
||||
data: [this.info.priceAndSale, this.info.priceAndSale],
|
||||
xField: '日期',
|
||||
yField: ['价格', '销量'],
|
||||
geometryOptions: [
|
||||
{
|
||||
geometry: 'line',
|
||||
color: '#5B8FF9',
|
||||
},
|
||||
{
|
||||
geometry: 'line',
|
||||
color: '#5AD8A6',
|
||||
}
|
||||
],
|
||||
});
|
||||
|
||||
dualAxes.render();
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
</style>
|
||||
@@ -7,6 +7,9 @@
|
||||
<h2>{{ title }}</h2>
|
||||
<p>{{ tips }}</p>
|
||||
</div>
|
||||
<div class="ailist-title__middle">
|
||||
<slot name="center"/>
|
||||
</div>
|
||||
<div class="ailist-title__right">
|
||||
<div class="aititle-right__btns">
|
||||
<slot name="rightBtn"/>
|
||||
@@ -75,6 +78,11 @@
|
||||
justify-content: space-between;
|
||||
height: 48px;
|
||||
|
||||
.ailist-title__middle {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.ailist-title__left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
511
src/components/LablesMember.vue
Normal file
@@ -0,0 +1,511 @@
|
||||
<template>
|
||||
<transition name="fade">
|
||||
<div class="LablesMember" v-if="isShow">
|
||||
<div class="mask"></div>
|
||||
<div class="LablesMember-wrapper">
|
||||
<i class="el-icon-close" @click="hide"></i>
|
||||
<div class="top">
|
||||
<img src="../assets/images/avatar.png" />
|
||||
<div class="top-right">
|
||||
<div class="top-user">
|
||||
<h2>用户:{{ $store.state.userInfo.name }}</h2>
|
||||
<span></span>
|
||||
</div>
|
||||
<p>会员中心</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="middle">
|
||||
<div class="middle-top">
|
||||
<div class="tab">
|
||||
<div @click="tabIndex = 0, currIndex = 0, getPriceList(1)" :class="[tabIndex === 0 ? 'active' : '']">
|
||||
<span>金币充值</span>
|
||||
</div>
|
||||
<div @click="tabIndex = 1, currIndex = 0, getPriceList(0)" :class="[tabIndex === 1 ? 'active' : '']">
|
||||
<span>年度会员</span>
|
||||
</div>
|
||||
<div @click="tabIndex = 2, currIndex = 0, getPriceList(2)" :class="[tabIndex === 2 ? 'active' : '']">
|
||||
<span>高级功能</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tab-content" v-if="tabIndex === 0">
|
||||
<div class="title">金币充值</div>
|
||||
<div class="tab-content__item--wrapper">
|
||||
<div
|
||||
class="tab-content__item"
|
||||
:class="[currIndex === i ? 'active' : '']"
|
||||
v-for="(price, i) in priceList"
|
||||
:key="i"
|
||||
@click="currIndex = i, getQrcode(price)">
|
||||
<h3>{{ price.remark }}</h3>
|
||||
<div class="price">
|
||||
<i>¥</i>
|
||||
<span>{{ price.price }}</span>
|
||||
</div>
|
||||
<div class="original-price">
|
||||
<i>¥</i>
|
||||
<span>{{ price.originPrice }}</span>
|
||||
</div>
|
||||
<p>{{ price.coin }}条/每年</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tab-content" v-if="tabIndex === 1">
|
||||
<div class="title">年度会员</div>
|
||||
<div class="tab-content__item--wrapper">
|
||||
<div
|
||||
class="tab-content__item"
|
||||
:class="[currIndex === i ? 'active' : '']"
|
||||
v-for="(price, i) in priceList"
|
||||
:key="i"
|
||||
@click="currIndex = i, getQrcode(price)">
|
||||
<h3>{{ price.title }}</h3>
|
||||
<div class="price">
|
||||
<i>¥</i>
|
||||
<span>{{ price.price }}</span>
|
||||
</div>
|
||||
<div class="original-price">
|
||||
<i>¥</i>
|
||||
<span>{{ price.originPrice }}</span>
|
||||
</div>
|
||||
<!-- <p>{{ price.coin }}条/每年</p> -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tab-content" v-if="tabIndex === 2">
|
||||
<div class="title">标签合成</div>
|
||||
<div class="tab-content__item--wrapper">
|
||||
<div
|
||||
class="tab-content__item"
|
||||
:class="[currIndex === i ? 'active' : (Number(labelInfo.level) >= Number(price.type) ? 'disabled' : '')]"
|
||||
:data-level="price.type"
|
||||
:data-index="labelInfo.level"
|
||||
v-for="(price, i) in priceList"
|
||||
:key="i"
|
||||
@click="getQrcode(price, i)">
|
||||
<h3>{{ price.remark }}</h3>
|
||||
<div class="price">
|
||||
<i>¥</i>
|
||||
<span>{{ price.price }}</span>
|
||||
</div>
|
||||
<div class="original-price">
|
||||
<i>¥</i>
|
||||
<span>{{ price.originPrice }}</span>
|
||||
</div>
|
||||
<p>{{ price.coin }}条/每年</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="title">支付方式</div>
|
||||
<div class="bottom">
|
||||
<div class="bottom-left">
|
||||
<div class="code">
|
||||
<vue-qr v-if="qrcode" :text="qrcode" :size="110" :margin="0" :logoSrc="wechatLogo"/>
|
||||
</div>
|
||||
<div class="paytype">
|
||||
<svg width="13" height="13" viewBox="0 0 13 13" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M12.11 0H.89A.89.89 0 0 0 0 .89v11.22c0 .491.399.89.89.89h11.22a.89.89 0 0 0 .89-.89V.89a.89.89 0 0 0-.89-.89zM6.5 10.65a5.592 5.592 0 0 1-1.848-.311c-.364.241-.975.639-1.215.75-.352.162-.25-.188-.25-.188L3.395 9.7C2.24 8.895 1.499 7.654 1.499 6.26c0-2.426 2.239-4.392 5-4.392 1.693 0 3.188.74 4.093 1.869l-4.905 2.27s-.4.152-.75-.062c-.35-.213-.813-.564-.813-.564s-.538-.458-.25.376l.751 1.756s.089.524.687.189c.468-.262 4.103-2.454 5.666-3.397a3.94 3.94 0 0 1 .523 1.954c0 2.425-2.239 4.391-5.001 4.391z" fill="#09BB07" fill-rule="nonzero"></path>
|
||||
</svg>
|
||||
<span>微信支付</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bottom-right">
|
||||
<div class="right-price">
|
||||
<i>¥</i>
|
||||
<span class="price">{{ currGoods.price || '' }}</span>
|
||||
</div>
|
||||
<div class="pay-btn">
|
||||
<el-button round size="mini" style="margin-right: 10px;" @click="isShow = false">取消支付</el-button>
|
||||
<el-button round size="mini" type="warning" @click="$store.dispatch('getUserInfo'), isShow = false">我已支付</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import VueQr from 'vue-qr'
|
||||
import { mapState } from 'vuex'
|
||||
export default {
|
||||
components: {
|
||||
VueQr
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
form: {
|
||||
mallId: this.$store.state.mallId,
|
||||
mallName: this.$store.state.mallName,
|
||||
code: ''
|
||||
},
|
||||
isShow: false,
|
||||
tabIndex: 0,
|
||||
currIndex: 0,
|
||||
qrcode: '',
|
||||
priceList: []
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
wechatLogo: () => require(`../assets/wechat_logo.png`),
|
||||
|
||||
...mapState(['labelInfo']),
|
||||
|
||||
currGoods () {
|
||||
if (!this.priceList.length) {
|
||||
return {}
|
||||
}
|
||||
|
||||
return this.priceList[this.currIndex]
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.getPriceList(1)
|
||||
},
|
||||
|
||||
methods: {
|
||||
getPriceList(type) {
|
||||
this.$http.post(`/api/priceConfig/page?module=${type}`).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.priceList = res.data.records
|
||||
if (res.data.records.length) {
|
||||
if (this.tabIndex !== 2) {
|
||||
this.getQrcode(res.data.records[0])
|
||||
} else {
|
||||
for (let i = 0; i < res.data.records.length; i++) {
|
||||
if (res.data.records[i].type > this.labelInfo.level) {
|
||||
this.getQrcode(res.data.records[i], i)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
getQrcode(item, index) {
|
||||
if (this.tabIndex === 2 && item.type <= this.labelInfo.level) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (this.tabIndex === 2) {
|
||||
this.currIndex = index
|
||||
}
|
||||
this.$http.post(`/api/order/createOrder`, null, {
|
||||
params: {
|
||||
priceConfigId: item.id
|
||||
}
|
||||
}).then(res => {
|
||||
if (res?.data?.id) {
|
||||
return res.data.id
|
||||
}
|
||||
}).then(id => this.$http.post(`/api/order/createPrepayOrder?id=${id}`)).then(res => {
|
||||
if (res?.data) {
|
||||
this.qrcode = res.data.codeUrl
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
show(i) {
|
||||
this.currIndex = 0
|
||||
this.tabIndex = {
|
||||
'0': 1,
|
||||
'1': 0,
|
||||
'2': 2
|
||||
}[i]
|
||||
this.getPriceList(i)
|
||||
this.isShow = true
|
||||
},
|
||||
|
||||
hide () {
|
||||
this.isShow = false
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.LablesMember {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
z-index: 1111;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
.title {
|
||||
margin: 20px 0 10px 40px;
|
||||
font-size: 16px;
|
||||
text-align: left;
|
||||
font-weight: 600;
|
||||
color: #2a2b2e;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.mask {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
z-index: 1;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba($color: #000000, $alpha: 0.8);
|
||||
}
|
||||
|
||||
.LablesMember-wrapper {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
z-index: 11;
|
||||
min-width: 916px;
|
||||
// height: 620px;
|
||||
padding: 40px 40px;
|
||||
transform: translate(-50%, -50%);
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
background: linear-gradient(41deg, #ffebd3, #fff8e3 61%, #fae2c4 99%);
|
||||
|
||||
.top {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
|
||||
img {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
p {
|
||||
color: #632e2e;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.top-user {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
|
||||
h2 {
|
||||
margin-right: 6px;
|
||||
font-size: 16px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
span {
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.el-icon-close {
|
||||
position: absolute;
|
||||
top: 12px;
|
||||
right: 12px;
|
||||
z-index: 11;
|
||||
font-size: 32px;
|
||||
color: #333;
|
||||
cursor: pointer;
|
||||
transform-origin: center center;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.6;
|
||||
// transform: translate(50%, -50%) rotate(180deg);
|
||||
}
|
||||
}
|
||||
|
||||
.middle {
|
||||
padding-bottom: 20px;
|
||||
border-radius: 20px;
|
||||
overflow: hidden;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 0 20px 0 hsla(0, 39%, 56%, .1), 0 0 16px 0 rgba(0, 0, 0, .08);
|
||||
|
||||
.middle-top {
|
||||
flex: 1;
|
||||
padding: 0 0;
|
||||
|
||||
.tab {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 50px;
|
||||
background: #fff3ee;
|
||||
|
||||
div {
|
||||
position: relative;
|
||||
flex: 1;
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
text-align: center;
|
||||
font-size: 22px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
color: #b69593;
|
||||
|
||||
span {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
&.active {
|
||||
color: #6f3333;
|
||||
|
||||
&::after {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
z-index: 1;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: url(../assets/tab_middle.png) no-repeat center;
|
||||
background-size: contain;
|
||||
content: '';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tab-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 0 40px;
|
||||
|
||||
.title {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
&__item--wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&__item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
width: 140px;
|
||||
height: 170px;
|
||||
margin-right: 14px;
|
||||
padding-top: 20px;
|
||||
background-color: #fff;
|
||||
border-radius: 10px;
|
||||
cursor: pointer;
|
||||
border: 1px solid rgba(0, 0, 0, .08);
|
||||
|
||||
&.active {
|
||||
border: 1px solid #ff7548;
|
||||
background: linear-gradient(33deg, #ffd1c5 -10%, #ffd1c5 21%, #ffe8e5 85%);
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
cursor: no-drop;
|
||||
background: #f4f4f4;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
h3 {
|
||||
margin-bottom: 20px;
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-top: 10px;
|
||||
color: #d9451e;
|
||||
}
|
||||
|
||||
.original-price {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 12px;
|
||||
color: #888;
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
.price {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
margin-bottom: 6px;
|
||||
color: #f13d3d;
|
||||
font-size: 16px;
|
||||
|
||||
span {
|
||||
font-weight: 700;
|
||||
font-size: 36px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.bottom {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
padding: 0 40px;
|
||||
|
||||
.bottom-right {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.bottom-left {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.paytype {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-top: 6px;
|
||||
|
||||
span {
|
||||
margin-left: 8px;
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
|
||||
.pay-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
.right-price {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
margin-bottom: 16px;
|
||||
color: #f13d3d;
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
|
||||
span {
|
||||
margin-left: 4px;
|
||||
font-size: 30px;
|
||||
font-weight: 900;
|
||||
}
|
||||
}
|
||||
|
||||
.code {
|
||||
width: 110px;
|
||||
height: 110px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
936
src/components/print/Print.vue
Normal file
@@ -0,0 +1,936 @@
|
||||
<template>
|
||||
<div class="print">
|
||||
<div class="print-wrapper" v-if="!isPrint">
|
||||
<div class="left">
|
||||
<div class="left-wrapper">
|
||||
<div class="title">基础元素</div>
|
||||
<div class="left-item__wrapper">
|
||||
<div class="ep-draggable-item item" tid="defaultModule.text">
|
||||
<i class="iconfont"></i>
|
||||
<span>文本</span>
|
||||
</div>
|
||||
<div class="ep-draggable-item item" tid="defaultModule.longText">
|
||||
<i class="iconfont"></i>
|
||||
<span>长文</span>
|
||||
</div>
|
||||
<div class="ep-draggable-item item" tid="defaultModule.table">
|
||||
<i class="iconfont"></i>
|
||||
<span>表格</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="title">辅助元素</div>
|
||||
<div class="left-item__wrapper">
|
||||
<div class="ep-draggable-item item" tid="defaultModule.hline">
|
||||
<i class="iconfont"></i>
|
||||
<span>横线</span>
|
||||
</div>
|
||||
<div class="ep-draggable-item item" tid="defaultModule.vline">
|
||||
<i class="iconfont"></i>
|
||||
<span>竖线</span>
|
||||
</div>
|
||||
<div class="ep-draggable-item item" tid="defaultModule.rect">
|
||||
<i class="iconfont"></i>
|
||||
<span>矩形</span>
|
||||
</div>
|
||||
<div class="ep-draggable-item item" tid="defaultModule.oval">
|
||||
<i class="iconfont"></i>
|
||||
<span>圆形</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="title">常用元素</div>
|
||||
<div class="left-item__wrapper" id="custom-provider">
|
||||
</div>
|
||||
<div class="title">
|
||||
<span>素材</span>
|
||||
</div>
|
||||
<div class="left-item__wrapper">
|
||||
<div
|
||||
class="item"
|
||||
style="cursor: pointer;"
|
||||
@click="search.type = 1, search.current = 1, isShowImage = true, getConfig()">
|
||||
<div>图片素材</div>
|
||||
</div>
|
||||
<div
|
||||
class="item"
|
||||
style="cursor: pointer;"
|
||||
@click="search.type = 0, search.current = 1, isShowImage = true, getConfig()">
|
||||
<div>文字素材</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="title">
|
||||
<span>动态数据(如日期)</span>
|
||||
<el-button type="primary" size="mini" @click="addField">添加</el-button>
|
||||
</div>
|
||||
<div class="left-item__wrapper">
|
||||
<div
|
||||
class="item"
|
||||
v-for="(item, index) in dynamicFromList"
|
||||
:key="index"
|
||||
style="cursor: pointer;"
|
||||
@click="addItemToCanvas(item.fieldName)">
|
||||
<div>{{ item.fieldName }}</div>
|
||||
<span class="el-icon-error" @click.stop="removeField(index)"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="center">
|
||||
<div class="center-header">
|
||||
<div class="paper">
|
||||
<el-button-group size="small">
|
||||
<template v-for="(value, type) in paperTypes">
|
||||
<el-button size="small" :type="curPaperType === type ? 'primary' : ''" @click="setPaper(type,value)" :key="type">
|
||||
{{ type }}
|
||||
</el-button>
|
||||
</template>
|
||||
<el-popover v-model="paperPopVisible" placement="top" :width="260" trigger="click">
|
||||
<div>
|
||||
<div style="font-size: 16px; font-weight: bold">设置纸张宽高(mm)</div>
|
||||
<div style="margin-top: 10px">
|
||||
<el-input size="small" style="margin-bottom: 10px" v-model="paperWidth" type="number" placeholder="宽(mm)" />
|
||||
<el-input size="small" v-model="paperHeight" type="number" placeholder="高(mm)" />
|
||||
</div>
|
||||
<el-button style="margin-top: 12px" size="small" @click.stop="setPaperOther">确定</el-button>
|
||||
</div>
|
||||
<el-button slot="reference" size="small" :type="'other' == curPaperType ? 'primary' : ''">自定义纸张</el-button>
|
||||
</el-popover>
|
||||
</el-button-group>
|
||||
<el-button @click="isShowTemplate = true" type="warning" size="small" style="margin-left: 10px;">模板库</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="center-wrapper">
|
||||
<div id="hiprint-printTemplate"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="right">
|
||||
<div id="PrintElementOptionSetting"></div>
|
||||
</div>
|
||||
</div>
|
||||
<ai-dialog :visible.sync="isShowPreview" title="预览" width="1200" customFooter>
|
||||
<div class="print-viewer" v-html="html"></div>
|
||||
<div class="dialog-footer" slot="footer">
|
||||
<el-button @click="isShowPreview = false">取消</el-button>
|
||||
</div>
|
||||
</ai-dialog>
|
||||
<ai-dialog :visible.sync="isShowImage" title="图片/文字素材" width="960" customFooter>
|
||||
<el-select v-model="search.type" placeholder="请选择图片/文字素材" size="small" @change="search.current = 1, getConfig()">
|
||||
<el-option label="图片素材" :value="1"></el-option>
|
||||
<el-option label="文字素材" :value="0"></el-option>
|
||||
</el-select>
|
||||
<ai-table
|
||||
v-if="search.type === 1"
|
||||
:tableData="tableData"
|
||||
:col-configs="colConfigs"
|
||||
:total="total"
|
||||
:current.sync="search.current"
|
||||
:size.sync="search.size"
|
||||
style="margin-top: 8px;"
|
||||
height="400"
|
||||
@getList="getConfig">
|
||||
<el-table-column slot="image" label="图片" align="left">
|
||||
<template v-slot="{ row }">
|
||||
<el-image
|
||||
v-if="search.type === 1"
|
||||
style="width: 80px; height: 80px"
|
||||
:src="row.imgUrl"
|
||||
:preview-src-list="[row.imgUrl]">
|
||||
</el-image>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column slot="options" label="操作" align="center">
|
||||
<template v-slot="{ row }">
|
||||
<div class="table-options">
|
||||
<el-button type="text" @click="row.type === '1' ? addImage(row.imgUrl) : addText(row.contents), isShowImage = false">添加</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
<ai-table
|
||||
v-if="search.type === 0"
|
||||
:tableData="tableData"
|
||||
:col-configs="colConfigs"
|
||||
:total="total"
|
||||
:current.sync="search.current"
|
||||
:size.sync="search.size"
|
||||
style="margin-top: 8px;"
|
||||
height="400"
|
||||
@getList="getConfig">
|
||||
<el-table-column slot="options" label="操作" align="center">
|
||||
<template v-slot="{ row }">
|
||||
<div class="table-options">
|
||||
<el-button type="text" @click="row.type === '1' ? addImage(row.imgUrl) : addText(row.contents), isShowImage = false">添加</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
<div class="dialog-footer" slot="footer">
|
||||
<el-button @click="isShowImage = false">取消</el-button>
|
||||
</div>
|
||||
</ai-dialog>
|
||||
<ai-dialog
|
||||
:visible.sync="isShowDynamicForm"
|
||||
title="动态数据"
|
||||
width="590px"
|
||||
@confirm="onConfirm">
|
||||
<el-form :model="dynamicFrom" ref="form" label-width="100px">
|
||||
<el-form-item
|
||||
label="数据名称:"
|
||||
:prop="`field_${dynamicFromList.length > 9 ? dynamicFromList.length + 1 : '0' + (dynamicFromList.length + 1)}`"
|
||||
:rules="[{ required: true, message: '请输入数据名称', trigger: 'blur' }]">
|
||||
<el-input placeholder="请输入数据名称" type="text" v-model="dynamicFrom[`field_${dynamicFromList.length > 9 ? dynamicFromList.length + 1 : '0' + (dynamicFromList.length + 1)}`]"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</ai-dialog>
|
||||
<ai-dialog :visible.sync="isShowTemplate" title="模板库" width="1060px" customFooter>
|
||||
<div class="templateList-wrapper" v-infinite-scroll="getTemplateList" :infinite-scroll-distance="20">
|
||||
<div class="templateList">
|
||||
<div class="templateList-item" v-for="(item, index) in templateList" :key="index">
|
||||
<!-- <img :src="item.previewUrl" /> -->
|
||||
<el-image
|
||||
style="height: 180px;"
|
||||
fit="contain"
|
||||
:src="item.previewUrl"
|
||||
:preview-src-list="[item.previewUrl]">
|
||||
</el-image>
|
||||
<h2>{{ item.name }}</h2>
|
||||
<el-button type="warning" size="mini" @click="updateTempate(item)">使用模板</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <ai-table
|
||||
:tableData="templateList"
|
||||
:col-configs="templateColConfigs"
|
||||
:total="templateTotal"
|
||||
:current.sync="searchTemplate.current"
|
||||
:size.sync="searchTemplate.size"
|
||||
height="480"
|
||||
@getList="getTemplateList"
|
||||
v-loading="templateLoading">
|
||||
<el-table-column slot="img" label="预览图" align="center">
|
||||
<template v-slot="{ row }">
|
||||
<el-image
|
||||
style="width: 200px; height: 200px"
|
||||
fit="contain"
|
||||
:src="row.previewUrl"
|
||||
:preview-src-list="[row.previewUrl]">
|
||||
</el-image>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column slot="options" label="操作" align="center" width="200">
|
||||
<template v-slot="{ row }">
|
||||
<div class="table-options">
|
||||
<el-button type="text" @click="showTemplate(row)">模板预览</el-button>
|
||||
<el-button type="text" @click="updateTempate(row)">使用</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table> -->
|
||||
<div class="dialog-footer" slot="footer">
|
||||
<el-button @click="isShowTemplate = false">取消</el-button>
|
||||
</div>
|
||||
</ai-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { hiprint, defaultElementTypeProvider, disAutoConnect } from 'vue-plugin-hiprint'
|
||||
import { newHiprintPrintTemplate } from '@/utils/template-helper'
|
||||
import { customProvider } from './customProvider'
|
||||
|
||||
disAutoConnect()
|
||||
|
||||
export default {
|
||||
props: {
|
||||
list: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return []
|
||||
}
|
||||
},
|
||||
|
||||
params: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return []
|
||||
}
|
||||
},
|
||||
|
||||
printData: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
template: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {
|
||||
"panels": [{
|
||||
"index": 0,
|
||||
"name": 1,
|
||||
"height": 200,
|
||||
"width": 200,
|
||||
"printElements": [],
|
||||
"paperNumberDisabled": true,
|
||||
"paperNumberContinue": true,
|
||||
"fontFamily": "Microsoft YaHei",
|
||||
"watermarkOptions": {}
|
||||
}]
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
isPrint: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
html: '',
|
||||
isShowPreview: false,
|
||||
hiprintTemplate: null,
|
||||
isShowTemplate: false,
|
||||
templateList: [],
|
||||
curPaper: {
|
||||
type: 'other',
|
||||
width: 200,
|
||||
height: 200
|
||||
},
|
||||
paperTypes: {
|
||||
'100 * 100': {
|
||||
width: 200,
|
||||
height: 200
|
||||
},
|
||||
'100 * 80': {
|
||||
width: 200,
|
||||
height: 160
|
||||
},
|
||||
'80 * 60': {
|
||||
width: 160,
|
||||
height: 120
|
||||
},
|
||||
'60 * 40': {
|
||||
width: 120,
|
||||
height: 80
|
||||
}
|
||||
},
|
||||
paperPopVisible: false,
|
||||
paperWidth: 200,
|
||||
paperHeight: 200,
|
||||
isShowDynamicForm: false,
|
||||
dynamicFrom: {
|
||||
},
|
||||
dynamicFromList: [],
|
||||
panel: null,
|
||||
contents: [],
|
||||
images: [],
|
||||
search: {
|
||||
current: 1,
|
||||
size: 10,
|
||||
type: 1
|
||||
},
|
||||
searchTemplate: {
|
||||
current: 1,
|
||||
size: 8,
|
||||
type: 1
|
||||
},
|
||||
templateTotal: 0,
|
||||
isShowImage: false,
|
||||
tableData: [],
|
||||
total: 0,
|
||||
templateColConfigs: [
|
||||
{ prop: 'name', label: '模板名称', align: 'left' },
|
||||
{ slot: 'img'}
|
||||
],
|
||||
templateLoading: false,
|
||||
hasMore: true
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
template: {
|
||||
handler(value) {
|
||||
if (value && this.hiprintTemplate && !this.isPrint) {
|
||||
const config = value.panels[0]
|
||||
this.hiprintTemplate.update(value)
|
||||
this.curPaper = {type: 'other', width: config.width, height: config.height}
|
||||
this.hiprintTemplate.setPaper(config.width, config.height)
|
||||
|
||||
if (this.params) {
|
||||
this.dynamicFromList = this.params
|
||||
}
|
||||
}
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
curPaperType() {
|
||||
let type = 'other'
|
||||
let types = this.paperTypes
|
||||
for (const key in types) {
|
||||
let item = types[key]
|
||||
let {width, height} = this.curPaper
|
||||
if (item.width === width && item.height === height) {
|
||||
type = key
|
||||
}
|
||||
}
|
||||
return type
|
||||
},
|
||||
|
||||
colConfigs () {
|
||||
if (this.search.type === 1) {
|
||||
return [
|
||||
{ slot: 'image' },
|
||||
{ prop: 'remark', label: '描述', align: 'center' }
|
||||
]
|
||||
}
|
||||
|
||||
return [
|
||||
{ prop: 'contents', label: '文本', align: 'center' },
|
||||
{ prop: 'remark', label: '描述', align: 'center' }
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
if (this.isPrint) {
|
||||
this.hiprintTemplate = newHiprintPrintTemplate('temulables')
|
||||
} else {
|
||||
hiprint.init({
|
||||
providers: [defaultElementTypeProvider(), customProvider({})]
|
||||
})
|
||||
this.buildLeftElement()
|
||||
this.buildDesigner()
|
||||
this.getConfig()
|
||||
|
||||
this.getTemplateList()
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
addField() {
|
||||
const num = this.dynamicFromList.length > 9 ? this.dynamicFromList.length + 1 : `0${this.dynamicFromList.length + 1}`
|
||||
|
||||
// eslint-disable-next-line no-empty
|
||||
if (this.dynamicFromList.length && !this.dynamicFromList.at(-1)[`field_${num}`]) {
|
||||
} else {
|
||||
this.$set(this.dynamicFrom, `field_${num}`, '')
|
||||
}
|
||||
|
||||
this.isShowDynamicForm = true
|
||||
},
|
||||
|
||||
removeField(index) {
|
||||
this.dynamicFromList.splice(index, 1)
|
||||
},
|
||||
|
||||
updateTempate(row) {
|
||||
this.templateLoading = true
|
||||
this.$http.post(`/api/templateRecommend/detail?id=${row.id}`).then(res => {
|
||||
if (res.code === 0) {
|
||||
const config = JSON.parse(res.data.content)
|
||||
this.hiprintTemplate.update(config)
|
||||
this.hiprintTemplate.setPaper(config.panels[0].width, config.panels[0].height)
|
||||
|
||||
this.dynamicFromList = JSON.parse(res.data.params)
|
||||
this.isShowTemplate = false
|
||||
}
|
||||
|
||||
this.templateLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
getTemplateList() {
|
||||
if (!this.hasMore) return
|
||||
if (this.templateLoading) return
|
||||
this.templateLoading = true
|
||||
this.$http.post(`/api/templateRecommend/getRecommendPage`, null, {
|
||||
params: this.searchTemplate
|
||||
}).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.templateList = [...this.templateList, ...res.data.records]
|
||||
this.templateTotal = res.data.total
|
||||
|
||||
if (res.data.records.length < this.searchTemplate.size) {
|
||||
this.hasMore = false
|
||||
} else {
|
||||
this.searchTemplate.current = this.searchTemplate.current + 1
|
||||
}
|
||||
|
||||
this.templateLoading = false
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
showTemplate (row) {
|
||||
this.templateLoading = true
|
||||
this.$http.post(`/api/templateRecommend/detail?id=${row.id}`).then(res => {
|
||||
this.templateLoading = false
|
||||
if (res.code === 0) {
|
||||
this.html = res.data.codes
|
||||
this.isShowPreview = true
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
getConfig() {
|
||||
this.$http.post(`/api/material/getPage?current=${this.search.current}&size=${this.search.size}&type=${this.search.type}`).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.tableData = res.data.records
|
||||
this.total = res.data.total
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
addImage(src) {
|
||||
this.panel.addPrintImage({
|
||||
options: {
|
||||
title: '',
|
||||
left: 70.5,
|
||||
top: 58.5,
|
||||
src: src,
|
||||
width: 100,
|
||||
height: 100,
|
||||
fit: 'contain'
|
||||
}
|
||||
})
|
||||
const el = this.hiprintTemplate.printPanels[0].printElements.at(-1)
|
||||
const designPaper = this.hiprintTemplate.printPanels[0].designPaper
|
||||
this.hiprintTemplate.printPanels[0].appendDesignPrintElement(designPaper, el, true)
|
||||
el.design(void 0, designPaper)
|
||||
},
|
||||
|
||||
addText(text, isSetField = false) {
|
||||
this.panel.addPrintText({
|
||||
options: {
|
||||
field: isSetField ? text : '',
|
||||
testData: isSetField ? text : '',
|
||||
title: isSetField ? '' : text,
|
||||
left: 70.5,
|
||||
top: 58.5,
|
||||
width: 140,
|
||||
height: 20,
|
||||
coordinateSync: true,
|
||||
contentPaddingLeft: 5.25,
|
||||
textContentVerticalAlign: 'middle',
|
||||
widthHeightSync: true,
|
||||
hideTitle: true,
|
||||
fontFamily: 'Microsoft YaHei',
|
||||
fontWeight: '700'
|
||||
}
|
||||
})
|
||||
const el = this.hiprintTemplate.printPanels[0].printElements.at(-1)
|
||||
const designPaper = this.hiprintTemplate.printPanels[0].designPaper
|
||||
this.hiprintTemplate.printPanels[0].appendDesignPrintElement(designPaper, el, true)
|
||||
el.design(void 0, designPaper)
|
||||
},
|
||||
|
||||
addItemToCanvas(name) {
|
||||
this.addText(name, true)
|
||||
},
|
||||
|
||||
onConfirm() {
|
||||
this.$refs.form.validate((valid) => {
|
||||
if (valid) {
|
||||
const num = this.dynamicFromList.length > 9 ? this.dynamicFromList.length + 1 : `0${this.dynamicFromList.length + 1}`
|
||||
this.dynamicFromList.push({
|
||||
fieldValue: `field_${num}`,
|
||||
fieldName: this.dynamicFrom[`field_${num}`]
|
||||
})
|
||||
this.isShowDynamicForm = false
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
buildLeftElement() {
|
||||
// eslint-disable-next-line no-undef
|
||||
hiprint.PrintElementTypeManager.buildByHtml($('.ep-draggable-item'))
|
||||
// eslint-disable-next-line no-undef
|
||||
$('#custom-provider').empty()
|
||||
// eslint-disable-next-line no-undef
|
||||
hiprint.PrintElementTypeManager.build($('#custom-provider'), 'customProvider')
|
||||
},
|
||||
|
||||
buildDesigner() {
|
||||
// eslint-disable-next-line no-undef
|
||||
$('#hiprint-printTemplate').empty()
|
||||
this.hiprintTemplate = newHiprintPrintTemplate('temulables', {
|
||||
template: this.template,
|
||||
settingContainer: '#PrintElementOptionSetting',
|
||||
onImageChooseClick: (target) => {
|
||||
let input = document.createElement('input')
|
||||
input.setAttribute('type', 'file')
|
||||
input.click()
|
||||
input.onchange = function () {
|
||||
var file = this.files[0]
|
||||
if (file) {
|
||||
var reader = new FileReader()
|
||||
reader.readAsDataURL(file)
|
||||
reader.onloadend = function () {
|
||||
target.refresh(reader.result)
|
||||
}
|
||||
}
|
||||
}
|
||||
input.remove()
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
this.$nextTick(() => {
|
||||
this.hiprintTemplate.design('#hiprint-printTemplate', {
|
||||
grid: true
|
||||
})
|
||||
|
||||
this.panel = this.hiprintTemplate.printPanels[0]
|
||||
})
|
||||
},
|
||||
|
||||
setPaperOther () {
|
||||
let value = {}
|
||||
value.width = this.paperWidth
|
||||
value.height = this.paperHeight
|
||||
this.setPaper('other', value)
|
||||
this.paperPopVisible = false
|
||||
},
|
||||
|
||||
setPaper(type, value) {
|
||||
try {
|
||||
if (Object.keys(this.paperTypes).includes(type)) {
|
||||
this.curPaper = {type: type, width: value.width, height: value.height}
|
||||
this.hiprintTemplate.setPaper(value.width, value.height)
|
||||
} else {
|
||||
this.curPaper = {type: 'other', width: value.width, height: value.height}
|
||||
this.hiprintTemplate.setPaper(value.width, value.height)
|
||||
}
|
||||
} catch (error) {
|
||||
this.$message.error(`操作失败: ${error}`)
|
||||
}
|
||||
},
|
||||
|
||||
print() {
|
||||
this.hiprintTemplate.print(this.printData)
|
||||
},
|
||||
|
||||
// js打印(不显示设计界面)
|
||||
toPrint (template, printData) {
|
||||
this.hiprintTemplate = newHiprintPrintTemplate('temulables')
|
||||
|
||||
setTimeout(() => {
|
||||
this.hiprintTemplate.update(template)
|
||||
this.hiprintTemplate.print(printData)
|
||||
}, 100)
|
||||
},
|
||||
|
||||
elementToString(el) {
|
||||
const node = document.createElement('div')
|
||||
node.innerHTML = el.html()
|
||||
|
||||
document.querySelector('body').appendChild(node)
|
||||
const html = node.innerHTML
|
||||
|
||||
document.querySelector('body').removeChild(node)
|
||||
return html
|
||||
},
|
||||
|
||||
savePdf() {
|
||||
this.hiprintTemplate.toPdf(this.printData, '测试导出pdf',{scale:2 }).then(v => {
|
||||
console.log(v)
|
||||
})
|
||||
},
|
||||
|
||||
save() {
|
||||
const html = this.elementToString(this.hiprintTemplate.getHtml(this.printData))
|
||||
const json = this.hiprintTemplate.getJson()
|
||||
|
||||
return {
|
||||
html,
|
||||
json,
|
||||
params: JSON.stringify(this.dynamicFromList)
|
||||
}
|
||||
},
|
||||
|
||||
preview() {
|
||||
this.html = this.elementToString(this.hiprintTemplate.getHtml(this.printData))
|
||||
this.isShowPreview = true
|
||||
},
|
||||
|
||||
getHtml(template, printData) {
|
||||
this.hiprintTemplate = newHiprintPrintTemplate('temulables')
|
||||
|
||||
this.hiprintTemplate.update(template)
|
||||
const html = this.elementToString(this.hiprintTemplate.getHtml(printData))
|
||||
return html
|
||||
},
|
||||
|
||||
clearPaper() {
|
||||
this.hiprintTemplate.clear()
|
||||
},
|
||||
|
||||
exportJson() {
|
||||
return this.hiprintTemplate.getJson()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.print {
|
||||
height: 100%;
|
||||
|
||||
.temuBarCode {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 1pt 3pt;
|
||||
}
|
||||
|
||||
.print-wrapper {
|
||||
display: flex;
|
||||
height: calc(100vh - 180px);
|
||||
|
||||
::v-deep(.prop-tab-items) {
|
||||
background-color: transparent !important;
|
||||
|
||||
.prop-tab-item {
|
||||
background-color: transparent !important;
|
||||
|
||||
.tab-title {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep(.hiprint-option-items .hiprint-option-item-label) {
|
||||
width: 100%;
|
||||
margin-bottom: 14px;
|
||||
text-align: left;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
::v-deep(.hiprint-printPanel) {
|
||||
display: block;
|
||||
|
||||
.dynamicField {
|
||||
background-color: #bfc2e9;
|
||||
border-color: #bfc2e9;
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep(.minicolors) {
|
||||
flex: 1;
|
||||
width: inherit;
|
||||
|
||||
input {
|
||||
width: 100% !important;
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep(.hiprint-option-item-field) {
|
||||
width: 100%;
|
||||
font-size: 14px;
|
||||
|
||||
input {
|
||||
height: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep(.hiprint-option-item-row) {
|
||||
display: block;
|
||||
}
|
||||
|
||||
::v-deep(.prop-tab-items) {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
::v-deep(.hiprint-option-items),
|
||||
::v-deep(.prop-tabs) {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
.left {
|
||||
width: 350px;
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
|
||||
.title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 320px;
|
||||
margin: 14px 0;
|
||||
}
|
||||
|
||||
.left-item__wrapper {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: 10px;
|
||||
|
||||
.item {
|
||||
display: flex;
|
||||
position: relative;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
left: 0!important;
|
||||
top: 0!important;
|
||||
width: 100px;
|
||||
margin-bottom: 10px;
|
||||
margin-right: 10px;
|
||||
padding: 10px 0;
|
||||
background-color: #eee;
|
||||
border-radius: 4px;
|
||||
|
||||
&:nth-of-type(3n) {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
i {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.el-icon-error {
|
||||
position: absolute;
|
||||
top: -6px;
|
||||
right: -6px;
|
||||
color: red;
|
||||
font-size: 18px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep(ul) {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
|
||||
.title {
|
||||
display: none;
|
||||
}
|
||||
|
||||
ul {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: 10px;
|
||||
|
||||
li {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100px;
|
||||
margin-bottom: 10px;
|
||||
margin-right: 10px;
|
||||
background-color: #eee;
|
||||
border-radius: 4px;
|
||||
|
||||
&:nth-of-type(3n) {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
a {
|
||||
margin-top: 10px;
|
||||
padding: 10px 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.center {
|
||||
display: flex;
|
||||
position: relative;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
padding: 0 10px;
|
||||
color: #000;
|
||||
|
||||
.center-wrapper {
|
||||
flex: 1;
|
||||
overflow-x: auto;
|
||||
overflow-y: auto;
|
||||
width: 100%;
|
||||
padding: 20px 20px 10px;
|
||||
}
|
||||
|
||||
.center-header {
|
||||
width: 100%;
|
||||
padding-bottom: 10px;
|
||||
|
||||
.paper {
|
||||
display: flex;
|
||||
position: relative;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.scale {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 0 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.right {
|
||||
width: 300px;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.print-viewer {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.templateList-wrapper {
|
||||
padding-right: 10px;
|
||||
|
||||
.templateList {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
||||
.templateList-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
width: 24%;
|
||||
margin-bottom: 20px;
|
||||
margin-right: 1.333%;
|
||||
padding: 10px;
|
||||
border-radius: 3px;
|
||||
overflow: hidden;
|
||||
background-color: #f4f4f4;
|
||||
|
||||
.el-button {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin-top: 12px;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
&:nth-of-type(4n) {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
132
src/components/print/customProvider.js
Normal file
@@ -0,0 +1,132 @@
|
||||
/* eslint-disable no-undef */
|
||||
import { hiprint } from 'vue-plugin-hiprint'
|
||||
|
||||
export const customProvider = function () {
|
||||
const addElementTypes = function (context) {
|
||||
context.removePrintElementTypes('customProvider')
|
||||
context.addPrintElementTypes('customProvider', [
|
||||
new hiprint.PrintElementTypeGroup('', [
|
||||
{
|
||||
tid: 'providerModule1.html',
|
||||
title: 'TEMU条码',
|
||||
data: 'XS888888888',
|
||||
type: 'html',
|
||||
formatter: function (data, options, sukData) {
|
||||
const elId = options.elId || 'barCode-' + new Date().getTime()
|
||||
const codeWidth = parseInt((options.width - 22) * 0.85)
|
||||
let printData = {
|
||||
labelCode: 123456789,
|
||||
productSkuId: `XXXXXXXXXXXXXX`,
|
||||
skuExtCode: 'XXXXXXXXXXXXXX',
|
||||
skuSpecName: 'XXXXX'
|
||||
}
|
||||
|
||||
options.elId = `${elId}`
|
||||
if (sukData) {
|
||||
printData = sukData
|
||||
}
|
||||
|
||||
$('body').append(`<div id="codewrapper-${elId}" style="width: ${codeWidth}pt">
|
||||
<svg id="${elId}" width="100%" display="block" height="100%" class="hibarcode_imgcode" preserveAspectRatio="none slice"></svg>
|
||||
</div>`)
|
||||
JsBarcode('#' + elId, printData.labelCode, {
|
||||
format: 'CODE128B',
|
||||
width: 2,
|
||||
height: parseInt(hinnn.pt.toPx(options.height - 22).toString()) * 0.6,
|
||||
margin: 0,
|
||||
displayValue: false
|
||||
})
|
||||
|
||||
const codeHtml = $(`#codewrapper-${elId}`).html()
|
||||
$(`body>#codewrapper-${elId}`).remove()
|
||||
|
||||
const resizeObserver = new ResizeObserver(() => {
|
||||
JsBarcode('#' + elId, printData.labelCode, {
|
||||
format: "CODE128B",
|
||||
width: 2,
|
||||
height: parseInt(hinnn.pt.toPx(options.height - 22).toString()) * 0.6,
|
||||
margin: 0,
|
||||
displayValue: false
|
||||
})
|
||||
})
|
||||
|
||||
setTimeout(() => {
|
||||
const node = document.getElementById(`temuBarCode-${elId}`)
|
||||
if (node) {
|
||||
resizeObserver.observe(node)
|
||||
}
|
||||
}, 0)
|
||||
var html = `
|
||||
<div class="temuBarCode" id="temuBarCode-${elId}">
|
||||
<div class="temuBarCode-top">
|
||||
<div class="hiprint-printElement-text-content hiprint-printElement-content">${printData.skuExtCode || printData.productSkcId}</div>
|
||||
<div class="hiprint-printElement-text-content hiprint-printElement-content">${printData.skuSpecName}</div>
|
||||
</div>
|
||||
<div class="temuBarCode-middle">
|
||||
<div class="hiprint-printElement-text-content hiprint-printElement-content temuBarCode-code" style="width: 100%">
|
||||
${codeHtml}
|
||||
</div>
|
||||
</div>
|
||||
<div class="temuBarCode-bottom">
|
||||
<div class="hiprint-printElement-text-content hiprint-printElement-content">${printData.productSkuId}</div>
|
||||
<div class="hiprint-printElement-text-content hiprint-printElement-content">Made in China</div>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
return html
|
||||
},
|
||||
options: {
|
||||
width: 316,
|
||||
height: 120,
|
||||
elId: ''
|
||||
},
|
||||
printElementType: {
|
||||
}
|
||||
},
|
||||
// {
|
||||
// tid: 'providerModule1.barcode',
|
||||
// title: '条形码',
|
||||
// data: 'XS888888888',
|
||||
// type: 'text',
|
||||
// options: {
|
||||
// field: 'barcode',
|
||||
// testData: 'XS888888888',
|
||||
// height: 32,
|
||||
// fontSize: 12,
|
||||
// lineHeight: 18,
|
||||
// textAlign: 'left',
|
||||
// textType: 'barcode',
|
||||
// hideTitle: false
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// tid: 'providerModule1.qrcode',
|
||||
// title: '二维码',
|
||||
// data: 'XS888888888',
|
||||
// type: 'text',
|
||||
// options: {
|
||||
// field: '',
|
||||
// testData: '',
|
||||
// height: 32,
|
||||
// fontSize: 12,
|
||||
// lineHeight: 18,
|
||||
// textType: 'qrcode',
|
||||
// hideTitle: false
|
||||
// }
|
||||
// },
|
||||
{
|
||||
tid: 'providerModule1.image',
|
||||
title: '图片',
|
||||
type: 'image',
|
||||
options: {
|
||||
contain: 'contain',
|
||||
src: 'http://lyshunong.oss-cn-beijing.aliyuncs.com/image/material/a6e14259412606502e49f1abd866039.png',
|
||||
}
|
||||
}
|
||||
])
|
||||
])
|
||||
}
|
||||
return {
|
||||
addElementTypes
|
||||
}
|
||||
}
|
||||
10
src/components/print/printData.js
Normal file
@@ -0,0 +1,10 @@
|
||||
export default {
|
||||
name: '黄磊',
|
||||
password: '12346',
|
||||
barcode: 'XS888888888',
|
||||
table: [
|
||||
{ id: '1', name: '王小可', gender: '男', count: '120', amount: '9089元' },
|
||||
{ id: '2', name: '梦之遥', gender: '女', count: '20', amount: '89元' },
|
||||
{ id: '3', name: '梦之遥', gender: '女', count: '720', amount: '29089元' }
|
||||
]
|
||||
}
|
||||
1075
src/components/print/template.js
Normal file
62364
src/components/print/vue-plugin-hiprint.js
Normal file
@@ -1,29 +1,82 @@
|
||||
/**
|
||||
利用chrome的fetch来避免跨域
|
||||
**/
|
||||
|
||||
import {getSign} from "@/api/aliExpress";
|
||||
import qs from "query-string"
|
||||
|
||||
/**
|
||||
* 根据图片URL获取Blob对象
|
||||
* @param imageUrl
|
||||
* @returns {Promise<unknown>}
|
||||
*/
|
||||
function getImageBlob(imageUrl) {
|
||||
return new Promise((resolve) => {
|
||||
fetch(imageUrl).then((response) => response.blob()) // 将响应转换为Blob对象
|
||||
.then((blobData) => {
|
||||
const fileName = imageUrl.match(/\/([^/]+)$/).at(-1)
|
||||
const reader = new FileReader();
|
||||
// 读取Blob对象的内容
|
||||
reader.onloadend = function () {
|
||||
const image = {blobData, fileName}
|
||||
resolve({image});
|
||||
};
|
||||
reader.readAsArrayBuffer(blobData); // 将Blob对象作为参数传递给FileReader的readAsArrayBuffer()方法
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 将cookie字符串转换为对象
|
||||
* @param cookieString
|
||||
* @returns {{}}
|
||||
*/
|
||||
function cookie2Obj(cookieString) {
|
||||
const cookieArray = cookieString.split(';');
|
||||
const cookieObj = {};
|
||||
for (let i = 0; i < cookieArray.length; i++) {
|
||||
const [key, value] = cookieArray[i].split('=');
|
||||
cookieObj[key] = value;
|
||||
}
|
||||
return cookieObj;
|
||||
}
|
||||
|
||||
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
|
||||
if (request.type == 'api') {
|
||||
let headers = {}, data;
|
||||
new Promise((resolve) => {
|
||||
let headers = {};
|
||||
if (request.needMallId) {
|
||||
headers.Mallid = request.mallId;
|
||||
}
|
||||
if (request.anti) {
|
||||
headers["Anti-Content"] = request.anti
|
||||
}
|
||||
headers['Content-Type'] = 'application/json';
|
||||
if (!request.isFormData) {
|
||||
headers['Content-Type'] = 'application/json';
|
||||
data = JSON.stringify(request.data)
|
||||
} else {
|
||||
const formData = new FormData();
|
||||
Object.keys(request.data).forEach(key => {
|
||||
const value = request.data[key]
|
||||
if (Array.isArray(value)) {
|
||||
value.forEach((subValue, i) => {
|
||||
formData.append(key + `[${i}]`, subValue)
|
||||
})
|
||||
} else {
|
||||
if (key == "image") {
|
||||
//跳过image的处理
|
||||
} else formData.append(key, request.data[key])
|
||||
}
|
||||
})
|
||||
data = formData
|
||||
}
|
||||
headers.cookie = getCookie();
|
||||
Promise.resolve().then(() => fetch(request.url, {
|
||||
'headers': headers,
|
||||
'method': 'POST',
|
||||
'referrerPolicy': 'no-referrer',
|
||||
'credentials': 'include',
|
||||
'body': JSON.stringify(request.data),
|
||||
'mode': 'cors'
|
||||
})).then((res) => {
|
||||
resolve(res.json());
|
||||
});
|
||||
}).then(sendResponse);
|
||||
if (request.isFormData && !!request.data.image) {//针对图片上传特殊的处理办法
|
||||
getImageBlob(request.data.image).then(res => data.append('image', res.image.blobData)).then(resolve)
|
||||
} else resolve()
|
||||
}).then(() => fetch(request.url, {
|
||||
headers, 'method': 'POST', 'referrerPolicy': 'no-referrer', 'credentials': 'include', 'body': data, 'mode': 'cors'
|
||||
})).then(res => res.json()).then(sendResponse);
|
||||
} else if (request.type == 'temuApi') {
|
||||
new Promise((resolve) => {
|
||||
let headers = {};
|
||||
@@ -33,26 +86,20 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
|
||||
headers['Content-Type'] = 'application/json';
|
||||
headers.cookie = getTemuCookie();
|
||||
Promise.resolve().then(() => fetch(request.url, {
|
||||
'headers': headers,
|
||||
'method': 'POST',
|
||||
'referrerPolicy': 'no-referrer',
|
||||
'credentials': 'include',
|
||||
'body': JSON.stringify(request.data),
|
||||
'mode': 'cors'
|
||||
'headers': headers, 'method': 'POST', 'referrerPolicy': 'no-referrer', 'credentials': 'include', 'body': JSON.stringify(request.data), 'mode': 'cors'
|
||||
})).then((res) => {
|
||||
resolve(res.json());
|
||||
}).catch(() => {
|
||||
resolve({success: false, errorCode: -1})
|
||||
});
|
||||
}).then(sendResponse);
|
||||
} else if (request.type == 'temu') {
|
||||
new Promise((resolve) => {
|
||||
let headers = {};
|
||||
headers['Content-Type'] = 'text/html';
|
||||
headers.cookie = getTemuCookie();
|
||||
//headers.cookie = getTemuCookie();
|
||||
Promise.resolve().then(() => fetch(request.url, {
|
||||
'headers': headers,
|
||||
'method': 'GET',
|
||||
'referrerPolicy': 'no-referrer',
|
||||
'credentials': 'include',
|
||||
'headers': headers, 'method': 'GET', 'referrerPolicy': 'no-referrer', //'credentials': 'include',
|
||||
'mode': 'cors'
|
||||
})).then((res) => {
|
||||
// 创建了一个数据读取器
|
||||
@@ -61,7 +108,7 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
|
||||
const decoder = new TextDecoder();
|
||||
|
||||
let text = ""
|
||||
reader.read().then(function processText({ done, value }) {
|
||||
reader.read().then(function processText({done, value}) {
|
||||
// Result 对象包含了两个属性:
|
||||
// done - 当 stream 传完所有数据时则变成 true
|
||||
// value - 数据片段。当 done 为 true 时始终为 undefined
|
||||
@@ -77,16 +124,18 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
|
||||
});
|
||||
}).then(sendResponse);
|
||||
} else if (request.type == 'aliexpress') {
|
||||
new Promise((resolve) => {
|
||||
new Promise(async (resolve) => {
|
||||
let headers = {};
|
||||
headers['Content-Type'] = 'text/html';
|
||||
headers.cookie = getAliexpressCookie();
|
||||
Promise.resolve().then(() => fetch(request.url, {
|
||||
'headers': headers,
|
||||
'method': 'GET',
|
||||
'referrerPolicy': 'no-referrer',
|
||||
'credentials': 'include',
|
||||
'mode': 'cors'
|
||||
const cookie = await getAliexpressCookie(request.url);
|
||||
const {_m_h5_c, _m_h5_tk} = cookie2Obj(cookie)
|
||||
const {query: {data, appKey}} = qs.parseUrl(request.url)
|
||||
const {formData = data} = request
|
||||
const {sign, t} = getSign(_m_h5_c || _m_h5_tk, appKey, formData)
|
||||
const url = qs.stringifyUrl({url: request.url, query: {sign, t}})
|
||||
headers.cookie = await getAliexpressCookie(url);
|
||||
Promise.resolve().then(() => fetch(url, {
|
||||
'headers': headers, 'method': 'POST', 'referrerPolicy': 'no-referrer', 'credentials': 'include', 'mode': 'cors'
|
||||
})).then((res) => {
|
||||
// 创建了一个数据读取器
|
||||
const reader = res.body.getReader();
|
||||
@@ -94,7 +143,7 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
|
||||
const decoder = new TextDecoder();
|
||||
|
||||
let text = ""
|
||||
reader.read().then(function processText({ done, value }) {
|
||||
reader.read().then(function processText({done, value}) {
|
||||
// Result 对象包含了两个属性:
|
||||
// done - 当 stream 传完所有数据时则变成 true
|
||||
// value - 数据片段。当 done 为 true 时始终为 undefined
|
||||
@@ -109,15 +158,81 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
|
||||
});
|
||||
});
|
||||
}).then(sendResponse);
|
||||
} else if (request.type == 'sheinApi') {
|
||||
new Promise((resolve) => {
|
||||
let headers = {};
|
||||
headers['Content-Type'] = 'application/json';
|
||||
headers.cookie = getSheinCookie()
|
||||
request.params = formatParams(request.params)
|
||||
let _url = request.url + (request.params ? ('?' + request.params) : '')
|
||||
Promise.resolve().then(() => fetch(_url, {
|
||||
'headers': headers, 'method': request.method, 'referrerPolicy': 'no-referrer', 'credentials': 'include', 'body': JSON.stringify(request.data), 'mode': 'cors'
|
||||
})).then((res) => {
|
||||
resolve(res.json());
|
||||
});
|
||||
}).then(sendResponse);
|
||||
} else if (request.type == 'geiwohuoApi') {
|
||||
new Promise((resolve) => {
|
||||
let headers = {};
|
||||
headers['Content-Type'] = 'application/json';
|
||||
headers['X-Req-Zone-Id'] = 'Asia/Shanghai';
|
||||
headers['X-Lt-Language'] = 'CN';
|
||||
Promise.resolve().then(() => fetch(request.url, {
|
||||
'headers': headers, 'method': request.method, 'referrerPolicy': 'no-referrer', 'credentials': 'include', 'body': JSON.stringify(request.data), 'mode': 'cors'
|
||||
})).then((res) => {
|
||||
resolve(res.json());
|
||||
}).catch(() => {
|
||||
resolve({success: false, errorCode: -1})
|
||||
});
|
||||
}).then(sendResponse);
|
||||
} else if (request.type == 'goodcangApi') {
|
||||
new Promise((resolve) => {
|
||||
let headers = {};
|
||||
headers['Content-Type'] = 'application/json';
|
||||
Promise.resolve().then(() => fetch(request.url, {
|
||||
'headers': headers, 'method': request.method, 'referrerPolicy': 'no-referrer', 'credentials': 'include', 'body': JSON.stringify(request.data), 'mode': 'cors'
|
||||
})).then((res) => {
|
||||
resolve(res.json());
|
||||
}).catch(() => {
|
||||
resolve({success: false, errorCode: -1})
|
||||
});
|
||||
}).then(sendResponse);
|
||||
} else if (request.type == 'xcApi') {
|
||||
new Promise(async (resolve) => {
|
||||
let headers = {}, data;
|
||||
headers.cookie = await getXcCookie();
|
||||
console.log(headers)
|
||||
if (!request.isFormData) {
|
||||
headers['Content-Type'] = 'application/json';
|
||||
data = JSON.stringify(request.data)
|
||||
} else {
|
||||
const formData = new FormData();
|
||||
Object.keys(request.data).forEach(key => {
|
||||
const value = request.data[key]
|
||||
if (Array.isArray(value)) {
|
||||
value.forEach((subValue, i) => {
|
||||
formData.append(key + `[${i}]`, subValue)
|
||||
})
|
||||
} else {
|
||||
if (key == "image") {
|
||||
//跳过image的处理
|
||||
} else formData.append(key, request.data[key])
|
||||
}
|
||||
})
|
||||
data = formData
|
||||
}
|
||||
Promise.resolve().then(() => fetch(request.url, {
|
||||
'headers': headers, 'method': request.method, 'referrerPolicy': 'strict-origin-when-cross-origin', 'credentials': 'include', 'body': data, 'mode': 'cors'
|
||||
})).then((res) => {
|
||||
resolve(res.json());
|
||||
}).catch(() => {
|
||||
resolve({success: false, errorCode: -1})
|
||||
});
|
||||
}).then(sendResponse);
|
||||
} else if (request.type == 'notify') {
|
||||
chrome.notifications.create(
|
||||
"" + Math.random(), {
|
||||
type: "basic",
|
||||
title: "TEMU助手",
|
||||
message: "您店铺【" + request.mallName + "】的商品【" + request.productName + "】成功加入发货台,请尽快处理",
|
||||
iconUrl: "./icons/48.png"
|
||||
}, null
|
||||
)
|
||||
chrome.notifications.create("" + Math.random(), {
|
||||
type: "basic", title: "TEMU助手", message: "您店铺【" + request.mallName + "】的商品【" + request.productName + "】成功加入发货台,请尽快处理", iconUrl: "./icons/48.png"
|
||||
}, null)
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -132,35 +247,32 @@ chrome.action.onClicked.addListener(function () {
|
||||
});
|
||||
|
||||
chrome.webRequest.onSendHeaders.addListener(details => {
|
||||
if (details.url && (details.url.indexOf('joinDeliveryGoodsOrderPlatform') != -1)) {
|
||||
if (details.url && (details.url.indexOf('joinDeliveryGoodsOrderPlatform') != -1)) {
|
||||
details.requestHeaders.push({
|
||||
name: 'Referer',
|
||||
value: 'https://kuajing.pinduoduo.com/main/order-manage'
|
||||
name: 'Referer', value: 'https://seller.kuajingmaihuo.com/main/order-manage'
|
||||
})
|
||||
for (let i = 0 ; i < details.requestHeaders.length; i++) {
|
||||
for (let i = 0; i < details.requestHeaders.length; i++) {
|
||||
if (details.requestHeaders[i].name == 'Origin') {
|
||||
details.requestHeaders[i].value = 'https://kuajing.pinduoduo.com'
|
||||
details.requestHeaders[i].value = 'https://seller.kuajingmaihuo.com'
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (details.url && (details.url.indexOf('mms/userInfo') != -1)) {
|
||||
} else if (details.url && (details.url.indexOf('mms/userInfo') != -1)) {
|
||||
details.requestHeaders.push({
|
||||
name: 'Referer',
|
||||
value: 'https://kuajing.pinduoduo.com/main/order-manage'
|
||||
name: 'Referer', value: 'https://seller.kuajingmaihuo.com/main/order-manage'
|
||||
})
|
||||
for (let i = 0 ; i < details.requestHeaders.length; i++) {
|
||||
for (let i = 0; i < details.requestHeaders.length; i++) {
|
||||
if (details.requestHeaders[i].name == 'Origin') {
|
||||
details.requestHeaders[i].value = 'https://kuajing.pinduoduo.com'
|
||||
details.requestHeaders[i].value = 'https://seller.kuajingmaihuo.com'
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{urls: ["<all_urls>"]},["requestHeaders", "extraHeaders"]);
|
||||
}, {urls: ["<all_urls>"]}, ["requestHeaders", "extraHeaders"]);
|
||||
|
||||
|
||||
function getCookie() {
|
||||
const url = new URL("https://kuajing.pinduoduo.com/");
|
||||
const url = new URL("https://seller.kuajingmaihuo.com/");
|
||||
let cStr = '';
|
||||
chrome.cookies.getAll({domain: url.host}, (cookie) => {
|
||||
cookie.map((c) => {
|
||||
@@ -181,8 +293,8 @@ function getTemuCookie() {
|
||||
return cStr;
|
||||
}
|
||||
|
||||
function getAliexpressCookie() {
|
||||
const url = new URL("https://www.aliexpress.us/");
|
||||
function getSheinCookie() {
|
||||
const url = new URL("https://www.shein.com/");
|
||||
let cStr = '';
|
||||
chrome.cookies.getAll({domain: url.host}, (cookie) => {
|
||||
cookie.map((c) => {
|
||||
@@ -190,4 +302,37 @@ function getAliexpressCookie() {
|
||||
});
|
||||
});
|
||||
return cStr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function getAliexpressCookie(link = "https://csp.aliexpress.com/") {
|
||||
let cStr = '';
|
||||
return new Promise((resolve, reject) => {
|
||||
chrome.cookies.getAll({url: link}, (cookie) => {
|
||||
cookie.map((c) => {
|
||||
cStr += c.name + '=' + c.value + ';';
|
||||
});
|
||||
resolve(cStr);
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
function getXcCookie(link = "http://xc.rqlis.com:888/") {
|
||||
let cStr = '';
|
||||
return new Promise((resolve, reject) => {
|
||||
chrome.cookies.getAll({url: link}, (cookie) => {
|
||||
cookie.map((c) => {
|
||||
cStr += c.name + '=' + c.value + ';';
|
||||
});
|
||||
resolve(cStr);
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
function formatParams(data) {
|
||||
const arr = []
|
||||
for (let name in data) {
|
||||
arr.push(encodeURIComponent(name) + "=" + encodeURIComponent(data[name]))
|
||||
}
|
||||
return arr.join("&")
|
||||
}
|
||||
|
||||
@@ -8,3 +8,4 @@ function injectScript(file, node) {
|
||||
injectScript( chrome.runtime.getURL('/js/jszip.min.js'), 'body');
|
||||
injectScript( chrome.runtime.getURL('/js/FileSaver.js'), 'body');
|
||||
injectScript( chrome.runtime.getURL('/js/download.js'), 'body');
|
||||
injectScript( chrome.runtime.getURL('/js/temuSeller.js'), 'body');
|
||||
|
||||
@@ -17,10 +17,28 @@ var relativeTime = require('dayjs/plugin/relativeTime')
|
||||
require('dayjs/locale/zh-cn')
|
||||
dayjs.extend(relativeTime)
|
||||
Vue.prototype.$dayjs = dayjs
|
||||
Vue.prototype.$base = "https://kuajing.pinduoduo.com"
|
||||
Vue.prototype.$base = "https://seller.kuajingmaihuo.com"
|
||||
Object.keys(utils).forEach(v => Vue.prototype[`$${v}`] = utils[v])
|
||||
|
||||
Vue.prototype.$http = instance
|
||||
utils.initWindow()
|
||||
Vue.directive('throttle', {
|
||||
bind: function (el, obj) {
|
||||
let timerId = null
|
||||
let flag = true
|
||||
|
||||
el.addEventListener('input', function () {
|
||||
if (!flag) return
|
||||
|
||||
flag = false
|
||||
timerId && clearTimeout(timerId)
|
||||
timerId = setTimeout(function () {
|
||||
flag = true
|
||||
obj.value()
|
||||
}, 800)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
new Vue({
|
||||
store,
|
||||
|
||||
@@ -11,13 +11,19 @@
|
||||
"48": "icons/48.png",
|
||||
"128": "icons/128.png"
|
||||
},
|
||||
"action": {
|
||||
},
|
||||
"action": {},
|
||||
"host_permissions": [
|
||||
"*://*.pinduoduo.com/",
|
||||
"*://*.jjcp52.com/",
|
||||
"*://*.kuajingmaihuo.com/",
|
||||
"*://*.temu.com/",
|
||||
"*://*.aliexpress.us/",
|
||||
"*://*.amazon.com/"
|
||||
"*://*.aliexpress.com/",
|
||||
"*://*.alicdn.com/",
|
||||
"*://*.amazon.com/",
|
||||
"*://*.shein.com/",
|
||||
"*://*.geiwohuo.com/",
|
||||
"*://*.ltwebstatic.com/",
|
||||
"*://*.goodcang.com/",
|
||||
"*://*.rqlis.com/"
|
||||
],
|
||||
"permissions": [
|
||||
"cookies",
|
||||
@@ -28,30 +34,103 @@
|
||||
"declarativeNetRequest",
|
||||
"declarativeNetRequestWithHostAccess",
|
||||
"declarativeNetRequestFeedback",
|
||||
"activeTab"
|
||||
"activeTab",
|
||||
"fileSystemProvider"
|
||||
],
|
||||
"declarative_net_request": {
|
||||
"rule_resources": [{
|
||||
"id": "1",
|
||||
"enabled": true,
|
||||
"path": "rules_1.json"
|
||||
}]
|
||||
"rule_resources": [
|
||||
{
|
||||
"id": "1",
|
||||
"enabled": true,
|
||||
"path": "rules_1.json"
|
||||
},
|
||||
{
|
||||
"id": "3",
|
||||
"enabled": true,
|
||||
"path": "rules_3.json"
|
||||
},
|
||||
{
|
||||
"id": "5",
|
||||
"enabled": true,
|
||||
"path": "rules_5.json"
|
||||
},
|
||||
{
|
||||
"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"
|
||||
},
|
||||
{
|
||||
"id": "10",
|
||||
"enabled": true,
|
||||
"path": "rules_10.json"
|
||||
},
|
||||
{
|
||||
"id": "11",
|
||||
"enabled": true,
|
||||
"path": "rules_11.json"
|
||||
},
|
||||
{
|
||||
"id": "12",
|
||||
"enabled": true,
|
||||
"path": "rules_12.json"
|
||||
}
|
||||
]
|
||||
},
|
||||
"content_scripts": [
|
||||
{
|
||||
"matches": [
|
||||
"*://*.aliexpress.us/item/*",
|
||||
"*://*.amazon.com/*"
|
||||
"*://*.aliexpress.com/item/*",
|
||||
"*://*.amazon.com/*",
|
||||
"*://*.shein.com/*"
|
||||
],
|
||||
"js": [
|
||||
"/content.js"
|
||||
]
|
||||
},
|
||||
{
|
||||
"matches": [
|
||||
"*://*.kuajingmaihuo.com/*"
|
||||
],
|
||||
"js": [
|
||||
"/js/temuSellerContent.js"
|
||||
]
|
||||
}
|
||||
],
|
||||
"web_accessible_resources": [
|
||||
{
|
||||
"resources": [ "js/download.js","js/jszip.min.js","js/FileSaver.js" ],
|
||||
"matches": [ "*://*.aliexpress.us/*", "*://*.amazon.com/*" ]
|
||||
"resources": [
|
||||
"js/download.js",
|
||||
"js/jszip.min.js",
|
||||
"js/FileSaver.js"
|
||||
],
|
||||
"matches": [
|
||||
"*://*.aliexpress.com/*",
|
||||
"*://*.amazon.com/*",
|
||||
"*://*.shein.com/*"
|
||||
]
|
||||
},
|
||||
{
|
||||
"resources": [
|
||||
"js/temuSeller.js"
|
||||
],
|
||||
"matches": [
|
||||
"*://*.kuajingmaihuo.com/*"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"manifest_version": 3,
|
||||
"name": "TEMU助手",
|
||||
"description": "TEMU助手 - 自动化提高生产效率",
|
||||
"version": "3.0.0",
|
||||
"version": "3.4.0",
|
||||
"background": {
|
||||
"service_worker": "/background.js"
|
||||
},
|
||||
@@ -11,13 +11,18 @@
|
||||
"48": "icons/48.png",
|
||||
"128": "icons/128.png"
|
||||
},
|
||||
"action": {
|
||||
},
|
||||
"action": {},
|
||||
"host_permissions": [
|
||||
"*://*.pinduoduo.com/",
|
||||
"*://124.71.2.127:8888/",
|
||||
"*://*.kuajingmaihuo.com/",
|
||||
"*://*.temu.com/",
|
||||
"*://*.aliexpress.us/",
|
||||
"*://*.amazon.com/"
|
||||
"*://*.aliexpress.com/",
|
||||
"*://*.alicdn.com/",
|
||||
"*://*.amazon.com/",
|
||||
"*://*.shein.com/",
|
||||
"*://*.geiwohuo.com/",
|
||||
"*://*.ltwebstatic.com/",
|
||||
"*://*.rqlis.com/"
|
||||
],
|
||||
"permissions": [
|
||||
"cookies",
|
||||
@@ -28,30 +33,103 @@
|
||||
"declarativeNetRequest",
|
||||
"declarativeNetRequestWithHostAccess",
|
||||
"declarativeNetRequestFeedback",
|
||||
"activeTab"
|
||||
"activeTab",
|
||||
"fileSystemProvider"
|
||||
],
|
||||
"declarative_net_request": {
|
||||
"rule_resources": [{
|
||||
"id": "1",
|
||||
"enabled": true,
|
||||
"path": "rules_1.json"
|
||||
}]
|
||||
"rule_resources": [
|
||||
{
|
||||
"id": "1",
|
||||
"enabled": true,
|
||||
"path": "rules_1.json"
|
||||
},
|
||||
{
|
||||
"id": "3",
|
||||
"enabled": true,
|
||||
"path": "rules_3.json"
|
||||
},
|
||||
{
|
||||
"id": "4",
|
||||
"enabled": true,
|
||||
"path": "rules_4.json"
|
||||
},
|
||||
{
|
||||
"id": "5",
|
||||
"enabled": true,
|
||||
"path": "rules_5.json"
|
||||
},
|
||||
{
|
||||
"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"
|
||||
},
|
||||
{
|
||||
"id": "11",
|
||||
"enabled": true,
|
||||
"path": "rules_11.json"
|
||||
},
|
||||
{
|
||||
"id": "12",
|
||||
"enabled": true,
|
||||
"path": "rules_12.json"
|
||||
}
|
||||
]
|
||||
},
|
||||
"content_scripts": [
|
||||
{
|
||||
"matches": [
|
||||
"*://*.aliexpress.us/item/*",
|
||||
"*://*.amazon.com/*"
|
||||
"*://*.aliexpress.com/item/*",
|
||||
"*://*.amazon.com/*",
|
||||
"*://*.shein.com/*"
|
||||
],
|
||||
"js": [
|
||||
"/content.js"
|
||||
]
|
||||
},
|
||||
{
|
||||
"matches": [
|
||||
"*://*.kuajingmaihuo.com/*"
|
||||
],
|
||||
"js": [
|
||||
"/js/temuSellerContent.js"
|
||||
]
|
||||
}
|
||||
],
|
||||
"web_accessible_resources": [
|
||||
{
|
||||
"resources": [ "js/download.js","js/jszip.min.js","js/FileSaver.js" ],
|
||||
"matches": [ "*://*.aliexpress.us/*", "*://*.amazon.com/*" ]
|
||||
"resources": [
|
||||
"js/download.js",
|
||||
"js/jszip.min.js",
|
||||
"js/FileSaver.js"
|
||||
],
|
||||
"matches": [
|
||||
"*://*.aliexpress.com/*",
|
||||
"*://*.amazon.com/*",
|
||||
"*://*.shein.com/*"
|
||||
]
|
||||
},
|
||||
{
|
||||
"resources": [
|
||||
"js/temuSeller.js"
|
||||
],
|
||||
"matches": [
|
||||
"*://*.kuajingmaihuo.com/*"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import Vue from 'vue'
|
||||
import VueRouter from 'vue-router'
|
||||
import store from '@/store'
|
||||
import media from "@/router/media";
|
||||
|
||||
Vue.use(VueRouter)
|
||||
|
||||
@@ -25,6 +26,11 @@ const router = new VueRouter({
|
||||
name: 'changePwd',
|
||||
component: () => import('../view/login/ChangePwd')
|
||||
},
|
||||
{
|
||||
path: 'waitCreate',
|
||||
name: 'waitCreate',
|
||||
component: () => import('../view/shipping/WaitCreate.vue')
|
||||
},
|
||||
{
|
||||
path: 'normalSendGoods',
|
||||
name: 'NormalSendGoods',
|
||||
@@ -50,23 +56,81 @@ const router = new VueRouter({
|
||||
name: 'waitShippingList',
|
||||
component: () => import('../view/shipping/WaitShippingList.vue')
|
||||
},
|
||||
|
||||
{
|
||||
path: 'myNormalOrder',
|
||||
name: 'myNormalOrder',
|
||||
component: () => import('../view/shipping/MyNormalOrder.vue')
|
||||
},
|
||||
{
|
||||
path: 'myUrgencyOrder',
|
||||
name: 'myUrgencyOrder',
|
||||
component: () => import('../view/shipping/MyUrgencyOrder.vue')
|
||||
},
|
||||
{
|
||||
path: 'productLabel',
|
||||
name: 'productLabel',
|
||||
component: () => import('../view/shipping/ProductLabel.vue')
|
||||
},
|
||||
{
|
||||
path: 'returnPackage',
|
||||
name: 'returnPackage',
|
||||
component: () => import('../view/stock/ReturnPackage.vue')
|
||||
},
|
||||
{
|
||||
path: 'returnDetail',
|
||||
name: 'returnDetail',
|
||||
component: () => import('../view/stock/ReturnDetail.vue')
|
||||
},
|
||||
{
|
||||
path: 'productList',
|
||||
name: 'productList',
|
||||
component: () => import('../view/product/ProductList.vue')
|
||||
},
|
||||
{
|
||||
path: 'copyProduct',
|
||||
name: 'copyProduct',
|
||||
component: () => import('../view/product/CopyProduct.vue')
|
||||
},
|
||||
{
|
||||
path: 'reducePrice',
|
||||
name: 'reducePrice',
|
||||
component: () => import('../view/product/ReducePrice.vue')
|
||||
path: 'sellerSelect',
|
||||
name: 'sellerSelect',
|
||||
component: () => import('../view/product/SellerSelect.vue')
|
||||
},
|
||||
{
|
||||
path: 'draft',
|
||||
name: 'draft',
|
||||
component: () => import('../view/product/Draft.vue')
|
||||
},
|
||||
{
|
||||
path: 'findSeller',
|
||||
name: 'findSeller',
|
||||
component: () => import('../view/product/FindSeller.vue')
|
||||
},
|
||||
{
|
||||
path: 'copyProductAliExpress',
|
||||
name: 'copyProductAliExpress',
|
||||
component: () => import('../view/product/CopyProductAliExpress.vue')
|
||||
},
|
||||
{
|
||||
path: 'priceDown',
|
||||
name: 'priceDown',
|
||||
component: () => import('../view/product/PriceDown.vue')
|
||||
},
|
||||
{
|
||||
path: 'batchUpload',
|
||||
name: 'batchUpload',
|
||||
component: () => import('../view/product/BatchUpload.vue')
|
||||
},
|
||||
|
||||
{
|
||||
path: 'niubiCopy',
|
||||
name: 'niubiCopy',
|
||||
component: () => import('../view/selection/NiubiCopy.vue')
|
||||
},
|
||||
{
|
||||
path: 'aliExpressCopy',
|
||||
name: 'aliExpressCopy',
|
||||
component: () => import('../view/selection/AliExpressCopy.vue')
|
||||
},
|
||||
{
|
||||
path: 'storeTrack',
|
||||
name: 'storeTrack',
|
||||
@@ -77,7 +141,46 @@ const router = new VueRouter({
|
||||
name: 'keywordTrack',
|
||||
component: () => import('../view/selection/keywordtrack/Index.vue')
|
||||
},
|
||||
|
||||
{
|
||||
path: 'favoriteTrack',
|
||||
name: 'favoriteTrack',
|
||||
component: () => import('../view/selection/favoritetrack/Index.vue')
|
||||
},
|
||||
{
|
||||
path: 'indexTrack',
|
||||
name: 'indexTrack',
|
||||
component: () => import('../view/selection/indextrack/Index.vue')
|
||||
},
|
||||
{
|
||||
path: 'newProduct',
|
||||
name: 'newProduct',
|
||||
component: () => import('../view/selection/newproducttrack/newproduct/Index.vue')
|
||||
},
|
||||
{
|
||||
path: 'newProductGroup',
|
||||
name: 'newProductGroup',
|
||||
component: () => import('../view/selection/newproducttrack/newproductgroup/Index.vue')
|
||||
},
|
||||
{
|
||||
path: 'bestSellers',
|
||||
name: 'bestSellers',
|
||||
component: () => import('../view/selection/bestsellers/Index.vue')
|
||||
},
|
||||
{
|
||||
path: 'singleTrack',
|
||||
name: 'singleTrack',
|
||||
component: () => import('../view/selection/singletrack/Index.vue')
|
||||
},
|
||||
{
|
||||
path: 'info',
|
||||
name: 'info',
|
||||
component: () => import('../view/Info.vue')
|
||||
},
|
||||
{
|
||||
path: 'priceFollow',
|
||||
name: 'priceFollow',
|
||||
component: () => import('../view/PriceFollow.vue')
|
||||
},
|
||||
{
|
||||
path: 'message',
|
||||
name: 'message',
|
||||
@@ -89,13 +192,114 @@ const router = new VueRouter({
|
||||
name: 'coinFlow',
|
||||
component: () => import('../view/CoinFlow.vue')
|
||||
},
|
||||
|
||||
|
||||
{
|
||||
path: 'costManageTemu',
|
||||
name: 'costManageTemu',
|
||||
component: () => import('../view/sale/CostManageTemu.vue')
|
||||
},
|
||||
{
|
||||
path: 'saleData',
|
||||
name: 'saleData',
|
||||
component: () => import('../view/ExportSaleData.vue')
|
||||
component: () => import('../view/sale/ExportSaleData.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: 'saleStatTemu',
|
||||
name: 'saleStatTemu',
|
||||
component: () => import('../view/sale/ExportSaleStatTemu.vue')
|
||||
},
|
||||
{
|
||||
path: 'priceAdjustment',
|
||||
name: 'priceAdjustment',
|
||||
component: () => import('../view/sale/PriceAdjustment.vue')
|
||||
},
|
||||
{
|
||||
path: 'logisticFee',
|
||||
name: 'logisticFee',
|
||||
component: () => import('../view/sale/LogisticFee.vue')
|
||||
},
|
||||
{
|
||||
path: 'billStat',
|
||||
name: 'billStat',
|
||||
component: () => import('../view/sale/ExportBillStatTemu.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: 'orderListShein',
|
||||
name: 'orderListShein',
|
||||
component: () => import('../view/shein/OrderListShein.vue')
|
||||
},
|
||||
{
|
||||
path: 'productListOdm',
|
||||
name: 'productListOdm',
|
||||
component: () => import('../view/shein/ProductListOdm.vue')
|
||||
},
|
||||
{
|
||||
path: 'returnRecordShein',
|
||||
name: 'returnRecordShein',
|
||||
component: () => import('../view/shein/ReturnRecordShein.vue')
|
||||
},
|
||||
{
|
||||
path: 'labelInfoShein',
|
||||
name: 'labelInfoShein',
|
||||
component: () => import('../view/shein/LabelInfoShein.vue')
|
||||
},
|
||||
{
|
||||
path: 'purchaseOrderListShein',
|
||||
name: 'purchaseOrderListShein',
|
||||
component: () => import('../view/shein/PurchaseOrderListShein.vue')
|
||||
},
|
||||
{
|
||||
path: 'syncDataTemu',
|
||||
name: 'syncDataTemu',
|
||||
component: () => import('../view/data/SyncDataTemu.vue')
|
||||
},
|
||||
|
||||
{
|
||||
path: 'sendGoods_xc',
|
||||
name: 'sendGoods_xc',
|
||||
component: () => import('../view/semi/SemiSendGoods_XC.vue')
|
||||
},
|
||||
|
||||
// {
|
||||
// path: 'statistics',
|
||||
// name: 'statistics',
|
||||
@@ -105,7 +309,47 @@ const router = new VueRouter({
|
||||
path: 'learning',
|
||||
name: 'learning',
|
||||
component: () => import('../view/Learning.vue')
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'qualification',
|
||||
name: 'qualification',
|
||||
children: [
|
||||
{
|
||||
path: 'oushuitong',
|
||||
name: 'oushuitong',
|
||||
meta: {
|
||||
activeMenu: '/qualification'
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'labelsTemplate',
|
||||
name: 'labelsTemplate',
|
||||
component: () => import('../view/lables/Template.vue')
|
||||
},
|
||||
{
|
||||
path: 'addLabelsTemplate',
|
||||
name: 'addLabelsTemplate',
|
||||
component: () => import('../view/lables/AddTemplate.vue'),
|
||||
meta: {
|
||||
activeMenu: '/labelsTemplate'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'labelsPrint',
|
||||
name: 'labelsPrint',
|
||||
component: () => import('../view/lables/Print.vue')
|
||||
},
|
||||
{
|
||||
path: 'skuManage',
|
||||
name: 'skuManage',
|
||||
component: () => import('../view/lables/SkuManage.vue'),
|
||||
meta: {
|
||||
activeMenu: '/labelsTemplate'
|
||||
}
|
||||
},
|
||||
...media
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -123,13 +367,21 @@ const router = new VueRouter({
|
||||
title: '注册'
|
||||
},
|
||||
component: () => import('../view/login/Register.vue')
|
||||
},
|
||||
{
|
||||
path: '/forget',
|
||||
name: 'forget',
|
||||
meta: {
|
||||
title: '注册'
|
||||
},
|
||||
component: () => import('../view/login/Forget.vue')
|
||||
}
|
||||
],
|
||||
scrollBehavior (to, from, savedPosition) {
|
||||
scrollBehavior(to, from, savedPosition) {
|
||||
if (savedPosition) {
|
||||
return savedPosition
|
||||
} else {
|
||||
return { x: 0, y: 0 }
|
||||
return {x: 0, y: 0}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
3
src/router/media.js
Normal file
@@ -0,0 +1,3 @@
|
||||
export default [
|
||||
{name: "imageTranslate", path: "imageTranslate", component: () => import("@/view/media/imageTranslate.vue")}
|
||||
]
|
||||
@@ -13,7 +13,10 @@ export default new Vuex.Store({
|
||||
mallName: '',
|
||||
mallList: [],
|
||||
activeDlgShow: false,
|
||||
userInfo: {}
|
||||
showSheinAlert: false,
|
||||
showTemuAlert: false,
|
||||
userInfo: {},
|
||||
labelInfo: {}
|
||||
},
|
||||
|
||||
mutations: {
|
||||
@@ -46,6 +49,15 @@ export default new Vuex.Store({
|
||||
},
|
||||
setActiveDlgShow(state, flag) {
|
||||
state.activeDlgShow = flag
|
||||
},
|
||||
setSheinAlertShow(state, flag) {
|
||||
state.showSheinAlert = flag
|
||||
},
|
||||
setTemuAlertShow(state, flag) {
|
||||
state.showTemuAlert = flag
|
||||
},
|
||||
setLabelInfo(state, info) {
|
||||
state.labelInfo = info
|
||||
}
|
||||
},
|
||||
|
||||
@@ -58,8 +70,25 @@ export default new Vuex.Store({
|
||||
resolve(res.data)
|
||||
}
|
||||
})
|
||||
store.dispatch('getLabelInfo')
|
||||
})
|
||||
},
|
||||
|
||||
getLabelInfo(store) {
|
||||
return new Promise(resolve => {
|
||||
request.post('/api/userExtend/getLabelDetail').then(res => {
|
||||
if (res.code === 0) {
|
||||
const isExpires = new Date().getTime() > new Date(res.data.expireTime).getTime() || res.data.skuUsed > res.data.skuTotal
|
||||
store.commit('setLabelInfo', {
|
||||
...res.data,
|
||||
isExpires
|
||||
})
|
||||
resolve(res.data)
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
SignOut(store, isClear) {
|
||||
if (isClear) {
|
||||
store.commit('logout')
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
export function timestampToTime(timestamp) {
|
||||
if (!timestamp) return ''
|
||||
// 时间戳为10位需*1000,时间戳为13位不需乘1000
|
||||
let date = new Date(timestamp);
|
||||
let Y = date.getFullYear() + "-";
|
||||
|
||||
48
src/utils/folder.js
Normal file
@@ -0,0 +1,48 @@
|
||||
import {sendChromeAPIMessage} from '@/api/chromeApi'
|
||||
|
||||
export async function createFolderApi(folderArr, mallId) {
|
||||
let res1 = await queryAllFolders(mallId)
|
||||
return await createFolder(res1, folderArr, 0, mallId)
|
||||
}
|
||||
|
||||
async function createFolder(folders, folderArr, index, mallId) {
|
||||
for (let i = 0; i < folders.childFolderList.length; i++) {
|
||||
if (folders.childFolderList[i].folderName == folderArr[index]) {
|
||||
if (folders.childFolderList[i].childFolderList.length == 0) {
|
||||
if (index == (folderArr.length - 1)) {
|
||||
return folders.childFolderList[i].folderId
|
||||
} else {
|
||||
return await createFolderFunc(folders.childFolderList[i].folderId, folderArr, ++index, mallId)
|
||||
}
|
||||
} else {
|
||||
return createFolder(folders.childFolderList[i], folderArr, ++index, mallId)
|
||||
}
|
||||
}
|
||||
}
|
||||
return await createFolderFunc(folders.folderId, folderArr, index, mallId)
|
||||
}
|
||||
|
||||
async function createFolderFunc(folderId, folderArr, index, mallId) {
|
||||
let tempFolderId = folderId
|
||||
await sendChromeAPIMessage({
|
||||
url: 'marvel-mms/cn/api/kiana/gmp/bg/phoenix/api/material/create-folder',
|
||||
needMallId: true,
|
||||
mallId: mallId,
|
||||
data: {
|
||||
parentId: tempFolderId,
|
||||
folderName: folderArr[index]
|
||||
}})
|
||||
let res1 = await queryAllFolders(mallId)
|
||||
|
||||
return await createFolder(res1, folderArr, 0, mallId)
|
||||
}
|
||||
|
||||
async function queryAllFolders(mallId) {
|
||||
let folders = await sendChromeAPIMessage({
|
||||
url: 'marvel-mms/cn/api/kiana/gmp/bg/phoenix/api/material/query-folders',
|
||||
needMallId: true,
|
||||
mallId: mallId,
|
||||
data: {}})
|
||||
|
||||
return folders.result.rootFolder
|
||||
}
|
||||
12
src/utils/html.js
Normal file
@@ -0,0 +1,12 @@
|
||||
export function extractImagesAndText(htmlString) {
|
||||
const parser = new DOMParser();
|
||||
const doc = parser.parseFromString(htmlString, "text/html");
|
||||
const images = Array.from(doc.querySelectorAll("img")).map(img => img.src);
|
||||
const text = doc.body.textContent.trim();
|
||||
const data = {
|
||||
images,
|
||||
text
|
||||
};
|
||||
const jsonData = JSON.stringify(data);
|
||||
return jsonData;
|
||||
}
|
||||
106
src/utils/image.js
Normal file
@@ -0,0 +1,106 @@
|
||||
import SparkMd5 from 'spark-md5'
|
||||
import {sendChromeAPIMessage} from '@/api/chromeApi'
|
||||
|
||||
export function getImageMd5(imageUrl) {
|
||||
return new Promise((resolve) => {
|
||||
fetch(imageUrl).then((response) => response.blob()) // 将响应转换为Blob对象
|
||||
.then((blobData) => {
|
||||
const fileName = imageUrl.match(/\/([^/]+)$/).at(-1)
|
||||
const reader = new FileReader();
|
||||
// 读取Blob对象的内容
|
||||
reader.onloadend = function () {
|
||||
const spark = new SparkMd5.ArrayBuffer()
|
||||
spark.append(reader.result);
|
||||
const md5 = spark.end()
|
||||
resolve({md5, fileName});
|
||||
};
|
||||
reader.readAsArrayBuffer(blobData); // 将Blob对象作为参数传递给FileReader的readAsArrayBuffer()方法
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
export function getImageMd5Local(file) {
|
||||
return new Promise((resolve) => {
|
||||
var reader = new FileReader()
|
||||
// 读取Blob对象的内容
|
||||
reader.onloadend = function () {
|
||||
/*const spark = new SparkMd5.ArrayBuffer()
|
||||
console.log(reader.result)
|
||||
spark.append(reader.result);*/
|
||||
const md5 = SparkMd5.hash(reader.result)
|
||||
resolve({md5, fileName: file.name});
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
})
|
||||
}
|
||||
|
||||
export async function uploadImage(folderId, imageUrl, mallId, local = false) {
|
||||
let res1
|
||||
if (local) {
|
||||
res1 = await getImageMd5Local(imageUrl)
|
||||
imageUrl = URL.createObjectURL(imageUrl)
|
||||
} else {
|
||||
res1 = await getImageMd5(imageUrl)
|
||||
}
|
||||
let detailList = []
|
||||
detailList.push({
|
||||
materialMd5: res1.md5,
|
||||
materialName: res1.fileName,
|
||||
materialType: 1
|
||||
})
|
||||
let res2 = await sendChromeAPIMessage({
|
||||
url: 'marvel-mms/cn/api/kiana/gmp/bg/phoenix/api/material/create',
|
||||
needMallId: true,
|
||||
mallId: mallId,
|
||||
data: {
|
||||
createDetailList: detailList,
|
||||
folderId: folderId
|
||||
}})
|
||||
await sleepSync(200)
|
||||
|
||||
if (res2.success) {
|
||||
if (res2.result.responseDetailList[0].alreadyExists) {
|
||||
return res2.result.responseDetailList[0].imgUrl
|
||||
} else {
|
||||
let res3 = await sendChromeAPIMessage({
|
||||
url: 'galerie/business/get_signature?sdk_version=js-0.0.16-alpha.0&tag_name=product-material-tag',
|
||||
needMallId: true,
|
||||
mallId: mallId,
|
||||
data: {
|
||||
bucket_tag: "product-material-tag"
|
||||
}
|
||||
})
|
||||
await sleepSync(200)
|
||||
|
||||
let res4 = await sendChromeAPIMessage({
|
||||
url: 'https://file.kuajingmaihuo.com/api/galerie/v3/store_image?sdk_version=js-0.0.16-alpha.0&tag_name=product-material-tag',
|
||||
isFormData: true,
|
||||
data: {
|
||||
url_width_height: true,
|
||||
image: imageUrl,
|
||||
upload_sign: res3.result.signature
|
||||
}
|
||||
})
|
||||
await sleepSync(200)
|
||||
|
||||
let res5 = await sendChromeAPIMessage({
|
||||
url: 'marvel-mms/cn/api/kiana/gmp/bg/phoenix/api/material/edit',
|
||||
needMallId: true,
|
||||
mallId: mallId,
|
||||
data: {
|
||||
id: res2.result.responseDetailList[0].id,
|
||||
materialName: res2.result.responseDetailList[0].materialName,
|
||||
materialType: 1,
|
||||
uploadStatus: 3,
|
||||
url: res4.url
|
||||
}
|
||||
})
|
||||
return res5.result.imgUrl
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function sleepSync(milliseconds) {
|
||||
return new Promise(resolve => setTimeout(resolve, milliseconds));
|
||||
}
|
||||
@@ -1,6 +1,9 @@
|
||||
import request from '../api'
|
||||
import store from '../store'
|
||||
import { Message } from 'element-ui'
|
||||
import JsBarcode from 'jsbarcode'
|
||||
import { Interpreter } from 'eval5'
|
||||
import { transform } from "@babel/standalone"
|
||||
|
||||
const dict = {
|
||||
url: "/api/dictionary/queryValsByCodeList",
|
||||
@@ -104,8 +107,8 @@ const userCheck = (mallId) => {
|
||||
tempMallId = store.state.mallId
|
||||
}
|
||||
if (res.type != 4 && tempMallId != store.state.userInfo.mallId) {
|
||||
Message.error('您当前登录的TEMU账号与会员绑定账号不一致')
|
||||
reject('您当前登录的TEMU账号与会员绑定账号不一致')
|
||||
Message.error('您当前登录的卖家中心店铺与会员绑定店铺不一致')
|
||||
reject('您当前登录的卖家中心店铺与会员绑定店铺不一致')
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -114,10 +117,34 @@ const userCheck = (mallId) => {
|
||||
})
|
||||
}
|
||||
|
||||
const sleepSync = (milliseconds) => {
|
||||
return new Promise(resolve => setTimeout(resolve, milliseconds));
|
||||
}
|
||||
|
||||
const initWindow = () => {
|
||||
const transformCode = (codeStr) => {
|
||||
return transform(codeStr, { presets: ['env'] }).code
|
||||
}
|
||||
|
||||
window.JsBarcode = JsBarcode
|
||||
window.eval = (code, context) => {
|
||||
const interpreter = new Interpreter(context || window, {
|
||||
timeout: 1000,
|
||||
})
|
||||
try {
|
||||
interpreter.evaluate(transformCode(code))
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
dict,
|
||||
dateUtil,
|
||||
userCheck
|
||||
sleepSync,
|
||||
userCheck,
|
||||
initWindow
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -16,7 +16,189 @@ export function transform(leftData) {
|
||||
// 普通属性
|
||||
rightData.productName = leftData.productName;
|
||||
rightData.materialMultiLanguages = leftData.productLocalExtAttr.materialMultiLanguages;
|
||||
rightData.productI18nReqs = leftData.productI18nList;
|
||||
rightData.productPropertyReqs = [];
|
||||
let flag = false
|
||||
for (let i = 0; i < leftData.productPropertyList.length; i++) {
|
||||
let val = {
|
||||
valueUnit: leftData.productPropertyList[i].valueUnit,
|
||||
propValue: leftData.productPropertyList[i].propValue,
|
||||
propName: leftData.productPropertyList[i].propName,
|
||||
refPid: leftData.productPropertyList[i].refPid,
|
||||
vid: leftData.productPropertyList[i].vid,
|
||||
controlType: leftData.productPropertyList[i].controlType || 1,
|
||||
numberInputValue: leftData.productPropertyList[i].numberInputValue || "",
|
||||
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;
|
||||
|
||||
let productSpecPropertyReqs = [];
|
||||
for(let i = 0; i < leftSkc.length; i++) {
|
||||
let rightSkcItem = {};
|
||||
rightSkcItem.previewImgUrls = leftSkc[i].previewImgUrls;
|
||||
rightSkcItem.productSkcCarouselImageI18nReqs = leftSkc[i].productSkcCarouselImageI18nVOList;
|
||||
rightSkcItem.extCode = leftSkc[i].extCode;
|
||||
rightSkcItem.mainProductSkuSpecReqs = leftSkc[i].mainProductSkuSpec || [
|
||||
{
|
||||
"parentSpecId": 0,
|
||||
"parentSpecName": "",
|
||||
"specId": 0,
|
||||
"specName": ""
|
||||
}
|
||||
];
|
||||
rightSkcItem.productSkuReqs = [];
|
||||
for(let j = 0; j < leftSkc[i].productSkuList.length; j++) {
|
||||
let leftSkuItem = leftSkc[i].productSkuList[j];
|
||||
let rightSkuItem = {};
|
||||
|
||||
rightSkuItem.thumbUrl = leftSkuItem.thumbUrl;
|
||||
rightSkuItem.productSkuThumbUrlI18nReqs = leftSkuItem.productSkuThumbUrlI18nVOList;
|
||||
rightSkuItem.extCode = leftSkuItem.extCode;
|
||||
rightSkuItem.supplierPrice = leftSkuItem.supplierPrice;
|
||||
rightSkuItem.currencyType = leftSkuItem.currencyType;
|
||||
rightSkuItem.productSkuSuggestedPriceReq = leftSkuItem.productSkuSuggestedPrice;
|
||||
rightSkuItem.productSkuMultiPackReq = leftSkuItem.productSkuMultiPack;
|
||||
if (rightSkuItem.productSkuMultiPackReq) {
|
||||
delete rightSkuItem.productSkuMultiPackReq.productSkuNetContent
|
||||
}
|
||||
rightSkuItem.productSkuMultiPackReq.productSkuNetContentReq = {}
|
||||
rightSkuItem.productSkuSpecReqs = leftSkuItem.productSkuSpecList;
|
||||
productSpecPropertyReqs.push({
|
||||
"parentSpecId": leftSkuItem.productSkuSpecList[0].parentSpecId,
|
||||
"parentSpecName": leftSkuItem.productSkuSpecList[0].parentSpecName,
|
||||
"specId": leftSkuItem.productSkuSpecList[0].specId,
|
||||
"specName": leftSkuItem.productSkuSpecList[0].specName,
|
||||
"refPid": 0,
|
||||
"pid": 0,
|
||||
"templatePid": 0,
|
||||
"propName": leftSkuItem.productSkuSpecList[0].specName,
|
||||
"vid": 0,
|
||||
"propValue": leftSkuItem.productSkuSpecList[0].specName,
|
||||
"valueUnit": "",
|
||||
"valueGroupId": 0,
|
||||
"valueGroupName": "",
|
||||
"valueExtendInfo": ""
|
||||
});
|
||||
rightSkuItem.productSkuId = 0;
|
||||
if (!leftSkuItem.productSkuWhExtAttr) {
|
||||
rightSkuItem.productSkuWhExtAttrReq = null
|
||||
} else {
|
||||
rightSkuItem.productSkuWhExtAttrReq = {
|
||||
"productSkuVolumeReq": leftSkuItem.productSkuWhExtAttr?.productSkuVolume,
|
||||
"productSkuWeightReq": leftSkuItem.productSkuWhExtAttr?.productSkuWeight,
|
||||
"productSkuBarCodeReqs": leftSkuItem.productSkuWhExtAttr?.productSkuBarCodes,
|
||||
"productSkuSensitiveAttrReq": {
|
||||
"isSensitive": leftSkuItem.productSkuWhExtAttr?.productSkuSensitiveAttr.isSensitive,
|
||||
"sensitiveList": leftSkuItem.productSkuWhExtAttr?.productSkuSensitiveAttr.sensitiveList},
|
||||
"productSkuSensitiveLimitReq": leftSkuItem.productSkuWhExtAttr?.productSkuSensitiveLimit,
|
||||
};
|
||||
}
|
||||
rightSkuItem.currencyType = leftSkuItem.currencyType;
|
||||
|
||||
rightSkcItem.productSkuReqs.push(rightSkuItem);
|
||||
}
|
||||
rightSkcItem.productSkcId = 0;
|
||||
|
||||
rightSkc.push(rightSkcItem);
|
||||
}
|
||||
rightData.productSkcReqs = rightSkc;
|
||||
|
||||
// Spec
|
||||
rightData.productSpecPropertyReqs = productSpecPropertyReqs;
|
||||
rightData.carouselImageUrls = leftData.carouselImageUrls;
|
||||
rightData.carouselImageI18nReqs = leftData.carouselImageI18nVOList;
|
||||
rightData.materialImgUrl = leftData.materialImgUrl;
|
||||
rightData.goodsLayerDecorationReqs = leftData.goodsLayerDecorationVOList;
|
||||
rightData.sizeTemplateIds = !leftData.sizeTemplateIds ? []: leftData.sizeTemplateIds;
|
||||
rightData.sizeTemplateId = leftData.sizeTemplateId || 0;
|
||||
rightData.showSizeTemplateIds = !leftData.showSizeTemplateIds ? []: leftData.showSizeTemplateIds;
|
||||
rightData.goodsModelReqs = !leftData.goodsModelList ? []: leftData.goodsModelList;
|
||||
rightData.productWhExtAttrReq = {
|
||||
outerGoodsUrl: leftData.productWhExtAttr.outerGoodsUrl,
|
||||
productOrigin: {
|
||||
countryShortName: leftData.productWhExtAttr.productOrigin ? leftData.productWhExtAttr.productOrigin.countryShortName: 'CN'
|
||||
}
|
||||
};
|
||||
rightData.personalizationSwitch = leftData.productWhExtAttr.personalizationSwitch || "0"
|
||||
rightData.productCarouseVideoReqList = leftData.carouseVideoVOList;
|
||||
rightData.goodsAdvantageLabelTypes = leftData.goodsAdvantageLabelVOList;
|
||||
rightData.productDetailVideoReqList = leftData.detailVideoVOList;
|
||||
if (leftData.productSpecPropertyVOS) {
|
||||
rightData.productSpecPropertyReqs = leftData.productSpecPropertyVOS
|
||||
}
|
||||
rightData.productOuterPackageImageReqs = [];
|
||||
for (let i = 0;i < leftData.outerPackageImages.length; i++) {
|
||||
rightData.productOuterPackageImageReqs.push({
|
||||
imageUrl: leftData.outerPackageImages[i].imageUrl
|
||||
})
|
||||
}
|
||||
if (leftData.productGuideFileI18nList) {
|
||||
rightData.productGuideFileI18nReqs = leftData.productGuideFileI18nList.map(item => {
|
||||
return {fileName: item.fileName,
|
||||
fileUrl: item.fileUrl,
|
||||
language: item.language,
|
||||
languages: item.languages}
|
||||
});
|
||||
} else {
|
||||
rightData.productGuideFileI18nReqs = []
|
||||
}
|
||||
rightData.productOuterPackageReq = leftData.productWhExtAttr.productOuterPackage;
|
||||
rightData.sensitiveTransNormalFileReqs = leftData.productWhExtAttr.sensitiveTransNormalFiles;
|
||||
rightData.productSaleExtAttrReq = {};
|
||||
rightData.productDraftId = "";
|
||||
|
||||
return JSON.stringify(rightData);
|
||||
}
|
||||
|
||||
export function transformSubmitForHalf(leftData, config, draftId) {
|
||||
let rightData = {};
|
||||
// 分类
|
||||
let leftCategory = leftData.categories;
|
||||
rightData.cat1Id = leftCategory.cat1.catId;
|
||||
rightData.cat2Id = leftCategory.cat2.catId;
|
||||
rightData.cat3Id = leftCategory.cat3.catId;
|
||||
rightData.cat4Id = leftCategory.cat4.catId;
|
||||
rightData.cat5Id = leftCategory.cat5.catId;
|
||||
rightData.cat6Id = leftCategory.cat6.catId;
|
||||
rightData.cat7Id = leftCategory.cat7.catId;
|
||||
rightData.cat8Id = leftCategory.cat8.catId;
|
||||
rightData.cat9Id = leftCategory.cat9.catId;
|
||||
rightData.cat10Id = leftCategory.cat10.catId;
|
||||
|
||||
// 普通属性
|
||||
rightData.productName = leftData.productName;
|
||||
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,
|
||||
@@ -86,7 +268,19 @@ export function transform(leftData) {
|
||||
"sensitiveList": leftSkuItem.productSkuWhExtAttr.productSkuSensitiveAttr.sensitiveList},
|
||||
"productSkuSensitiveLimitReq": leftSkuItem.productSkuWhExtAttr.productSkuSensitiveLimit,
|
||||
};
|
||||
let warehouseStockQuantityReqs = []
|
||||
for (let k = 0; k < config.wareHouseList.length; k++) {
|
||||
warehouseStockQuantityReqs.push({
|
||||
warehouseId: config.wareHouseList[k],
|
||||
targetStockAvailable: config.stockNumber
|
||||
})
|
||||
}
|
||||
let productSkuStockQuantityReq = {
|
||||
warehouseStockQuantityReqs: warehouseStockQuantityReqs
|
||||
}
|
||||
rightSkuItem.productSkuStockQuantityReq = productSkuStockQuantityReq
|
||||
rightSkuItem.currencyType = leftSkuItem.currencyType;
|
||||
rightSkuItem.supplierPrice = leftSkuItem.supplierPrice + config.upMoney * 100;
|
||||
|
||||
rightSkcItem.productSkuReqs.push(rightSkuItem);
|
||||
}
|
||||
@@ -102,15 +296,24 @@ export function transform(leftData) {
|
||||
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;
|
||||
rightData.productWhExtAttrReq = {
|
||||
outerGoodsUrl: leftData.productWhExtAttr.outerGoodsUrl,
|
||||
productOrigin: {
|
||||
countryShortName: leftData.productWhExtAttr.productOrigin.countryShortName
|
||||
countryShortName: leftData.productWhExtAttr.productOrigin ? leftData.productWhExtAttr.productOrigin.countryShortName: 'CN'
|
||||
}
|
||||
};
|
||||
rightData.personalizationSwitch = leftData.productWhExtAttr.personalizationSwitch || 0
|
||||
rightData.productCarouseVideoReqList = leftData.carouseVideoVOList;
|
||||
rightData.goodsAdvantageLabelTypes = leftData.goodsAdvantageLabelVOList;
|
||||
rightData.productDetailVideoReqList = leftData.detailVideoVOList;
|
||||
@@ -133,7 +336,278 @@ export function transform(leftData) {
|
||||
rightData.productOuterPackageReq = leftData.productWhExtAttr.productOuterPackage;
|
||||
rightData.sensitiveTransNormalFileReqs = leftData.productWhExtAttr.sensitiveTransNormalFiles;
|
||||
rightData.productSaleExtAttrReq = {};
|
||||
rightData.productDraftId = "";
|
||||
rightData.productShipmentReq = {
|
||||
freightTemplateId: config.freightTemplateId,
|
||||
shipmentLimitSecond: config.sendGoodsSecond
|
||||
}
|
||||
let bindSiteIds = []
|
||||
if (leftData.productSaleExtAttr?.productSemiManaged?.bindSites) {
|
||||
leftData.productSaleExtAttr?.productSemiManaged?.bindSites.map(ii => {
|
||||
bindSiteIds.push(ii.siteId)
|
||||
})
|
||||
}
|
||||
rightData.productSemiManagedReq = {
|
||||
bindSiteIds: bindSiteIds
|
||||
}
|
||||
let targetRouteList = []
|
||||
for (let m = 0; m < config.wareHouseList.length; m++) {
|
||||
targetRouteList.push({
|
||||
warehouseId: config.wareHouseList[m],
|
||||
siteIdList: bindSiteIds
|
||||
})
|
||||
}
|
||||
rightData.productWarehouseRouteReq = {
|
||||
targetRouteList: targetRouteList
|
||||
}
|
||||
rightData.productDraftId = draftId;
|
||||
|
||||
return rightData;
|
||||
}
|
||||
|
||||
export function transformAliExpress(content) {
|
||||
let template = {
|
||||
cat1Id: 0,
|
||||
cat2Id: 0,
|
||||
cat3Id: 0,
|
||||
cat4Id: 0,
|
||||
cat5Id: 0,
|
||||
cat6Id: 0,
|
||||
cat7Id: 0,
|
||||
cat8Id: 0,
|
||||
cat9Id: 0,
|
||||
cat10Id: 0,
|
||||
materialMultiLanguages: [],
|
||||
productName: content.title,
|
||||
productPropertyReqs: [],
|
||||
productSkcReqs: [],
|
||||
productSpecPropertyReqs: [],
|
||||
carouselImageUrls: content.carouselImageUrls,
|
||||
carouselImageI18nReqs: [],
|
||||
materialImgUrl: content.carouselImageUrls[0],
|
||||
goodsLayerDecorationReqs: [],
|
||||
sizeTemplateIds: [],
|
||||
showSizeTemplateIds: [],
|
||||
goodsModelReqs: [],
|
||||
productWhExtAttrReq: {
|
||||
outerGoodsUrl: "",
|
||||
productOrigin: {
|
||||
countryShortName: "CN"
|
||||
}
|
||||
},
|
||||
productCarouseVideoReqList: [],
|
||||
goodsAdvantageLabelTypes: [],
|
||||
productDetailVideoReqList: [],
|
||||
productOuterPackageImageReqs: [],
|
||||
productOuterPackageReq: {},
|
||||
sensitiveTransNormalFileReqs: [],
|
||||
productGuideFileI18nReqs: [],
|
||||
productSaleExtAttrReq: {},
|
||||
productNonAuditExtAttrReq: {
|
||||
california65WarningInfoReq: {}
|
||||
},
|
||||
productDraftId: 0
|
||||
}
|
||||
|
||||
if (!!content.text) {
|
||||
template.goodsLayerDecorationReqs.push({
|
||||
floorId: null,
|
||||
lang: "zh",
|
||||
key: "DecImage",
|
||||
type: "text",
|
||||
priority: 0,
|
||||
contentList: [
|
||||
{
|
||||
text: content.text,
|
||||
textModuleDetails: {
|
||||
fontSize: 12,
|
||||
fontColor: "#333333",
|
||||
backgroundColor: "#ffffff",
|
||||
align: "left"
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
for (let i = 0; i < content.detailImageList.length; i++) {
|
||||
let imgList = []
|
||||
imgList.push({imgUrl: content.detailImageList[i]})
|
||||
template.goodsLayerDecorationReqs.push({
|
||||
floorId: null,
|
||||
lang: "zh",
|
||||
key: "DecImage",
|
||||
type: "image",
|
||||
priority: 0,
|
||||
contentList: imgList
|
||||
})
|
||||
}
|
||||
|
||||
return template
|
||||
}
|
||||
|
||||
export function transformShein(leftData) {
|
||||
let rightData = {};
|
||||
// 普通属性
|
||||
rightData.back_size_attribute_list = []
|
||||
rightData.brand_code = ''
|
||||
rightData.category_id = leftData.category_id
|
||||
rightData.category_id_list = []
|
||||
if (leftData.category_info.level_one_category_id) {
|
||||
rightData.category_id_list.push(leftData.category_info.level_one_category_id)
|
||||
}
|
||||
if (leftData.category_info.level_two_category_id) {
|
||||
rightData.category_id_list.push(leftData.category_info.level_two_category_id)
|
||||
}
|
||||
if (leftData.category_info.level_three_category_id) {
|
||||
rightData.category_id_list.push(leftData.category_info.level_three_category_id)
|
||||
}
|
||||
if (leftData.category_info.level_four_category_id) {
|
||||
rightData.category_id_list.push(leftData.category_info.level_four_category_id)
|
||||
}
|
||||
rightData.certificate_list = []
|
||||
rightData.confirm_size_img = false
|
||||
rightData.extra = {
|
||||
"switch_to_spu_pic": false,
|
||||
"from_page_id": null,
|
||||
"spu_tag": [],
|
||||
"transformCvSizeImage": false,
|
||||
"useCvTransformImage": false,
|
||||
"confirm_volume_sku": [],
|
||||
"confirm_weight_sku": []
|
||||
}
|
||||
rightData.image_info = {}
|
||||
rightData.multi_language_desc_list = [
|
||||
{
|
||||
"language": "en",
|
||||
"name": ""
|
||||
},
|
||||
{
|
||||
"language": "fr",
|
||||
"name": ""
|
||||
},
|
||||
{
|
||||
"language": "es",
|
||||
"name": ""
|
||||
},
|
||||
{
|
||||
"language": "de",
|
||||
"name": ""
|
||||
},
|
||||
{
|
||||
"language": "it",
|
||||
"name": ""
|
||||
},
|
||||
{
|
||||
"language": "ru",
|
||||
"name": ""
|
||||
},
|
||||
{
|
||||
"language": "ar",
|
||||
"name": ""
|
||||
},
|
||||
{
|
||||
"language": "zh-tw",
|
||||
"name": ""
|
||||
},
|
||||
{
|
||||
"language": "zh-cn",
|
||||
"name": ""
|
||||
},
|
||||
{
|
||||
"language": "th",
|
||||
"name": ""
|
||||
},
|
||||
{
|
||||
"language": "id",
|
||||
"name": ""
|
||||
},
|
||||
{
|
||||
"language": "nl",
|
||||
"name": ""
|
||||
},
|
||||
{
|
||||
"language": "tr",
|
||||
"name": ""
|
||||
},
|
||||
{
|
||||
"language": "vi",
|
||||
"name": ""
|
||||
},
|
||||
{
|
||||
"language": "pt-br",
|
||||
"name": ""
|
||||
},
|
||||
{
|
||||
"language": "he",
|
||||
"name": ""
|
||||
},
|
||||
{
|
||||
"language": "sv",
|
||||
"name": ""
|
||||
},
|
||||
{
|
||||
"language": "pl",
|
||||
"name": ""
|
||||
},
|
||||
{
|
||||
"language": "pt-pt",
|
||||
"name": ""
|
||||
},
|
||||
{
|
||||
"language": "ko",
|
||||
"name": ""
|
||||
},
|
||||
{
|
||||
"language": "ja",
|
||||
"name": ""
|
||||
},
|
||||
{
|
||||
"language": "el-gr",
|
||||
"name": ""
|
||||
},
|
||||
{
|
||||
"language": "cs-cz",
|
||||
"name": ""
|
||||
},
|
||||
{
|
||||
"language": "ro",
|
||||
"name": ""
|
||||
}
|
||||
]
|
||||
rightData.multi_language_name_list = []
|
||||
let lang = leftData.multi_language_name_list.filter(item => {
|
||||
return item.language == 'zh-cn'
|
||||
})
|
||||
rightData.multi_language_name_list.push({
|
||||
language: 'zh-cn',
|
||||
name: lang[0].name
|
||||
})
|
||||
rightData.part_info_list = []
|
||||
rightData.plm_pattern_id_list = []
|
||||
rightData.product_attribute_list = leftData.product_attribute_list
|
||||
rightData.product_type_id = leftData.product_type_id
|
||||
rightData.product_video_list = leftData.product_video_list
|
||||
rightData.sample_sku_back_size = leftData.sample_sku_back_size
|
||||
rightData.site_list = leftData.site_list
|
||||
rightData.size_attribute_list = leftData.size_attribute_list
|
||||
rightData.skc_list = leftData.skc_list
|
||||
rightData.skc_list.map(item => {
|
||||
item.image_info.image_group_code = null
|
||||
item.image_info.image_info_list.map(item1 => {
|
||||
item1.image_item_id = null
|
||||
})
|
||||
})
|
||||
rightData.skc_list.map(item => {
|
||||
delete item.skc_name
|
||||
item.sku_list.map(item1 => {
|
||||
delete item1.sku_code
|
||||
})
|
||||
})
|
||||
rightData.spp_relate_spu_name = ""
|
||||
rightData.spu_name = ""
|
||||
rightData.suit_flag = 0
|
||||
rightData.supplier_code = null
|
||||
rightData.top_category_id = leftData.category_info.level_one_category_id
|
||||
|
||||
return JSON.stringify(rightData);
|
||||
}
|
||||
13
src/utils/template-helper.js
Normal file
@@ -0,0 +1,13 @@
|
||||
import { hiprint } from 'vue-plugin-hiprint'
|
||||
|
||||
const templateMap = {}
|
||||
|
||||
export function newHiprintPrintTemplate(key, options) {
|
||||
let template = new hiprint.PrintTemplate(options)
|
||||
templateMap[key] = template
|
||||
return template
|
||||
}
|
||||
|
||||
export function getHiprintPrintTemplate(key) {
|
||||
return templateMap[key]
|
||||
}
|
||||
@@ -2,26 +2,28 @@
|
||||
<div class="admin">
|
||||
<div class="admin-top">
|
||||
<div class="logo">
|
||||
<img src="../assets/images/logo.png" />
|
||||
<img src="../assets/images/logo.png"/>
|
||||
<span>v{{ version }}</span>
|
||||
</div>
|
||||
<div class="admin-right">
|
||||
<el-tooltip class="item" effect="dark" content="金币信息" placement="top">
|
||||
<div class="left" @click="toActive">
|
||||
<div class="left" @click="openMember(1)">
|
||||
<div :style="{marginLeft: '0px'}">{{ $store.state.userInfo.coin }}</div>
|
||||
<span style="margin-right: 10px;"><img src="../assets/coin.png" width="30"/></span>
|
||||
</div>
|
||||
</el-tooltip>
|
||||
<el-button type="button" :class="'el-button el-button--primary'" @click="sign">签到</el-button>
|
||||
<!--<el-button type="button" :class="'el-button el-button--primary'" @click="openFolder">打开文件夹</el-button>-->
|
||||
<el-tooltip class="item" effect="dark" content="用户激活" placement="top">
|
||||
<div class="left" @click="toActive">
|
||||
<div class="left" @click="openMember(0)">
|
||||
<span>会员信息:</span>
|
||||
<div :style="{marginLeft: '10px', color: $store.state.userInfo.flag == 1? 'green': 'red'}">{{ getStateInfo }}</div>
|
||||
</div>
|
||||
</el-tooltip>
|
||||
<el-dropdown @command="handleClick">
|
||||
<div class="userinfo">
|
||||
<span>{{ $store.state.userInfo.name + "(" + $store.state.userInfo.phone + ")" }}</span>
|
||||
<img src="../assets/images/bottom.png" />
|
||||
<span>{{ userInfo.name + "(" + userInfo.phone + ")" }}</span>
|
||||
<img src="../assets/images/bottom.png"/>
|
||||
</div>
|
||||
<el-dropdown-menu slot="dropdown">
|
||||
<!-- <el-dropdown-item command="phone">修改手机</el-dropdown-item> -->
|
||||
@@ -36,50 +38,161 @@
|
||||
<div class="admin-main">
|
||||
<el-scrollbar class="left">
|
||||
<el-menu
|
||||
:default-active="activePath"
|
||||
:collapse-transition="true"
|
||||
unique-opened
|
||||
background-color="#545c64"
|
||||
router
|
||||
text-color="#fff"
|
||||
:collapse="isCollapse">
|
||||
:default-active="activePath"
|
||||
:collapse-transition="true"
|
||||
unique-opened
|
||||
background-color="#545c64"
|
||||
router
|
||||
text-color="#fff"
|
||||
:collapse="isCollapse">
|
||||
<el-menu-item index="/welcome">
|
||||
<i class="el-icon-monitor"></i>
|
||||
<span slot="title">工作台</span>
|
||||
</el-menu-item>
|
||||
|
||||
<el-submenu index="/imageTranslate">
|
||||
<template #title>
|
||||
<i class="el-icon-s-goods"/>
|
||||
<span>AI助手</span>
|
||||
</template>
|
||||
<el-menu-item index="/imageTranslate">图片翻译</el-menu-item>
|
||||
</el-submenu>
|
||||
|
||||
<el-submenu index="/normalSendGoods">
|
||||
<template slot="title">
|
||||
<i class="el-icon-shopping-cart-2"></i>
|
||||
<span slot="title">备货单管理</span>
|
||||
</template>
|
||||
<el-menu-item index="/waitCreate">创建备货单</el-menu-item>
|
||||
<el-menu-item index="/normalSendGoods">抢仓发货</el-menu-item>
|
||||
<el-menu-item index="/shippingDesk">发货台管理</el-menu-item>
|
||||
<el-menu-item index="/waitPackageList">待装箱发货单</el-menu-item>
|
||||
<el-menu-item index="/waitShippingList">待收货发货单</el-menu-item>
|
||||
<el-menu-item index="/shippingList">已收货发货单</el-menu-item>
|
||||
<el-menu-item index="/myNormalOrder">普通备货单</el-menu-item>
|
||||
<el-menu-item index="/myUrgencyOrder">紧急备货单</el-menu-item>
|
||||
<el-menu-item index="/productLabel">商品条码管理</el-menu-item>
|
||||
</el-submenu>
|
||||
|
||||
<el-submenu index="/copyProduct">
|
||||
<template slot="title">
|
||||
<i class="el-icon-goods"></i>
|
||||
<span slot="title">商品管理</span>
|
||||
</template>
|
||||
<el-menu-item index="/productList">商品列表</el-menu-item>
|
||||
<el-menu-item index="/copyProduct">商品复制</el-menu-item>
|
||||
<el-menu-item index="/findSeller">查找买手</el-menu-item>
|
||||
<el-menu-item index="/priceDown">拒绝调价</el-menu-item>
|
||||
<!--<el-menu-item index="/batchUpload">批量上品</el-menu-item>-->
|
||||
<el-menu-item v-if="$store.state.userInfo.phone == '18610967550' || isAdmin" 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">
|
||||
<template slot="title">
|
||||
<i class="el-icon-house"></i>
|
||||
<span slot="title">库存管理</span>
|
||||
</template>
|
||||
<el-menu-item index="/returnPackage">退货包裹管理</el-menu-item>
|
||||
<el-menu-item index="/returnDetail">退货明细</el-menu-item>
|
||||
</el-submenu>
|
||||
<el-submenu index="/niubiCopy">
|
||||
<template slot="title">
|
||||
<i class="el-icon-magic-stick"></i>
|
||||
<span slot="title">选品采集</span>
|
||||
</template>
|
||||
<el-menu-item index="/niubiCopy">智能复制</el-menu-item>
|
||||
<el-menu-item index="/storeTrack">店铺跟踪</el-menu-item>
|
||||
<el-menu-item index="/keywordTrack">关键字跟踪</el-menu-item>
|
||||
<el-menu-item index="/niubiCopy">商品采集</el-menu-item>
|
||||
<el-menu-item index="/aliExpressCopy">速卖通采集</el-menu-item>
|
||||
<el-submenu index="/track" style="padding-left: 15px;">
|
||||
<template slot="title">
|
||||
<span slot="title">选品跟踪</span>
|
||||
</template>
|
||||
<el-menu-item index="/storeTrack">店铺跟踪</el-menu-item>
|
||||
<el-menu-item index="/keywordTrack">关键字跟踪</el-menu-item>
|
||||
<el-menu-item index="/favoriteTrack">我的收藏</el-menu-item>
|
||||
</el-submenu>
|
||||
<el-submenu index="/newproductTrack" style="padding-left: 15px;">
|
||||
<template slot="title">
|
||||
<span slot="title">新品跟踪(免费)</span>
|
||||
</template>
|
||||
<el-menu-item index="/newProduct">上架新品</el-menu-item>
|
||||
<el-menu-item index="/newProductGroup">我的分组</el-menu-item>
|
||||
</el-submenu>
|
||||
<el-menu-item index="/singleTrack">单品跟踪</el-menu-item>
|
||||
<el-menu-item index="/bestSellers">7天畅销品</el-menu-item>
|
||||
<el-menu-item index="/indexTrack">首页商品跟踪</el-menu-item>
|
||||
</el-submenu>
|
||||
|
||||
<el-menu-item index="/saleData">
|
||||
<i class="el-icon-s-data"></i>
|
||||
<span slot="title">销售数据</span>
|
||||
<el-submenu index="/qualification">
|
||||
<template slot="title">
|
||||
<i class="el-icon-s-check"></i>
|
||||
<span slot="title">资质合规</span>
|
||||
</template>
|
||||
<el-menu-item>
|
||||
<template #title>
|
||||
<a style="color: white" :href="'https://www.evatmaster.com/ost/registered?channelNo=SCBFWYSHZTEMUXZSQDHZ'" target="_blank">
|
||||
<span>欧税通</span>
|
||||
</a>
|
||||
</template>
|
||||
</el-menu-item>
|
||||
</el-submenu>
|
||||
<el-submenu index="/saleManager">
|
||||
<template slot="title">
|
||||
<i class="el-icon-s-data"></i>
|
||||
<span slot="title">销售管理</span>
|
||||
</template>
|
||||
<el-menu-item index="/costManageTemu">成本管理</el-menu-item>
|
||||
<el-menu-item index="/saleData">销售管理</el-menu-item>
|
||||
<el-menu-item index="/saleStatTemu">销售统计</el-menu-item>
|
||||
<el-menu-item index="/saleOut">售罄看板</el-menu-item>
|
||||
<el-menu-item index="/afterSaleStat">售后统计</el-menu-item>
|
||||
<el-menu-item index="/afterSaleDeductStat">售后赔付统计</el-menu-item>
|
||||
<el-menu-item index="/priceAdjustment">调价管理</el-menu-item>
|
||||
<el-menu-item index="/logisticFee">物流统计</el-menu-item>
|
||||
<el-menu-item index="/billStat">账务明细统计</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="/orderListShein">发货订单</el-menu-item>
|
||||
<el-menu-item index="/productListOdm">商品列表(ODM)</el-menu-item>
|
||||
<el-menu-item v-if="isAdmin || $store.state.userInfo.phone == '18666013582'" index="/returnRecordShein">退货与报废单列表</el-menu-item>
|
||||
<el-menu-item v-if="isAdmin || $store.state.userInfo.phone == '17607119772'" index="/labelInfoShein">
|
||||
标签管理
|
||||
</el-menu-item>
|
||||
<el-menu-item v-if="isAdmin || $store.state.userInfo.phone == '17607119772'" index="/purchaseOrderListShein">
|
||||
发货单列表
|
||||
</el-menu-item>
|
||||
<el-menu-item index="/saleStatShein">商家账单统计</el-menu-item>
|
||||
</el-submenu>
|
||||
<el-submenu index="/dataManager" v-if="isAdmin">
|
||||
<template slot="title">
|
||||
<i class="el-icon-s-data"></i>
|
||||
<span slot="title">数据管理</span>
|
||||
</template>
|
||||
<el-menu-item index="/syncDataTemu">数据同步(TEMU)</el-menu-item>
|
||||
</el-submenu>
|
||||
<el-submenu index="/semi" v-if="$store.state.userInfo.phone == '18571466720'">
|
||||
<template slot="title">
|
||||
<i class="el-icon-s-data"></i>
|
||||
<span slot="title">半托管</span>
|
||||
</template>
|
||||
<el-menu-item index="/sendGoods_xc">发货(芯仓)</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">
|
||||
<i class="el-icon-money"></i>
|
||||
<span slot="title">调价管理</span>
|
||||
</el-menu-item>-->
|
||||
<el-menu-item index="/learning">
|
||||
<i class="el-icon-eleme"></i>
|
||||
<span slot="title">新手园地</span>
|
||||
@@ -88,6 +201,25 @@
|
||||
<i class="el-icon-s-data"></i>
|
||||
<span slot="title">数据统计</span>
|
||||
</el-menu-item> -->
|
||||
<el-submenu index="labels">
|
||||
<template slot="title">
|
||||
<i class="el-icon-s-goods"></i>
|
||||
<div slot="title" style="display: inline-block;">
|
||||
<span>高级功能</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-submenu index="/labelsTemplate" style="padding-left: 15px;">
|
||||
<template slot="title">
|
||||
<div slot="title" style="display: inline-block; ">
|
||||
<span>标签管理</span>
|
||||
<el-button type="text" style="margin-left: 57px; padding: 0;" @click.stop="openMember(2)">开通</el-button>
|
||||
</div>
|
||||
</template>
|
||||
<el-menu-item index="/labelsTemplate">模板管理</el-menu-item>
|
||||
<el-menu-item index="/labelsPrint">标签打印</el-menu-item>
|
||||
</el-submenu>
|
||||
</el-submenu>
|
||||
|
||||
</el-menu>
|
||||
</el-scrollbar>
|
||||
<div class="container">
|
||||
@@ -99,303 +231,459 @@
|
||||
</div>
|
||||
</div>
|
||||
<el-dialog
|
||||
title="激活充值"
|
||||
:visible="$store.state.activeDlgShow"
|
||||
:close-on-click-modal="false"
|
||||
width="1200"
|
||||
:before-close="handleClose">
|
||||
title="激活充值"
|
||||
:visible="$store.state.activeDlgShow"
|
||||
:close-on-click-modal="false"
|
||||
width="1200"
|
||||
: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>
|
||||
</div>
|
||||
<LablesMember ref="LablesMember"></LablesMember>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {mapMutations, mapState} from 'vuex'
|
||||
import AiPayment from "@/components/AiPayment.vue";
|
||||
import LablesMember from '@/components/LablesMember'
|
||||
import {sendAliexpressAPIMessage, sendGoodcangAPIMessage} from "@/api/chromeApi";
|
||||
|
||||
export default {
|
||||
components: {AiPayment},
|
||||
data () {
|
||||
return {
|
||||
isCollapse: false,
|
||||
activePath: '/home',
|
||||
form: {
|
||||
mallId: this.$store.state.mallId,
|
||||
mallName: this.$store.state.mallName,
|
||||
code: ''
|
||||
},
|
||||
version: '',
|
||||
vipType: ["体验会员","月会员","半年会员","年会员","多店通用年会员"]
|
||||
export default {
|
||||
components: {AiPayment, LablesMember},
|
||||
data() {
|
||||
return {
|
||||
isCollapse: false,
|
||||
activePath: '/home',
|
||||
form: {
|
||||
mallId: this.$store.state.mallId,
|
||||
mallName: this.$store.state.mallName,
|
||||
code: ''
|
||||
},
|
||||
version: '',
|
||||
vipType: ["体验会员", "月会员", "半年会员", "年会员", "多店通用年会员"]
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
freeLogo: () => require("../assets/free.png"),
|
||||
getStateInfo() {
|
||||
if (this.$store.state.userInfo.flag == 0) {
|
||||
return '未激活';
|
||||
} else if (this.$store.state.userInfo.flag == 1) {
|
||||
if (this.$store.state.userInfo.type != 4) {
|
||||
return `(${this.$store.state.userInfo.mallName})` + this.vipType[this.$store.state.userInfo.type] + '(' + this.$store.state.userInfo.expireTime.substring(0, 10) + ')';
|
||||
} else {
|
||||
return this.vipType[this.$store.state.userInfo.type] + '(' + this.$store.state.userInfo.expireTime.substring(0, 10) + ')'
|
||||
}
|
||||
|
||||
} else {
|
||||
return '已过期';
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
getStateInfo() {
|
||||
if (this.$store.state.userInfo.flag == 0) {
|
||||
return '未激活';
|
||||
} else if (this.$store.state.userInfo.flag == 1) {
|
||||
if (this.$store.state.userInfo.type != 4) {
|
||||
return `(${this.$store.state.userInfo.mallName})` + this.vipType[this.$store.state.userInfo.type];
|
||||
} else {
|
||||
return this.vipType[this.$store.state.userInfo.type]
|
||||
}
|
||||
|
||||
} else {
|
||||
return '已过期';
|
||||
}
|
||||
},
|
||||
...mapState(['mallName', 'mallList', 'userInfo']),
|
||||
isAdmin: v => ['18571466720'].includes(v.userInfo.phone),
|
||||
},
|
||||
|
||||
...mapState(['mallName', 'mallList'])
|
||||
},
|
||||
|
||||
watch: {
|
||||
$route (v) {
|
||||
watch: {
|
||||
$route(v) {
|
||||
if (v.meta && v.meta.activeMenu) {
|
||||
this.activePath = v.meta.activeMenu
|
||||
} else {
|
||||
this.activePath = v.fullPath
|
||||
}
|
||||
},
|
||||
|
||||
created () {
|
||||
const devVersion = require('../manifest.development.json').version
|
||||
const prodVersion = require('../manifest.production.json').version
|
||||
this.version = process.env.NODE_ENV === 'production' ? prodVersion : devVersion
|
||||
this.activePath = this.$route.fullPath
|
||||
},
|
||||
|
||||
methods: {
|
||||
...mapMutations(['setActiveDlgShow']),
|
||||
handleClick (e) {
|
||||
if (e === 'logout') {
|
||||
this.$store.dispatch('SignOut', false)
|
||||
} else if (e === 'pwd') {
|
||||
this.$router.push('changePwd')
|
||||
} else if (e === 'message') {
|
||||
this.$router.push('message')
|
||||
} else if (e === 'coin') {
|
||||
this.$router.push('coinFlow')
|
||||
}
|
||||
},
|
||||
handleClose() {
|
||||
this.form.mallId = "";
|
||||
this.form.mallName = "";
|
||||
this.form.code = "";
|
||||
this.setActiveDlgShow(false)
|
||||
},
|
||||
toActive() {
|
||||
this.setActiveDlgShow(true)
|
||||
},
|
||||
getMessage(type) {
|
||||
return `你使用的是“${this.vipType[type]}”兑换券,确定兑换?`;
|
||||
},
|
||||
active() {
|
||||
this.$refs.form.validate((valid) => {
|
||||
if (valid) {
|
||||
this.$http.post(`/api/coupon/getDetail`, null, {
|
||||
params: {
|
||||
code: this.form.code
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
let msg = this.getMessage(res.data.type);
|
||||
this.$confirm(msg, '温馨提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'info'
|
||||
}).then(() => {
|
||||
this.$http.post(`/api/order/upgradeByCode`, null, {
|
||||
params: {
|
||||
...this.form
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success('激活成功')
|
||||
this.$store.dispatch('getUserInfo')
|
||||
this.setActiveDlgShow(false)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
created() {
|
||||
const devVersion = require('../manifest.development.json').version
|
||||
const prodVersion = require('../manifest.production.json').version
|
||||
this.version = process.env.NODE_ENV === 'production' ? prodVersion : devVersion
|
||||
if (this.$route.meta && this.$route.meta.activeMenu) {
|
||||
this.activePath = this.$route.meta.activeMenu
|
||||
} else {
|
||||
this.activePath = this.$route.fullPath
|
||||
}
|
||||
// this.testGoodcang()
|
||||
},
|
||||
|
||||
methods: {
|
||||
...mapMutations(['setActiveDlgShow']),
|
||||
handleClick(e) {
|
||||
if (e === 'logout') {
|
||||
this.$store.dispatch('SignOut', false)
|
||||
} else if (e === 'pwd') {
|
||||
this.$router.push('changePwd')
|
||||
} else if (e === 'message') {
|
||||
this.$router.push('message')
|
||||
} else if (e === 'coin') {
|
||||
this.$router.push('coinFlow')
|
||||
}
|
||||
},
|
||||
|
||||
openMember(index) {
|
||||
this.$refs.LablesMember.show(index)
|
||||
},
|
||||
|
||||
handleClose() {
|
||||
this.form.mallId = "";
|
||||
this.form.mallName = "";
|
||||
this.form.code = "";
|
||||
this.setActiveDlgShow(false)
|
||||
},
|
||||
toActive() {
|
||||
this.setActiveDlgShow(true)
|
||||
},
|
||||
getMessage(type) {
|
||||
return `你使用的是“${this.vipType[type]}”兑换券,确定兑换?`;
|
||||
},
|
||||
active() {
|
||||
this.$refs.form.validate((valid) => {
|
||||
if (valid) {
|
||||
this.$http.post(`/api/coupon/getDetail`, null, {
|
||||
params: {
|
||||
code: this.form.code
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
let msg = this.getMessage(res.data.type);
|
||||
this.$confirm(msg, '温馨提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'info'
|
||||
}).then(() => {
|
||||
this.$http.post(`/api/order/upgradeByCode`, null, {
|
||||
params: {
|
||||
...this.form
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success('激活成功')
|
||||
this.$store.dispatch('getUserInfo')
|
||||
this.setActiveDlgShow(false)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
})
|
||||
},
|
||||
sign() {
|
||||
this.$http.post(`/api/malluser/sign`).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success('签到成功')
|
||||
this.$store.dispatch('getUserInfo')
|
||||
}
|
||||
})
|
||||
},
|
||||
async openFolder() {
|
||||
console.log(22)
|
||||
let fileList = []
|
||||
const res = await window.showDirectoryPicker({})
|
||||
const detalAction = async (obj) => {
|
||||
if (obj.entries) {
|
||||
const dirs = obj.entries()
|
||||
for await (const entry of dirs) {
|
||||
if (entry[1].entries) {
|
||||
detalAction(entry[1])
|
||||
} else {
|
||||
fileList.push({
|
||||
name: entry[0],
|
||||
path: obj.name,
|
||||
fileHandle: entry[1],
|
||||
file: await entry[1].getFile()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
await detalAction(res);
|
||||
console.log("--fileList--", fileList)
|
||||
},
|
||||
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(
|
||||
JSON.stringify({
|
||||
"channelId": "701301",
|
||||
"jsonBody": JSON.stringify({
|
||||
"tab": "online_product",
|
||||
"sort": {},
|
||||
"filter": {
|
||||
"queryCategory": null,
|
||||
"lowerPrice": null,
|
||||
"upperPrice": null,
|
||||
"status": "0",
|
||||
"productId": null,
|
||||
"pagination": {
|
||||
"pageSize": 10,
|
||||
"current": 3
|
||||
}
|
||||
}
|
||||
}),
|
||||
"from": "SELF",
|
||||
"bizParam": "{\"version\":\"simple\"}"
|
||||
})
|
||||
)
|
||||
sendAliexpressAPIMessage({
|
||||
url: url
|
||||
}).then(res => {
|
||||
//console.log(res)
|
||||
})
|
||||
},
|
||||
testGoodcang() {
|
||||
sendGoodcangAPIMessage({
|
||||
url: "/api/v1/product/list",
|
||||
method: 'POST',
|
||||
data: {
|
||||
"page_index": 1,
|
||||
"page_size": 20,
|
||||
"product_status": 1
|
||||
}
|
||||
}).then(res => {
|
||||
console.log(res)
|
||||
})
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
// this.getAliexpressGoodsList()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.admin {
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
.admin {
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
overflow: hidden;
|
||||
background: #f4f4f4;
|
||||
|
||||
.fade-transform-leave-active,
|
||||
.fade-transform-enter-active {
|
||||
transition: all .4s;
|
||||
}
|
||||
|
||||
.fade-transform-enter {
|
||||
opacity: 0;
|
||||
transform: translateX(-20px);
|
||||
}
|
||||
|
||||
.fade-transform-leave-to {
|
||||
opacity: 0;
|
||||
transform: translateX(20px);
|
||||
}
|
||||
|
||||
.admin-main {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: calc(100% - 64px);
|
||||
overflow: hidden;
|
||||
background: #f4f4f4;
|
||||
border-top: 1px solid rgba(0, 0, 0, 0.15);
|
||||
|
||||
.fade-transform-leave-active,
|
||||
.fade-transform-enter-active {
|
||||
transition: all .4s;
|
||||
.container {
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
|
||||
.container-app {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.fade-transform-enter {
|
||||
opacity: 0;
|
||||
transform: translateX(-20px);
|
||||
.left {
|
||||
width: 246px;
|
||||
height: 100%;
|
||||
background: #545c64;
|
||||
|
||||
img {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin-right: 10px;
|
||||
opacity: 0.8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.admin-top {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
height: 64px;
|
||||
padding: 0 24px 0 36px;
|
||||
// box-shadow: 0px 1px 0px 0px rgba(128, 128, 128, 0.1);
|
||||
background: #fff;
|
||||
|
||||
.logo {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
|
||||
span {
|
||||
position: relative;
|
||||
bottom: 12px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 60px;
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
line-height: 25px;
|
||||
color: #1F2635;
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-top: 1px;
|
||||
line-height: 17px;
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
color: #A5A9BC;
|
||||
}
|
||||
}
|
||||
|
||||
.fade-transform-leave-to {
|
||||
opacity: 0;
|
||||
transform: translateX(20px);
|
||||
}
|
||||
|
||||
.admin-main {
|
||||
.admin-middle {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: calc(100% - 64px);
|
||||
overflow: hidden;
|
||||
border-top: 1px solid rgba(0,0,0,0.15);
|
||||
height: 64px;
|
||||
|
||||
.container {
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
span {
|
||||
position: relative;
|
||||
margin-right: 60px;
|
||||
height: 64px;
|
||||
line-height: 64px;
|
||||
font-size: 16px;
|
||||
color: #1F2635;
|
||||
cursor: pointer;
|
||||
transition: all ease 0.5s;
|
||||
|
||||
.container-app {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
&.active::after {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
bottom: 9px;
|
||||
z-index: 1;
|
||||
width: 52px;
|
||||
height: 4px;
|
||||
background: #00A971;
|
||||
transform: translateX(-50%);
|
||||
content: ' ';
|
||||
}
|
||||
|
||||
&.active, &:hover {
|
||||
color: #1FBAD6;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.admin-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
|
||||
.left {
|
||||
width: 246px;
|
||||
height: 100%;
|
||||
background: #545c64;
|
||||
|
||||
img {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin-right: 10px;
|
||||
opacity: 0.8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.admin-top {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
height: 64px;
|
||||
padding: 0 24px 0 36px;
|
||||
// box-shadow: 0px 1px 0px 0px rgba(128, 128, 128, 0.1);
|
||||
background: #fff;
|
||||
|
||||
.logo {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
|
||||
span {
|
||||
position: relative;
|
||||
bottom: 12px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 60px;
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
line-height: 25px;
|
||||
color: #1F2635;
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-top: 1px;
|
||||
line-height: 17px;
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
color: #A5A9BC;
|
||||
}
|
||||
}
|
||||
|
||||
.admin-middle {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 64px;
|
||||
cursor: pointer;
|
||||
transition: all ease 0.3s;
|
||||
|
||||
span {
|
||||
position: relative;
|
||||
margin-right: 60px;
|
||||
height: 64px;
|
||||
line-height: 64px;
|
||||
font-size: 16px;
|
||||
color: #1F2635;
|
||||
cursor: pointer;
|
||||
transition: all ease 0.5s;
|
||||
|
||||
&.active::after {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
bottom: 9px;
|
||||
z-index: 1;
|
||||
width: 52px;
|
||||
height: 4px;
|
||||
background: #00A971;
|
||||
transform: translateX(-50%);
|
||||
content: ' ';
|
||||
}
|
||||
|
||||
&.active, &:hover {
|
||||
color: #1FBAD6;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
&:hover {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
.admin-right {
|
||||
.userinfo {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
height: 56px;
|
||||
margin-left: 20px;
|
||||
cursor: pointer;
|
||||
transition: all ease 0.3s;
|
||||
|
||||
.left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
transition: all ease 0.3s;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.5;
|
||||
}
|
||||
&:hover {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.userinfo {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 56px;
|
||||
margin-left: 20px;
|
||||
cursor: pointer;
|
||||
transition: all ease 0.3s;
|
||||
.avatar {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
span {
|
||||
margin-right: 8px;
|
||||
color: #1F2635;
|
||||
font-size: 14px;
|
||||
}
|
||||
span {
|
||||
margin-right: 8px;
|
||||
color: #1F2635;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#kefu {
|
||||
position: fixed;
|
||||
right: 20px;
|
||||
bottom: 40px;
|
||||
z-index: 999;
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
}
|
||||
|
||||
#kefu .topBtn {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
background-color: #fff;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
background-position: center center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 40px 40px;
|
||||
-webkit-animation: wobble 250ms infinite;
|
||||
animation: wobble 250ms infinite;
|
||||
background-image: url('data:image/svg+xml;%20charset=utf8,%3Csvg%20t%3D%221575450105478%22%20class%3D%22icon%22%20viewBox%3D%220%200%201220%201024%22%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20p-id%3D%222883%22%20width%3D%2248%22%20height%3D%2248%22%3E%3Cpath%20d%3D%22M609.524%20103.522c-222.89%200-403.712%20178.472-403.712%20398.78%200%20220.31%20180.823%20398.782%20403.712%20398.782%20222.889%200%20403.712-178.473%20403.712-398.781%200-220.309-180.823-398.781-403.712-398.781v48.762c196.1%200%20354.95%20156.785%20354.95%20350.019s-158.85%20350.019-354.95%20350.019-354.95-156.785-354.95-350.02c0-193.233%20158.85-350.018%20354.95-350.018v-48.762z%22%20fill%3D%22%231296db%22%20p-id%3D%222884%22%3E%3C%2Fpath%3E%3Cpath%20d%3D%22M786.578%20916.34c166.45-69.217%20278.408-231.055%20278.408-414.035%200-248.026-203.847-449.219-455.457-449.219-251.619%200-455.457%20201.188-455.457%20449.22%200%2055.397%2010.152%20109.367%2029.718%20159.975%204.855%2012.56-1.39%2026.677-13.949%2031.533-12.56%204.855-26.677-1.39-31.532-13.949a490.396%20490.396%200%200%201-3.042-8.078c-1.85%200.077-3.711%200.116-5.581%200.116C58.06%20671.903%200%20614.597%200%20543.903c0-65.005%2049.09-118.69%20112.68-126.91C153.65%20182.56%20360.56%204.324%20609.528%204.324c248.962%200%20455.877%20178.24%20496.85%20412.67%2063.583%208.225%20112.669%2061.907%20112.669%20126.909%200%2070.694-58.06%20128-129.686%20128-1.89%200-3.771-0.04-5.642-0.119-47.536%20129.702-148.34%20235.841-279.493%20290.027-1.161%2033.464-29.012%2060.24-63.2%2060.24-34.925%200-63.237-27.944-63.237-62.416%200-34.471%2028.312-62.415%2063.237-62.415%2017.892%200%2034.048%207.333%2045.551%2019.12z%22%20fill%3D%22%231296db%22%20p-id%3D%222885%22%3E%3C%2Fpath%3E%3Cpath%20d%3D%22M609.528%20611.405c-58.933%200-112.056-10.644-158.472-28.342-16.123-6.147-30.211-12.702-42.138-19.208-6.926-3.777-11.447-6.59-13.437-7.972-19.24-13.373-44.428%205.446-37.059%2027.688%2035.296%20106.527%20136.054%20179.913%20251.106%20179.913%20115.05%200%20215.796-73.384%20251.092-179.913%207.37-22.243-17.82-41.062-37.06-27.687-1.99%201.383-6.51%204.195-13.434%207.972-11.926%206.505-26.012%2013.06-42.133%2019.207-46.413%2017.698-99.533%2028.342-158.465%2028.342z%22%20fill%3D%22%231296db%22%20p-id%3D%222886%22%3E%3C%2Fpath%3E%3C%2Fsvg%3E');
|
||||
}
|
||||
</style>
|
||||
|
||||
158
src/view/Info.vue
Normal file
@@ -0,0 +1,158 @@
|
||||
<template>
|
||||
<ai-list class="Learning" v-loading="isLoading" element-loading-text="拼命加载中" element-loading-spinner="el-icon-loading">
|
||||
<ai-title
|
||||
slot="title"
|
||||
title="弹窗消息"
|
||||
tips="点击“一键已读”之后,需要回到“卖家中心”刷新界面,弹窗即可消失"
|
||||
isShowBottomBorder>
|
||||
<template #rightBtn>
|
||||
<div class="title-right">
|
||||
<div>
|
||||
<el-button type="primary" @click="readAllMsg">一键全部已读</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</ai-title>
|
||||
<template slot="content">
|
||||
<ai-table
|
||||
:tableData="tableData"
|
||||
:col-configs="colConfigs"
|
||||
:isShowPagination="false"
|
||||
style="margin-top: 8px;"
|
||||
@getList="getList">
|
||||
<el-table-column slot="options" label="操作" align="center" fixed="right" width="140px">
|
||||
<template v-slot="{ row }">
|
||||
<div class="table-options">
|
||||
<el-button type="text" @click="edit(row)">处理</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
<AiDialog
|
||||
title="未读消息列表"
|
||||
:visible.sync="isShow"
|
||||
:close-on-click-modal="false"
|
||||
customFooter
|
||||
width="80%">
|
||||
<el-tabs tab-position="left" style="height: 500px;">
|
||||
<el-tab-pane v-for="item in msgList" :label="item.title" :key="item.id"><div v-html="item.content"></div></el-tab-pane>
|
||||
</el-tabs>
|
||||
<div class="dialog-footer" slot="footer">
|
||||
<el-button @click="isShow = false">关闭</el-button>
|
||||
<el-button @click="readAll()" type="primary">一键已读</el-button>
|
||||
</div>
|
||||
</AiDialog>
|
||||
</template>
|
||||
</ai-list>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'vuex'
|
||||
import {sendChromeAPIMessage} from '@/api/chromeApi'
|
||||
import { Message } from 'element-ui'
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
colConfigs: [
|
||||
{ prop: 'mallName', label: '店铺名称', align: 'left' },
|
||||
{ prop: 'unreadNum', label: '未读数量', align: 'left' }
|
||||
],
|
||||
tableData: [],
|
||||
dataList: [],
|
||||
msgList: [],
|
||||
total: 0,
|
||||
isShow: false,
|
||||
id: '',
|
||||
currentMallId: '',
|
||||
isLoading: false
|
||||
}
|
||||
},
|
||||
|
||||
created () {
|
||||
this.getList()
|
||||
},
|
||||
computed: {
|
||||
...mapState(['mallList']),
|
||||
},
|
||||
|
||||
methods: {
|
||||
async getList () {
|
||||
this.isLoading = true
|
||||
for (let i = 0; i < this.mallList.length; i++) {
|
||||
let mallInfo = this.mallList[i]
|
||||
let res = await sendChromeAPIMessage({
|
||||
url: 'bg/quick/api/merchant/msgBox/unreadMsgDetail',
|
||||
needMallId: true,
|
||||
mallId: mallInfo.mallId,
|
||||
data: {}})
|
||||
if (res.success && res.errorCode == 1000000) {
|
||||
this.dataList.push({mallId: mallInfo.mallId, data: res.result.unreadPopMsg})
|
||||
this.tableData.push({mallId: mallInfo.mallId, mallName: mallInfo.mallName, unreadNum: (res.result.unreadPopMsg ? res.result.unreadPopMsg.length: 0)})
|
||||
}
|
||||
}
|
||||
this.isLoading = false
|
||||
},
|
||||
edit(row) {
|
||||
let temp = this.dataList.filter(item => {
|
||||
return item.mallId == row.mallId
|
||||
})
|
||||
this.msgList = temp[0].data
|
||||
this.currentMallId = temp[0].mallId
|
||||
this.isShow = true
|
||||
},
|
||||
async readAllMsg() {
|
||||
for (let i = 0; i < this.dataList.length; i++) {
|
||||
let tempMallId = this.dataList[i].mallId
|
||||
let tempMsgList = this.dataList[i].data
|
||||
|
||||
for (let j = 0; j < tempMsgList.length; j++) {
|
||||
let res = await sendChromeAPIMessage({
|
||||
url: 'bg/quick/api/merchant/msgBox/read',
|
||||
needMallId: true,
|
||||
mallId: tempMallId,
|
||||
data: {msgId: tempMsgList[j].id}})
|
||||
if (!res.success || res.errorCode != 1000000) {
|
||||
Message.error("一个信息标记已读失败")
|
||||
}
|
||||
}
|
||||
let temp = this.tableData.filter(item => {
|
||||
return item.mallId == tempMallId
|
||||
})
|
||||
temp[0].unreadNum = 0
|
||||
}
|
||||
Message.success("消息标记已读完成,刷新卖家中心弹窗即可消失")
|
||||
},
|
||||
async readAll() {
|
||||
if (!this.currentMallId) {
|
||||
Message.error("请选择要标记已读的店铺")
|
||||
return
|
||||
}
|
||||
let count = this.msgList.length
|
||||
for (let i = 0; i < this.msgList.length; i++) {
|
||||
let res = await sendChromeAPIMessage({
|
||||
url: 'bg/quick/api/merchant/msgBox/read',
|
||||
needMallId: true,
|
||||
mallId: this.currentMallId,
|
||||
data: {msgId: this.msgList[i].id}})
|
||||
if (!res.success || res.errorCode != 1000000) {
|
||||
Message.error("一个信息标记已读失败")
|
||||
} else {
|
||||
count--
|
||||
}
|
||||
}
|
||||
for (let j = 0; j < this.tableData.length; j++) {
|
||||
if (this.tableData[j].mallId == this.currentMallId) {
|
||||
this.tableData[j].unreadNum = count
|
||||
break
|
||||
}
|
||||
}
|
||||
Message.success("消息标记已读完成,刷新卖家中心弹窗即可消失")
|
||||
this.isShow = false
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
</style>
|
||||
|
||||
247
src/view/PriceFollow.vue
Normal file
@@ -0,0 +1,247 @@
|
||||
<template>
|
||||
<ai-list class="Learning" v-loading="isLoading" element-loading-text="拼命加载中" element-loading-spinner="el-icon-loading">
|
||||
<ai-title
|
||||
slot="title"
|
||||
title="跟价管理"
|
||||
tips="点击“一键拒绝”之后,需要回到“卖家中心”刷新界面,调价弹窗即可消失"
|
||||
isShowBottomBorder>
|
||||
</ai-title>
|
||||
<template slot="content">
|
||||
<ai-table
|
||||
:tableData="tableData"
|
||||
:col-configs="colConfigs"
|
||||
:isShowPagination="false"
|
||||
style="margin-top: 8px;"
|
||||
@getList="getList">
|
||||
<el-table-column slot="options" label="操作" align="center" fixed="right" width="140px">
|
||||
<template v-slot="{ row }">
|
||||
<div class="table-options">
|
||||
<el-button type="text" @click="edit(row)">处理</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
<AiDialog
|
||||
title="调价列表"
|
||||
:visible.sync="isShow"
|
||||
:close-on-click-modal="false"
|
||||
customFooter
|
||||
width="80%">
|
||||
<ai-table
|
||||
:tableData="priceList"
|
||||
:col-configs="priceColConfigs"
|
||||
:isShowPagination="false"
|
||||
style="margin-top: 8px;">
|
||||
<el-table-column slot="newSupplyPrice" label="调整后价格" align="center">
|
||||
<template v-slot="{ row }">
|
||||
<div style="color: red">{{row.newSupplyPrice }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column slot="price" label="当前价格" align="center">
|
||||
<template v-slot="{ row }">
|
||||
<div style="color: green">{{row.price }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
<div class="dialog-footer" slot="footer">
|
||||
<el-button @click="isShow = false">关闭</el-button>
|
||||
<el-button @click="rejectAll()" type="primary">一键拒绝</el-button>
|
||||
</div>
|
||||
</AiDialog>
|
||||
</template>
|
||||
</ai-list>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'vuex'
|
||||
import {sendChromeAPIMessage} from '@/api/chromeApi'
|
||||
import { Message } from 'element-ui'
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
colConfigs: [
|
||||
{ prop: 'mallName', label: '店铺名称', align: 'left' },
|
||||
{ prop: 'priceTotal', label: '调价数量', align: 'left' }
|
||||
],
|
||||
priceColConfigs: [
|
||||
{ prop: 'productName', label: '商品名称', align: 'left' },
|
||||
{ prop: 'skcId', label: 'SKC', align: 'left' },
|
||||
{ prop: 'spec', label: 'SKU属性集', align: 'left' },
|
||||
{ slot: 'newSupplyPrice', label: '调价后价格', align: 'left' },
|
||||
{ slot: 'price', label: '当前价格', align: 'left' }
|
||||
],
|
||||
tableData: [],
|
||||
dataList: [],
|
||||
priceList: [],
|
||||
total: 0,
|
||||
isShow: false,
|
||||
id: '',
|
||||
currentMallId: '',
|
||||
isLoading: false
|
||||
}
|
||||
},
|
||||
|
||||
created () {
|
||||
this.getList()
|
||||
},
|
||||
computed: {
|
||||
...mapState(['mallList']),
|
||||
},
|
||||
|
||||
methods: {
|
||||
async getList () {
|
||||
this.isLoading = true
|
||||
for (let i = 0; i < this.mallList.length; i++) {
|
||||
let mallInfo = this.mallList[i]
|
||||
let res = await sendChromeAPIMessage({
|
||||
url: 'marvel-mms/cn/api/kiana/gmp/bg/magneto/api/price/priceAdjust/gmpReducePricePopup',
|
||||
needMallId: true,
|
||||
mallId: mallInfo.mallId,
|
||||
data: {}})
|
||||
if (res.success && res.errorCode == 1000000) {
|
||||
let tempData = []
|
||||
res.result.popUpAutoPass12.adjustList.map(item => {
|
||||
let temp = {
|
||||
id: item.id,
|
||||
productName: item.productName,
|
||||
skcId: item.skcId,
|
||||
popUpType: 1,
|
||||
createTime: res.result.createTime,
|
||||
versionId: res.result.popUpAutoPass12.versionId,
|
||||
newSupplyPrice: item.newSupplyPrice / 100,
|
||||
}
|
||||
item.skuInfoItemList.map(item1 => {
|
||||
tempData.push({...temp, price: item1.price / 100, spec: item1.spec})
|
||||
})
|
||||
})
|
||||
res.result.popUpAutoPass24.adjustList.map(item => {
|
||||
let temp = {
|
||||
id: item.id,
|
||||
productName: item.productName,
|
||||
skcId: item.skcId,
|
||||
popUpType: 2,
|
||||
createTime: res.result.createTime,
|
||||
versionId: res.result.popUpAutoPass24.versionId,
|
||||
newSupplyPrice: item.newSupplyPrice / 100,
|
||||
}
|
||||
item.skuInfoItemList.map(item1 => {
|
||||
tempData.push({...temp, price: item1.price / 100, spec: item1.spec})
|
||||
})
|
||||
})
|
||||
res.result.popUpOthers.adjustList.map(item => {
|
||||
let temp = {
|
||||
id: item.id,
|
||||
productName: item.productName,
|
||||
skcId: item.skcId,
|
||||
popUpType: 3,
|
||||
createTime: res.result.createTime,
|
||||
versionId: res.result.popUpOthers.versionId,
|
||||
newSupplyPrice: item.newSupplyPrice / 100,
|
||||
}
|
||||
item.skuInfoItemList.map(item1 => {
|
||||
tempData.push({...temp, price: item1.price / 100, spec: item1.spec})
|
||||
})
|
||||
})
|
||||
this.dataList.push({mallId: mallInfo.mallId, data: tempData})
|
||||
this.tableData.push({mallId: mallInfo.mallId, mallName: mallInfo.mallName, priceTotal: (res.result.popUpAutoPass12.total + res.result.popUpAutoPass24.total + res.result.popUpOthers.total)})
|
||||
}
|
||||
}
|
||||
this.isLoading = false
|
||||
},
|
||||
edit(row) {
|
||||
let temp = this.dataList.filter(item => {
|
||||
return item.mallId == row.mallId
|
||||
})
|
||||
this.priceList = temp[0].data
|
||||
this.currentMallId = temp[0].mallId
|
||||
this.isShow = true
|
||||
},
|
||||
async rejectAll() {
|
||||
let check = await this.$userCheck(this.currentMallId)
|
||||
if (!this.currentMallId) {
|
||||
Message.error("请选择要操作的店铺")
|
||||
return
|
||||
}
|
||||
if (this.priceList.length == 0) {
|
||||
Message.success("该店铺无调价通知,无需处理")
|
||||
return
|
||||
}
|
||||
let popUpType1VersionId = ''
|
||||
let popUpType2VersionId = ''
|
||||
let popUpType3VersionId = ''
|
||||
let createTime = null
|
||||
let ids = []
|
||||
this.priceList.map(item => {
|
||||
if (item.popUpType == 1) {
|
||||
popUpType1VersionId = item.versionId
|
||||
createTime = item.createTime
|
||||
ids.push(item.id)
|
||||
}
|
||||
})
|
||||
let res = null
|
||||
if (ids.length > 0) {
|
||||
res = await sendChromeAPIMessage({
|
||||
url: 'marvel-mms/cn/api/kiana/gmp/bg/magneto/api/price/adjust/price-reduce-popup-click',
|
||||
needMallId: true,
|
||||
mallId: this.currentMallId,
|
||||
data: {
|
||||
"rejectOrderIdList": ids,
|
||||
"maxOrderId": popUpType1VersionId,
|
||||
"popUpType": 1,
|
||||
"createTime": createTime
|
||||
}})
|
||||
}
|
||||
ids = []
|
||||
this.priceList.map(item => {
|
||||
if (item.popUpType == 2) {
|
||||
createTime = item.createTime
|
||||
popUpType2VersionId = item.versionId
|
||||
ids.push(item.id)
|
||||
}
|
||||
})
|
||||
if (ids.length > 0) {
|
||||
res = await sendChromeAPIMessage({
|
||||
url: 'marvel-mms/cn/api/kiana/gmp/bg/magneto/api/price/adjust/price-reduce-popup-click',
|
||||
needMallId: true,
|
||||
mallId: this.currentMallId,
|
||||
data: {
|
||||
"rejectOrderIdList": ids,
|
||||
"maxOrderId": popUpType2VersionId,
|
||||
"popUpType": 2,
|
||||
"createTime": createTime
|
||||
}})
|
||||
}
|
||||
ids = []
|
||||
this.priceList.map(item => {
|
||||
if (item.popUpType == 3) {
|
||||
createTime = item.createTime
|
||||
popUpType3VersionId = item.versionId
|
||||
ids.push(item.id)
|
||||
}
|
||||
})
|
||||
if (ids.length > 0) {
|
||||
res = await sendChromeAPIMessage({
|
||||
url: 'marvel-mms/cn/api/kiana/gmp/bg/magneto/api/price/adjust/price-reduce-popup-click',
|
||||
needMallId: true,
|
||||
mallId: this.currentMallId,
|
||||
data: {
|
||||
"rejectOrderIdList": ids,
|
||||
"maxOrderId": popUpType3VersionId,
|
||||
"popUpType": 3,
|
||||
"createTime": createTime
|
||||
}})
|
||||
}
|
||||
if (res.success && res.errorCode == 1000000) {
|
||||
Message.success("调价通知一键拒绝成功")
|
||||
this.isShow = false
|
||||
} else {
|
||||
Message.error("调价通知一键拒绝失败")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
</style>
|
||||
|
||||
@@ -32,9 +32,12 @@
|
||||
</div>
|
||||
</ai-card>
|
||||
</div>
|
||||
<ai-card title="常用工具" v-if="false">
|
||||
<div class="">
|
||||
dsad
|
||||
<ai-card title="TEMU助手功能概览">
|
||||
<template #right>
|
||||
<a href="https://www.yuque.com/liushiwei-f582m/kb/bmqqls0o5ybd6c8p?singleDoc" style="color: blue; font-size: 18px; text-decoration: underline;" target="_blank">在线帮助手册</a>
|
||||
</template>
|
||||
<div style="height: 1000px">
|
||||
<BiVueMindmap ref="bi-vue-mindmap" :isReadonly="true" :flatNodes="mindmapNodes" />
|
||||
</div>
|
||||
</ai-card>
|
||||
<AiDialog
|
||||
@@ -58,9 +61,13 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import BiVueMindmap from "bi-vue-mindmap";
|
||||
|
||||
export default {
|
||||
name: 'AdminHome',
|
||||
components: {
|
||||
BiVueMindmap,
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
noticeList: [],
|
||||
@@ -70,7 +77,278 @@
|
||||
changeLogList: [],
|
||||
isImportant: false,
|
||||
version: '',
|
||||
isShowDownload: false
|
||||
isShowDownload: false,
|
||||
mindmapNodes: [
|
||||
{
|
||||
id: "01",
|
||||
parentId: null,
|
||||
title: "TEMU助手"
|
||||
},
|
||||
{
|
||||
id: "0101",
|
||||
parentId: "01",
|
||||
title: "TEMU"
|
||||
},
|
||||
{
|
||||
id: "010101",
|
||||
parentId: "0101",
|
||||
title: "辅助运营"
|
||||
},
|
||||
{
|
||||
id: "01010101",
|
||||
parentId: "010101",
|
||||
title: "备货单管理",
|
||||
isFolded: true
|
||||
},
|
||||
{
|
||||
id: "0101010101",
|
||||
parentId: "01010101",
|
||||
title: "创建备货单:批量领取系统下的备货单"
|
||||
},
|
||||
{
|
||||
id: "0101010102",
|
||||
parentId: "01010101",
|
||||
title: "抢仓发货:同时操作多个店铺自动抢仓并创建发货单",
|
||||
resources: [{
|
||||
type: "VIDEO",
|
||||
url: "http://temu.jjcp52.com/dist/qiangcang.mp4"
|
||||
}]
|
||||
},
|
||||
{
|
||||
id: "0101010103",
|
||||
parentId: "01010101",
|
||||
title: "发货台管理:批量从“发货台”创建发货单"
|
||||
},
|
||||
{
|
||||
id: "0101010104",
|
||||
parentId: "01010101",
|
||||
title: "待装箱发货单:对应“备货单管理”->“发货单列表”,“待装箱发货”列表,支持导出"
|
||||
},
|
||||
{
|
||||
id: "0101010105",
|
||||
parentId: "01010101",
|
||||
title: "待收货发货单:对应“备货单管理”->“发货单列表”,“待仓库收货”列表,支持导出"
|
||||
},
|
||||
{
|
||||
id: "0101010106",
|
||||
parentId: "01010101",
|
||||
title: "已收货发货单:对应“备货单管理”->“发货单列表”,“已收货”列表,支持导出"
|
||||
},
|
||||
{
|
||||
id: "0101010107",
|
||||
parentId: "01010101",
|
||||
title: "普通备货单:对应“备货单管理”->“我的备货单”,“普通备货单”列表,支持导出、成本统计"
|
||||
},
|
||||
{
|
||||
id: "0101010108",
|
||||
parentId: "01010101",
|
||||
title: "紧急备货单:对应“备货单管理”->“我的备货单”,“紧急备货单”列表,支持导出、成本统计"
|
||||
},
|
||||
{
|
||||
id: "0101010109",
|
||||
parentId: "01010101",
|
||||
title: "商品条码管理:对应“备货单管理”->“商品条码管理”,支持导出,可用于自定义生成标签,提高贴标效率"
|
||||
},
|
||||
{
|
||||
id: "01010102",
|
||||
parentId: "010101",
|
||||
title: "商品管理",
|
||||
isFolded: true
|
||||
},
|
||||
{
|
||||
id: "0101010201",
|
||||
parentId: "01010102",
|
||||
title: "商品管理:对应“商品管理”->“商品列表”,支持导出,支持半托管"
|
||||
},
|
||||
{
|
||||
id: "0101010202",
|
||||
parentId: "01010102",
|
||||
title: "商品复制:店铺之间快速商品拷贝"
|
||||
},
|
||||
{
|
||||
id: "0101010203",
|
||||
parentId: "01010102",
|
||||
title: "查找买手:根据SKC查询买手名字"
|
||||
},
|
||||
{
|
||||
id: "0101010204",
|
||||
parentId: "01010102",
|
||||
title: "上新生命周期:对应“商品管理”->“上新生命周期管理”,支持导出未发布到站点、已下架的数据"
|
||||
},
|
||||
{
|
||||
id: "01010103",
|
||||
parentId: "010101",
|
||||
title: "库存管理",
|
||||
isFolded: true
|
||||
},
|
||||
{
|
||||
id: "0101010301",
|
||||
parentId: "01010103",
|
||||
title: "退货包裹管理:对应“库存管理”->“退货包裹管理”,支持导出"
|
||||
},
|
||||
{
|
||||
id: "0101010302",
|
||||
parentId: "01010103",
|
||||
title: "退货明细:对应“库存管理”->“退货明细”,支持导出"
|
||||
},
|
||||
{
|
||||
id: "01010104",
|
||||
parentId: "010101",
|
||||
title: "销售管理",
|
||||
isFolded: true
|
||||
},
|
||||
{
|
||||
id: "0101010401",
|
||||
parentId: "01010104",
|
||||
title: "成本管理:维护SKU的成本价格,用于成本、利润的计算和统计"
|
||||
},
|
||||
{
|
||||
id: "0101010402",
|
||||
parentId: "01010104",
|
||||
title: "销售管理:对应“销售管理”->“销售管理”,统计今日销量/销售额、今日利润/利润率、库存/在途库存,支持数据导出"
|
||||
},
|
||||
{
|
||||
id: "0101010403",
|
||||
parentId: "01010104",
|
||||
title: "销售统计:统计过去一段时间内,总体销售额/单量/成本/利润/利润率的统计,以及SKC/SKU维度的销售额/利润/单量的统计,支持导出"
|
||||
},
|
||||
{
|
||||
id: "0101010404",
|
||||
parentId: "01010104",
|
||||
title: "售罄看板:对应“销售管理”->“售罄看板”,支持导出"
|
||||
},
|
||||
{
|
||||
id: "0101010405",
|
||||
parentId: "01010104",
|
||||
title: "售后统计:对应“结算管理”->“售后管理”,计算预计扣款,白卖件数,支持导出"
|
||||
},
|
||||
{
|
||||
id: "0101010406",
|
||||
parentId: "01010104",
|
||||
title: "售后赔付统计:对应“结算管理”->“对账中心”->“扣款详情”,统计过去一段时间内店铺的扣款总金额/次数,支持导出"
|
||||
},
|
||||
{
|
||||
id: "0101010407",
|
||||
parentId: "01010104",
|
||||
title: "物流统计:对应“履约服务账单->明细->缴费记录”,以及“发货单列表->物流计费重核实”,统计一段时期内物流费用,以及货物重量,物流费用分布"
|
||||
},
|
||||
{
|
||||
id: "0101010408",
|
||||
parentId: "01010104",
|
||||
title: "账务明细统计:对应“账户资金->对账中心->账务明细”,真实统计一段时间内的实际收入,以及各种类型的支出,汇总统计"
|
||||
},
|
||||
{
|
||||
id: "01010105",
|
||||
parentId: "010101",
|
||||
title: "其他",
|
||||
isFolded: true
|
||||
},
|
||||
{
|
||||
id: "0101010501",
|
||||
parentId: "01010105",
|
||||
title: "弹窗消息:支持一键已读所有店铺的弹窗消息"
|
||||
},
|
||||
{
|
||||
id: "0101010502",
|
||||
parentId: "01010105",
|
||||
title: "拒绝调价:辅助批量点击“我不接受”按钮,减轻工作量,避免遗漏",
|
||||
resources: [{
|
||||
type: "PIC",
|
||||
url: "http://temu.jjcp52.com/dist/refuse-price.png"
|
||||
}]
|
||||
},
|
||||
{
|
||||
id: "010102",
|
||||
parentId: "0101",
|
||||
title: "选品采集"
|
||||
},
|
||||
{
|
||||
id: "01010201",
|
||||
parentId: "010102",
|
||||
title: "商品采集:根据TEMU前端地址,采集商品信息到店铺草稿箱,减轻上品工作量",
|
||||
resources: [{
|
||||
type: "VIDEO",
|
||||
url: "http://temu.jjcp52.com/dist/xuanpin.mp4"
|
||||
}]
|
||||
},
|
||||
{
|
||||
id: "01010202",
|
||||
parentId: "010102",
|
||||
title: "速卖通采集:根据“速卖通”前端地址,采集商品信息到店铺草稿箱,减轻上品工作量"
|
||||
},
|
||||
{
|
||||
id: "01010203",
|
||||
parentId: "010102",
|
||||
title: "选品跟踪",
|
||||
isFolded: true
|
||||
},
|
||||
{
|
||||
id: "0101020301",
|
||||
parentId: "01010203",
|
||||
title: "店铺跟踪:跟踪指定店铺的销售趋势、价格趋势,采集跟卖。(暂时不可用)"
|
||||
},
|
||||
{
|
||||
id: "0101020302",
|
||||
parentId: "01010203",
|
||||
title: "关键字跟踪:根据筛选关键字,跟踪该关键字在TEMU前端搜索结果的销售趋势、价格趋势,采集跟卖"
|
||||
},
|
||||
{
|
||||
id: "0101020303",
|
||||
parentId: "01010203",
|
||||
title: "新品跟踪:跟踪TEMU前端“Best Sellers”->“Within last 7 days”的新品,采集跟卖"
|
||||
},
|
||||
{
|
||||
id: "0101020304",
|
||||
parentId: "01010203",
|
||||
title: "单品跟踪:根据TEMU前端地址,采集销售趋势、价格趋势"
|
||||
},
|
||||
{
|
||||
id: "0102",
|
||||
parentId: "01",
|
||||
title: "SHEIN(希音)"
|
||||
},
|
||||
{
|
||||
id: "010201",
|
||||
parentId: "0102",
|
||||
title: "辅助运营",
|
||||
isFolded: true
|
||||
},
|
||||
{
|
||||
id: "01020101",
|
||||
parentId: "010201",
|
||||
title: "成本管理:维护SKU的成本价格,用于成本、利润的计算和统计"
|
||||
},
|
||||
{
|
||||
id: "01020102",
|
||||
parentId: "010201",
|
||||
title: "销售管理:对应SHEIN商家后台“商品管理”->“备货信息(新)”,统计当天的销售额、销量、库存等信息,计算成本和利润"
|
||||
},
|
||||
{
|
||||
id: "01020103",
|
||||
parentId: "010201",
|
||||
title: "证书中心:对应SHEIN商家后台“商品管理”->“证书中心”,导出已驳回和待补充的证书列表,线下跟踪"
|
||||
},
|
||||
{
|
||||
id: "01020104",
|
||||
parentId: "010201",
|
||||
title: "商品复制:希音店铺间商品进行快速复制,节省上品时间"
|
||||
},
|
||||
{
|
||||
id: "01020105",
|
||||
parentId: "010201",
|
||||
title: "发货订单:对应SHEIN商家后台“订单管理”->“发货订单”,提供急采/备货订单的导出,同时带上成本价格,方便对账与结算"
|
||||
},
|
||||
{
|
||||
id: "01020106",
|
||||
parentId: "010201",
|
||||
title: "退货与报废单列表:对应SHEIN商家后台“质量管理”->“退货与报废单列表”,提供退货订单明细的导出,同时带上成本价格,方便对账与结算"
|
||||
},
|
||||
{
|
||||
id: "01020107",
|
||||
parentId: "010201",
|
||||
title: "商家账单统计:对应SHEIN商家后台“财务管理”->“商家账单”,统计一段时期内销售额、单量、成本、利润、利润率,SKC/SKU维度统计排名,支持导出"
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
|
||||
@@ -82,6 +360,7 @@
|
||||
this.getNoticeList()
|
||||
this.getChangelog()
|
||||
this.getMyNewestNotice()
|
||||
this.checkBindWx()
|
||||
},
|
||||
|
||||
methods: {
|
||||
@@ -112,7 +391,21 @@
|
||||
link.click()
|
||||
document.body.removeChild(link)
|
||||
},
|
||||
|
||||
checkBindWx() {
|
||||
this.$http.post(`/api/malluser/bindWxCount`).then(res => {
|
||||
if (res.code == 0) {
|
||||
if (res.data == 0) {
|
||||
this.$confirm('您尚未绑定微信消息推送,将不会收到消息通知,影响体验, 请前往绑定?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
this.$router.push('message')
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
read () {
|
||||
if (this.isImportant) {
|
||||
this.$http.post('/api/notice/read').then(res => {
|
||||
|
||||
361
src/view/data/SyncDataTemu.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="数据同步(TEMU)"
|
||||
isShowBottomBorder>
|
||||
</ai-title>
|
||||
|
||||
<template slot="content">
|
||||
<el-card class="box-card">
|
||||
<div slot="header" class="clearfix">
|
||||
<span>店铺列表</span>
|
||||
</div>
|
||||
<div>
|
||||
<el-checkbox :indeterminate="isMallIndeterminate" v-model="checkAllMall" @change="handleCheckAllMallChange">全选</el-checkbox>
|
||||
<div style="margin: 15px 0;"></div>
|
||||
<el-checkbox-group v-model="checkMallList" @change="handleCheckedMallChange">
|
||||
<el-checkbox v-for="mall in $store.state.mallList" style="width: 300px; margin-right: 0px" :label="mall.mallId" :key="mall.mallId">{{mall.isSemiManagedMall ? mall.mallName + '(半托管)': mall.mallName}}</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
</div>
|
||||
</el-card>
|
||||
<el-card class="box-card" style="margin-top: 5px;">
|
||||
<div slot="header" class="clearfix">
|
||||
<span>同步操作</span>
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
<label style="width:90px">时间范围:</label>
|
||||
<el-date-picker
|
||||
v-model="dateRange"
|
||||
type="daterange"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
format="yyyy-MM-dd"
|
||||
value-format="yyyy-MM-dd"
|
||||
:picker-options="pickerOptions">
|
||||
</el-date-picker>
|
||||
</div>
|
||||
<br>
|
||||
<el-checkbox :indeterminate="isOptionIndeterminate" v-model="checkAllOptions" @change="handleCheckAllOptionChange">全选</el-checkbox>
|
||||
<div style="margin: 15px 0;"></div>
|
||||
<el-checkbox-group v-model="checkOptionList" @change="handleCheckedOptionChange">
|
||||
<el-checkbox v-for="option in options" style="width: 300px; margin-right: 0px" :label="option.value" :key="option.value">{{option.label}}</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
</div>
|
||||
</el-card>
|
||||
<div style="display: grid; grid-template-columns: 1fr; gap: 16px; margin-top: 10px;">
|
||||
<el-button type="button" :class="'el-button el-button--primary'" @click="sync()">同步</el-button>
|
||||
<!--<el-button type="button" :class="'el-button el-button--primary'" @click="toSyncWaitDeliveryOrder()">同步“待仓库收货”发货单</el-button>
|
||||
<el-button type="button" :class="'el-button el-button--primary'" @click="toSyncDeliveryOrder()">同步历史发货单</el-button>
|
||||
<el-button type="button" :class="'el-button el-button--primary'" @click="toBeginCollectResource()">采集资源位</el-button>-->
|
||||
</div>
|
||||
<el-card class="box-card" style="margin-top: 5px;">
|
||||
<div slot="header" class="clearfix">
|
||||
<span>日志输出</span>
|
||||
</div>
|
||||
<div id="log-container" v-html="logsContent" style="height: 500px; background-color: black; overflow-y: scroll; border: 1px solid #000; padding: 5px; color: white"></div>
|
||||
</el-card>
|
||||
</template>
|
||||
</ai-list>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Message } from 'element-ui'
|
||||
import {sendChromeAPIMessage} from '@/api/chromeApi'
|
||||
import {timestampToTime} from '@/utils/date'
|
||||
|
||||
export default {
|
||||
name: 'SyncDataTemu',
|
||||
|
||||
data () {
|
||||
return {
|
||||
isLoading: false,
|
||||
categoryList: [],
|
||||
checkAllMall: false,
|
||||
checkAllOptions: false,
|
||||
checkMallList: [],
|
||||
checkOptionList: [],
|
||||
isMallIndeterminate: false,
|
||||
isOptionIndeterminate: false,
|
||||
mallList: [],
|
||||
currentIndex: 0,
|
||||
pageSize: 100,
|
||||
pageNo: 1,
|
||||
syncProductData: [],
|
||||
deliveryOrderList: [],
|
||||
|
||||
currentWaitDeliveryIndex: 0,
|
||||
waitDeliveryData: [],
|
||||
|
||||
options: [
|
||||
{label: '同步已上架商品列表', value: 0},
|
||||
{label: '同步今日待收货发货单', value: 1},
|
||||
{label: '同步今日销售数据', value: 2},
|
||||
{label: '同步SKU历史销售数据', value: 3}
|
||||
],
|
||||
|
||||
dateRange: [new Date(), new Date()],
|
||||
pickerOptions: {
|
||||
disabledDate(time) {
|
||||
return time.getTime() > Date.now()
|
||||
}
|
||||
},
|
||||
|
||||
logsList: [],
|
||||
|
||||
reqListData: []
|
||||
}
|
||||
},
|
||||
created() {
|
||||
},
|
||||
computed: {
|
||||
logsContent() {
|
||||
return this.logsList.join('<br>')
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleCheckAllMallChange(val) {
|
||||
if (val) {
|
||||
this.checkMallList = this.mallList.map(item => {
|
||||
return item.mallId
|
||||
})
|
||||
} else {
|
||||
this.checkMallList = []
|
||||
}
|
||||
this.isMallIndeterminate = false;
|
||||
},
|
||||
handleCheckedMallChange(value) {
|
||||
let checkedCount = value.length;
|
||||
this.checkAllMall = checkedCount === this.mallList.length;
|
||||
this.isMallIndeterminate = checkedCount > 0 && checkedCount < this.mallList.length;
|
||||
},
|
||||
handleCheckAllOptionChange(val) {
|
||||
if (val) {
|
||||
this.checkOptionList = this.options.map(item => {
|
||||
return item.value
|
||||
})
|
||||
} else {
|
||||
this.checkOptionList = []
|
||||
}
|
||||
this.isOptionIndeterminate = false;
|
||||
},
|
||||
handleCheckedOptionChange(value) {
|
||||
let checkedCount = value.length;
|
||||
this.checkAllOptions = checkedCount === this.options.length;
|
||||
this.isOptionIndeterminate = checkedCount > 0 && checkedCount < this.options.length;
|
||||
},
|
||||
async sync() {
|
||||
if (this.checkMallList.length == 0) {
|
||||
Message.error("请选择要同步的店铺")
|
||||
return
|
||||
}
|
||||
if (this.checkOptionList.length == 0) {
|
||||
Message.error("请选择要同步的操作")
|
||||
return
|
||||
}
|
||||
this.isLoading = true
|
||||
for (let i = 0; i < this.checkOptionList.length; i++) {
|
||||
this.pageNo = 1
|
||||
if (this.checkOptionList[i] == 0) { // 同步商品
|
||||
for (let j = 0; j < this.checkMallList.length; j++) {
|
||||
let mallInfo = this.$store.state.mallList.filter(item => {
|
||||
return item.mallId == this.checkMallList[j]
|
||||
})
|
||||
let mallName = mallInfo[0].mallName
|
||||
this.syncProductData = []
|
||||
await this.syncProduct(this.checkMallList[j], mallName)
|
||||
}
|
||||
}
|
||||
if (this.checkOptionList[i] == 1) { // 同步待发货发货单
|
||||
for (let j = 0; j < this.checkMallList.length; j++) {
|
||||
let mallInfo = this.$store.state.mallList.filter(item => {
|
||||
return item.mallId == this.checkMallList[j]
|
||||
})
|
||||
let mallName = mallInfo[0].mallName
|
||||
this.deliveryOrderList = []
|
||||
await this.syncDeliveryOrder(this.checkMallList[i], mallName)
|
||||
}
|
||||
}
|
||||
if (this.checkOptionList[i] == 2) { // 同步今日销售数据
|
||||
for (let j = 0; j < this.checkMallList.length; j++) {
|
||||
this.reqListData = []
|
||||
await this.syncTodaySaleData(this.checkMallList[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
this.isLoading = false
|
||||
},
|
||||
async syncProduct(mallId, mallName) {
|
||||
let res = await sendChromeAPIMessage({url: 'bg-visage-mms/product/skc/pageQuery',
|
||||
anti:true,
|
||||
needMallId: true,
|
||||
mallId: mallId,
|
||||
data: {
|
||||
pageSize: this.pageSize,
|
||||
page: this.pageNo,
|
||||
skcSiteStatus: 1
|
||||
}
|
||||
})
|
||||
if (res.errorCode == 1000000) {
|
||||
res.result.pageItems.map(item => {
|
||||
let temp = {
|
||||
mallId: mallId,
|
||||
mallName: mallName,
|
||||
productName: item.productName,
|
||||
spu: item.productId,
|
||||
skc: item.productSkcId,
|
||||
skcCode: item.extCode,
|
||||
createTime: timestampToTime(item.createdAt)
|
||||
}
|
||||
|
||||
item.productSkuSummaries.map(item1 => {
|
||||
let temp1 = {
|
||||
...temp,
|
||||
skuCode: item1.extCode,
|
||||
sku: item1.productSkuId,
|
||||
mainPic: item1.thumbUrl,
|
||||
price: item1.supplierPrice /100
|
||||
}
|
||||
let specArr = item1.productSkuSpecList.map(item2 => {
|
||||
return item2.specName
|
||||
})
|
||||
temp1.skuSpec = specArr.join(',')
|
||||
|
||||
this.syncProductData.push(temp1)
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
if (res.result.pageItems.length == this.pageSize) {
|
||||
this.pageNo ++
|
||||
await this.syncProduct(mallId, mallName)
|
||||
} else {
|
||||
this.$http.post('/api/stock/product/addBatch', this.syncProductData
|
||||
).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.logs(mallName, '已上架商品', true)
|
||||
} else {
|
||||
this.logs(mallName, '已上架商品', false)
|
||||
}
|
||||
})
|
||||
}
|
||||
} else {
|
||||
this.logs(mallName, '已上架商品', false)
|
||||
}
|
||||
},
|
||||
async syncDeliveryOrder(mallId, mallName) {
|
||||
let now = new Date()
|
||||
now.setHours(0, 0, 0, 0)
|
||||
let start = now.getTime()
|
||||
let end = start + 86400*1000 - 1000
|
||||
|
||||
let res = await sendChromeAPIMessage({url: 'bgSongbird-api/supplier/deliverGoods/management/pageQueryDeliveryBatch',
|
||||
anti:true,
|
||||
needMallId: true,
|
||||
mallId: mallId,
|
||||
data: {
|
||||
pageNo: this.pageNo,
|
||||
pageSize: this.pageSize,
|
||||
productLabelCodeStyle: 0,
|
||||
onlyTaxWarehouseWaitApply: false,
|
||||
deliverTimeFrom: start,
|
||||
deliverTimeTo: end,
|
||||
status: 1
|
||||
}
|
||||
})
|
||||
if (res.errorCode == 1000000) {
|
||||
res.result.list.map(item => {
|
||||
let temp = {
|
||||
mallId: mallId,
|
||||
mallName: mallName,
|
||||
subWarehouseName: item.subWarehouseName,
|
||||
expressCompany: item.expressCompany,
|
||||
deliveryOrderSn: item.deliveryOrderSn
|
||||
}
|
||||
|
||||
item.deliveryOrderList.map(item1 => {
|
||||
temp = {
|
||||
...temp,
|
||||
productName: item1.subPurchaseOrderBasicVO.productName,
|
||||
skc: item1.productSkcId,
|
||||
skcCode: item1.skcExtCode,
|
||||
isFirst: item1.subPurchaseOrderBasicVO.isFirst ? 1: 0,
|
||||
subPurchaseOrderSn: item1.subPurchaseOrderSn,
|
||||
createTime: timestampToTime(item1.deliverTime)
|
||||
}
|
||||
|
||||
item1.packageDetailList.map(item2 => {
|
||||
temp = {
|
||||
...temp,
|
||||
sku: item2.productSkuId,
|
||||
num: item2.skuNum
|
||||
}
|
||||
})
|
||||
this.deliveryOrderList.push(temp)
|
||||
})
|
||||
})
|
||||
|
||||
if (res.result.list.length == this.pageSize) {
|
||||
this.pageNo ++
|
||||
await this.syncDeliveryOrder(mallId, mallName)
|
||||
} else {
|
||||
this.$http.post('/api/stock/orderInfo/addBatch', this.deliveryOrderList
|
||||
).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.logs(mallName, '今日待收货发货单', true)
|
||||
} else {
|
||||
this.logs(mallName, '今日待收货发货单', false)
|
||||
}
|
||||
})
|
||||
}
|
||||
} else {
|
||||
this.logs(mallName, '今日待收货发货单', false)
|
||||
}
|
||||
},
|
||||
async syncTodaySaleData(mallId) {
|
||||
let res = await sendChromeAPIMessage({
|
||||
url: 'marvel-mms/cn/api/kiana/venom/sales/management/list',
|
||||
needMallId: true,
|
||||
mallId: mallId,
|
||||
data: {
|
||||
pageNo: this.pageNo,
|
||||
pageSize: this.pageSize,
|
||||
isLack: 0,
|
||||
priceAdjustRecentDays: 7
|
||||
}})
|
||||
if (res.errorCode == 1000000) {
|
||||
for(let i = 0;i < res.result.subOrderList.length; i++) {
|
||||
let item = res.result.subOrderList[i]
|
||||
for(let j = 0;j < item.skuQuantityDetailList.length; j++) {
|
||||
this.reqListData.push({
|
||||
mallId: mallId,
|
||||
sku: item.skuQuantityDetailList[j].productSkuId,
|
||||
saleNum: item.skuQuantityDetailList[j].todaySaleVolume,
|
||||
salePrice: item.skuQuantityDetailList[j].supplierPrice / 100
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if (this.pageSize == res.result.subOrderList.length) {
|
||||
this.pageNo ++
|
||||
await this.syncTodaySaleData(mallId)
|
||||
} else {
|
||||
await this.$http.post('http://192.168.1.199:8080/jeecg-boot/eshop/saleManage/addBatch', this.reqListData)
|
||||
}
|
||||
}
|
||||
},
|
||||
logs(mallName, subject, flag) {
|
||||
if (flag) {
|
||||
this.logsList.unshift(`【${mallName}】${subject}<b style='color: green'>同步成功</b>`)
|
||||
} else {
|
||||
this.logsList.unshift(`【${mallName}】${subject}<b style='color: red'>同步失败</b>`)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
</style>
|
||||
181
src/view/lables/AddTemplate.vue
Normal file
@@ -0,0 +1,181 @@
|
||||
<template>
|
||||
<AiDetail class="add-label">
|
||||
<template #title>
|
||||
<ai-title title="添加模板" isShowBack :isShowBottomBorder="true" @onBackClick="cancel">
|
||||
<template #center>
|
||||
<label>模板名称:</label>
|
||||
<el-input placeholder="请输入模板名称" size="small" v-model="name" style="width: 200px;"></el-input>
|
||||
</template>
|
||||
<template #rightBtn>
|
||||
<el-button @click="preview" size="small" type="danger">预览</el-button>
|
||||
<!-- <el-button @click="savePdf" size="small" type="primary">下载pdf</el-button> -->
|
||||
<el-button @click="print" size="small">打印</el-button>
|
||||
<el-button @click="clearPaper" size="small" type="danger">清空纸张</el-button>
|
||||
<el-button @click="saveTemplate" size="small" type="primary" :loading="isLoading">保存</el-button>
|
||||
</template>
|
||||
</ai-title>
|
||||
</template>
|
||||
<template #content>
|
||||
<ai-card title="标签模板" class="card" :hideTitle="true" v-loading="isLoading">
|
||||
<template #content>
|
||||
<div class="add-label__wrapper">
|
||||
<Print
|
||||
ref="printRef"
|
||||
:template="template"
|
||||
:printData="printData"
|
||||
:isPrint="false"
|
||||
:params="params">
|
||||
</Print>
|
||||
</div>
|
||||
</template>
|
||||
</ai-card>
|
||||
</template>
|
||||
</AiDetail>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Print from '@/components/print/Print'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Print
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
name: '',
|
||||
template: {
|
||||
"panels": [{
|
||||
"index": 0,
|
||||
"name": 1,
|
||||
"height": 200,
|
||||
"width": 200,
|
||||
"paperHeader": 0,
|
||||
"paperFooter": 547,
|
||||
"printElements": [],
|
||||
"paperNumberLeft": 500,
|
||||
"paperNumberTop": 530,
|
||||
"paperNumberDisabled": true,
|
||||
"paperNumberContinue": true,
|
||||
"fontFamily": "Microsoft YaHei",
|
||||
"scale": 1,
|
||||
"watermarkOptions": {}
|
||||
}]
|
||||
},
|
||||
printData: {},
|
||||
id: '',
|
||||
info: {},
|
||||
params: [],
|
||||
isLoading: false
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.printData = {
|
||||
labelCode: 123456789,
|
||||
productSkuId: `XXXXXXXXXXXXXX`,
|
||||
skuExtCode: 'XXXXXXXXXXXXXX',
|
||||
skuSpecName: 'XXXXX'
|
||||
}
|
||||
|
||||
if (this.$route.query.id) {
|
||||
this.id = this.$route.query.id
|
||||
|
||||
this.getInfo()
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
cancel() {
|
||||
this.$router.go(-1)
|
||||
},
|
||||
|
||||
getInfo() {
|
||||
this.isLoading = true
|
||||
this.$http.post(`/api/template/detail?id=${this.$route.query.id}`).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.info = res.data
|
||||
this.name = res.data.name
|
||||
this.params = JSON.parse(res.data.params)
|
||||
|
||||
this.$nextTick(() => {
|
||||
this.template = JSON.parse(res.data.content)
|
||||
})
|
||||
}
|
||||
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
preview () {
|
||||
this.$refs.printRef.preview()
|
||||
},
|
||||
|
||||
savePdf () {
|
||||
this.$refs.printRef.savePdf()
|
||||
},
|
||||
|
||||
rotatePaper () {
|
||||
this.$refs.printRef.rotatePaper()
|
||||
},
|
||||
|
||||
saveTemplate () {
|
||||
if (!this.name) {
|
||||
return this.$message.error('模板名称不能为空')
|
||||
}
|
||||
|
||||
const data = this.$refs.printRef.save()
|
||||
this.isLoading = true
|
||||
|
||||
const url = this.id ? `/api/template/modify` : `/api/template/addTemplate`
|
||||
this.$http.post(url, {
|
||||
name: this.name,
|
||||
codes: data.html,
|
||||
content: JSON.stringify(data.json),
|
||||
params: data.params,
|
||||
id: this.id || ''
|
||||
}).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.isLoading = false
|
||||
this.$message.success('模板创建成功')
|
||||
this.cancel()
|
||||
} else {
|
||||
this.isLoading = false
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
print() {
|
||||
this.$refs.printRef.print()
|
||||
},
|
||||
|
||||
clearPaper () {
|
||||
this.$refs.printRef.clearPaper()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.add-label {
|
||||
::v-deep(.ai-detail__content--wrapper) {
|
||||
max-width: 100%;
|
||||
height: 100%;
|
||||
margin: 0 20px;
|
||||
}
|
||||
|
||||
.card {
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
|
||||
::v-deep(.ai-card__body) {
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.add-label__wrapper {
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
343
src/view/lables/Print.vue
Normal file
@@ -0,0 +1,343 @@
|
||||
<template>
|
||||
<ai-list class="Print-page">
|
||||
<ai-title
|
||||
slot="title"
|
||||
title="标签打印"
|
||||
isShowBottomBorder>
|
||||
</ai-title>
|
||||
<template slot="content">
|
||||
<div class="search-item__wrapper">
|
||||
<div class="left">
|
||||
<div class="search-item">
|
||||
<el-radio-group v-model="addType" @click="lableList = [], search.productSkuId = '', search.productSkcId = ''">
|
||||
<el-radio-button label="1">按发货单打印</el-radio-button>
|
||||
<el-radio-button label="2">按SKC打印</el-radio-button>
|
||||
<el-radio-button label="3">按SKU打印</el-radio-button>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
</div>
|
||||
<div class="right"></div>
|
||||
</div>
|
||||
<div class="search-item__wrapper">
|
||||
<div class="left">
|
||||
<div class="search-item" v-show="addType === '1'">
|
||||
<label>发货单:</label>
|
||||
<el-select v-model="search.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>
|
||||
<el-button style="margin-left: 10px;" size="small" :disabled="!search.mallId" :loading="isLoading" @click="searchSkuList">查询</el-button>
|
||||
</div>
|
||||
<div class="search-item" v-show="addType === '2' || addType === '3'">
|
||||
<label>{{ addType === '2' ? 'SKC:' : 'SKU:' }}</label>
|
||||
<el-input
|
||||
v-if="addType === '3'"
|
||||
v-model="search.productSkuId"
|
||||
style="width: 250px"
|
||||
size="small"
|
||||
clearable
|
||||
placeholder="多个查询请用户逗号分割"
|
||||
suffix-icon="iconfont iconSearch">
|
||||
</el-input>
|
||||
<el-input
|
||||
v-else
|
||||
v-model="search.productSkcId"
|
||||
style="width: 250px"
|
||||
size="small"
|
||||
placeholder="多个查询请用户逗号分割"
|
||||
clearable
|
||||
suffix-icon="iconfont iconSearch">
|
||||
</el-input>
|
||||
<el-button style="margin-left: 10px;" @click="getList" size="small" :loading="isLoading">查询</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<ai-table
|
||||
:tableData="lableList"
|
||||
:col-configs="colConfigs"
|
||||
:isShowPagination="false"
|
||||
:height="height"
|
||||
@getList="() => {}"
|
||||
:loading="isLoading">
|
||||
<el-table-column slot="options" label="操作" align="center" fixed="right" width="120px">
|
||||
<template v-slot="{ row }">
|
||||
<div class="table-options">
|
||||
<el-button type="text" @click="toPrint(row)">打印</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
<Print ref="printRef" :isPrint="true"></Print>
|
||||
<ai-dialog
|
||||
:visible.sync="isShow"
|
||||
title="打印数量"
|
||||
width="890px"
|
||||
@confirm="onConfirm">
|
||||
<el-form class="ai-form" :model="form" ref="form" label-width="100px">
|
||||
<el-form-item label="打印数量" style="width: 100%;" prop="count" :rules="[{ required: true, message: '请输入打印数量', trigger: 'change' }]">
|
||||
<el-input-number v-model="form.count" :min="1" :max="500" label="请输入打印数量"></el-input-number>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</ai-dialog>
|
||||
</template>
|
||||
</ai-list>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Print from '@/components/print/Print'
|
||||
import template from '@/components/print/template'
|
||||
import { sendChromeAPIMessage } from '@/api/chromeApi'
|
||||
|
||||
export default {
|
||||
name: 'PrintPage',
|
||||
|
||||
components: {
|
||||
Print
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
colConfigs: [
|
||||
{ prop: 'mallName', label: '店铺名称', align: 'left' },
|
||||
{ prop: 'labelCode', label: '条码编码', align: 'center' },
|
||||
{ prop: 'productSkcId', label: 'SKC', align: 'center' },
|
||||
{ prop: 'productSkuId', label: 'SKU', align: 'center' },
|
||||
{ prop: 'skuExtCode', label: 'SKU货号', align: 'center' },
|
||||
{ prop: 'skuSpecName', label: '次销售属性', align: 'center' },
|
||||
{ prop: 'deliveryNum', label: '发货数', align: 'center' }
|
||||
],
|
||||
search: {
|
||||
mallId: '',
|
||||
productSkuId: '',
|
||||
productSkcId: '',
|
||||
page: 1,
|
||||
size: -1,
|
||||
templateId: ''
|
||||
},
|
||||
addType: '1',
|
||||
isLoading: false,
|
||||
lableList: [],
|
||||
height: 600,
|
||||
skuChoosedList: [],
|
||||
isShow: false,
|
||||
form: {
|
||||
count: 1
|
||||
},
|
||||
printData: [],
|
||||
templateList: [],
|
||||
page: 1
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
currMall () {
|
||||
if (!this.$store.state.mallList.length) {
|
||||
return {}
|
||||
}
|
||||
|
||||
return this.$store.state.mallList.filter(v => v.mallId === this.search.mallId)[0]
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.$nextTick(() => {
|
||||
this.height = document.querySelector('.ai-list__content--right').clientHeight - 140
|
||||
})
|
||||
},
|
||||
|
||||
methods: {
|
||||
toPrint(row) {
|
||||
this.isLoading = true
|
||||
if (this.addType === '1') {
|
||||
this.$http.post(`/api/template/myTemplate?productSkuId=${row.productSkuId}`).then(res => {
|
||||
if (!res.data.records.length) {
|
||||
this.isLoading = false
|
||||
return this.$message.error('该SKU未配置模板')
|
||||
}
|
||||
|
||||
this.$http.post(`/api/template/detail?id=${res.data.records[0].id}`).then(res => {
|
||||
if (res.code === 0) {
|
||||
const params = JSON.parse(res.data.params)
|
||||
const getValue = v => params.filter(e => e.fieldValue === v)[0].fieldName
|
||||
Object.keys(row).forEach(key => {
|
||||
if (params.findIndex(v => v.fieldValue === key) > -1) {
|
||||
row[getValue(key)] = row[key]
|
||||
}
|
||||
})
|
||||
|
||||
this.isLoading = false
|
||||
this.$refs.printRef.toPrint(JSON.parse(res.data.content), new Array(row.deliveryNum).fill(row))
|
||||
} else {
|
||||
this.isLoading = false
|
||||
}
|
||||
})
|
||||
})
|
||||
} else {
|
||||
this.$http.post(`/api/template/detail?id=${row.templateId}`).then(res => {
|
||||
this.isLoading = false
|
||||
if (res.code === 0) {
|
||||
if (!res.data) {
|
||||
this.isLoading = false
|
||||
return this.$message.error('该SKU未配置模板')
|
||||
}
|
||||
const params = JSON.parse(res.data.params)
|
||||
const getValue = v => params.filter(e => e.fieldValue === v)[0].fieldName
|
||||
Object.keys(row).forEach(key => {
|
||||
if (params.findIndex(v => v.fieldValue === key) > -1) {
|
||||
row[getValue(key)] = row[key]
|
||||
}
|
||||
})
|
||||
|
||||
this.printData = {
|
||||
template: JSON.parse(res.data.content),
|
||||
data: row
|
||||
}
|
||||
this.isShow = true
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
onConfirm () {
|
||||
this.$refs.form.validate((valid) => {
|
||||
if (valid) {
|
||||
this.isShow = false
|
||||
this.$refs.printRef.toPrint(this.printData.template, new Array(this.form.count).fill(this.printData.data))
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
printAll() {
|
||||
this.$refs.printRef.toPrint(template, this.skuChoosedList)
|
||||
},
|
||||
|
||||
getSkuList () {
|
||||
if (!this.search.mallId) {
|
||||
return this.$message.error('请选择店铺')
|
||||
}
|
||||
},
|
||||
|
||||
getList () {
|
||||
this.$http.post('/api/templateSku/getMySkuPage', null, {
|
||||
params: this.search
|
||||
}).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.lableList = res.data.records
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
getDeliveryOrderSn (page) {
|
||||
return new Promise(resolve => {
|
||||
sendChromeAPIMessage({
|
||||
url: 'bgSongbird-api/supplier/deliverGoods/management/pageQueryDeliveryBatch',
|
||||
needMallId: true,
|
||||
mallId: this.search.mallId,
|
||||
anti: true,
|
||||
data: {
|
||||
pageNo: page,
|
||||
status: 1,
|
||||
onlyTaxWarehouseWaitApply: false,
|
||||
productLabelCodeStyle: 0,
|
||||
pageSize: 200
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.errorCode == 1000000) {
|
||||
resolve({
|
||||
list: [].concat(res.result.list.map(v => v.deliveryOrderList.map(e => e.deliveryOrderSn)).flat()),
|
||||
isHasNext: res.result.total && res.result.list.length && (res.result.list.length < 200 && res.result.total > 200)
|
||||
})
|
||||
} else {
|
||||
resolve({ list: [], isHasNext: false })
|
||||
}
|
||||
}).catch(() => {
|
||||
resolve({ list: [], isHasNext: false })
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
getLabels (deliveryOrderSnList) {
|
||||
return new Promise(resolve => {
|
||||
sendChromeAPIMessage({
|
||||
url: 'bgSongbird-api/supplier/deliverGoods/management/printProductSkuLabel',
|
||||
needMallId: true,
|
||||
mallId: this.search.mallId,
|
||||
anti: true,
|
||||
data: {
|
||||
deliveryOrderSnList: deliveryOrderSnList
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.errorCode == 1000000) {
|
||||
resolve(res.result.map(v => {
|
||||
return {
|
||||
mallName: this.$store.state.mallList.filter(v => v.mallId === this.search.mallId)[0].mallName,
|
||||
productName: v.productName,
|
||||
productSkcId: v.productSkcId,
|
||||
productSkuId: v.productSkuId,
|
||||
labelCode: v.labelCode,
|
||||
skuExtCode: v.skuExtCode,
|
||||
deliveryNum: v.deliveryNum,
|
||||
skuSpecName: v.secondarySpecVOList.map(item => {
|
||||
return item.specName
|
||||
}).join(',')
|
||||
}
|
||||
}))
|
||||
} else {
|
||||
resolve([])
|
||||
}
|
||||
}).catch(() => {
|
||||
resolve([])
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
async searchSkuList () {
|
||||
let page = 1
|
||||
let isHasNext = true
|
||||
let list = []
|
||||
let deliveryOrderSnList = []
|
||||
this.isLoading = true
|
||||
while (isHasNext) {
|
||||
const result = await this.getDeliveryOrderSn(page)
|
||||
page = page + 1
|
||||
isHasNext = result.isHasNext ? true : false
|
||||
deliveryOrderSnList.push(...result.list)
|
||||
|
||||
await this.$sleepSync(1000)
|
||||
}
|
||||
|
||||
const len = Math.ceil(deliveryOrderSnList.length / 100)
|
||||
for (let i = 0; i < len; i++) {
|
||||
this.page = 1
|
||||
const ids = [...new Set(deliveryOrderSnList)].slice(i * 100, i * 100 + 100)
|
||||
const res = await this.getLabels(ids)
|
||||
list.push(...res)
|
||||
await this.$sleepSync(500)
|
||||
}
|
||||
|
||||
this.isLoading = false
|
||||
|
||||
this.lableList = list
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.Print-page {
|
||||
.search-item__wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
&>div {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
573
src/view/lables/SkuManage.vue
Normal file
@@ -0,0 +1,573 @@
|
||||
<template>
|
||||
<ai-list class="Template">
|
||||
<ai-title
|
||||
slot="title"
|
||||
title="管理SKU"
|
||||
isShowBack
|
||||
isShowBottomBorder
|
||||
@onBackClick="$router.go(-1)">
|
||||
</ai-title>
|
||||
<template slot="content">
|
||||
<ai-search-bar>
|
||||
<template #left>
|
||||
<el-button type="primary" size="small" @click="chooseSkuList = [], isShow = true">添加</el-button>
|
||||
<el-upload
|
||||
action
|
||||
:limit="1"
|
||||
:show-file-list="false"
|
||||
accept=".xls,.xlsx"
|
||||
:auto-upload="false"
|
||||
:file-list="fileList"
|
||||
:on-change="onExcelChange">
|
||||
<el-button size="small" type="danger" :disabled="!skuList.length">Excel导入</el-button>
|
||||
</el-upload>
|
||||
<json-excel
|
||||
:data="skuList"
|
||||
:fields="jsonFields"
|
||||
name="SKU列表.xls"
|
||||
worksheet="SKU列表">
|
||||
<el-button size="small" type="warning" :disabled="!skuList.length">Excel导出</el-button>
|
||||
</json-excel>
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-search-bar>
|
||||
<template #left>
|
||||
<div class="search-item" style="margin-bottom: 0;">
|
||||
<label>SKU:</label>
|
||||
<el-input
|
||||
v-model="search.productSkuId"
|
||||
style="width: 250px"
|
||||
size="small"
|
||||
clearable
|
||||
placeholder="请输入SKU"
|
||||
suffix-icon="iconfont iconSearch"
|
||||
@clear="getList">
|
||||
</el-input>
|
||||
</div>
|
||||
<div class="search-item" style="margin-bottom: 0;">
|
||||
<label>SKC:</label>
|
||||
<el-input
|
||||
v-model="search.productSkcId"
|
||||
style="width: 250px"
|
||||
size="small"
|
||||
placeholder="请输入SKC"
|
||||
clearable
|
||||
suffix-icon="iconfont iconSearch"
|
||||
@clear="getList">
|
||||
</el-input>
|
||||
</div>
|
||||
<div class="search-item" style="margin-bottom: 0;">
|
||||
<label style="width: 100px;">仅显示未填写:</label>
|
||||
<el-select v-model="search.isShowWhite" placeholder="请选择" clearable size="small">
|
||||
<el-option label="是" value="1"></el-option>
|
||||
<el-option label="否" value="0"></el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
<el-button style="margin-left: 10px;" @click="getList" size="small" :loading="pageShow">查询</el-button>
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-table
|
||||
:tableData="list"
|
||||
:col-configs="colConfigs"
|
||||
style="margin-top: 8px;"
|
||||
@getList="getList"
|
||||
@selection-change="handleSelectionChange"
|
||||
v-loading="pageShow"
|
||||
:isShowPagination="false">
|
||||
<el-table-column
|
||||
v-for="(item, index) in relationList"
|
||||
:key="index"
|
||||
:prop="item.field"
|
||||
:show-overflow-tooltip="true"
|
||||
:label="item.name"
|
||||
align="center">
|
||||
</el-table-column>
|
||||
<el-table-column slot="options" label="操作" align="center" fixed="right" width="120px">
|
||||
<template v-slot="{ row }">
|
||||
<div class="table-options">
|
||||
<el-button type="text" @click="remove(row.id)">删除</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
<ai-dialog
|
||||
:visible.sync="isShow"
|
||||
title="添加SKU"
|
||||
width="1400px"
|
||||
customFooter
|
||||
@confirm="onConfirm">
|
||||
<div class="search-item__wrapper">
|
||||
<div class="left">
|
||||
<div class="search-item">
|
||||
<label>添加方式:</label>
|
||||
<el-radio-group v-model="addType" size="small" @change="onSearchRest">
|
||||
<el-radio-button label="1">按类目添加</el-radio-button>
|
||||
<el-radio-button label="2">按SKC添加</el-radio-button>
|
||||
<el-radio-button label="3">按SKU添加</el-radio-button>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
<div class="search-item">
|
||||
<label>店铺:</label>
|
||||
<el-select v-model="lableSearch.mallId" placeholder="请选择店铺" size="small">
|
||||
<el-option
|
||||
v-for="item in $store.state.mallList"
|
||||
:key="item.mallId"
|
||||
:label="item.mallName"
|
||||
:value="item.mallId">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="right"></div>
|
||||
</div>
|
||||
<div class="search-item__wrapper">
|
||||
<div class="left">
|
||||
<div class="search-item" v-show="addType === '1'">
|
||||
<label>商品分类:</label>
|
||||
<el-cascader
|
||||
style="width: 280px;"
|
||||
v-model="targetCatId"
|
||||
:props="props"
|
||||
size="small"
|
||||
filterable
|
||||
:show-all-levels="false"
|
||||
collapse-tags
|
||||
clearable>
|
||||
</el-cascader>
|
||||
<el-button style="margin-left: 10px;" @click="onCateChange" size="small" :disabled="!lableSearch.mallId" :loading="isLoading">查询</el-button>
|
||||
</div>
|
||||
<div class="search-item" v-show="addType === '2'">
|
||||
<label>SKC:</label>
|
||||
<el-input
|
||||
v-model="skuReqParams.SKC"
|
||||
style="width: 250px"
|
||||
size="small"
|
||||
placeholder="多个查询请用户逗号分割"
|
||||
clearable
|
||||
@clear="getSkuList()"
|
||||
suffix-icon="iconfont iconSearch">
|
||||
</el-input>
|
||||
<el-button style="margin-left: 10px;" @click="getSkuList" size="small" :disabled="!lableSearch.mallId" :loading="isLoading">查询</el-button>
|
||||
</div>
|
||||
<div class="search-item" v-show="addType === '3'">
|
||||
<label>SKU:</label>
|
||||
<el-input
|
||||
v-if="addType === '3'"
|
||||
v-model="skuReqParams.SKU"
|
||||
style="width: 250px"
|
||||
size="small"
|
||||
placeholder="多个查询请用户逗号分割"
|
||||
clearable
|
||||
@clear="getSkuList()"
|
||||
suffix-icon="iconfont iconSearch">
|
||||
</el-input>
|
||||
<el-button style="margin-left: 10px;" @click="getSkuList" size="small" :disabled="!lableSearch.mallId" :loading="isLoading">查询</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<ai-table
|
||||
height="370"
|
||||
:tableData="lableList"
|
||||
:col-configs="colConfigs"
|
||||
:total="lableTotal"
|
||||
:current.sync="lableSearch.current"
|
||||
:size.sync="lableSearch.size"
|
||||
style="margin-top: 8px;"
|
||||
:pageSizes="[10, 20, 50, 100, 500, 1000]"
|
||||
v-loading="isLoading"
|
||||
:isShowPagination="false"
|
||||
@getList="() => {}"
|
||||
@selection-change="handleSelectionChange">
|
||||
<el-table-column slot="productName" width="300px" :show-overflow-tooltip="true" label="商品名称" fixed="left">
|
||||
<template slot-scope="scope">
|
||||
<div>
|
||||
<el-image :src="scope.row.mainImageUrl" style="width: 40px; height: 40px" class="image" :preview-src-list="[scope.row.mainImageUrl]" />
|
||||
{{ scope.row.productName }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
<template #footer>
|
||||
<el-button @click="isShow = false">取消</el-button>
|
||||
<el-button @click="onConfirm" type="primary" :loading="btnLoading">确认</el-button>
|
||||
</template>
|
||||
</ai-dialog>
|
||||
</template>
|
||||
</ai-list>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { sendChromeAPIMessage } from '@/api/chromeApi'
|
||||
import * as XLSX from 'xlsx'
|
||||
import JsonExcel from 'vue-json-excel'
|
||||
export default {
|
||||
name: 'SkuManage',
|
||||
|
||||
components: {
|
||||
JsonExcel
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
total: 0,
|
||||
search: {
|
||||
current: 1,
|
||||
size: -1,
|
||||
productSkuId: '',
|
||||
productSkcId: '',
|
||||
isShowWhite: ''
|
||||
},
|
||||
lableSearch: {
|
||||
current: 1,
|
||||
size: 100,
|
||||
mallId: ''
|
||||
},
|
||||
lableTotal: 0,
|
||||
lableList: [],
|
||||
isShow: false,
|
||||
skuReqParams: {
|
||||
page: 1,
|
||||
pageSize: 100,
|
||||
SKC: '',
|
||||
SKU: ''
|
||||
},
|
||||
isLoading: false,
|
||||
addType: '1',
|
||||
props: {
|
||||
value: 'catId',
|
||||
label: 'catName',
|
||||
multiple: true,
|
||||
checkStrictly: true,
|
||||
lazy: true,
|
||||
lazyLoad (value, resolve) {
|
||||
sendChromeAPIMessage({
|
||||
url: 'bg-anniston-mms/category/children/list',
|
||||
needMallId: true,
|
||||
data: {
|
||||
parentCatId: value.level === 0 ? '' : value.value
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.errorCode === 1000000) {
|
||||
resolve(res.result.categoryNodeVOS.map(v => {
|
||||
return {
|
||||
...v,
|
||||
leaf: v.isLeaf
|
||||
}
|
||||
}))
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
targetCatId: [],
|
||||
skuList: [],
|
||||
chooseSkuList: [],
|
||||
id: '',
|
||||
fileList: [],
|
||||
pageShow: false,
|
||||
relationList: [],
|
||||
btnLoading: false
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
list () {
|
||||
if (!this.skuList.length) {
|
||||
return []
|
||||
}
|
||||
|
||||
if (this.search.isShowWhite !== '1') {
|
||||
return this.skuList
|
||||
}
|
||||
|
||||
const keys = this.relationList.map(v => v.field)
|
||||
return this.skuList.filter(v => keys.some(e => !v[e]))
|
||||
},
|
||||
|
||||
currMall () {
|
||||
if (!this.$store.state.mallList.length) {
|
||||
return {}
|
||||
}
|
||||
|
||||
return this.$store.state.mallList.filter(v => v.mallId === this.lableSearch.mallId)[0]
|
||||
},
|
||||
|
||||
colConfigs () {
|
||||
const fields = this.isShow ? [] : this.relationList.map(v => {
|
||||
return {
|
||||
prop: v.field,
|
||||
label: v.name,
|
||||
align: 'center'
|
||||
}
|
||||
})
|
||||
|
||||
return [
|
||||
{ type: 'selection' },
|
||||
{ prop: 'mallName', label: '店铺名称', align: 'left' },
|
||||
{ prop: 'productName', label: '商品名称', align: 'center' },
|
||||
{ prop: 'labelCode', label: '条码编码', align: 'center' },
|
||||
{ prop: 'productSkcId', label: 'SKC', align: 'center' },
|
||||
{ prop: 'productSkuId', label: 'SKU', align: 'center' },
|
||||
{ prop: 'skuExtCode', label: 'SKU货号', align: 'center' },
|
||||
{ prop: 'skuSpecName', label: '次销售属性', align: 'center' },
|
||||
...fields
|
||||
]
|
||||
},
|
||||
|
||||
jsonFields () {
|
||||
const obj = {}
|
||||
this.colConfigs.filter(v => !!v.prop).forEach(v => {
|
||||
obj[v.label] = v.prop
|
||||
})
|
||||
|
||||
return {
|
||||
...obj
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
created () {
|
||||
this.id = this.$route.query.id || ''
|
||||
this.getRelation()
|
||||
this.getList()
|
||||
},
|
||||
|
||||
methods: {
|
||||
toAdd () {
|
||||
this.$router.push('/addLabelsTemplate')
|
||||
},
|
||||
|
||||
getRelation () {
|
||||
this.$http.post(`/api/templateRelation/getRelation?templateId=${this.$route.query.id}`).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.relationList = res.data
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
readXLSX(file) {
|
||||
return new Promise(resolve => {
|
||||
const reader = new FileReader()
|
||||
reader.readAsBinaryString(file)
|
||||
reader.onload = evt => {
|
||||
const data = evt.target.result
|
||||
const workbook = XLSX.read(data, { type: 'binary' })
|
||||
const ws = workbook.Sheets[workbook.SheetNames[0]]
|
||||
const jsonData = XLSX.utils.sheet_to_json(ws)
|
||||
resolve(jsonData)
|
||||
|
||||
this.fileList = []
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
onExcelChange (file) {
|
||||
this.pageShow = true
|
||||
this.readXLSX(file.raw).then(res => {
|
||||
this.$http.post(`/api/templateSku/updateBatchSku`, res.map(v => {
|
||||
const result = {
|
||||
templateId: this.id
|
||||
}
|
||||
Object.keys(this.jsonFields).forEach(item => {
|
||||
result[this.jsonFields[item]] = v[item]
|
||||
})
|
||||
|
||||
return result
|
||||
})).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.$message.success('导入成功')
|
||||
this.isShow = false
|
||||
this.getList()
|
||||
}
|
||||
this.pageShow = false
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
onSearchRest() {
|
||||
this.skuReqParams.SKC = ''
|
||||
this.skuReqParams.SKU = ''
|
||||
},
|
||||
|
||||
handleSelectionChange(e) {
|
||||
this.chooseSkuList = e
|
||||
},
|
||||
|
||||
getSKCList(catIds, page) {
|
||||
return new Promise(resolve => {
|
||||
sendChromeAPIMessage({
|
||||
url: 'bg-visage-mms/product/skc/pageQuery',
|
||||
needMallId: true,
|
||||
mallId: this.lableSearch.mallId,
|
||||
anti: true,
|
||||
data: {
|
||||
page,
|
||||
pageSize: 200,
|
||||
catIds: catIds
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.errorCode == 1000000) {
|
||||
resolve({
|
||||
list: res.result.pageItems.map(v => v.productSkcId),
|
||||
isHasNext: res.result.total && res.result.pageItems.length && (res.result.pageItems.length < 200 && res.result.total > 200)
|
||||
})
|
||||
} else {
|
||||
resolve({ list: [], isHasNext: false })
|
||||
}
|
||||
}).catch(() => {
|
||||
resolve({ list: [], isHasNext: false })
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
async onCateChange() {
|
||||
let page = 1
|
||||
let list = []
|
||||
let isHasNext = true
|
||||
this.lableList = []
|
||||
this.isLoading = true
|
||||
while (isHasNext) {
|
||||
const result = await this.getSKCList([].concat(this.targetCatId.flat()), page)
|
||||
page = page + 1
|
||||
isHasNext = result.isHasNext ? true : false
|
||||
list.push(...result.list)
|
||||
|
||||
await this.$sleepSync(1000)
|
||||
}
|
||||
|
||||
const skcList = [...new Set(list)]
|
||||
const len = Math.ceil(skcList.length / 100)
|
||||
for (let i = 0; i < len; i++) {
|
||||
this.skuReqParams.page = 1
|
||||
this.skuReqParams.SKC = [...new Set(list)].slice(i * 100, i * 100 + 100).join(',')
|
||||
await this.requestSKUList(true)
|
||||
await this.$sleepSync(500)
|
||||
}
|
||||
this.isLoading = false
|
||||
},
|
||||
|
||||
requestSKUList(flag) {
|
||||
return sendChromeAPIMessage({
|
||||
url: 'bg-visage-mms/labelcode/pageQuery',
|
||||
needMallId: true,
|
||||
mallId: this.lableSearch.mallId,
|
||||
anti: true,
|
||||
data: {
|
||||
page: this.skuReqParams.page,
|
||||
pageSize: 200,
|
||||
productSkcIdList: (['2', '1'].includes(this.addType)) ? this.skuReqParams.SKC.split(',') : [],
|
||||
productSkuIdList: this.addType === '3' ? this.skuReqParams.SKU.split(',') : []
|
||||
}
|
||||
}).then(async (res) => {
|
||||
if (res.errorCode == 1000000) {
|
||||
const list = res.result.pageItems.map(v => {
|
||||
return {
|
||||
mallId: this.lableSearch.mallId,
|
||||
mallName: this.currMall.mallName,
|
||||
productName: v.productName,
|
||||
productSkcId: v.labelCodeVO.productSkcId,
|
||||
productSkuId: v.labelCodeVO.productSkuId,
|
||||
labelCode: v.labelCodeVO.labelCode,
|
||||
skuExtCode: v.labelCodeVO.skuExtCode,
|
||||
skuSpecName: v.productSkuSpecList.map(item => {
|
||||
return item.specName
|
||||
}).join(',')
|
||||
}
|
||||
})
|
||||
this.lableTotal = res.result.total
|
||||
this.lableList.push(...list)
|
||||
|
||||
if (res.result.total > this.lableList.length) {
|
||||
this.skuReqParams.page++
|
||||
await this.$sleepSync(500)
|
||||
await this.requestSKUList()
|
||||
} else {
|
||||
!flag && (this.isLoading = false)
|
||||
}
|
||||
} else {
|
||||
this.isLoading = false
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
getSkuList () {
|
||||
if (!this.lableSearch.mallId) {
|
||||
return this.$message.error('请选择店铺')
|
||||
}
|
||||
|
||||
this.lableList = []
|
||||
this.skuReqParams.page = 1
|
||||
this.isLoading = true
|
||||
this.requestSKUList()
|
||||
},
|
||||
|
||||
getList () {
|
||||
this.pageShow = true
|
||||
this.$http.post(`/api/templateSku/getMySkuPage`, null, {
|
||||
params: {
|
||||
...this.search,
|
||||
templateId: this.id
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.skuList = res.data.records
|
||||
}
|
||||
|
||||
this.pageShow = false
|
||||
})
|
||||
},
|
||||
|
||||
onConfirm () {
|
||||
if (!this.chooseSkuList.length) {
|
||||
return this.$message.error('请选择SKU')
|
||||
}
|
||||
|
||||
this.btnLoading = true
|
||||
this.$http.post(`/api/templateSku/addBatchSku`, this.chooseSkuList.map(v => {
|
||||
return {
|
||||
...v,
|
||||
templateId: this.id
|
||||
}
|
||||
})).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.$message.success('添加成功')
|
||||
this.isShow = false
|
||||
this.getList()
|
||||
}
|
||||
|
||||
this.btnLoading = false
|
||||
}).catch(() => {
|
||||
this.btnLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
remove (id) {
|
||||
this.$confirm('确定删除该数据?', '温馨提示', {
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
this.$http.post(`/api/templateSku/removeById?id=${id}`).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success('删除成功')
|
||||
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.Template {
|
||||
.search-item__wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
&>div {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
205
src/view/lables/Template.vue
Normal file
@@ -0,0 +1,205 @@
|
||||
<template>
|
||||
<ai-list class="Template">
|
||||
<ai-title
|
||||
slot="title"
|
||||
title="模板管理"
|
||||
isShowBottomBorder>
|
||||
<template #rightBtn>
|
||||
<div class="tips" slot="rightBtn" :class="[$store.state.labelInfo.isExpires ? 'active' : '']">
|
||||
<p>有效期:{{ $store.state.labelInfo.expireTime }}</p>
|
||||
<p>已使用SKU数:{{ $store.state.labelInfo.skuUsed }}/{{ $store.state.labelInfo.skuTotal }}</p>
|
||||
</div>
|
||||
</template>
|
||||
</ai-title>
|
||||
<template slot="content">
|
||||
<ai-search-bar>
|
||||
<template #left>
|
||||
<div class="search-item">
|
||||
<label>SKU:</label>
|
||||
<el-input
|
||||
v-model="search.productSkuId"
|
||||
style="width: 250px"
|
||||
size="small"
|
||||
clearable
|
||||
placeholder="请输入SKU"
|
||||
suffix-icon="iconfont iconSearch">
|
||||
</el-input>
|
||||
</div>
|
||||
<div class="search-item">
|
||||
<label>SKC:</label>
|
||||
<el-input
|
||||
v-model="search.productSkcId"
|
||||
style="width: 250px"
|
||||
size="small"
|
||||
placeholder="请输入SKC"
|
||||
clearable
|
||||
suffix-icon="iconfont iconSearch">
|
||||
</el-input>
|
||||
</div>
|
||||
<div class="search-item">
|
||||
<label>模板名称:</label>
|
||||
<el-input
|
||||
v-model="search.name"
|
||||
style="width: 250px"
|
||||
size="small"
|
||||
placeholder="请输入模板名称"
|
||||
clearable
|
||||
suffix-icon="iconfont iconSearch">
|
||||
</el-input>
|
||||
</div>
|
||||
<el-button type="primary" @click="getList" size="small" :loading="isLoading">查询</el-button>
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-search-bar>
|
||||
<template #left>
|
||||
<el-button type="button" class="el-button el-button--primary" @click="toAdd('')">添加</el-button>
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-table
|
||||
:tableData="tableData"
|
||||
:col-configs="colConfigs"
|
||||
:total="total"
|
||||
:current.sync="search.current"
|
||||
:size.sync="search.size"
|
||||
style="margin-top: 8px;"
|
||||
@getList="getList"
|
||||
:loading="isLoading">
|
||||
<el-table-column slot="options" label="操作" align="center" fixed="right" width="240px">
|
||||
<template v-slot="{ row }">
|
||||
<div class="table-options">
|
||||
<el-button type="text" @click="toAddSku(row.id)">管理SKU</el-button>
|
||||
<!-- <el-button type="text" @click="savePDF(row.id)">保存PDF</el-button> -->
|
||||
<el-button type="text" @click="toAdd(row.id)">编辑</el-button>
|
||||
<el-button type="text" @click="remove(row.id)">删除</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
<Print ref="printRef" :isPrint="true"></Print>
|
||||
</template>
|
||||
</ai-list>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Print from '@/components/print/Print'
|
||||
export default {
|
||||
name: 'PringTemplate',
|
||||
|
||||
components: {
|
||||
Print
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
colConfigs: [
|
||||
{ prop: 'name', label: '模板名称', align: 'left' },
|
||||
{ prop: 'skuTotal', label: '绑定SKU数量', align: 'center' },
|
||||
{ prop: 'createTime', label: '创建时间', align: 'center' }
|
||||
],
|
||||
isLoading: false,
|
||||
tableData: [],
|
||||
total: 0,
|
||||
search: {
|
||||
current: 1,
|
||||
size: 10,
|
||||
name: '',
|
||||
productSkuId: '',
|
||||
productSkcId: ''
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
created () {
|
||||
this.getList()
|
||||
},
|
||||
|
||||
methods: {
|
||||
toAdd (id = '') {
|
||||
this.$router.push(`/addLabelsTemplate?id=${id}`)
|
||||
},
|
||||
|
||||
savePDF (id) {
|
||||
this.isLoading = true
|
||||
|
||||
this.$http.post(`/api/template/detail?id=${id}`).then(res => {
|
||||
if (res.code === 0) {
|
||||
const template = JSON.parse(res.data.content)
|
||||
|
||||
this.$http.post(`/api/templateSku/getMySkuPage?size=-1&templateId=${id}`).then(res => {
|
||||
if (res.code === 0) {
|
||||
const html = this.$refs.printRef.toPrint(template, res.data.records)
|
||||
console.log(html)
|
||||
this.isLoading = false
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
toAddSku (id) {
|
||||
this.$router.push(`/skuManage?id=${id}`)
|
||||
},
|
||||
|
||||
getList () {
|
||||
this.isLoading = true
|
||||
this.$http.post('/api/template/myTemplate', null, {
|
||||
params: {
|
||||
...this.search
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.tableData = res.data.records
|
||||
this.total = res.data.total
|
||||
}
|
||||
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
remove (id) {
|
||||
this.$confirm('确定删除该模板?', '温馨提示', {
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
this.$http.post(`/api/template/removeById?id=${id}`).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success('删除成功')
|
||||
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
onConfirm () {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.Template {
|
||||
.search-item {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.tips {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: green;
|
||||
|
||||
&.active {
|
||||
color: red;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
|
||||
&:first-child {
|
||||
margin-right: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
380
src/view/login/Forget.vue
Normal file
@@ -0,0 +1,380 @@
|
||||
<template>
|
||||
<div class="login">
|
||||
<div class="body">
|
||||
<div class="middle">
|
||||
<div class="right">
|
||||
<div class="tab">
|
||||
<h2 class="active" @click="currIndex = 0">找回密码</h2>
|
||||
</div>
|
||||
<el-form :model="form" label-position="top" ref="form" label-width="100px" class="form">
|
||||
<el-form-item
|
||||
prop="phone"
|
||||
:rules="[{ required: true, message: '请输入手机号', trigger: 'blur' }, { validator: phoneReg, trigger: 'blur' }]">
|
||||
<el-input maxlength="11" placeholder="请输入手机号" v-model="form.phone"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
prop="password"
|
||||
:rules="[{ required: true, message: '请输入密码', trigger: 'blur' }]">
|
||||
<el-input placeholder="请输入密码" type="password" v-model="form.password"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
prop="repassword"
|
||||
:rules="[{ required: true, message: '请再次输入密码', trigger: 'blur' }]">
|
||||
<el-input placeholder="请再次输入密码" type="password" v-model="form.repassword"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="" prop="code" :rules="[{ required: true, message: '请输入验证码', trigger: 'blur' }]">
|
||||
<div class="code-item">
|
||||
<el-input style="width: 300px;" maxlength="4" placeholder="请输入验证码" v-model="form.code"></el-input>
|
||||
<span @click="getCode" :loading="btnLoading">{{ isStart ? time + ' S' : '发送验证码' }}</span>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-button type="primary" style="width: 100%" @click="login" :loading="btnLoading">设置</el-button>
|
||||
</el-form>
|
||||
<div class="login-footer">
|
||||
<div class="left">
|
||||
<i class="hover" @click="$router.back()">返回登录</i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import CryptoJS from 'crypto-js'
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
form: {
|
||||
password: '',
|
||||
repassword: '',
|
||||
code: '',
|
||||
phone: ''
|
||||
},
|
||||
phoneReg: (rule, value, callback) => {
|
||||
if (/^1[0-9]{10,10}$/.test(value)) {
|
||||
return callback()
|
||||
}
|
||||
|
||||
callback(new Error('手机号格式错误'))
|
||||
},
|
||||
timer: null,
|
||||
time: 60,
|
||||
isSend: false,
|
||||
isStart: false,
|
||||
isLoading: false,
|
||||
currIndex: 0,
|
||||
btnLoading: false,
|
||||
loginType: '0'
|
||||
}
|
||||
},
|
||||
|
||||
mounted () {
|
||||
},
|
||||
|
||||
methods: {
|
||||
login () {
|
||||
this.$refs.form.validate((valid) => {
|
||||
if (valid) {
|
||||
if (this.form.password != this.form.repassword) {
|
||||
this.$message.error('两次密码输入不一致');
|
||||
return;
|
||||
}
|
||||
this.btnLoading = true
|
||||
this.$http.post(`/api/malluser/forget`, null, {
|
||||
params: {
|
||||
...this.form
|
||||
}
|
||||
}, {
|
||||
headers: {
|
||||
Authorization: 'Basic cGM6cGM='
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.$message.success('注册成功')
|
||||
|
||||
setTimeout(() => {
|
||||
this.$router.replace('/login')
|
||||
}, 500)
|
||||
}
|
||||
|
||||
this.btnLoading = false
|
||||
}).catch(() => {
|
||||
this.btnLoading = false
|
||||
})
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
})
|
||||
},
|
||||
encryptPhone (phone) {
|
||||
const u = navigator.userAgent
|
||||
const isIos = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/)
|
||||
var key = 'thanks,temulll11'
|
||||
var iv = CryptoJS.enc.Latin1.parse(key)
|
||||
var encrypted = CryptoJS.AES.encrypt(phone, iv, {
|
||||
iv: iv,
|
||||
mode: CryptoJS.mode.CBC,
|
||||
padding: CryptoJS.pad.ZeroPadding
|
||||
})
|
||||
|
||||
if (isIos) {
|
||||
return encodeURIComponent(encrypted.toString())
|
||||
} else {
|
||||
return encrypted.toString()
|
||||
}
|
||||
},
|
||||
|
||||
getCode () {
|
||||
if (this.isSend) {
|
||||
return this.$message.error('验证码已发送')
|
||||
}
|
||||
|
||||
this.$refs.form.validateField('phone', e => {
|
||||
if (!e) {
|
||||
let phone = this.encryptPhone(this.form.phone)
|
||||
this.isSend = true
|
||||
this.btnLoading = true
|
||||
this.$http.post(`/api/sms/getRegSmsCodeNew?phone=${phone}`, {}, {
|
||||
withoutToken: true
|
||||
}).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.$message.success('验证码发送成功')
|
||||
this.isStart = true
|
||||
this.timer = setInterval(() => {
|
||||
if (this.time === 0) {
|
||||
this.isSend = false
|
||||
this.isStart = false
|
||||
this.time = 60
|
||||
clearInterval(this.timer)
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
this.time = this.time - 1
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
this.btnLoading = false
|
||||
this.isSend = false
|
||||
}).catch(() => {
|
||||
this.isSend = false
|
||||
this.btnLoading = false
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
onChange (e) {
|
||||
this.$emit('change', e)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.login {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100vh;
|
||||
|
||||
.body {
|
||||
position: relative;
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
background-color: #cdc8c8;
|
||||
// background: url(../../assets/images/login/login.png) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
|
||||
.middle {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
z-index: 11;
|
||||
width: 1280px;
|
||||
transform: translate(-50%, -50%);
|
||||
|
||||
& > .left {
|
||||
padding-top: 42px;
|
||||
font-family: MicrosoftYaHei;
|
||||
|
||||
p {
|
||||
line-height: 24px;
|
||||
margin-top: 12px;
|
||||
margin-bottom: 13px;
|
||||
font-size: 18px;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
span {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
& > .right {
|
||||
width: 500px;
|
||||
padding: 63px 40px 42px;
|
||||
box-shadow: 0px 2px 12px 0px rgba(0, 0, 0, 0.06);
|
||||
background: #fff;
|
||||
border-radius: 16px;
|
||||
backdrop-filter: blur(6px);
|
||||
overflow: hidden;
|
||||
|
||||
.tab {
|
||||
display: flex;
|
||||
position: relative;
|
||||
align-items: center;
|
||||
margin-bottom: 36px;
|
||||
padding-bottom: 17px;
|
||||
border-bottom: 1px solid #DCDFE6;
|
||||
|
||||
&::after {
|
||||
position: absolute;
|
||||
bottom: -1px;
|
||||
left: 0;
|
||||
z-index: 1;
|
||||
width: 81px;
|
||||
height: 2px;
|
||||
background: #1FBAD6;
|
||||
content: ' ';
|
||||
transition: all ease-in-out 0.3s;
|
||||
}
|
||||
|
||||
&.tab-active:after {
|
||||
transform: translateX(138px);
|
||||
}
|
||||
|
||||
h2 {
|
||||
width: 81px;
|
||||
line-height: 24px;
|
||||
text-align: center;
|
||||
font-size: 20px;
|
||||
font-family: SJsuqian;
|
||||
color: #000000;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
transition: all ease 0.4s;
|
||||
|
||||
&.active, &:hover {
|
||||
color: #1FBAD6;
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
margin-right: 58px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.login-type {
|
||||
font-size: 14px;
|
||||
font-family: SJsuqian;
|
||||
text-align: center;
|
||||
color: #54657D;
|
||||
cursor: pointer;
|
||||
transition: all ease-in-out 0.4s;
|
||||
|
||||
&:hover {
|
||||
color: #1FBAD6;
|
||||
}
|
||||
}
|
||||
|
||||
.login-footer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-top: 21px;
|
||||
margin-bottom: 38px;
|
||||
|
||||
div {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
span {
|
||||
font-family: SJsuqian;
|
||||
color: #54657D;
|
||||
}
|
||||
|
||||
i {
|
||||
font-family: SJsuqian;
|
||||
color: #1FBAD6;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep .el-form {
|
||||
.el-input__inner {
|
||||
height: 48px;
|
||||
border-color: #DCDFE6;
|
||||
background-color: transparent;
|
||||
|
||||
&:focus, &:hover {
|
||||
border-color: #1FBAD6;
|
||||
}
|
||||
|
||||
&::placeholder {
|
||||
color: #666666;
|
||||
}
|
||||
}
|
||||
|
||||
.el-form-item.is-error .el-input__inner, .el-form-item.is-error .el-input__inner:focus, .el-form-item.is-error .el-textarea__inner, .el-form-item.is-error .el-textarea__inner:focus {
|
||||
border-color: #F56C6C;
|
||||
}
|
||||
|
||||
.el-form-item {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.el-button {
|
||||
height: 48px;
|
||||
margin-top: 28px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.code-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
|
||||
span {
|
||||
width: 110px;
|
||||
height: 48px;
|
||||
line-height: 48px;
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
border-radius: 4px;
|
||||
transition: all cubic-bezier(0.215, 0.61, 0.355, 1) 0.3s;
|
||||
border: 1px solid #DCDFE6;
|
||||
|
||||
&:hover {
|
||||
border-color: #1FBAD6;
|
||||
}
|
||||
}
|
||||
|
||||
.el-form-item {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.copyright {
|
||||
position: fixed;
|
||||
bottom: 24px;
|
||||
left: 50%;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
color: #fff;
|
||||
letter-spacing: 1px;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -24,9 +24,16 @@
|
||||
<span>没有账号?</span>
|
||||
<i class="hover" @click="$router.push('/register')">立即注册</i>
|
||||
</div>
|
||||
<div class="left" style="margin-left: 10px;">
|
||||
<span>忘记密码?</span>
|
||||
<i class="hover" @click="$router.push('/forget')">找回密码</i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="kefu" @click="gotoKefu">
|
||||
<label slot="reference" class="topBtn" title="联系客服"></label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -139,6 +146,9 @@
|
||||
|
||||
onChange (e) {
|
||||
this.$emit('change', e)
|
||||
},
|
||||
gotoKefu() {
|
||||
window.open('https://work.weixin.qq.com/kfid/kfcaa4208f661131eba', '_blank')
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -348,4 +358,30 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#kefu {
|
||||
position: fixed;
|
||||
right: 20px;
|
||||
bottom: 40px;
|
||||
z-index: 999;
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
}
|
||||
|
||||
#kefu .topBtn {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
background-color: #fff;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
background-position: center center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 40px 40px;
|
||||
-webkit-animation: wobble 250ms infinite;
|
||||
animation: wobble 250ms infinite;
|
||||
background-image: url('data:image/svg+xml;%20charset=utf8,%3Csvg%20t%3D%221575450105478%22%20class%3D%22icon%22%20viewBox%3D%220%200%201220%201024%22%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20p-id%3D%222883%22%20width%3D%2248%22%20height%3D%2248%22%3E%3Cpath%20d%3D%22M609.524%20103.522c-222.89%200-403.712%20178.472-403.712%20398.78%200%20220.31%20180.823%20398.782%20403.712%20398.782%20222.889%200%20403.712-178.473%20403.712-398.781%200-220.309-180.823-398.781-403.712-398.781v48.762c196.1%200%20354.95%20156.785%20354.95%20350.019s-158.85%20350.019-354.95%20350.019-354.95-156.785-354.95-350.02c0-193.233%20158.85-350.018%20354.95-350.018v-48.762z%22%20fill%3D%22%231296db%22%20p-id%3D%222884%22%3E%3C%2Fpath%3E%3Cpath%20d%3D%22M786.578%20916.34c166.45-69.217%20278.408-231.055%20278.408-414.035%200-248.026-203.847-449.219-455.457-449.219-251.619%200-455.457%20201.188-455.457%20449.22%200%2055.397%2010.152%20109.367%2029.718%20159.975%204.855%2012.56-1.39%2026.677-13.949%2031.533-12.56%204.855-26.677-1.39-31.532-13.949a490.396%20490.396%200%200%201-3.042-8.078c-1.85%200.077-3.711%200.116-5.581%200.116C58.06%20671.903%200%20614.597%200%20543.903c0-65.005%2049.09-118.69%20112.68-126.91C153.65%20182.56%20360.56%204.324%20609.528%204.324c248.962%200%20455.877%20178.24%20496.85%20412.67%2063.583%208.225%20112.669%2061.907%20112.669%20126.909%200%2070.694-58.06%20128-129.686%20128-1.89%200-3.771-0.04-5.642-0.119-47.536%20129.702-148.34%20235.841-279.493%20290.027-1.161%2033.464-29.012%2060.24-63.2%2060.24-34.925%200-63.237-27.944-63.237-62.416%200-34.471%2028.312-62.415%2063.237-62.415%2017.892%200%2034.048%207.333%2045.551%2019.12z%22%20fill%3D%22%231296db%22%20p-id%3D%222885%22%3E%3C%2Fpath%3E%3Cpath%20d%3D%22M609.528%20611.405c-58.933%200-112.056-10.644-158.472-28.342-16.123-6.147-30.211-12.702-42.138-19.208-6.926-3.777-11.447-6.59-13.437-7.972-19.24-13.373-44.428%205.446-37.059%2027.688%2035.296%20106.527%20136.054%20179.913%20251.106%20179.913%20115.05%200%20215.796-73.384%20251.092-179.913%207.37-22.243-17.82-41.062-37.06-27.687-1.99%201.383-6.51%204.195-13.434%207.972-11.926%206.505-26.012%2013.06-42.133%2019.207-46.413%2017.698-99.533%2028.342-158.465%2028.342z%22%20fill%3D%22%231296db%22%20p-id%3D%222886%22%3E%3C%2Fpath%3E%3C%2Fsvg%3E');
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -52,6 +52,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import CryptoJS from 'crypto-js'
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
@@ -92,9 +93,12 @@
|
||||
this.$message.success('两次密码输入不一致');
|
||||
return;
|
||||
}
|
||||
const devVersion = require('../../manifest.development.json').version
|
||||
const prodVersion = require('../../manifest.production.json').version
|
||||
this.btnLoading = true
|
||||
this.$http.post(`/api/malluser/reg`, {
|
||||
...this.form
|
||||
...this.form,
|
||||
version: process.env.NODE_ENV === 'production' ? prodVersion : devVersion
|
||||
}, {
|
||||
headers: {
|
||||
Authorization: 'Basic cGM6cGM='
|
||||
@@ -118,6 +122,23 @@
|
||||
}
|
||||
})
|
||||
},
|
||||
encryptPhone (phone) {
|
||||
const u = navigator.userAgent
|
||||
const isIos = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/)
|
||||
var key = 'thanks,temulll11'
|
||||
var iv = CryptoJS.enc.Latin1.parse(key)
|
||||
var encrypted = CryptoJS.AES.encrypt(phone, iv, {
|
||||
iv: iv,
|
||||
mode: CryptoJS.mode.CBC,
|
||||
padding: CryptoJS.pad.ZeroPadding
|
||||
})
|
||||
|
||||
if (isIos) {
|
||||
return encodeURIComponent(encrypted.toString())
|
||||
} else {
|
||||
return encrypted.toString()
|
||||
}
|
||||
},
|
||||
|
||||
getCode () {
|
||||
if (this.isSend) {
|
||||
@@ -126,9 +147,10 @@
|
||||
|
||||
this.$refs.form.validateField('phone', e => {
|
||||
if (!e) {
|
||||
let phone = this.encryptPhone(this.form.phone)
|
||||
this.isSend = true
|
||||
this.btnLoading = true
|
||||
this.$http.post(`/api/sms/getRegSmsCode?phone=${this.form.phone}`, {}, {
|
||||
this.$http.post(`/api/sms/getRegSmsCodeNew?phone=${phone}`, {}, {
|
||||
withoutToken: true
|
||||
}).then(res => {
|
||||
if (res.code === 0) {
|
||||
|
||||
31
src/view/media/imageTranslate.vue
Normal file
@@ -0,0 +1,31 @@
|
||||
<script>
|
||||
import AiDetail from "@/components/AiDetail.vue";
|
||||
|
||||
export default {
|
||||
name: "imageTranslate",
|
||||
components: {AiDetail},
|
||||
data() {
|
||||
return {
|
||||
form: {}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ai-detail class="imageTranslate">
|
||||
<ai-title slot="title" title="图片翻译" isShowBottomBorder/>
|
||||
<template #content>
|
||||
<el-form>
|
||||
|
||||
|
||||
|
||||
</el-form>
|
||||
</template>
|
||||
</ai-detail>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.imageTranslate {
|
||||
}
|
||||
</style>
|
||||
305
src/view/product/BatchUpload.vue
Normal file
@@ -0,0 +1,305 @@
|
||||
<template>
|
||||
<ai-list class="list" v-loading="isLoading" element-loading-text="拼命加载中" element-loading-spinner="el-icon-loading">
|
||||
<ai-title
|
||||
slot="title"
|
||||
title="批量上品"
|
||||
:tips="`上传一件商品将消耗${coin}金币`"
|
||||
isShowBottomBorder>
|
||||
</ai-title>
|
||||
<template slot="content">
|
||||
<el-form :model="form" ref="form" label-width="180px" class="form">
|
||||
<el-divider content-position="left">模板来源</el-divider>
|
||||
<el-form-item label="模板店铺来源" style="width: 100%;" prop="sourceMallId" :rules="[{ required: true, message: '请选择模板店铺来源', trigger: 'blur' }]">
|
||||
<el-select style="width: 380px" v-model="form.sourceMallId" placeholder="请选择模板店铺来源">
|
||||
<el-option
|
||||
v-for="item in mallList"
|
||||
:key="item.mallId"
|
||||
:label="item.mallName"
|
||||
:value="item.mallId">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
prop="sourceSpuId"
|
||||
label="模板SPU ID:"
|
||||
style="width: 480px"
|
||||
:rules="[{ required: true, message: '请输入模板SPU ID', trigger: 'blur' }]">
|
||||
<el-input size="small" placeholder="请输入模板SPU ID" v-model="form.sourceSpuId"></el-input>
|
||||
</el-form-item>
|
||||
<el-divider content-position="left">目标店铺</el-divider>
|
||||
<el-form-item label="店铺" style="width: 100%;" prop="targetMallId" :rules="[{ required: true, message: '请选择目标店铺', trigger: 'blur' }]">
|
||||
<el-select style="width: 380px" v-model="form.targetMallId" placeholder="请选择目标店铺">
|
||||
<el-option
|
||||
v-for="item in mallList"
|
||||
:key="item.mallId"
|
||||
:label="item.mallName"
|
||||
:value="item.mallId">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-button type="button" :class="'el-button el-button--primary'" @click="openFolder">选择文件夹</el-button>
|
||||
</el-form>
|
||||
</template>
|
||||
</ai-list>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Message } from 'element-ui'
|
||||
import {sendChromeAPIMessage} from '@/api/chromeApi'
|
||||
import {timestampToTime} from '@/utils/date'
|
||||
import {transform} from '@/utils/product'
|
||||
import { createFolderApi } from "@/utils/folder.js"
|
||||
import { uploadImage } from "@/utils/image.js"
|
||||
import { formatDate } from "@/utils/date.js"
|
||||
|
||||
export default {
|
||||
name: 'BatchUpload',
|
||||
|
||||
data () {
|
||||
return {
|
||||
form: {
|
||||
sourceMallId: '',
|
||||
sourceSpuId: '',
|
||||
targetMallId: ''
|
||||
},
|
||||
content: null,
|
||||
mallObj: null,
|
||||
folderId: null,
|
||||
successCount: 0,
|
||||
mainPicList: [],
|
||||
mainPicUrl: null,
|
||||
detailPicList: [],
|
||||
coin: 150,
|
||||
colConfigs: [
|
||||
{ slot: 'productName', label: '商品名称', width: '180px', align: 'left', fixed: 'left' },
|
||||
{ prop: 'category', 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: 'productSkuId', label: 'SKU ID', width: '120px', align: 'left' },
|
||||
{ prop: 'skcSiteStatus', label: '是否在售', width: '120px', align: 'left' },
|
||||
{ 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' }
|
||||
],
|
||||
isLoading: false,
|
||||
tableData: [],
|
||||
currentIndex: 0
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
mallList () {
|
||||
const filteredData = this.$store.state.mallList.filter(item => {
|
||||
return item.isSemiManagedMall == false
|
||||
})
|
||||
|
||||
return filteredData
|
||||
}
|
||||
},
|
||||
created () {
|
||||
},
|
||||
methods: {
|
||||
async openFolder() {
|
||||
this.$refs.form.validate(async (valid) => {
|
||||
if (valid) {
|
||||
let res1 = await sendChromeAPIMessage({
|
||||
url: 'bg-visage-mms/product/query',
|
||||
needMallId: true,
|
||||
mallId: this.form.sourceMallId,
|
||||
data: {
|
||||
productEditTaskUid: '',
|
||||
productId: this.form.sourceSpuId
|
||||
}})
|
||||
if (res1.errorCode == 1000000) {
|
||||
this.content = JSON.parse(transform(res1.result))
|
||||
this.mallObj = this.$store.state.mallList.filter(item => {
|
||||
return item.mallId == this.form.targetMallId
|
||||
})
|
||||
}
|
||||
this.successCount = 0
|
||||
this.mainPicList = []
|
||||
this.detailPicList = []
|
||||
this.folderId = await createFolderApi(formatDate(new Date()).split('-'), this.form.targetMallId)
|
||||
|
||||
const res = await window.showDirectoryPicker({})
|
||||
await this.dealAction("", res)
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
},
|
||||
async dealAction (root, obj) {
|
||||
console.log(obj)
|
||||
if (obj.entries) {
|
||||
let dirs = obj.entries()
|
||||
if (root == "") {
|
||||
let length = 0
|
||||
for await (const temp of dirs) {
|
||||
length ++
|
||||
}
|
||||
if (this.$store.state.userInfo.coin < length * this.coin) {
|
||||
Message.error("金币不足,请先充值金币")
|
||||
return
|
||||
}
|
||||
}
|
||||
if (root == '') {
|
||||
dirs = obj.entries()
|
||||
for await (const entry of dirs) {
|
||||
/*if (entry[1].kind == 'file') {
|
||||
let prefix = entry[0].split('.').pop()
|
||||
if (prefix == 'png' || prefix == 'jpg' || prefix == 'jpeg') {
|
||||
let file = await entry[1].getFile()
|
||||
let img = await uploadImage(this.folderId, file, this.form.targetMallId, true)
|
||||
this.mainPicUrl = img
|
||||
this.$sleepSync(500)
|
||||
}
|
||||
} else {*/
|
||||
if (entry[1].kind == 'directory') {
|
||||
await this.dealAction(obj.name + "/" + entry[0], entry[1])
|
||||
}
|
||||
//}
|
||||
}
|
||||
} else {
|
||||
this.mainPicList = []
|
||||
this.detailPicList = []
|
||||
await this.toUploadProduct(root, obj)
|
||||
}
|
||||
}
|
||||
},
|
||||
async toUploadProduct(root, obj) {
|
||||
const dirs = obj.entries()
|
||||
for await (const entry of dirs) {
|
||||
if (entry[1].kind == 'file') {
|
||||
let prefix = entry[0].split('.').pop()
|
||||
if (prefix == 'png' || prefix == 'jpg' || prefix == 'jpeg') {
|
||||
let file = await entry[1].getFile()
|
||||
let img = await uploadImage(this.folderId, file, this.form.targetMallId, true)
|
||||
this.mainPicUrl = img
|
||||
this.$sleepSync(200)
|
||||
}
|
||||
} else if (entry[0] != '详情图' && entry[1].kind == 'directory') {
|
||||
let tempList = await this.getPictureList(root + '/' + entry[0], entry[1])
|
||||
this.mainPicList.push({color: entry[0], imgList: tempList})
|
||||
} else if (entry[0] == '详情图' && entry[1].kind == 'directory') {
|
||||
this.detailPicList = await this.getPictureList(root + '/' + entry[0], entry[1])
|
||||
}
|
||||
|
||||
}
|
||||
if (this.mainPicList.length >= 0 && this.detailPicList.length >= 0) {
|
||||
await this.beginAddToDraft(obj.name)
|
||||
this.$sleepSync(200)
|
||||
}
|
||||
|
||||
},
|
||||
async getPictureList(root, obj) {
|
||||
const dirs = obj.entries()
|
||||
let images = []
|
||||
for await (const entry of dirs) {
|
||||
if (entry[1].kind == 'file') {
|
||||
let prefix = entry[0].split('.').pop()
|
||||
if (prefix == 'png' || prefix == 'jpg' || prefix == 'jpeg') {
|
||||
let file = await entry[1].getFile()
|
||||
let img = await uploadImage(this.folderId, file, this.form.targetMallId, true)
|
||||
if (null == img) {
|
||||
|
||||
} else {
|
||||
images.push({
|
||||
name: entry[0].split('.')[0],
|
||||
url: img
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
images.sort((a, b) => {
|
||||
if (!isNaN(a.name) && !isNaN(b.name)) {
|
||||
return (Number(a.name) - Number(b.name))
|
||||
} else {
|
||||
return a.name - b.name
|
||||
}
|
||||
})
|
||||
|
||||
return images
|
||||
},
|
||||
async beginAddToDraft(name) {
|
||||
let category = null
|
||||
let i = 1
|
||||
while(true) {
|
||||
if (!this.content['cat'+i+'Id']) {
|
||||
break
|
||||
}
|
||||
i++
|
||||
}
|
||||
category = this.content['cat'+(i-1)+'Id']
|
||||
let data = {catId: category}
|
||||
this.content.personalizationSwitch = this.content.personalizationSwitch || 0
|
||||
|
||||
let res = await sendChromeAPIMessage({
|
||||
url: 'bg-visage-mms/product/draft/add',
|
||||
needMallId: true,
|
||||
mallId: this.form.targetMallId,
|
||||
data: data})
|
||||
if (res.errorCode == 1000000) {
|
||||
let draftId = res.result.productDraftId
|
||||
this.content.productDraftId = draftId
|
||||
|
||||
// 变化部分
|
||||
this.content.productName = name
|
||||
this.content.materialImgUrl = this.mainPicList[0].imgList[0].url
|
||||
|
||||
for (let i = 0; i < this.content.productSkcReqs.length; i++) {
|
||||
for (let j = 0; j < this.mainPicList.length; j++) {
|
||||
if (this.content.productSkcReqs[i].mainProductSkuSpecReqs[0].specName == this.mainPicList[j].color) {
|
||||
this.content.productSkcReqs[i].previewImgUrls = this.mainPicList[j].imgList
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let res1 = await sendChromeAPIMessage({
|
||||
url: 'bg-visage-mms/product/draft/save',
|
||||
needMallId: true,
|
||||
mallId: this.form.targetMallId,
|
||||
data: {
|
||||
...this.content
|
||||
}})
|
||||
if (res1.errorCode == 1000000) {
|
||||
Message.success("商品【" + name + "】成功添加到草稿箱")
|
||||
} else {
|
||||
Message.error(res1.errorMsg)
|
||||
}
|
||||
} else {
|
||||
Message.error("【拼多多】" + res.errorMsg)
|
||||
}
|
||||
|
||||
await this.$sleepSync(500)
|
||||
}
|
||||
}
|
||||
}
|
||||
</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>
|
||||
@@ -26,6 +26,7 @@
|
||||
style="margin-top: 8px;"
|
||||
:current.sync="search.current" :size.sync="search.size"
|
||||
@selection-change="handleSelectionChange"
|
||||
height="700"
|
||||
@getList="getList">
|
||||
</ai-table>
|
||||
</div>
|
||||
@@ -45,7 +46,7 @@
|
||||
<template #left>
|
||||
<div class="search-item">
|
||||
<label style="width:90px">店铺:</label>
|
||||
<el-select v-model="productPage.mallId" @change="productTableData = [], productPage.total = 0, productPage.page =1, getProductList()" placeholder="请选择">
|
||||
<el-select v-model="productPage.mallId" @change="productTableData = [], productPage.total = 0, productPage.page =1, getProductOrDraftList()" placeholder="请选择">
|
||||
<el-option
|
||||
v-for="item in $store.state.mallList"
|
||||
:key="item.mallId"
|
||||
@@ -54,6 +55,21 @@
|
||||
</el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
<div class="search-item">
|
||||
<label style="width:90px">模板来源:</label>
|
||||
<el-select v-model="productPage.from" @change="productTableData = [], productPage.total = 0, productPage.page =1, getProductOrDraftList()" placeholder="请选择">
|
||||
<el-option
|
||||
key="0"
|
||||
label="商品列表"
|
||||
value="0">
|
||||
</el-option>
|
||||
<el-option
|
||||
key="1"
|
||||
label="草稿箱列表"
|
||||
value="1">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
<div class="search-item">
|
||||
<label style="width:90px">SKC:</label>
|
||||
<el-input size="small" placeholder="请输入SKC,多个用,隔开" v-model="productPage.productSkcIds" @keyup.enter.native="productPage.page =1, getProductList()"></el-input>
|
||||
@@ -67,10 +83,11 @@
|
||||
<el-button @click="productPage= {
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
from: '0',
|
||||
productName: '',
|
||||
productSkcIds: ''
|
||||
}, getProductList()">重置</el-button>
|
||||
<el-button type="primary" @click="productPage.page =1, getProductList()">查询</el-button>
|
||||
}, getProductOrDraftList()">重置</el-button>
|
||||
<el-button type="primary" @click="productPage.page =1, getProductOrDraftList()">查询</el-button>
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-table
|
||||
@@ -80,7 +97,7 @@
|
||||
:current.sync="productPage.page" :size.sync="productPage.pageSize"
|
||||
style="margin-top: 8px;"
|
||||
@selection-change="productHandleSelectionChange"
|
||||
@getList="getProductList">
|
||||
@getList="getProductOrDraftList">
|
||||
</ai-table>
|
||||
</div>
|
||||
</template>
|
||||
@@ -98,19 +115,51 @@
|
||||
width="790px"
|
||||
customFooter
|
||||
@close="handleClose">
|
||||
<el-form class="ai-form" :model="form" label-width="120px" ref="form">
|
||||
<el-form class="ai-form" :model="form" label-width="160px" ref="form">
|
||||
<el-form-item
|
||||
prop="isSemi"
|
||||
label="是否半托管:"
|
||||
:rules="[{ required: true, message: '请选择是否半托管', trigger: 'blur' }]">
|
||||
<el-radio-group v-model="form.isSemi" size="medium">
|
||||
<el-radio :label="false">否</el-radio>
|
||||
<el-radio :label="true">是</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="店铺" style="width: 100%;" prop="targetMallId" :rules="[{ required: true, message: '请选择店铺', trigger: 'blur' }]">
|
||||
<el-select style="width: 380px" v-model="form.targetMallId" placeholder="请选择">
|
||||
<el-select multiple style="width: 380px" v-model="form.targetMallId" placeholder="请选择">
|
||||
<el-option
|
||||
v-for="item in $store.state.mallList"
|
||||
v-for="item in mallList"
|
||||
:key="item.mallId"
|
||||
:label="item.mallName"
|
||||
:value="item.mallId">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="商品分类" style="width: 100%;" prop="targetCatId" :rules="[{ required: true, message: '请选择商品分类', trigger: 'blur' }]">
|
||||
<el-cascader style="width: 380px" v-model="form.targetCatId" :props="props"></el-cascader>
|
||||
<el-form-item v-if="form.isSemi" label="经营站点" style="width: 100%;" prop="siteId" :rules="[{ required: true, message: '请选择经营站点', trigger: 'blur' }]">
|
||||
<el-select style="width: 380px" multiple v-model="form.siteId" placeholder="请选择">
|
||||
<el-option
|
||||
v-for="item in siteList"
|
||||
:key="item.siteId"
|
||||
:label="item.siteName"
|
||||
:value="item.siteId">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
prop="isSameCategory"
|
||||
label="是否保持相同类目:"
|
||||
:rules="[{ required: true, message: '请选择是否保持相同类目', trigger: 'blur' }]">
|
||||
<el-radio-group v-model="form.isSameCategory" size="medium">
|
||||
<el-radio :label="false">否</el-radio>
|
||||
<el-radio :label="true">是</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="!form.isSameCategory" label="商品分类" style="width: 100%;" prop="targetCatId" :rules="[{ required: true, message: '请选择商品分类', trigger: 'blur' }]">
|
||||
<ai-lazy-cascader
|
||||
style="width: 380px"
|
||||
v-model="form.targetCatId"
|
||||
filterable
|
||||
:props="props"></ai-lazy-cascader>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div class="dialog-footer" slot="footer">
|
||||
@@ -126,10 +175,11 @@ import {sendChromeAPIMessage} from '@/api/chromeApi'
|
||||
import {timestampToTime} from '@/utils/date'
|
||||
import {transform} from '@/utils/product'
|
||||
import { Message } from 'element-ui'
|
||||
import AiLazyCascader from "@/components/AiLazyCascader.vue"
|
||||
|
||||
export default {
|
||||
name: 'CopyProduct',
|
||||
|
||||
components: {AiLazyCascader},
|
||||
data () {
|
||||
return {
|
||||
search: {
|
||||
@@ -144,12 +194,12 @@ import { Message } from 'element-ui'
|
||||
value: 'catId',
|
||||
label: 'catName',
|
||||
lazy: true,
|
||||
lazyLoad (node, resolve) {
|
||||
lazyLoad (value, resolve) {
|
||||
sendChromeAPIMessage({
|
||||
url: 'bg-anniston-mms/category/children/list',
|
||||
needMallId: true,
|
||||
data: {
|
||||
parentCatId: node.value || ''
|
||||
parentCatId: value || ''
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.errorCode === 1000000) {
|
||||
@@ -161,6 +211,32 @@ import { Message } from 'element-ui'
|
||||
}))
|
||||
}
|
||||
})
|
||||
},
|
||||
lazySearch(queryString, resolve) {
|
||||
sendChromeAPIMessage({
|
||||
url: 'bg-anniston-mms/category/search',
|
||||
needMallId: true,
|
||||
data: {
|
||||
searchText: queryString || ''
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.errorCode === 1000000) {
|
||||
resolve(res.result.categoryPaths.map(v => {
|
||||
let value = []
|
||||
let label = []
|
||||
for (let i = 1; i <= 10; i++ ) {
|
||||
if (v['cat'+i+'NodeVO']) {
|
||||
value.push(v['cat'+i+'NodeVO'].catId)
|
||||
label.push(v['cat'+i+'NodeVO'].catName)
|
||||
}
|
||||
}
|
||||
return {
|
||||
catId: value,
|
||||
catName: label
|
||||
}
|
||||
}))
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
colConfigs: [
|
||||
@@ -176,7 +252,7 @@ import { Message } from 'element-ui'
|
||||
|
||||
dlgShow: false,
|
||||
productTableData: [],
|
||||
productPage: {page: 1, pageSize: 10, mallId: '', productName: '', productSkcIds: '', total: 0},
|
||||
productPage: {page: 1, pageSize: 10, mallId: '', from: '0', productName: '', productSkcIds: '', total: 0},
|
||||
productColConfigs: [
|
||||
{ type: "selection", width: '70px', align: 'left', fixed: 'left'},
|
||||
{ prop: 'productSpu', label: 'SPU ID', align: 'left' },
|
||||
@@ -189,13 +265,27 @@ import { Message } from 'element-ui'
|
||||
productIds: [],
|
||||
form: {
|
||||
targetMallId: '',
|
||||
targetCatId: []
|
||||
}
|
||||
targetCatId: [],
|
||||
isSemi: false,
|
||||
isSameCategory: true,
|
||||
siteId: []
|
||||
},
|
||||
siteList: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
mallList () {
|
||||
const filteredData = this.$store.state.mallList.filter(item => {
|
||||
return item.isSemiManagedMall == this.form.isSemi
|
||||
})
|
||||
|
||||
return filteredData
|
||||
}
|
||||
},
|
||||
|
||||
created () {
|
||||
this.getList()
|
||||
this.getSiteList()
|
||||
if (this.$store.state.mallList.length > 0) {
|
||||
this.productPage.mallId = this.$store.state.mallList[0].mallId
|
||||
}
|
||||
@@ -203,7 +293,7 @@ import { Message } from 'element-ui'
|
||||
|
||||
methods: {
|
||||
getList () {
|
||||
this.$http.post('/api/product/myPage',null,{
|
||||
this.$http.post('/api/product/myPage?type=0',null,{
|
||||
params: {
|
||||
...this.search
|
||||
}
|
||||
@@ -212,6 +302,19 @@ import { Message } from 'element-ui'
|
||||
this.total = res.data.total
|
||||
})
|
||||
},
|
||||
getSiteList() {
|
||||
sendChromeAPIMessage({
|
||||
url: 'bg-visage-mms/config/common/site/query',
|
||||
needMallId: true,
|
||||
mallId: this.$store.state.mallList[0].mallId,
|
||||
data: {}}).then((res) => {
|
||||
if (res.success) {
|
||||
this.siteList = res.result.siteBaseList.filter(item => {
|
||||
return item.matchSemiManaged
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
remove () {
|
||||
if (this.ids.length <= 0) {
|
||||
alert('请选择要删除的商品');
|
||||
@@ -239,7 +342,7 @@ import { Message } from 'element-ui'
|
||||
// 添加模板
|
||||
handleClose() {
|
||||
this.productTableData = []
|
||||
this.productPage = {page: 1, pageSize: 10, total: 0}
|
||||
this.productPage = {page: 1, pageSize: 10, from: '0', total: 0}
|
||||
this.dlgShow = false
|
||||
},
|
||||
toAddTemplate() {
|
||||
@@ -252,10 +355,46 @@ import { Message } from 'element-ui'
|
||||
return;
|
||||
}
|
||||
this.dlgShow = true
|
||||
this.getProductList()
|
||||
this.getProductOrDraftList()
|
||||
}
|
||||
})
|
||||
},
|
||||
getProductOrDraftList() {
|
||||
if (this.productPage.from == '0') {
|
||||
this.getProductList()
|
||||
} else {
|
||||
this.getDraftList()
|
||||
}
|
||||
},
|
||||
getDraftList() {
|
||||
let params = {};
|
||||
params.page = this.productPage.page;
|
||||
params.pageSize = this.productPage.pageSize;
|
||||
if (this.productPage.productName) {
|
||||
params.productName = this.productPage.productName
|
||||
}
|
||||
sendChromeAPIMessage({
|
||||
url: 'bg-visage-mms/product/draft/pageQuery',
|
||||
needMallId: true,
|
||||
mallId: this.productPage.mallId,
|
||||
data: {
|
||||
...params
|
||||
}}).then((res) => {
|
||||
if (res.errorCode == 1000000) {
|
||||
this.productPage.total = res.result.total
|
||||
this.productTableData = res.result.pageItems.map((item) => {
|
||||
return {
|
||||
productSpu: item.productDraftId,
|
||||
productSkc: '',
|
||||
productName: item.productName,
|
||||
createTime: timestampToTime(item.updatedAt)
|
||||
};
|
||||
})
|
||||
} else {
|
||||
this.getDraftList()
|
||||
}
|
||||
});
|
||||
},
|
||||
getProductList() {
|
||||
let params = {};
|
||||
params.page = this.productPage.page;
|
||||
@@ -301,11 +440,15 @@ import { Message } from 'element-ui'
|
||||
}
|
||||
this.productIds.map((productSpu, index) => {
|
||||
setTimeout(() => {
|
||||
this.saveTemplate(productSpu, index)
|
||||
if (this.productPage.from == '0') {
|
||||
this.saveProductTemplate(productSpu, index)
|
||||
} else {
|
||||
this.saveDraftTemplate(productSpu, index)
|
||||
}
|
||||
}, 200 * index)
|
||||
})
|
||||
},
|
||||
saveTemplate(spu, index) {
|
||||
saveProductTemplate(spu, index) {
|
||||
sendChromeAPIMessage({
|
||||
url: 'bg-visage-mms/product/query',
|
||||
needMallId: true,
|
||||
@@ -324,6 +467,7 @@ import { Message } from 'element-ui'
|
||||
mallName: mallInfo[0].mallName,
|
||||
productSpu: res.result.productId,
|
||||
productName: res.result.productName,
|
||||
type: 0,
|
||||
content: content
|
||||
}).then(res1 => {
|
||||
if (res1.code == 0) {
|
||||
@@ -334,7 +478,40 @@ import { Message } from 'element-ui'
|
||||
}
|
||||
})
|
||||
} else {
|
||||
this.saveTemplate(spu, index)
|
||||
this.saveProductTemplate(spu, index)
|
||||
}
|
||||
})
|
||||
},
|
||||
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)
|
||||
}
|
||||
})
|
||||
},
|
||||
@@ -348,49 +525,82 @@ import { Message } from 'element-ui'
|
||||
addToDraft() {
|
||||
this.$refs.form.validate((valid) => {
|
||||
if (valid) {
|
||||
this.ids.map((id, index) => {
|
||||
let product = this.tableData.filter((item) => {
|
||||
return item.id == id
|
||||
})
|
||||
setTimeout(() => {
|
||||
sendChromeAPIMessage({
|
||||
url: 'bg-visage-mms/product/draft/add',
|
||||
needMallId: true,
|
||||
mallId: this.form.targetMallId,
|
||||
data: {
|
||||
catId: this.form.targetCatId[this.form.targetCatId.length - 1]
|
||||
}}).then((res) => {
|
||||
if (res.errorCode == 1000000) {
|
||||
let draftId = res.result.productDraftId
|
||||
let content = JSON.parse(product[0].content)
|
||||
let i = 0
|
||||
for (; i < this.form.targetCatId.length; i++) {
|
||||
content['cat' + (i+1) + 'Id'] = this.form.targetCatId[i]
|
||||
}
|
||||
for (; i < 10; i++) {
|
||||
content['cat' + (i+1) + 'Id'] = ''
|
||||
}
|
||||
content.productDraftId = draftId
|
||||
sendChromeAPIMessage({
|
||||
url: 'bg-visage-mms/product/draft/save',
|
||||
needMallId: true,
|
||||
mallId: this.form.targetMallId,
|
||||
data: {
|
||||
...content
|
||||
}}).then((res) => {
|
||||
if (res.errorCode == 1000000) {
|
||||
Message.success("商品【" + product[0].productName + "】成功添加到草稿箱")
|
||||
}
|
||||
})
|
||||
} else {
|
||||
Message.error("【拼多多】" + res.errorMsg)
|
||||
}
|
||||
})
|
||||
}, 1000*index)
|
||||
})
|
||||
this.beginAddToDraft()
|
||||
|
||||
this.mallDlgShow = false
|
||||
}
|
||||
})
|
||||
},
|
||||
async beginAddToDraft() {
|
||||
for (let xx = 0 ; xx < this.ids.length; xx++) {
|
||||
let id = this.ids[xx]
|
||||
let product = this.tableData.filter((item) => {
|
||||
return item.id == id
|
||||
})
|
||||
let content = JSON.parse(product[0].content)
|
||||
let category = null
|
||||
if (this.form.isSameCategory) {
|
||||
let i = 1
|
||||
while(true) {
|
||||
if (!content['cat'+i+'Id']) {
|
||||
break
|
||||
}
|
||||
i++
|
||||
}
|
||||
category = content['cat'+(i-1)+'Id']
|
||||
} else {
|
||||
category = this.form.targetCatId[this.form.targetCatId.length - 1]
|
||||
}
|
||||
let data = {catId: category}
|
||||
if (this.form.isSemi) {
|
||||
data.productSemiManagedReq = {
|
||||
bindSiteIds: this.form.siteId
|
||||
}
|
||||
}
|
||||
content.personalizationSwitch = content.personalizationSwitch || 0
|
||||
|
||||
for (let kk = 0; kk < this.form.targetMallId.length; kk++) {
|
||||
let res = await sendChromeAPIMessage({
|
||||
url: 'bg-visage-mms/product/draft/add',
|
||||
needMallId: true,
|
||||
mallId: this.form.targetMallId[kk],
|
||||
data: data})
|
||||
if (res.errorCode == 1000000) {
|
||||
let draftId = res.result.productDraftId
|
||||
if (!this.form.isSameCategory) {
|
||||
let i = 0
|
||||
for (; i < this.form.targetCatId.length; i++) {
|
||||
content['cat' + (i+1) + 'Id'] = this.form.targetCatId[i]
|
||||
}
|
||||
for (; i < 10; i++) {
|
||||
content['cat' + (i+1) + 'Id'] = ''
|
||||
}
|
||||
}
|
||||
content.productDraftId = draftId
|
||||
if (this.form.isSemi) {
|
||||
content.productSemiManagedReq = {
|
||||
bindSiteIds: this.form.siteId
|
||||
}
|
||||
}
|
||||
let res1 = await sendChromeAPIMessage({
|
||||
url: 'bg-visage-mms/product/draft/save',
|
||||
needMallId: true,
|
||||
mallId: this.form.targetMallId[kk],
|
||||
data: {
|
||||
...content
|
||||
}})
|
||||
if (res1.errorCode == 1000000) {
|
||||
Message.success("商品【" + product[0].productName + "】成功添加到草稿箱")
|
||||
} else {
|
||||
Message.error(res1.errorMsg)
|
||||
}
|
||||
} else {
|
||||
Message.error("【拼多多】" + res.errorMsg)
|
||||
}
|
||||
|
||||
await this.$sleepSync(500)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
402
src/view/product/CopyProductAliExpress.vue
Normal file
@@ -0,0 +1,402 @@
|
||||
<template>
|
||||
<div>
|
||||
<ai-list class="list" v-loading="isLoading" :element-loading-text="'数据正在加载中……'">
|
||||
<ai-title
|
||||
slot="title"
|
||||
title="商品模板"
|
||||
tips="请先在当前浏览器登录“速卖通跨境卖家中心”,期间保持登录状态"
|
||||
isShowBottomBorder>
|
||||
</ai-title>
|
||||
<template slot="content">
|
||||
<div class="content">
|
||||
<ai-search-bar>
|
||||
<template #left>
|
||||
<el-button type="button" :icon="'el-icon-delete'" :class="'el-button el-button--primary'" @click="remove()">删除</el-button>
|
||||
<el-button type="button" :class="'el-button el-button--primary'" @click="toAddTemplate()">添加商品模板</el-button>
|
||||
<el-button type="button" :class="'el-button el-button--primary'" @click="beforeAddToDraft">添加到草稿箱</el-button>
|
||||
</template>
|
||||
<template #right>
|
||||
<el-button size="small" circle icon="el-icon-refresh-right" @click="getList()"></el-button>
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-table
|
||||
:tableData="tableData"
|
||||
:col-configs="colConfigs"
|
||||
:total="total"
|
||||
style="margin-top: 8px;"
|
||||
:current.sync="search.current" :size.sync="search.size"
|
||||
@selection-change="handleSelectionChange"
|
||||
@getList="getList">
|
||||
</ai-table>
|
||||
</div>
|
||||
</template>
|
||||
</ai-list>
|
||||
|
||||
<el-dialog
|
||||
title="商品列表"
|
||||
:visible.sync="dlgShow"
|
||||
:close-on-click-modal="false"
|
||||
width="80%"
|
||||
:before-close="handleClose">
|
||||
<ai-list class="list">
|
||||
<template slot="content">
|
||||
<div class="content">
|
||||
<ai-search-bar>
|
||||
<template #left>
|
||||
<div class="search-item">
|
||||
<label style="width:90px">模板来源:</label>
|
||||
<el-select v-model="productPage.from" @change="productTableData = [], productPage.total = 0, productPage.page =1, getProductOrDraftList()" placeholder="请选择">
|
||||
<el-option
|
||||
key="0"
|
||||
label="商品列表"
|
||||
value="0">
|
||||
</el-option>
|
||||
<el-option
|
||||
key="1"
|
||||
label="草稿箱列表"
|
||||
value="1">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
<div class="search-item">
|
||||
<label style="width:90px">商品名称:</label>
|
||||
<el-input size="small" placeholder="请输入商品名称" v-model="productPage.productName" @keyup.enter.native="productPage.page =1, getProductList()"></el-input>
|
||||
</div>
|
||||
</template>
|
||||
<template #right>
|
||||
<el-button @click="productPage= {
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
from: '0',
|
||||
productName: '',
|
||||
productSkcIds: ''
|
||||
}, getProductOrDraftList()">重置</el-button>
|
||||
<el-button type="primary" @click="productPage.page =1, getProductOrDraftList()">查询</el-button>
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-table
|
||||
:tableData="productTableData"
|
||||
:col-configs="productColConfigs"
|
||||
:total="productPage.total"
|
||||
:current.sync="productPage.page" :size.sync="productPage.pageSize"
|
||||
style="margin-top: 8px;"
|
||||
@selection-change="productHandleSelectionChange"
|
||||
@getList="getProductOrDraftList">
|
||||
<el-table-column slot="imageUrl" width="120px" label="图片" align="center">
|
||||
<template slot-scope="scope">
|
||||
<div>
|
||||
<el-image :src="scope.row.imageUrl" class="image" :preview-src-list="[scope.row.imageUrl]" />
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
</div>
|
||||
</template>
|
||||
</ai-list>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="dlgShow = false">取 消</el-button>
|
||||
<el-button type="primary" @click="saveProduct">添加到模板</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {sendChromeAPIMessage, sendAliexpressAPIMessage} from '@/api/chromeApi'
|
||||
import {timestampToTime} from '@/utils/date'
|
||||
import {transformShein} from '@/utils/product'
|
||||
import { Message } from 'element-ui'
|
||||
import AiLazyCascader from "@/components/AiLazyCascader.vue"
|
||||
|
||||
export default {
|
||||
name: 'CopyProduct',
|
||||
components: {AiLazyCascader},
|
||||
data () {
|
||||
return {
|
||||
search: {
|
||||
current: 1,
|
||||
size: 10,
|
||||
productName: '',
|
||||
mallName: '',
|
||||
startDate: '',
|
||||
endDate: ''
|
||||
},
|
||||
colConfigs: [
|
||||
{ type: "selection", width: '70px', align: 'left', fixed: 'left'},
|
||||
{ prop: 'productSpu', label: 'SPU', width: 180, align: 'left' },
|
||||
{ prop: 'productName', label: '商品名称', align: 'left' },
|
||||
{ prop: 'createTime', label: '添加时间', width: '180px', fixed: 'right'}
|
||||
],
|
||||
tableData: [],
|
||||
total: 0,
|
||||
ids: [],
|
||||
|
||||
dlgShow: false,
|
||||
productTableData: [],
|
||||
productPage: {page: 1, pageSize: 10, mallId: '', from: '0', productName: '', productSkcIds: '', total: 0},
|
||||
productColConfigs: [
|
||||
{ type: "selection", width: '70px', align: 'left', fixed: 'left'},
|
||||
{ prop: 'productSpu', label: 'SPU ID', width: 180, align: 'left' },
|
||||
{ slot: 'imageUrl', label: '图片', align: 'left' },
|
||||
{ prop: 'productName', label: '商品名称', align: 'left' },
|
||||
{ prop: 'createTime', label: '创建时间', width: 180, align: 'left' }
|
||||
],
|
||||
|
||||
productIds: [],
|
||||
siteList: [],
|
||||
isLoading: false
|
||||
}
|
||||
},
|
||||
|
||||
created () {
|
||||
this.getList()
|
||||
},
|
||||
|
||||
methods: {
|
||||
getList () {
|
||||
this.$http.post('/api/product/myPage?type=1',null,{
|
||||
params: {
|
||||
...this.search
|
||||
}
|
||||
}).then(res => {
|
||||
this.tableData = res.data.records
|
||||
this.total = res.data.total
|
||||
})
|
||||
},
|
||||
remove () {
|
||||
if (this.ids.length <= 0) {
|
||||
alert('请选择要删除的商品');
|
||||
return;
|
||||
}
|
||||
this.$confirm('确定要删除?', '温馨提示', {
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
this.$http.post('/api/product/delByIds',this.ids
|
||||
).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success('删除成功!')
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
handleSelectionChange(val) {
|
||||
this.ids = [];
|
||||
val.forEach(e => {
|
||||
this.ids.push(e.id);
|
||||
});
|
||||
},
|
||||
|
||||
// 添加模板
|
||||
handleClose() {
|
||||
this.productTableData = []
|
||||
this.productPage = {page: 1, pageSize: 10, from: '0', total: 0}
|
||||
this.dlgShow = false
|
||||
},
|
||||
toAddTemplate() {
|
||||
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.dlgShow = true
|
||||
this.getProductOrDraftList()
|
||||
}
|
||||
})
|
||||
},
|
||||
getProductOrDraftList() {
|
||||
if (this.productPage.from == '0') {
|
||||
this.getProductList()
|
||||
} else {
|
||||
this.getDraftList()
|
||||
}
|
||||
},
|
||||
getDraftList() {
|
||||
let params = {};
|
||||
params.page = this.productPage.page;
|
||||
params.pageSize = this.productPage.pageSize;
|
||||
if (this.productPage.productName) {
|
||||
params.productName = this.productPage.productName
|
||||
}
|
||||
sendChromeAPIMessage({
|
||||
url: 'bg-visage-mms/product/draft/pageQuery',
|
||||
needMallId: true,
|
||||
mallId: this.productPage.mallId,
|
||||
data: {
|
||||
...params
|
||||
}}).then((res) => {
|
||||
if (res.errorCode == 1000000) {
|
||||
this.productPage.total = res.result.total
|
||||
this.productTableData = res.result.pageItems.map((item) => {
|
||||
return {
|
||||
productSpu: item.productDraftId,
|
||||
productSkc: '',
|
||||
productName: item.productName,
|
||||
createTime: timestampToTime(item.updatedAt)
|
||||
};
|
||||
})
|
||||
} else {
|
||||
this.getDraftList()
|
||||
}
|
||||
});
|
||||
},
|
||||
async getProductList() {
|
||||
this.isLoading = true
|
||||
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(
|
||||
JSON.stringify({
|
||||
"channelId": "701301",
|
||||
"jsonBody": JSON.stringify({
|
||||
"tab": "online_product",
|
||||
"sort": {},
|
||||
"filter": {
|
||||
"queryCategory": null,
|
||||
"lowerPrice": null,
|
||||
"upperPrice": null,
|
||||
"status": "0",
|
||||
"productId": null,
|
||||
"pagination": {
|
||||
"pageSize": this.productPage.page,
|
||||
"current": this.productPage.pageSize
|
||||
}
|
||||
}
|
||||
}),
|
||||
"from":"SELF",
|
||||
"bizParam":"{\"version\":\"simple\"}"
|
||||
})
|
||||
)
|
||||
let res = await sendAliexpressAPIMessage({
|
||||
url: url
|
||||
})
|
||||
res = JSON.parse(res)
|
||||
this.isLoading = false
|
||||
if (res.ret.indexOf('SUCCESS::调用成功') >= 0) {
|
||||
this.productPage.total = res.data.data.pagination.total
|
||||
this.productTableData = res.data.data.table.dataSource.map((item) => {
|
||||
return {
|
||||
productSpu: item.productId,
|
||||
productName: item.itemDesc.title,
|
||||
imageUrl: item.itemDesc.imageUrl,
|
||||
createTime: timestampToTime(item.selfCreateDesc)
|
||||
};
|
||||
})
|
||||
}
|
||||
},
|
||||
productHandleSelectionChange(val) {
|
||||
this.productIds = [];
|
||||
val.forEach(e => {
|
||||
this.productIds.push(e.productSpu);
|
||||
});
|
||||
},
|
||||
saveProduct() {
|
||||
if (this.productIds.length <= 0) {
|
||||
Message.error('请选择商品');
|
||||
return;
|
||||
}
|
||||
this.productIds.map((productSpu, index) => {
|
||||
setTimeout(() => {
|
||||
if (this.productPage.from == '0') {
|
||||
this.saveProductTemplate(productSpu, index)
|
||||
} else {
|
||||
this.saveDraftTemplate(productSpu, index)
|
||||
}
|
||||
}, 200 * index)
|
||||
})
|
||||
},
|
||||
saveProductTemplate(spu, index) {
|
||||
sendGeiwohuoAPIMessage({
|
||||
url: 'spmp-api-prefix/spmp/product/get_product_detail',
|
||||
data: {
|
||||
spu_name: spu
|
||||
}}).then((res) => {
|
||||
if (res.code == 0) {
|
||||
let content = transformShein(res.info)
|
||||
let productName = res.info.multi_language_name_list.filter(item => {
|
||||
return item.language == 'zh-cn'
|
||||
})
|
||||
console.log(productName)
|
||||
this.$http.post('/api/product/add', {
|
||||
productSpu: res.info.spu_name,
|
||||
productName: productName[0].name,
|
||||
type: 2,
|
||||
content: content
|
||||
}).then(res1 => {
|
||||
if (res1.code == 0) {
|
||||
Message.success("商品【" + productName[0].name + "】成功添加为商品模板")
|
||||
if (index == this.productIds.length - 1) {
|
||||
this.getList()
|
||||
}
|
||||
}
|
||||
})
|
||||
} else {
|
||||
this.saveProductTemplate(spu, index)
|
||||
}
|
||||
})
|
||||
},
|
||||
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 = transformShein(res.info)
|
||||
let productName = res.info.multi_language_name_list.filter(item => {
|
||||
return item.language == 'zh-cn'
|
||||
})
|
||||
this.$http.post('/api/product/add', {
|
||||
productSpu: spu,
|
||||
productName: productName[0].name,
|
||||
content: content,
|
||||
type: 2
|
||||
}).then(res1 => {
|
||||
if (res1.code == 0) {
|
||||
Message.success("商品【" + productName[0].name + "】成功添加为商品模板")
|
||||
if (index == this.productIds.length - 1) {
|
||||
this.getList()
|
||||
}
|
||||
}
|
||||
})
|
||||
} else {
|
||||
this.saveDraftTemplate(spu, index)
|
||||
}
|
||||
})
|
||||
},
|
||||
beforeAddToDraft() {
|
||||
if (this.ids.length <= 0) {
|
||||
Message.error('请选择商品模板');
|
||||
return;
|
||||
}
|
||||
this.addToDraft()
|
||||
},
|
||||
addToDraft() {
|
||||
this.ids.map((id, index) => {
|
||||
let product = this.tableData.filter((item) => {
|
||||
return item.id == id
|
||||
})
|
||||
let content = JSON.parse(product[0].content)
|
||||
setTimeout(() => {
|
||||
sendGeiwohuoAPIMessage({
|
||||
url: 'spmp-api-prefix/spmp/product/save_draft',
|
||||
data: content
|
||||
}).then((res) => {
|
||||
if (res.code == 0) {
|
||||
Message.success("商品【" + product[0].productName + "】成功添加到草稿箱")
|
||||
} else {
|
||||
Message.error(res.errorMsg)
|
||||
}
|
||||
})
|
||||
}, 1000*index)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
</style>
|
||||
486
src/view/product/Draft.vue
Normal file
@@ -0,0 +1,486 @@
|
||||
<template>
|
||||
<div>
|
||||
<ai-list class="list" v-loading="isLoading" :element-loading-text="loadingText">
|
||||
<ai-title
|
||||
slot="title"
|
||||
title="草稿箱管理"
|
||||
tips="请先在当前浏览器登录“拼多多跨境卖家中心”,期间保持登录状态"
|
||||
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>
|
||||
<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>
|
||||
</ai-title>
|
||||
<template slot="content">
|
||||
<div class="content">
|
||||
<ai-search-bar>
|
||||
<template #left>
|
||||
<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>
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-table
|
||||
:tableData="tableData"
|
||||
:col-configs="colConfigs"
|
||||
style="margin-top: 8px;"
|
||||
@selection-change="handleSelectionChange"
|
||||
:isShowPagination="false">
|
||||
</ai-table>
|
||||
</div>
|
||||
</template>
|
||||
</ai-list>
|
||||
|
||||
<ai-dialog
|
||||
title="配置参数"
|
||||
:visible.sync="dlgShow"
|
||||
:close-on-click-modal="false"
|
||||
width="790px"
|
||||
customFooter
|
||||
@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="请选择运费模板">
|
||||
<el-option
|
||||
v-for="item in freightTmplList"
|
||||
:key="item.freightTemplateId"
|
||||
:label="item.templateName"
|
||||
:value="item.freightTemplateId">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</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
|
||||
v-for="item in wareHouseList"
|
||||
:key="item.warehouseId"
|
||||
:label="item.warehouseName"
|
||||
:value="item.warehouseId">
|
||||
</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>
|
||||
<el-button type="primary" @click="toBtachSubmit">确定</el-button>
|
||||
</div>
|
||||
</ai-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {sendChromeAPIMessage} from '@/api/chromeApi'
|
||||
import {timestampToTime} from '@/utils/date'
|
||||
import {transformSubmitForHalf} from '@/utils/product'
|
||||
import { Message, MessageBox } from 'element-ui'
|
||||
|
||||
export default {
|
||||
name: 'Draft',
|
||||
data () {
|
||||
return {
|
||||
mallId: '',
|
||||
siteId: '',
|
||||
siteList: [],
|
||||
search: {
|
||||
startPage: 1,
|
||||
endPage: 10,
|
||||
productName: ''
|
||||
},
|
||||
colConfigs: [
|
||||
{ type: "selection", width: '70px', align: 'left', fixed: 'left'},
|
||||
{ prop: 'spuId', label: 'SPU ID', width: '100px', align: 'left' },
|
||||
{ prop: 'productName', label: '商品名称', align: 'left' },
|
||||
{ prop: 'category', label: '商品分类', align: 'left'},
|
||||
{ prop: 'bindSites', label: '经营站点', width: '120px', align: 'left'},
|
||||
{ prop: 'updatedAt', label: '修改时间', width: '180px', fixed: 'right'}
|
||||
],
|
||||
isLoading: false,
|
||||
page: 1,
|
||||
pageSize: 100,
|
||||
tableData: [],
|
||||
|
||||
dlgShow: false,
|
||||
|
||||
configForm: {
|
||||
sendGoodsSecond: 172800,
|
||||
freightTemplateId: '',
|
||||
stockNumber: 5,
|
||||
siteList: [],
|
||||
upMoney: 0.0,
|
||||
wareHouseList: [],
|
||||
brandId: '',
|
||||
brandName: ''
|
||||
},
|
||||
|
||||
wareHouseList: [],
|
||||
freightTmplList: [],
|
||||
|
||||
ids: [],
|
||||
|
||||
sites: [],
|
||||
loadingText: '拼命加载中……',
|
||||
|
||||
successNumber: 0,
|
||||
errorNumber: 0,
|
||||
brandList: [],
|
||||
selectBrand: {}
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.getSiteList()
|
||||
},
|
||||
|
||||
methods: {
|
||||
toLoad() {
|
||||
if (!this.mallId) {
|
||||
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,
|
||||
mallId: this.mallId,
|
||||
data: {
|
||||
page: this.page,
|
||||
pageSize: this.pageSize,
|
||||
...this.search,
|
||||
bindSiteIds: sites
|
||||
}})
|
||||
|
||||
if (res.success && res.errorCode == 1000000) {
|
||||
res.result.pageItems.map(item => {
|
||||
let category = ''
|
||||
for (let i = 1; i < 11; i++) {
|
||||
if (item.categories['cat'+i].catName) {
|
||||
category += '->' + item.categories['cat'+i].catName
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
category = category.substring(2)
|
||||
let site = []
|
||||
let siteId = []
|
||||
item.copyFromFullyToSemiInfo.bindSites.map(item1 => {
|
||||
site.push(item1.siteName)
|
||||
siteId.push(item1.siteId)
|
||||
})
|
||||
this.tableData.push({
|
||||
spuId: item.productDraftId,
|
||||
productName: item.productName,
|
||||
category: category,
|
||||
bindSites: site.join(','),
|
||||
bindSiteIds: siteId.join(','),
|
||||
updatedAt: timestampToTime(item.updatedAt)
|
||||
})
|
||||
})
|
||||
|
||||
if (this.page == 1 && res.result.pageItems.length == 0) {
|
||||
this.isLoading = false
|
||||
}
|
||||
else if (res.result.pageItems.length == this.pageSize && this.page < this.search.endPage) {
|
||||
this.page ++
|
||||
this.getDraftList()
|
||||
} else {
|
||||
this.isLoading = false
|
||||
}
|
||||
}
|
||||
},
|
||||
async batchSubmitConfig() {
|
||||
if (this.ids.length <= 0) {
|
||||
Message.error('请选择要提交的商品');
|
||||
return;
|
||||
}
|
||||
|
||||
this.sites = []
|
||||
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
|
||||
this.successNumber = 0
|
||||
this.errorNumber = 0
|
||||
this.submitSpu(0)
|
||||
}
|
||||
})
|
||||
},
|
||||
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,
|
||||
mallId: this.mallId,
|
||||
data: {
|
||||
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})
|
||||
|
||||
if (res1.success && res1.errorCode == 1000000) {
|
||||
this.successNumber += 1
|
||||
} else {
|
||||
this.errorNumber += 1
|
||||
}
|
||||
setTimeout(() => {
|
||||
idx ++
|
||||
this.submitSpu(idx)
|
||||
}, 1000)
|
||||
}
|
||||
},
|
||||
async getFreightTmplList(siteId) {
|
||||
let res = await sendChromeAPIMessage({
|
||||
url: 'bg-visage-mms/freight/template/list',
|
||||
needMallId: true,
|
||||
mallId: this.mallId,
|
||||
data: {
|
||||
siteIds: siteId
|
||||
}})
|
||||
|
||||
if (res.success && res.errorCode == 1000000) {
|
||||
res.result.freightTmplSimpleList.map(item => {
|
||||
this.freightTmplList.push({
|
||||
freightTemplateId: item.freightTemplateId,
|
||||
templateName: item.templateName
|
||||
})
|
||||
})
|
||||
}
|
||||
},
|
||||
async getWareahouseList(siteId) {
|
||||
let res = await sendChromeAPIMessage({
|
||||
url: 'marvel-mms/cn/api/kiana/starlaod/btg/sales/stock/querySiteCanSelectWarehouseList',
|
||||
needMallId: true,
|
||||
mallId: this.mallId,
|
||||
data: {
|
||||
siteIdList: siteId
|
||||
}})
|
||||
|
||||
if (res.success && res.errorCode == 1000000) {
|
||||
res.result.warehouseDTOList.map(item => {
|
||||
item.validWarehouseList.map(item1 => {
|
||||
this.wareHouseList.push({
|
||||
warehouseId: item1.warehouseId,
|
||||
warehouseName: item1.warehouseName
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
},
|
||||
handleSelectionChange(val) {
|
||||
this.ids = [];
|
||||
val.forEach(e => {
|
||||
this.ids.push(e.spuId);
|
||||
});
|
||||
},
|
||||
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
|
||||
})
|
||||
}
|
||||
},
|
||||
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>
|
||||
|
||||
<style scoped lang="scss">
|
||||
</style>
|
||||
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>
|
||||
269
src/view/product/PriceDown.vue
Normal file
@@ -0,0 +1,269 @@
|
||||
<template>
|
||||
<ai-list class="list" v-loading="isLoading" :element-loading-text="loadingText" element-loading-spinner="el-icon-loading">
|
||||
<ai-title
|
||||
slot="title"
|
||||
title="拒绝调价"
|
||||
isShowBottomBorder>
|
||||
</ai-title>
|
||||
<template slot="content">
|
||||
<div class="content">
|
||||
<ai-search-bar>
|
||||
<template #right>
|
||||
<el-button type="primary" @click="toLoad">加载</el-button>
|
||||
<el-button type="primary" @click="beforeRejct">拒绝调价</el-button>
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-card title="数据明细" style="padding-bottom: 40px;">
|
||||
<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="250px" :show-overflow-tooltip='true' label="商品名称" fixed="left">
|
||||
<template slot-scope="scope">
|
||||
<div>
|
||||
<el-image :src="scope.row.image" style="width: 40px; height: 40px" class="image" :preview-src-list="[scope.row.image]" />
|
||||
{{ scope.row.productName }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
</ai-card>
|
||||
</div>
|
||||
<AiDialog
|
||||
title="拒绝原因"
|
||||
:visible.sync="rejectShow"
|
||||
:close-on-click-modal="false"
|
||||
customFooter
|
||||
height="500px"
|
||||
width="500px">
|
||||
<el-form :model="rejectForm" ref="rejectForm" class="form">
|
||||
<el-form-item
|
||||
prop="reason"
|
||||
label="拒绝原因:"
|
||||
:rules="[{ required: true, message: '请输入拒绝原因', trigger: 'blur' }]">
|
||||
<el-input :rows="3" placeholder="请输入拒绝原因" type="textarea" v-model="rejectForm.reason"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="rejectShow = false">关 闭</el-button>
|
||||
<el-button type="primary" @click="toReject">拒绝</el-button>
|
||||
</span>
|
||||
</AiDialog>
|
||||
</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: 'PriceDown',
|
||||
|
||||
data () {
|
||||
return {
|
||||
reqData: {
|
||||
pageInfo: {
|
||||
pageSize: 100,
|
||||
pageNo: 1
|
||||
},
|
||||
status: 1
|
||||
},
|
||||
colConfigs: [
|
||||
{ slot: 'productName', label: '商品名称', width: '250px', align: 'left', fixed: 'left' },
|
||||
{ prop: 'mallName', label: '店铺来源', width: '250px', align: 'left', fixed: 'left' },
|
||||
{ prop: 'priceOrderSn', label: '调价单号', width: '140px', align: 'left', fixed: 'left' },
|
||||
{ prop: 'skcId', label: 'SKC ID', width: '120px', align: 'left' },
|
||||
{ prop: 'skcExtCode', label: 'SKC货号', width: '100px', align: 'left' },
|
||||
{ prop: 'priceBeforeExchange', label: '原申报价格', width: '100px', align: 'left' },
|
||||
{ prop: 'newSupplyPrice', label: '调整后申报价格', width: '100px', align: 'left' },
|
||||
{ prop: 'source', label: '申请来源', width: '120px', align: 'left' },
|
||||
{ prop: 'adjustReason', label: '调价原因', align: 'left' }
|
||||
],
|
||||
loadingText: '',
|
||||
isLoading: false,
|
||||
tableData: [],
|
||||
currentIndex: 0,
|
||||
rejectForm: {
|
||||
reason: ''
|
||||
},
|
||||
rejectShow: false
|
||||
}
|
||||
},
|
||||
components: {
|
||||
JsonExcel
|
||||
},
|
||||
created () {
|
||||
},
|
||||
methods: {
|
||||
beforeGetList() {
|
||||
this.$userCheck().then(() => {
|
||||
this.toLoad()
|
||||
}).catch((err) => {
|
||||
|
||||
})
|
||||
},
|
||||
async toLoad() {
|
||||
if (this.$store.state.mallList.length == 0) {
|
||||
Message.error("请登录卖家中心,如已登录,请刷新助手")
|
||||
return
|
||||
}
|
||||
this.reqData.pageInfo.pageNo = this.startPage
|
||||
this.tableData = []
|
||||
this.currentIndex = 0
|
||||
this.isLoading = true
|
||||
for (let i = 0; i < this.$store.state.mallList.length; i++) {
|
||||
this.reqData.pageInfo.pageNo = 1
|
||||
this.loadingText = `正在加载店铺【${this.$store.state.mallList[i].mallName}】的调价信息`
|
||||
await this.load(this.$store.state.mallList[i])
|
||||
}
|
||||
this.isLoading = false
|
||||
},
|
||||
async load(mallObj) {
|
||||
let res = await sendChromeAPIMessage({
|
||||
url: 'marvel-mms/cn/api/kiana/magneto/price-adjust/page-query',
|
||||
needMallId: true,
|
||||
mallId: mallObj.mallId,
|
||||
anti: true,
|
||||
data: this.reqData})
|
||||
if (res.errorCode == 1000000 && res.result.total > 0) {
|
||||
for(let i = 0;i < res.result.list.length; i++) {
|
||||
let item = res.result.list[i];
|
||||
let data = {};
|
||||
data.id = item.id
|
||||
data.productName = item.productName
|
||||
data.image = item.image
|
||||
data.priceOrderSn = item.priceOrderSn
|
||||
data.skcId = item.skcId
|
||||
data.skcExtCode = item.skcExtCode
|
||||
data.source = item.source
|
||||
data.mallName = mallObj.mallName
|
||||
data.mallId = mallObj.mallId
|
||||
data.adjustReason = item.adjustReason
|
||||
data.newSupplyPrice = item.newSupplyPrice / 100
|
||||
data.num = item.skuInfoItemList.length
|
||||
let skus = []
|
||||
item.skuInfoItemList.map(item => {
|
||||
skus.push(item.productSkuId)
|
||||
})
|
||||
data.skus = skus.join(',')
|
||||
/*for(let k = 0; k < item.skuInfoItemList.length; k++) {
|
||||
data = {...data,
|
||||
productSkuId: item.skuInfoItemList[k].productSkuId,
|
||||
priceBeforeExchange: item.skuInfoItemList[k].priceBeforeExchange / 100,
|
||||
skuExtCode: item.skuInfoItemList[k].skuExtCode,
|
||||
spec: item.skuInfoItemList[k].spec
|
||||
}
|
||||
|
||||
this.tableData.push(data)
|
||||
}*/
|
||||
this.tableData.push(data)
|
||||
|
||||
}
|
||||
if (res.result.list.length == this.reqData.pageInfo.pageSize) {
|
||||
this.reqData.pageInfo.pageNo ++
|
||||
await this.load(mallObj)
|
||||
}
|
||||
}
|
||||
},
|
||||
beforeRejct() {
|
||||
if (this.tableData.length <= 0) {
|
||||
Message.error('请先加载待拒绝调价');
|
||||
return;
|
||||
}
|
||||
this.rejectShow = true
|
||||
},
|
||||
async toReject() {
|
||||
this.$refs.rejectForm.validate(async (valid) => {
|
||||
if (valid) {
|
||||
this.loadingText = '正在拼命处理中~'
|
||||
this.isLoading = true
|
||||
this.rejectShow = false
|
||||
await this.reject()
|
||||
this.isLoading = false
|
||||
}
|
||||
})
|
||||
},
|
||||
async reject() {
|
||||
let rejectIds = []
|
||||
for (let i = 0; i < this.tableData.length; i++) {
|
||||
rejectIds.push(this.tableData[i].id)
|
||||
}
|
||||
for (let j = 0; j < rejectIds.length; j++) {
|
||||
let obj = this.tableData.filter(item => {
|
||||
return item.id == rejectIds[j]
|
||||
})
|
||||
if (obj.length == 0) continue
|
||||
obj = this.tableData.filter(item => {
|
||||
return item.skus == obj[0].skus
|
||||
})
|
||||
let params = {}
|
||||
if (obj.length > 1) {
|
||||
params.adjustId = obj[0].id
|
||||
params.adjustResultMap = {}
|
||||
for (let k = 0; k < obj.length; k++) {
|
||||
params.adjustResultMap[obj[k].id] = 2
|
||||
}
|
||||
params.result = 2
|
||||
} else {
|
||||
params = {
|
||||
adjustId: obj[0].id,
|
||||
reason: this.rejectForm.reason,
|
||||
result: 2
|
||||
}
|
||||
}
|
||||
// console.log(obj[0].mallName, params)
|
||||
let res = await sendChromeAPIMessage({
|
||||
url: 'gmp/bg/magneto/api/price/purchase-adjust/review',
|
||||
needMallId: true,
|
||||
mallId: obj[0].mallId,
|
||||
anti: true,
|
||||
data: params})
|
||||
if (res.success) {
|
||||
this.removeByRejectId(obj)
|
||||
// this.remove(skuIds[j])
|
||||
}
|
||||
await this.$sleepSync(300)
|
||||
}
|
||||
},
|
||||
removeByRejectId(objArr) {
|
||||
for (let j = 0; j < objArr.length; j++) {
|
||||
for (let i = 0; i < this.tableData.length; i++) {
|
||||
if (this.tableData[i].id == objArr[j].id) {
|
||||
this.tableData.splice(i, 1)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</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>
|
||||
364
src/view/product/ProductList.vue
Normal file
@@ -0,0 +1,364 @@
|
||||
<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 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>
|
||||
</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: 'MyNormalOrder',
|
||||
|
||||
data () {
|
||||
return {
|
||||
form: {
|
||||
mallId: ''
|
||||
},
|
||||
startPage: 1,
|
||||
endPage: 10,
|
||||
reqData: {
|
||||
productName: '',
|
||||
page: 1,
|
||||
pageSize: 100,
|
||||
skcSiteStatus: '',
|
||||
bindSiteId: '',
|
||||
certPunishTypes: [],
|
||||
productCertAuditStatuses: [],
|
||||
jitStockQuantitySection: {
|
||||
leftValue: '',
|
||||
rightValue: ''
|
||||
}
|
||||
},
|
||||
options: [
|
||||
{label: '是', value: 1},
|
||||
{label: '否', value: 0}
|
||||
],
|
||||
colConfigs: [
|
||||
{ slot: 'productName', label: '商品名称', width: '180px', align: 'left', fixed: 'left' },
|
||||
{ prop: 'category', 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: 'productSkuId', label: 'SKU ID', width: '120px', align: 'left' },
|
||||
{ prop: 'skcSiteStatus', label: '是否在售', width: '120px', align: 'left' },
|
||||
{ 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' }
|
||||
],
|
||||
isLoading: false,
|
||||
tableData: [],
|
||||
jsonFields: {
|
||||
"商品名称": "productName",
|
||||
"图片": "mainImageUrl",
|
||||
"分类": "category",
|
||||
"SPU ID": "productId",
|
||||
"SKC ID": "productSkcId",
|
||||
"SKU ID": "productSkuId",
|
||||
"是否在售": "skcSiteStatus",
|
||||
"SKC货号": "extCode",
|
||||
"SKU货号": "skuExtCode",
|
||||
"SKU属性": "specName",
|
||||
"库存": "skuStockQuantity",
|
||||
"资质上传状态": "productCertAuditStatus",
|
||||
"合规下架风险": "certPunishType",
|
||||
"申报价格(CNY)": "supplierPrice",
|
||||
"今日销量": "todaySalesVolume",
|
||||
"上架时间": "createdAt"
|
||||
},
|
||||
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()
|
||||
}).catch((err) => {
|
||||
this.form.mallId = ''
|
||||
})
|
||||
},
|
||||
toLoad() {
|
||||
if (!this.form.mallId) {
|
||||
Message.error("请选择店铺")
|
||||
return
|
||||
}
|
||||
if (!this.startPage || (this.startPage < 1)) {
|
||||
Message.error("起始页不能为空,且不能小于1")
|
||||
return
|
||||
}
|
||||
if (!this.endPage || (this.startPage < 1)) {
|
||||
Message.error("结束页不能为空")
|
||||
return
|
||||
}
|
||||
if (this.startPage > this.endPage) {
|
||||
Message.error("起始页不能大于结束页")
|
||||
return
|
||||
}
|
||||
this.reqData.page = this.startPage
|
||||
this.tableData = []
|
||||
this.currentIndex = 0
|
||||
this.isLoading = true
|
||||
this.load()
|
||||
},
|
||||
load() {
|
||||
sendChromeAPIMessage({
|
||||
url: 'bg-visage-mms/product/skc/pageQuery',
|
||||
needMallId: true,
|
||||
mallId: this.form.mallId,
|
||||
anti: true,
|
||||
data: this.reqData}).then((res) => {
|
||||
if (res.errorCode == 1000000) {
|
||||
for(let i = 0;i < res.result.pageItems.length; i++) {
|
||||
let item = res.result.pageItems[i];
|
||||
let data = {};
|
||||
data.productName = item.productName
|
||||
data.mainImageUrl = item.mainImageUrl
|
||||
data.productId = item.productId
|
||||
data.productSkcId = item.productSkcId
|
||||
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++) {
|
||||
if (item.categories['cat'+i].catName) {
|
||||
data.category += '->' + item.categories['cat'+i].catName
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
data.category = data.category.substring(2)
|
||||
|
||||
for(let k = 0; k < item.productSkuSummaries.length; k++) {
|
||||
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 (res.result.pageItems.length == this.reqData.pageSize && this.reqData.page < this.endPage) {
|
||||
this.reqData.page ++
|
||||
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>
|
||||
@@ -1,395 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<ai-list class="list">
|
||||
<ai-title
|
||||
slot="title"
|
||||
title="商品模板"
|
||||
tips="请先在当前浏览器登录“拼多多跨境卖家中心”,期间保持登录状态"
|
||||
isShowBottomBorder>
|
||||
</ai-title>
|
||||
<template slot="content">
|
||||
<div class="content">
|
||||
<ai-search-bar>
|
||||
<template #left>
|
||||
<el-button type="button" :icon="'el-icon-delete'" :class="'el-button el-button--primary'" @click="remove()">删除</el-button>
|
||||
<el-button v-if="$store.state.mallName" type="button" :class="'el-button el-button--primary'" @click="toAddTemplate()">添加商品模板</el-button>
|
||||
<el-button v-if="$store.state.mallName" type="button" :class="'el-button el-button--primary'" @click="beforeAddToDraft">添加到草稿箱</el-button>
|
||||
</template>
|
||||
<template #right>
|
||||
<el-button size="small" circle icon="el-icon-refresh-right" @click="getList()"></el-button>
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-table
|
||||
:tableData="tableData"
|
||||
:col-configs="colConfigs"
|
||||
:total="total"
|
||||
style="margin-top: 8px;"
|
||||
:current.sync="search.current" :size.sync="search.size"
|
||||
@selection-change="handleSelectionChange"
|
||||
@getList="getList">
|
||||
</ai-table>
|
||||
</div>
|
||||
</template>
|
||||
</ai-list>
|
||||
|
||||
<el-dialog
|
||||
title="商品列表"
|
||||
:visible.sync="dlgShow"
|
||||
:close-on-click-modal="false"
|
||||
width="80%"
|
||||
:before-close="handleClose">
|
||||
<ai-list class="list">
|
||||
<template slot="content">
|
||||
<div class="content">
|
||||
<ai-search-bar>
|
||||
<template #left>
|
||||
<div class="search-item">
|
||||
<label style="width:90px">店铺:</label>
|
||||
<el-select v-model="productPage.mallId" @change="productTableData = [], productPage.total = 0, productPage.page =1, getProductList()" placeholder="请选择">
|
||||
<el-option
|
||||
v-for="item in $store.state.mallList"
|
||||
:key="item.mallId"
|
||||
:label="item.mallName"
|
||||
:value="item.mallId">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
<div class="search-item">
|
||||
<label style="width:90px">SKC:</label>
|
||||
<el-input size="small" placeholder="请输入SKC,多个用,隔开" v-model="productPage.productSkcIds" @keyup.enter.native="productPage.page =1, getProductList()"></el-input>
|
||||
</div>
|
||||
<div class="search-item">
|
||||
<label style="width:90px">商品名称:</label>
|
||||
<el-input size="small" placeholder="请输入商品名称" v-model="productPage.productName" @keyup.enter.native="productPage.page =1, getProductList()"></el-input>
|
||||
</div>
|
||||
</template>
|
||||
<template #right>
|
||||
<el-button @click="productPage= {
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
productName: '',
|
||||
productSkcIds: ''
|
||||
}, getProductList()">重置</el-button>
|
||||
<el-button type="primary" @click="search.page =1, getProductList()">查询</el-button>
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-table
|
||||
:tableData="productTableData"
|
||||
:col-configs="productColConfigs"
|
||||
:total="productPage.total"
|
||||
:current.sync="productPage.page" :size.sync="productPage.pageSize"
|
||||
style="margin-top: 8px;"
|
||||
@selection-change="productHandleSelectionChange"
|
||||
@getList="getProductList">
|
||||
</ai-table>
|
||||
</div>
|
||||
</template>
|
||||
</ai-list>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="dlgShow = false">取 消</el-button>
|
||||
<el-button type="primary" @click="saveProduct">添加到模板</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
|
||||
<ai-dialog
|
||||
title="请选择店铺"
|
||||
:visible.sync="mallDlgShow"
|
||||
:close-on-click-modal="false"
|
||||
width="790px"
|
||||
customFooter
|
||||
@close="handleClose">
|
||||
<el-form class="ai-form" :model="form" label-width="120px" ref="form">
|
||||
<el-form-item label="店铺" style="width: 100%;" prop="targetMallId" :rules="[{ required: true, message: '请选择店铺', trigger: 'blur' }]">
|
||||
<el-select style="width: 380px" v-model="form.targetMallId" placeholder="请选择">
|
||||
<el-option
|
||||
v-for="item in $store.state.mallList"
|
||||
:key="item.mallId"
|
||||
:label="item.mallName"
|
||||
:value="item.mallId">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="商品分类" style="width: 100%;" prop="targetCatId" :rules="[{ required: true, message: '请选择商品分类', trigger: 'blur' }]">
|
||||
<el-cascader style="width: 380px" v-model="form.targetCatId" :props="props"></el-cascader>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div class="dialog-footer" slot="footer">
|
||||
<el-button @click="mallDlgShow = false">取 消</el-button>
|
||||
<el-button type="primary" @click="addToDraft">确定</el-button>
|
||||
</div>
|
||||
</ai-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {sendChromeAPIMessage} from '@/api/chromeApi'
|
||||
import {timestampToTime} from '@/utils/date'
|
||||
import {transform} from '@/utils/product'
|
||||
import { Message } from 'element-ui'
|
||||
|
||||
export default {
|
||||
name: 'ReducePrice',
|
||||
|
||||
data () {
|
||||
return {
|
||||
search: {
|
||||
current: 1,
|
||||
size: 10,
|
||||
productName: '',
|
||||
mallName: '',
|
||||
startDate: '',
|
||||
endDate: ''
|
||||
},
|
||||
props: {
|
||||
value: 'catId',
|
||||
label: 'catName',
|
||||
lazy: true,
|
||||
lazyLoad (node, resolve) {
|
||||
sendChromeAPIMessage({
|
||||
url: 'bg-anniston-mms/category/children/list',
|
||||
needMallId: true,
|
||||
data: {
|
||||
parentCatId: node.value || ''
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.errorCode === 1000000) {
|
||||
resolve(res.result.categoryNodeVOS.map(v => {
|
||||
return {
|
||||
...v,
|
||||
leaf: v.isLeaf
|
||||
}
|
||||
}))
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
colConfigs: [
|
||||
{ type: "selection", width: '70px', align: 'left', fixed: 'left'},
|
||||
{ prop: 'productSpu', label: 'SPU', align: 'left' },
|
||||
{ prop: 'productName', label: '商品名称', align: 'left' },
|
||||
{ prop: 'mallName', label: '来源店铺', align: 'left'},
|
||||
{ prop: 'createTime', label: '添加时间', width: '180px', fixed: 'right'}
|
||||
],
|
||||
tableData: [],
|
||||
total: 0,
|
||||
ids: [],
|
||||
|
||||
dlgShow: false,
|
||||
productTableData: [],
|
||||
productPage: {page: 1, pageSize: 10, mallId: '', productName: '', productSkcIds: '', total: 0},
|
||||
productColConfigs: [
|
||||
{ type: "selection", width: '70px', align: 'left', fixed: 'left'},
|
||||
{ prop: 'productSpu', label: 'SPU ID', align: 'left' },
|
||||
{ prop: 'productSkc', label: 'SKC ID', align: 'left' },
|
||||
{ prop: 'productName', label: '商品名称', align: 'left' },
|
||||
{ prop: 'createTime', label: '创建时间', align: 'left' }
|
||||
],
|
||||
|
||||
mallDlgShow: false,
|
||||
productIds: [],
|
||||
form: {
|
||||
targetMallId: '',
|
||||
targetCatId: []
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
created () {
|
||||
this.getList()
|
||||
if (this.$store.state.mallList.length > 0) {
|
||||
this.productPage.mallId = this.$store.state.mallList[0].mallId
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
getList () {
|
||||
this.$http.post('/api/product/myPage',null,{
|
||||
params: {
|
||||
...this.search
|
||||
}
|
||||
}).then(res => {
|
||||
this.tableData = res.data.records
|
||||
this.total = res.data.total
|
||||
})
|
||||
},
|
||||
remove () {
|
||||
if (this.ids.length <= 0) {
|
||||
alert('请选择要删除的商品');
|
||||
return;
|
||||
}
|
||||
this.$confirm('确定要删除?', '温馨提示', {
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
this.$http.post('/api/product/delByIds',this.ids
|
||||
).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$message.success('删除成功!')
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
handleSelectionChange(val) {
|
||||
this.ids = [];
|
||||
val.forEach(e => {
|
||||
this.ids.push(e.id);
|
||||
});
|
||||
},
|
||||
|
||||
// 添加模板
|
||||
handleClose() {
|
||||
this.productTableData = []
|
||||
this.productPage = {page: 1, pageSize: 10, total: 0}
|
||||
this.dlgShow = false
|
||||
},
|
||||
toAddTemplate() {
|
||||
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.dlgShow = true
|
||||
this.getProductList()
|
||||
}
|
||||
})
|
||||
},
|
||||
getProductList() {
|
||||
let params = {};
|
||||
params.page = this.productPage.page;
|
||||
params.pageSize = this.productPage.pageSize;
|
||||
if (this.productPage.productName) {
|
||||
params.productName = this.productPage.productName
|
||||
}
|
||||
if (this.productPage.productSkcIds) {
|
||||
params.productSkcIds = this.productPage.productSkcIds.split(',')
|
||||
}
|
||||
sendChromeAPIMessage({
|
||||
url: 'bg-visage-mms/product/skc/pageQuery',
|
||||
needMallId: true,
|
||||
mallId: this.productPage.mallId,
|
||||
data: {
|
||||
...params
|
||||
}}).then((res) => {
|
||||
if (res.errorCode == 1000000) {
|
||||
this.productPage.total = res.result.total
|
||||
this.productTableData = res.result.pageItems.map((item) => {
|
||||
return {
|
||||
productSpu: item.productId,
|
||||
productSkc: item.productSkcId,
|
||||
productName: item.productName,
|
||||
createTime: timestampToTime(item.createdAt)
|
||||
};
|
||||
})
|
||||
} else {
|
||||
Message.error("【拼多多】" + res.errorMsg)
|
||||
}
|
||||
});
|
||||
},
|
||||
productHandleSelectionChange(val) {
|
||||
this.productIds = [];
|
||||
val.forEach(e => {
|
||||
this.productIds.push(e.productSpu);
|
||||
});
|
||||
},
|
||||
saveProduct() {
|
||||
if (this.productIds.length <= 0) {
|
||||
Message.error('请选择商品');
|
||||
return;
|
||||
}
|
||||
this.productIds.map((productSpu, index) => {
|
||||
setTimeout(() => {
|
||||
sendChromeAPIMessage({
|
||||
url: 'bg-visage-mms/product/query',
|
||||
needMallId: true,
|
||||
mallId: this.productPage.mallId,
|
||||
data: {
|
||||
productEditTaskUid: '',
|
||||
productId: productSpu
|
||||
}}).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: res.result.productId,
|
||||
productName: res.result.productName,
|
||||
content: content
|
||||
}).then(res1 => {
|
||||
if (res1.code == 0) {
|
||||
Message.success("商品【" + res.result.productName + "】成功添加为商品模板")
|
||||
if (index == this.productIds.length - 1) {
|
||||
this.getList()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}, 200 * index)
|
||||
})
|
||||
},
|
||||
beforeAddToDraft() {
|
||||
if (this.ids.length <= 0) {
|
||||
Message.error('请选择商品模板');
|
||||
return;
|
||||
}
|
||||
this.mallDlgShow = true
|
||||
},
|
||||
addToDraft() {
|
||||
this.$refs.form.validate((valid) => {
|
||||
if (valid) {
|
||||
this.ids.map((id, index) => {
|
||||
let product = this.tableData.filter((item) => {
|
||||
return item.id == id
|
||||
})
|
||||
setTimeout(() => {
|
||||
sendChromeAPIMessage({
|
||||
url: 'bg-visage-mms/product/draft/add',
|
||||
needMallId: true,
|
||||
mallId: this.form.targetMallId,
|
||||
data: {
|
||||
catId: this.form.targetCatId[this.form.targetCatId.length - 1]
|
||||
}}).then((res) => {
|
||||
if (res.errorCode == 1000000) {
|
||||
let draftId = res.result.productDraftId
|
||||
let content = JSON.parse(product[0].content)
|
||||
let i = 0
|
||||
for (; i < this.form.targetCatId.length; i++) {
|
||||
content['cat' + (i+1) + 'Id'] = this.form.targetCatId[i]
|
||||
}
|
||||
for (; i < 10; i++) {
|
||||
content['cat' + (i+1) + 'Id'] = ''
|
||||
}
|
||||
content.productDraftId = draftId
|
||||
sendChromeAPIMessage({
|
||||
url: 'bg-visage-mms/product/draft/save',
|
||||
needMallId: true,
|
||||
mallId: this.form.targetMallId,
|
||||
data: {
|
||||
...content
|
||||
}}).then((res) => {
|
||||
if (res.errorCode == 1000000) {
|
||||
Message.success("商品【" + product[0].productName + "】成功添加到草稿箱")
|
||||
}
|
||||
})
|
||||
} else {
|
||||
Message.error("【拼多多】" + res.errorMsg)
|
||||
}
|
||||
})
|
||||
}, 1000*index)
|
||||
})
|
||||
this.mallDlgShow = false
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
</style>
|
||||
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>
|
||||
251
src/view/sale/AfterSaleDeductStat.vue
Normal file
@@ -0,0 +1,251 @@
|
||||
<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() + 86400000
|
||||
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)
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
</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>
|
||||
310
src/view/sale/AfterSaleStat.vue
Normal file
@@ -0,0 +1,310 @@
|
||||
<template>
|
||||
<ai-list class="list" v-loading="isLoading" element-loading-text="拼命加载中" element-loading-spinner="el-icon-loading">
|
||||
<ai-title
|
||||
slot="title"
|
||||
title="售后统计"
|
||||
tips="请事先在“成本管理”维护好成本,否则部分计算不准确"
|
||||
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}, 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, skuIds) {
|
||||
let productSkuIds = []
|
||||
let i = (params.page - 1) * params.pageSize
|
||||
let j = 0
|
||||
for (; i < skuIds.length; i++) {
|
||||
productSkuIds.push(skuIds[i])
|
||||
j ++
|
||||
if (j == params.pageSize) break
|
||||
}
|
||||
if (productSkuIds.length == 0) return
|
||||
let res = await sendChromeAPIMessage({
|
||||
url: 'bg-visage-mms/product/skc/pageQuery',
|
||||
needMallId: true,
|
||||
mallId: this.mallId,
|
||||
data: {
|
||||
page: 1,
|
||||
pageSize: params.pageSize,
|
||||
productSkuIds
|
||||
}})
|
||||
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
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
params.page ++
|
||||
await this.getProductList(params, skuIds)
|
||||
}
|
||||
},
|
||||
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>
|
||||
366
src/view/sale/CostManageTemu.vue
Normal file
@@ -0,0 +1,366 @@
|
||||
<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.mallId = ''
|
||||
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.isLoading = true
|
||||
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.isLoading = false
|
||||
this.$message.success('导入成功')
|
||||
this.getList()
|
||||
} else {
|
||||
this.isLoading = false
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
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>
|
||||
428
src/view/sale/ExportBillStatTemu.vue
Normal file
@@ -0,0 +1,428 @@
|
||||
<template>
|
||||
<ai-list class="list" v-loading="isLoading" element-loading-text="拼命加载中" element-loading-spinner="el-icon-loading">
|
||||
<ai-title
|
||||
slot="title"
|
||||
title="账务明细统计"
|
||||
tips="数据来源于“账户资金->对账中心->账务明细”"
|
||||
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">
|
||||
</el-date-picker>
|
||||
</div>
|
||||
<div>
|
||||
<label style="width:90px">店铺:</label>
|
||||
<el-select v-model="mallId" placeholder="请选择" size="small">
|
||||
<el-option
|
||||
v-for="item in $store.state.mallList"
|
||||
:key="item.mallId"
|
||||
:label="item.mallName"
|
||||
:value="item.mallId">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
<el-button type="button" :class="'el-button el-button--primary'" @click="toBeginStat">开始统计</el-button>
|
||||
<el-button type="primary" icon="el-icon-download" @click="downloadPicture">下载图片</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</ai-title>
|
||||
<template slot="content">
|
||||
<div id="app-content">
|
||||
<ai-card title="数据概览" style="padding-bottom: 40px;">
|
||||
<el-divider content-position="center">收入概览</el-divider>
|
||||
<div>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="4">
|
||||
<div>
|
||||
<el-card shadow="always" class="amountItem">
|
||||
<el-statistic
|
||||
group-separator=","
|
||||
:precision="2"
|
||||
:value-style="{color: 'red'}"
|
||||
:value="transIncome + nonSllerDuty"
|
||||
title="总收入"
|
||||
>
|
||||
</el-statistic>
|
||||
</el-card>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<div>
|
||||
<el-card shadow="always" class="amountItem">
|
||||
<el-statistic
|
||||
group-separator=","
|
||||
:precision="2"
|
||||
:value="transIncome"
|
||||
title="交易收入"
|
||||
>
|
||||
</el-statistic>
|
||||
</el-card>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<div>
|
||||
<el-card shadow="always" class="amountItem">
|
||||
<el-statistic
|
||||
group-separator=","
|
||||
:value="nonSllerDuty"
|
||||
:precision="2"
|
||||
title="非商责平台售后补贴金额"
|
||||
>
|
||||
</el-statistic>
|
||||
</el-card>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
<el-divider content-position="center">支出概览</el-divider>
|
||||
<div>
|
||||
<el-row>
|
||||
<el-col :span="4">
|
||||
<div>
|
||||
<el-card shadow="always" class="amountItem">
|
||||
<el-statistic
|
||||
group-separator=","
|
||||
:precision="2"
|
||||
:value-style="{color: 'red'}"
|
||||
:value="logisticAmount+customerOutcome+afterSaleAmount+eprAmount+withdrawAmount"
|
||||
title="总支出"
|
||||
></el-statistic>
|
||||
</el-card>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<div>
|
||||
<el-card shadow="always" class="amountItem">
|
||||
<el-statistic
|
||||
group-separator=","
|
||||
:precision="2"
|
||||
:value="logisticAmount"
|
||||
title="仓储综合服务费"
|
||||
></el-statistic>
|
||||
</el-card>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<div>
|
||||
<el-card shadow="always" class="amountItem">
|
||||
<el-statistic
|
||||
group-separator=","
|
||||
:precision="2"
|
||||
:value="customerOutcome"
|
||||
title="消费者退款金额"
|
||||
></el-statistic>
|
||||
</el-card>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<div>
|
||||
<el-card shadow="always" class="amountItem">
|
||||
<el-statistic
|
||||
group-separator=","
|
||||
:precision="2"
|
||||
:value="afterSaleAmount"
|
||||
title="消费者及履约保障-售后问题"
|
||||
>
|
||||
</el-statistic>
|
||||
</el-card>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<div>
|
||||
<el-card shadow="always" class="amountItem">
|
||||
<el-statistic
|
||||
group-separator=","
|
||||
:precision="2"
|
||||
:value="eprAmount"
|
||||
title="合规EPR物流包装环保费"
|
||||
>
|
||||
</el-statistic>
|
||||
</el-card>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<div>
|
||||
<el-card shadow="always" class="amountItem">
|
||||
<el-statistic
|
||||
group-separator=","
|
||||
:precision="2"
|
||||
:value="withdrawAmount"
|
||||
title="提现"
|
||||
>
|
||||
</el-statistic>
|
||||
</el-card>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</ai-card>
|
||||
</div>
|
||||
<ai-dialog
|
||||
title="提示"
|
||||
:visible.sync="isTipDlgShow"
|
||||
:close-on-click-modal="false"
|
||||
width="790px"
|
||||
customFooter
|
||||
@close="isDlgShow = false">
|
||||
<div style="display: block;height: 30px;">卖家中心出现图形验证码,请前往卖家中心“账户资金->对账中心->账务明细”,随机选择一条数据,点击“查看详情”,处理验证码</div>
|
||||
<div class="dialog-footer" slot="footer">
|
||||
<el-button @click="isTipDlgShow = false">取消</el-button>
|
||||
<el-button style="width: 180px;" @click="toGoon">已验证,继续统计</el-button>
|
||||
<el-button type="primary" @click="gotoValid">前往验证</el-button>
|
||||
</div>
|
||||
</ai-dialog>
|
||||
</template>
|
||||
|
||||
|
||||
</ai-list>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {sendChromeAPIMessage } from '@/api/chromeApi'
|
||||
import { Message } from 'element-ui'
|
||||
import html2canvas from 'html2canvas'
|
||||
|
||||
export default {
|
||||
name: 'ExportBillStatTemu',
|
||||
|
||||
data () {
|
||||
return {
|
||||
mallId: null,
|
||||
dateRange: null,
|
||||
|
||||
transIncome: 0.0,
|
||||
customerOutcome: 0.0,
|
||||
nonSllerDuty: 0.0,
|
||||
afterSaleAmount: 0.0,
|
||||
logisticAmount: 0.0,
|
||||
eprAmount: 0.0,
|
||||
withdrawAmount: 0.0,
|
||||
|
||||
currentPage: 1,
|
||||
pageSize: 100,
|
||||
flowList: [],
|
||||
currentIndex: 0,
|
||||
|
||||
isTipDlgShow: false,
|
||||
|
||||
isLoading: false
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
},
|
||||
methods: {
|
||||
toBeginStat() {
|
||||
if (!this.dateRange) {
|
||||
Message.error("请选择统计时间范围")
|
||||
return
|
||||
}
|
||||
if (!this.mallId) {
|
||||
Message.error("请选择店铺")
|
||||
return
|
||||
}
|
||||
this.$userCheck(this.mallId).then(async () => {
|
||||
this.currentPage = 1
|
||||
this.flowList = []
|
||||
this.isLoading = true
|
||||
|
||||
this.transIncome = 0.0
|
||||
this.customerOutcome = 0.0
|
||||
this.nonSllerDuty = 0.0
|
||||
this.afterSaleAmount = 0.0
|
||||
this.logisticAmount = 0.0
|
||||
this.eprAmount = 0.0
|
||||
this.withdrawAmount = 0.0
|
||||
this.currentIndex = 0
|
||||
|
||||
await this.beginStat()
|
||||
this.nonSllerDuty = Math.round(this.nonSllerDuty * 100) / 100
|
||||
this.isLoading = false
|
||||
}).catch((err) => {
|
||||
this.mallId = ''
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
async beginStat() {
|
||||
let res = await sendChromeAPIMessage({
|
||||
url: 'api/merchant/fund/detail/pageSearch',
|
||||
needMallId: true,
|
||||
mallId: this.mallId,
|
||||
data: {
|
||||
moneyChangeTypeList: [],
|
||||
fundType: [],
|
||||
beginTime: this.dateRange[0].getTime(),
|
||||
endTime: this.dateRange[1].getTime() + 86400*1000 - 1,
|
||||
pageSize: this.pageSize,
|
||||
pageNum: this.currentPage
|
||||
}})
|
||||
if (res.errorCode == 1000000) {
|
||||
this.flowList = this.flowList.concat(res.result.resultList)
|
||||
|
||||
if (res.result.resultList.length == this.pageSize) {
|
||||
this.currentPage ++
|
||||
await this.beginStat()
|
||||
} else {
|
||||
this.currentIndex = 0
|
||||
await this.stat()
|
||||
}
|
||||
}
|
||||
},
|
||||
async stat() {
|
||||
for (; this.currentIndex < this.flowList.length; this.currentIndex++) {
|
||||
if (this.isTipDlgShow) {
|
||||
this.currentIndex --
|
||||
break
|
||||
}
|
||||
if (this.flowList[this.currentIndex].fundType == 100) { // 结算
|
||||
await this.$sleepSync(300)
|
||||
await this.querySattement(this.flowList[this.currentIndex])
|
||||
} else if (this.flowList[this.currentIndex].fundType == 200) { // 提现
|
||||
this.withdrawAmount += this.flowList[this.currentIndex].originAmount / 100
|
||||
} else if (this.flowList[this.currentIndex].fundType == 400 && this.flowList[this.currentIndex].bizType == "deduct_risk_punish") { // 消费者及履约保障-售后问题
|
||||
this.afterSaleAmount += Number(this.flowList[this.currentIndex].amount.replace('¥', ''))
|
||||
} else if (this.flowList[this.currentIndex].fundType == 400 && this.flowList[this.currentIndex].bizType == "deduct_storage_service_fee") { // 仓储综合服务费
|
||||
this.logisticAmount += Number(this.flowList[this.currentIndex].amount.replace('¥', ''))
|
||||
} else if (this.flowList[this.currentIndex].fundType == 400 && this.flowList[this.currentIndex].bizType == "deduct_epr") { // 合规EPR物流包装环保费
|
||||
this.eprAmount += Number(this.flowList[this.currentIndex].amount.replace('¥', ''))
|
||||
}
|
||||
}
|
||||
},
|
||||
async toGoon() {
|
||||
this.isTipDlgShow = false
|
||||
this.isLoading = true
|
||||
await this.stat()
|
||||
},
|
||||
async querySattement(obj) {
|
||||
let res = await sendChromeAPIMessage({
|
||||
url: 'api/merchant/fund/detail/item',
|
||||
needMallId: true,
|
||||
mallId: this.mallId,
|
||||
anti: true,
|
||||
data: {
|
||||
fundType: obj.fundType,
|
||||
batchId: obj.transSn,
|
||||
createdTime: obj.createTime
|
||||
}})
|
||||
if (res.errorCode == 1000000) {
|
||||
for (let i = 0; i < res.result.length; i++) {
|
||||
if (res.result[i].fundItemType == 1) { // 交易收入
|
||||
this.transIncome += Number(res.result[i].amount)
|
||||
} else if (res.result[i].fundItemType == 3) { // 消费者退款金额
|
||||
this.customerOutcome += Number(res.result[i].amount)
|
||||
} else if (res.result[i].fundItemType == 5) { // 非商责平台售后补贴金额
|
||||
this.nonSllerDuty += Number(res.result[i].amount)
|
||||
}
|
||||
}
|
||||
} else if (res.error_code == '54001') {
|
||||
this.isLoading = false
|
||||
this.isTipDlgShow = true
|
||||
}
|
||||
},
|
||||
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);
|
||||
}
|
||||
},
|
||||
gotoValid() {
|
||||
window.open("https://seller.kuajingmaihuo.com/labor/bill", '_blank')
|
||||
}
|
||||
}
|
||||
}
|
||||
</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;
|
||||
}
|
||||
|
||||
.amountItem {
|
||||
margin: 10px;
|
||||
}
|
||||
</style>
|
||||
@@ -3,6 +3,7 @@
|
||||
<ai-title
|
||||
slot="title"
|
||||
title="销售数据"
|
||||
tips="请事先在“成本管理”维护好成本,否则部分计算不准确"
|
||||
isShowBottomBorder>
|
||||
<template #rightBtn>
|
||||
<div class="title-right">
|
||||
@@ -38,53 +39,96 @@
|
||||
</el-select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ai-dialog
|
||||
title="导出SKU历史销量"
|
||||
:visible.sync="downloadSkuSaleNumberDlg"
|
||||
:close-on-click-modal="false"
|
||||
width="790px"
|
||||
append-to-body
|
||||
customFooter
|
||||
@close="handleClose">
|
||||
<el-form class="ai-form" :model="skuDownloadForm" label-width="160px" ref="skuDownloadForm">
|
||||
<el-form-item label="日期范围" style="width: 100%;" prop="date" :rules="[{ required: true, message: '请选择时间范围', trigger: 'blur' }]">
|
||||
<el-date-picker
|
||||
v-model="skuDownloadForm.date"
|
||||
type="daterange"
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期">
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div class="dialog-footer" slot="footer">
|
||||
<el-button @click="downloadSkuSaleNumberDlg = false">取 消</el-button>
|
||||
<el-button type="primary" @click="toDownloadSkuSaleNumber">确定</el-button>
|
||||
</div>
|
||||
</ai-dialog>
|
||||
</template>
|
||||
</ai-title>
|
||||
<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>
|
||||
<h2>可用库存总量(件)</h2>
|
||||
<p>{{ inventoryTotal }}</p>
|
||||
</div>
|
||||
<div class="item">
|
||||
<h2>库存总额</h2>
|
||||
<p>{{ inventoryMoeny }}</p>
|
||||
<h2>可用库存总额</h2>
|
||||
<p>{{ inventoryMoney }}</p>
|
||||
</div>
|
||||
<div class="item">
|
||||
<h2>已收货总量</h2>
|
||||
<p>{{ deliveryTotal }}</p>
|
||||
<h2><span>在途库存总量(件)<el-tooltip
|
||||
effect="dark"
|
||||
content="包括暂不可用库存以及已发货库存"
|
||||
placement="right">
|
||||
<i class="el-icon-question"
|
||||
style="font-size: 16px; vertical-align: middle;"></i>
|
||||
</el-tooltip></span></h2>
|
||||
<p>{{ inroadTotal }}</p>
|
||||
</div>
|
||||
<div class="item">
|
||||
<h2>已收货总货值</h2>
|
||||
<p>{{ deliveryMoeny }}</p>
|
||||
<h2><span>在途库存总额<el-tooltip
|
||||
effect="dark"
|
||||
content="(暂不可用库存+已发货库存)*申报价格"
|
||||
placement="right">
|
||||
<i class="el-icon-question"
|
||||
style="font-size: 16px; vertical-align: middle;"></i>
|
||||
</el-tooltip></span></h2>
|
||||
<p>{{ inroadTotalMoney }}</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>
|
||||
<el-button style="margin-right: 10px;" v-if="type === '0'" type="primary" @click="downloadSaleData">导出数据</el-button>
|
||||
<json-excel
|
||||
:data="list"
|
||||
v-if="type === '0'"
|
||||
:fields="jsonFields"
|
||||
:before-generate = "startDownload"
|
||||
name="销售数据.xls"
|
||||
worksheet="销售统计">
|
||||
<el-button type="primary">导出数据</el-button>
|
||||
:data="skuSaleNumberList"
|
||||
v-show="false"
|
||||
:fields="skuSaleNumberFields"
|
||||
:before-generate = "startSkuSaleNumberDownload"
|
||||
name="SKU历史销量.xls"
|
||||
worksheet="SKU历史销量">
|
||||
<el-button type="primary" id="downloadSkuSaleNumber"></el-button>
|
||||
</json-excel>
|
||||
<el-button type="primary" :disabled="!mallId" @click="toDownload">导出SKU历史销量</el-button>
|
||||
</template>
|
||||
<ai-table
|
||||
ref="table0"
|
||||
:isShowPagination="false"
|
||||
:tableData="list"
|
||||
height="500"
|
||||
:tableData="filteredData"
|
||||
height="700"
|
||||
:col-configs="colConfigs"
|
||||
:total="list.length"
|
||||
:total="filteredData.length"
|
||||
style="margin-top: 8px;"
|
||||
@getList="() => {}">
|
||||
</ai-table>
|
||||
@@ -104,6 +148,7 @@
|
||||
</json-excel>
|
||||
</template>
|
||||
<ai-table
|
||||
ref="table1"
|
||||
:isShowPagination="false"
|
||||
:tableData="last30DaySkuList"
|
||||
height="500"
|
||||
@@ -128,6 +173,7 @@
|
||||
</json-excel>
|
||||
</template>
|
||||
<ai-table
|
||||
ref="table2"
|
||||
:isShowPagination="false"
|
||||
:tableData="last30DaySkcList"
|
||||
height="500"
|
||||
@@ -138,6 +184,8 @@
|
||||
</ai-table>
|
||||
</ai-card>
|
||||
</template>
|
||||
|
||||
|
||||
</ai-list>
|
||||
</template>
|
||||
|
||||
@@ -147,6 +195,8 @@ import {sendChromeAPIMessage} from '@/api/chromeApi'
|
||||
import JsonExcel from 'vue-json-excel'
|
||||
import {formatDate} from '@/utils/date'
|
||||
import { Message } from 'element-ui'
|
||||
import * as XLSX from 'xlsx'
|
||||
import { saveAs } from 'file-saver'
|
||||
|
||||
export default {
|
||||
name: 'ExportSaleData',
|
||||
@@ -160,73 +210,43 @@ import { Message } from 'element-ui'
|
||||
mallName: '',
|
||||
type: '0',
|
||||
isLoading: false,
|
||||
pageSize: 100,
|
||||
pageSize: 50,
|
||||
currentPage: 1,
|
||||
todayTotal: 0,
|
||||
todayMoney: 0.0,
|
||||
profitMoney: 0.0,
|
||||
profitPercent: 0,
|
||||
inventoryTotal: 0,
|
||||
inventoryMoeny: 0.0,
|
||||
deliveryTotal: 0,
|
||||
deliveryMoeny: 0.0,
|
||||
allProductList: [],
|
||||
inventoryMoney: 0.0,
|
||||
inroadTotal: 0,
|
||||
inroadTotalMoney: 0.0,
|
||||
costList: [],
|
||||
startDate: '',
|
||||
endDate: '',
|
||||
skuIds: [],
|
||||
jsonFields: {
|
||||
"商品名称": "productName",
|
||||
"店铺名称": "mallName",
|
||||
"评分": "mark",
|
||||
"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.unavailableWarehouseInventoryNum",
|
||||
"库存数据 - 已发货库存": "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",
|
||||
}
|
||||
|
||||
skuSaleNumberFields: {},
|
||||
skuSaleNumberList: [],
|
||||
downloadSkuSaleNumberDlg: false,
|
||||
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 [
|
||||
{
|
||||
@@ -234,14 +254,16 @@ import { Message } from 'element-ui'
|
||||
label: '商品名称',
|
||||
"show-overflow-tooltip": true,
|
||||
width: '280px',
|
||||
align: 'left'
|
||||
align: 'left',
|
||||
fixed: 'left'
|
||||
},
|
||||
{
|
||||
prop: 'mallName',
|
||||
label: '店铺名称',
|
||||
"show-overflow-tooltip": true,
|
||||
width: '120px',
|
||||
align: 'left'
|
||||
align: 'left',
|
||||
fixed: 'left'
|
||||
},
|
||||
{
|
||||
prop: 'mark',
|
||||
@@ -250,19 +272,29 @@ import { Message } from 'element-ui'
|
||||
width: '80px',
|
||||
align: 'left'
|
||||
},
|
||||
{
|
||||
prop: 'hotTag',
|
||||
label: '是否热销',
|
||||
"show-overflow-tooltip": true,
|
||||
width: '80px',
|
||||
align: 'left'
|
||||
},
|
||||
{
|
||||
prop: 'productId',
|
||||
label: 'SPU',
|
||||
width: '120px',
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
prop: 'productSkcId',
|
||||
label: 'SKC',
|
||||
width: '120px',
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
prop: 'productSkuId',
|
||||
label: 'SKU ID',
|
||||
width: '120px',
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
@@ -273,22 +305,78 @@ import { Message } from 'element-ui'
|
||||
{
|
||||
prop: 'skuExtCode',
|
||||
label: 'SKU货号',
|
||||
width: '120px',
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
prop: 'todaySaleVolume',
|
||||
label: '今日销量',
|
||||
width: '120px',
|
||||
align: 'center',
|
||||
sortable: true,
|
||||
'sort-method': (a, b) => {
|
||||
return a.todaySaleVolume - b.todaySaleVolume
|
||||
}
|
||||
},
|
||||
{
|
||||
prop: 'lastSevenDaysSaleVolume',
|
||||
label: '近7天',
|
||||
width: '120px',
|
||||
align: 'center',
|
||||
sortable: true,
|
||||
'sort-method': (a, b) => {
|
||||
return a.lastSevenDaysSaleVolume - b.lastSevenDaysSaleVolume
|
||||
}
|
||||
},
|
||||
{
|
||||
prop: 'lastThirtyDaysSaleVolume',
|
||||
label: '近30天',
|
||||
width: '120px',
|
||||
align: 'center',
|
||||
sortable: true,
|
||||
'sort-method': (a, b) => {
|
||||
return a.lastThirtyDaysSaleVolume - b.lastThirtyDaysSaleVolume
|
||||
}
|
||||
},
|
||||
{
|
||||
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: '加入站点时长',
|
||||
width: '160px',
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
prop: 'isVerifyPrice',
|
||||
label: '开款核价状态',
|
||||
width: '160px',
|
||||
align: 'center',
|
||||
format: v => v ? '核价通过': '核价未通过 / 无法备货'
|
||||
},
|
||||
{
|
||||
prop: 'supplierPrice',
|
||||
label: '申报价格(CNY)',
|
||||
width: '160px',
|
||||
align: 'center',
|
||||
format: v => v / 100,
|
||||
fixed: "right"
|
||||
@@ -296,8 +384,8 @@ import { Message } from 'element-ui'
|
||||
{
|
||||
prop: 'warehouseInventoryNum',
|
||||
label: '仓内可用库存',
|
||||
width: '160px',
|
||||
align: 'center',
|
||||
fixed: "right",
|
||||
sortable: true,
|
||||
'sort-method': (a, b) => {
|
||||
return a.warehouseInventoryNum - b.warehouseInventoryNum
|
||||
@@ -305,7 +393,8 @@ import { Message } from 'element-ui'
|
||||
},
|
||||
{
|
||||
prop: 'productTotalPrice',
|
||||
label: '库存货值(CNY)',
|
||||
label: '可用库存货值(CNY)',
|
||||
width: '180px',
|
||||
align: 'center',
|
||||
fixed: "right",
|
||||
sortable: true,
|
||||
@@ -317,6 +406,7 @@ import { Message } from 'element-ui'
|
||||
prop: 'purchaseConfig',
|
||||
label: '备货逻辑',
|
||||
align: 'center',
|
||||
width: '120px',
|
||||
fixed: "right",
|
||||
sortable: true,
|
||||
'sort-method': (a, b) => {
|
||||
@@ -328,7 +418,7 @@ import { Message } from 'element-ui'
|
||||
return -1
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
]
|
||||
@@ -457,6 +547,13 @@ import { Message } from 'element-ui'
|
||||
align: 'center',
|
||||
fixed: 'left'
|
||||
},
|
||||
{
|
||||
prop: 'supplierPrice',
|
||||
label: '申报价格',
|
||||
width: '120px',
|
||||
align: 'center',
|
||||
fixed: 'left'
|
||||
},
|
||||
{
|
||||
prop: 'productSkuId',
|
||||
label: 'SKU ID',
|
||||
@@ -506,6 +603,7 @@ import { Message } from 'element-ui'
|
||||
"SKC货号": "skcExtCode",
|
||||
"SKU ID": "productSkuId",
|
||||
"SKU货号": "skuExtCode",
|
||||
"申报价格": "supplierPrice",
|
||||
"图片链接": "productSkcPicture"
|
||||
}
|
||||
|
||||
@@ -535,20 +633,22 @@ import { Message } from 'element-ui'
|
||||
|
||||
methods: {
|
||||
changeDataType() {
|
||||
|
||||
this.$nextTick(() => { //在数据加载完,重新渲染表格
|
||||
this.$refs['table'+this.type].doLayout();
|
||||
})
|
||||
},
|
||||
beforeGetList() {
|
||||
this.list = []
|
||||
this.currentPage = 1
|
||||
this.todayMoney = 0.0
|
||||
this.todayTotal = 0
|
||||
this.inventoryMoeny = 0.0
|
||||
this.profitMoney = 0.0
|
||||
this.profitPercent = 0
|
||||
this.inventoryMoney = 0.0
|
||||
this.inventoryTotal = 0
|
||||
this.deliveryTotal = 0
|
||||
this.deliveryMoeny = 0.0
|
||||
this.allProductList = []
|
||||
this.inroadTotalMoney = 0.0
|
||||
this.inroadTotal = 0
|
||||
if (!this.mallId) {
|
||||
|
||||
Message.error("请先选择店铺")
|
||||
return
|
||||
}
|
||||
@@ -560,34 +660,30 @@ import { Message } from 'element-ui'
|
||||
this.isLoading = true
|
||||
this.$userCheck(this.mallId).then(() => {
|
||||
this.last30DaySkcList = []
|
||||
this.getAllProductList()
|
||||
this.getSkuCostList()
|
||||
this.getList()
|
||||
}).catch((err) => {
|
||||
this.mallId = ''
|
||||
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,
|
||||
anti: true,
|
||||
mallId: this.mallId,
|
||||
data: {
|
||||
pageNo: this.currentPage,
|
||||
@@ -600,12 +696,14 @@ import { Message } from 'element-ui'
|
||||
let item = res.result.subOrderList[i];
|
||||
let data = {};
|
||||
data.productName = item.productName;
|
||||
data.category = item.category;
|
||||
data.productId = item.productId;
|
||||
data.productSkcId = item.productSkcId;
|
||||
data.skcExtCode = item.skcExtCode;
|
||||
data.purchaseConfig = item.purchaseConfig;
|
||||
data.productSkcPicture = item.productSkcPicture;
|
||||
data.mark = item.mark.toFixed(1)
|
||||
data.hotTag = item.hotTag ? '是': '否'
|
||||
data.mallName = this.mallName;
|
||||
|
||||
this.last30DaySkcList.push({
|
||||
@@ -625,26 +723,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.inventoryMoeny += new Number(((item.skuQuantityDetailList[j].supplierPrice / 100) * item.skuQuantityDetailList[j].inventoryNumInfo.warehouseInventoryNum).toFixed(2))
|
||||
this.inventoryMoeny = new Number(this.inventoryMoeny.toFixed(2))
|
||||
this.list.push(data);
|
||||
|
||||
// 计算已发货货值
|
||||
for(let k = 0; k < this.allProductList.length; k++) {
|
||||
if (this.allProductList[k].product_sku_id == data.productSkuId) {
|
||||
this.deliveryMoeny += (item.skuQuantityDetailList[j].supplierPrice / 100) * this.allProductList[k].product_sku_number
|
||||
this.deliveryMoeny = new Number(this.deliveryMoeny.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 ++
|
||||
@@ -652,6 +754,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('销售数据加载完成,可进行导出')
|
||||
|
||||
@@ -677,7 +785,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)
|
||||
@@ -759,6 +868,178 @@ import { Message } from 'element-ui'
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
toDownload() {
|
||||
this.downloadSkuSaleNumberDlg = true
|
||||
},
|
||||
startSkuSaleNumberDownload() {
|
||||
|
||||
},
|
||||
handleClose() {
|
||||
this.downloadSkuSaleNumberDlg = false
|
||||
},
|
||||
async toDownloadSkuSaleNumber() {
|
||||
this.downloadSkuSaleNumberDlg = false
|
||||
this.isLoading = true
|
||||
if (!this.skuDownloadForm.date) {
|
||||
Message.error("请选择时间")
|
||||
return
|
||||
}
|
||||
let beginDateStr = formatDate(this.skuDownloadForm.date[0])
|
||||
let endDateStr = formatDate(this.skuDownloadForm.date[1])
|
||||
|
||||
let temp = {}
|
||||
temp = {
|
||||
'SKC': 'skc',
|
||||
'SKU': 'sku',
|
||||
'SKU货号': 'skuExtCode',
|
||||
'申报价格': 'supplierPrice'
|
||||
}
|
||||
let beginTime = new Date(this.skuDownloadForm.date[0])
|
||||
let endTime = new Date(this.skuDownloadForm.date[1])
|
||||
for (; beginTime.getTime() <= endTime.getTime(); ) {
|
||||
let dateStr = formatDate(endTime)
|
||||
temp[dateStr] = dateStr
|
||||
|
||||
endTime.setDate(endTime.getDate() - 1)
|
||||
}
|
||||
this.skuSaleNumberFields = temp
|
||||
|
||||
let tempSkuList = this.list.filter(item => {
|
||||
return item.onSalesDurationOffline != '-天'
|
||||
})
|
||||
let tempSkuIds = []
|
||||
tempSkuList.map(i => {
|
||||
tempSkuIds.push(i.productSkuId)
|
||||
})
|
||||
|
||||
this.skuSaleNumberList = []
|
||||
this.list.map(item => {
|
||||
if (item.onSalesDurationOffline != '-天') {
|
||||
let temp = {
|
||||
sku: item.productSkuId,
|
||||
skc: item.productSkcId,
|
||||
skuExtCode: item.skuExtCode,
|
||||
supplierPrice: this.getSupplierPrice(item.productSkuId)
|
||||
}
|
||||
beginTime = new Date(this.skuDownloadForm.date[0])
|
||||
endTime = new Date(this.skuDownloadForm.date[1])
|
||||
|
||||
for (; beginTime.getTime() <= endTime.getTime(); ) {
|
||||
let dateStr = formatDate(endTime)
|
||||
temp[dateStr] = 0
|
||||
|
||||
endTime.setDate(endTime.getDate() - 1)
|
||||
}
|
||||
|
||||
this.skuSaleNumberList.push(temp)
|
||||
}
|
||||
})
|
||||
|
||||
let reqSkusIds = [], pageSize = 200
|
||||
for (let i = 0; i < tempSkuIds.length; i++) {
|
||||
reqSkusIds.push(tempSkuIds[i])
|
||||
if (reqSkusIds.length % pageSize == 0 || ((i+1) == tempSkuIds.length)) {
|
||||
let res = await sendChromeAPIMessage({
|
||||
url: 'oms/bg/venom/api/supplier/sales/management/querySkuSalesNumber',
|
||||
needMallId: true,
|
||||
mallId: this.mallId,
|
||||
data: {
|
||||
"productSkuIds": reqSkusIds,
|
||||
"startDate": beginDateStr,
|
||||
"endDate": endDateStr
|
||||
}})
|
||||
|
||||
if (res.success) {
|
||||
res.result.map(item => {
|
||||
for (let i = 0; i < this.skuSaleNumberList.length; i++) {
|
||||
if (this.skuSaleNumberList[i].sku == item.prodSkuId) {
|
||||
this.skuSaleNumberList[i][item.date] = item.salesNumber
|
||||
break
|
||||
}
|
||||
}
|
||||
})
|
||||
} else {
|
||||
this.isLoading = false
|
||||
Message.error("获取SKU历史销量数据失败")
|
||||
break
|
||||
}
|
||||
|
||||
if ((i+1) == tempSkuIds.length) {
|
||||
document.getElementById('downloadSkuSaleNumber').click()
|
||||
this.isLoading = false
|
||||
}
|
||||
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
|
||||
},
|
||||
async downloadSaleData() {
|
||||
let res = await this.$http.post('/api/malluser/info')
|
||||
if (res.code == 0) {
|
||||
this.$store.commit('setUserInfo', res.data)
|
||||
if (res.data.flag != 1) {
|
||||
Message.error('您的账号未激活或已失效,请激活后使用')
|
||||
this.$store.commit('setActiveDlgShow', true)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 假设你有一个表格数据的数组
|
||||
const data = [
|
||||
["商品名称", "SPU", "SKC", "SKU ID", "SKU属性", "SKU货号", "加入站点时长", "图片链接", "申报价格(CNY)", "开款核价状态", "缺货数量",
|
||||
"建议备货量", "可售天数", "库存可售天数", "仓内库存可售天数","近7日用户加购数量", "用户累计加购数量", "已订阅待提醒到货", "销售数据 - 今日",
|
||||
"销售数据 - 近7天", "销售数据 - 近30天", "销售数据 - 今日销售额", "销售数据 - 利润", "销售数据 - 利润率", "库存数据 - 仓内可用库存",
|
||||
"库存数据 - 仓内暂不可用库存", "库存数据 - 已发货库存", "库存数据 - 已下单待发货库存", "库存数据 - 待审核备货库存", "VMI备货单数 - 待发货",
|
||||
"VMI备货单数 - 在途单数", "VMI备货单数 - 发货延迟", "VMI备货单数 - 到货延迟", "非VMI备货单数 - 待发货", "非VMI备货单数 - 在途单数",
|
||||
"非VMI备货单数 - 发货延迟", "非VMI备货单数 - 到货延迟", "备货逻辑", "可用库存货值(CNY)", "在途库存货值(CNY)", "店铺名称", "评分",
|
||||
"是否热销", "生产建议信息 - 建议生产数", "生产建议信息 - 剩余件数", "类目"]
|
||||
]
|
||||
|
||||
this.list.map(item => {
|
||||
data.push([item.productName, item.productId, item.productSkcId, item.productSkuId, item.className, item.skuExtCode, item.onSalesDurationOffline, item.productSkcPicture, item.supplierPrice/ 100, item.isVerifyPrice? '核价通过': '核价未通过 / 无法备货', item.lackQuantity,
|
||||
item.adviceQuantity, item.availableSaleDays, item.availableSaleDaysFromInventory, item.warehouseAvailableSaleDays, item.inCartNumber7d, item.inCardNumber, item.nomsgSubsCntCntSth, item.todaySaleVolume,
|
||||
item.lastSevenDaysSaleVolume, item.lastThirtyDaysSaleVolume, item.saleMoney, item.profitMoney, item.profitPercent, item.inventoryNumInfo?.warehouseInventoryNum,
|
||||
item.inventoryNumInfo?.waitOnShelfNum, item.inventoryNumInfo?.waitReceiveNum, item.inventoryNumInfo?.waitDeliveryInventoryNum, item.inventoryNumInfo?.waitApproveInventoryNum, item.vmiOrderInfo?.waitDeliveryNum,
|
||||
item.vmiOrderInfo?.transportationNum, item.vmiOrderInfo?.deliveryDelayNum, item.vmiOrderInfo?.arrivalDelayNum, item.notVmiOrderInfo?.waitDeliveryNum, item.notVmiOrderInfo?.transportationNum,
|
||||
item.notVmiOrderInfo?.deliveryDelayNum, item.notVmiOrderInfo?.arrivalDelayNum, item.purchaseConfig, item.productTotalPrice, item.inroadTotalPrice, item.mallName, item.mark,
|
||||
item.hotTag, item.adviceProduceNum, item.availableProduceNum, item.category])
|
||||
})
|
||||
|
||||
// 将数据转换为工作表
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
224
src/view/sale/ExportSaleOutData.vue
Normal file
@@ -0,0 +1,224 @@
|
||||
<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">
|
||||
<ai-search-bar>
|
||||
<template #left>
|
||||
<el-radio-group v-model="type" @change="onChange">
|
||||
<el-radio-button label="0">即将售罄</el-radio-button>
|
||||
<el-radio-button label="1">已售罄</el-radio-button>
|
||||
</el-radio-group>
|
||||
</template>
|
||||
<template #right>
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-card title="数据明细" style="padding-bottom: 40px;">
|
||||
<template #right>
|
||||
<json-excel
|
||||
:data="tableData"
|
||||
:fields="jsonFields"
|
||||
:before-generate = "startDownload"
|
||||
name="即将售罄明细.xls"
|
||||
worksheet="即将售罄明细">
|
||||
<el-button type="primary" :disabled="!mallId || (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="() => {}">
|
||||
</ai-table>
|
||||
</ai-card>
|
||||
</template>
|
||||
</ai-list>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {sendChromeAPIMessage} from '@/api/chromeApi'
|
||||
import JsonExcel from 'vue-json-excel'
|
||||
import { Message } from 'element-ui'
|
||||
|
||||
export default {
|
||||
name: 'ExportSaleOutData',
|
||||
|
||||
data () {
|
||||
return {
|
||||
type: '0',
|
||||
isLoading: false,
|
||||
tableData: [],
|
||||
mallId: '',
|
||||
colConfigs: [
|
||||
{ prop: 'productName', label: '商品名称', align: 'left' },
|
||||
{ prop: 'catName', label: '类目', align: 'left' },
|
||||
{ prop: 'productSkcId', label: 'SKC ID', align: 'left' },
|
||||
{ prop: 'skcExtCode', label: 'SKC货号', align: 'left' },
|
||||
{ prop: 'productSkuId', label: 'SKU ID', align: 'left' },
|
||||
{ prop: 'skuExtCode', label: 'SKU货号', align: 'left' },
|
||||
{ prop: 'className', label: 'SKU属性', align: 'left' },
|
||||
{ prop: 'prodSkuPayQtyTotal7d', label: '近7天SKU销量', align: 'left' },
|
||||
{ prop: 'prodSkcPayQtyTotal7d', label: '近7天SKC销量', align: 'left' },
|
||||
{ prop: 'totalStock', label: '仓内可用库存', align: 'left' },
|
||||
{ prop: 'stockNotAvailable', label: '仓内暂不可用库存', align: 'left' },
|
||||
{ prop: 'totalWaitReceiveNum', label: '已发货库存', align: 'left' },
|
||||
{ prop: 'stockAvailable', label: '合计库存', align: 'left' },
|
||||
{ prop: 'stockAvlbDays', label: '库存可售天数', align: 'left' },
|
||||
{ prop: 'p7dSellOutSimuAmount', label: '近7天销售损失(CNY)', align: 'left' },
|
||||
{ prop: 'p7dSellOutSimuAmountRatio', label: '近7天销售损失占比', align: 'left' },
|
||||
{ prop: 'prodSkuPayQtyTotal7d2', label: '近7天sku已支付销量', align: 'left' },
|
||||
{ prop: 'waitDeliverOrderSnList', label: '待发货备货单ID', align: 'left' }
|
||||
],
|
||||
jsonFields: {
|
||||
"商品名称": "productName",
|
||||
"类目": "catName",
|
||||
"SKC ID": "productSkcId",
|
||||
"SKC货号": "skcExtCode",
|
||||
"SKU ID": "productSkuId",
|
||||
"SKU货号": "skuExtCode",
|
||||
"SKU属性": "className",
|
||||
"近7天SKU销量": "prodSkuPayQtyTotal7d",
|
||||
"近7天SKC销量": "prodSkcPayQtyTotal7d",
|
||||
"仓内可用库存": "totalStock",
|
||||
"仓内暂不可用库存": "stockNotAvailable",
|
||||
"已发货库存": "totalWaitReceiveNum",
|
||||
"合计库存": "stockAvailable",
|
||||
"库存可售天数": "stockAvlbDays",
|
||||
"近7天销售损失(CNY)": "p7dSellOutSimuAmount",
|
||||
"近7天销售损失占比": "p7dSellOutSimuAmountRatio",
|
||||
"近7天sku已支付销量": "prodSkuPayQtyTotal7d2",
|
||||
"待发货备货单ID": "waitDeliverOrderSnList"
|
||||
},
|
||||
|
||||
currentPage: 1
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
},
|
||||
|
||||
components: {
|
||||
JsonExcel
|
||||
},
|
||||
|
||||
created () {
|
||||
},
|
||||
|
||||
methods: {
|
||||
onChange (e) {
|
||||
this.tableData = []
|
||||
this.currentPage = 1
|
||||
if (e === '0') {
|
||||
this.getList(1)
|
||||
} else {
|
||||
this.getList(2)
|
||||
}
|
||||
},
|
||||
beforeGetList() {
|
||||
if (!this.mallId) {
|
||||
Message.error("请先选择店铺")
|
||||
return
|
||||
}
|
||||
this.currentPage = 1
|
||||
this.tableData = []
|
||||
this.$userCheck(this.mallId).then(() => {
|
||||
this.isLoading = true
|
||||
if (this.type == '0') {
|
||||
this.getList(1)
|
||||
} else {
|
||||
this.getList(2)
|
||||
}
|
||||
}).catch((err) => {
|
||||
this.mallId = ''
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
getList (detailType) {
|
||||
sendChromeAPIMessage({
|
||||
url: 'marvel-mms/cn/api/kiana/venom/sold/out/querySoldOutDetail',
|
||||
needMallId: true,
|
||||
mallId: this.mallId,
|
||||
anti: true,
|
||||
data: {
|
||||
"pageNo": this.currentPage,
|
||||
"pageSize": 200,
|
||||
"detailType": detailType
|
||||
}}).then((res) => {
|
||||
if (res.errorCode == 1000000) {
|
||||
res.result.soldOutDetailList.map(item => {
|
||||
this.tableData.push({...item,
|
||||
p7dSellOutSimuAmount: item.p7dSellOutSimuAmount/100,
|
||||
p7dSellOutSimuAmountRatio: (item.p7dSellOutSimuAmountRatio * 100).toFixed(2) + '%',
|
||||
waitDeliverOrderSnList: item.waitDeliverOrderSnList.join(',')})
|
||||
})
|
||||
if (200 == res.result.soldOutDetailList.length) {
|
||||
this.currentPage ++
|
||||
setTimeout(() => {
|
||||
this.getList(detailType)
|
||||
}, 1000)
|
||||
} else {
|
||||
this.isLoading = false
|
||||
}
|
||||
} else {
|
||||
setTimeout(() => {
|
||||
this.getList(detailType)
|
||||
}, 1000)
|
||||
}
|
||||
})
|
||||
},
|
||||
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;
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</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>
|
||||
889
src/view/sale/ExportSaleStatTemu.vue
Normal file
@@ -0,0 +1,889 @@
|
||||
<template>
|
||||
<ai-list class="list" v-loading="isLoading" element-loading-text="拼命加载中" element-loading-spinner="el-icon-loading">
|
||||
<ai-title
|
||||
slot="title"
|
||||
title="销售统计"
|
||||
tips="最多只能统计近60天的销售数据"
|
||||
isShowBottomBorder>
|
||||
<template #rightBtn>
|
||||
<div class="title-right">
|
||||
<div>
|
||||
<label style="width:90px">时间范围:</label>
|
||||
<el-date-picker
|
||||
v-model="dateRange"
|
||||
type="daterange"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
format="yyyy-MM-dd"
|
||||
value-format="yyyy-MM-dd">
|
||||
</el-date-picker>
|
||||
</div>
|
||||
<div>
|
||||
<label style="width:90px">店铺:</label>
|
||||
<el-select v-model="mallId" placeholder="请选择" size="small">
|
||||
<el-option
|
||||
v-for="item in $store.state.mallList"
|
||||
:key="item.mallId"
|
||||
:label="item.mallName"
|
||||
:value="item.mallId">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
<el-button type="button" :class="'el-button el-button--primary'" @click="toBeginStat">开始统计</el-button>
|
||||
<el-button type="primary" icon="el-icon-download" @click="downloadPicture">下载图片</el-button>
|
||||
<json-excel
|
||||
:data="skcList"
|
||||
:fields="skcJsonFields"
|
||||
name="SKC销售统计.xls"
|
||||
worksheet="SKC销售统计">
|
||||
<el-button type="primary" icon="el-icon-download">下载SKC统计</el-button>
|
||||
</json-excel>
|
||||
<json-excel
|
||||
:data="skuList"
|
||||
:fields="skuJsonFields"
|
||||
name="SKU销售统计.xls"
|
||||
worksheet="SKU销售统计">
|
||||
<el-button type="primary" icon="el-icon-download">下载SKU统计</el-button>
|
||||
</json-excel>
|
||||
</div>
|
||||
</template>
|
||||
</ai-title>
|
||||
<template slot="content">
|
||||
<div id="app-content">
|
||||
<ai-card title="数据概览" style="padding-bottom: 40px;">
|
||||
<div>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="5">
|
||||
<div>
|
||||
<el-statistic
|
||||
group-separator=","
|
||||
:precision="2"
|
||||
:value="saleAmount"
|
||||
title="销售额"
|
||||
>
|
||||
</el-statistic>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="5">
|
||||
<div>
|
||||
<el-statistic
|
||||
group-separator=","
|
||||
:value="saleCount"
|
||||
title="单量"
|
||||
>
|
||||
</el-statistic>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="5">
|
||||
<div>
|
||||
<el-statistic
|
||||
group-separator=","
|
||||
:precision="2"
|
||||
:value="costAmount"
|
||||
title="成本"
|
||||
></el-statistic>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="5">
|
||||
<div>
|
||||
<el-statistic
|
||||
group-separator=","
|
||||
:precision="2"
|
||||
:value="profitAmount"
|
||||
title="利润"
|
||||
></el-statistic>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<div>
|
||||
<el-statistic
|
||||
group-separator=","
|
||||
:precision="2"
|
||||
:value="profitPercent"
|
||||
title="利润率"
|
||||
>
|
||||
<template slot="suffix">%</template>
|
||||
</el-statistic>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</ai-card>
|
||||
<ai-card title="趋势分析" style="padding-bottom: 40px;">
|
||||
<div>
|
||||
<div id="chart1"></div>
|
||||
</div>
|
||||
</ai-card>
|
||||
<div>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<ai-card title="SKC销售额TOP10排行">
|
||||
<ai-table
|
||||
ref="table0"
|
||||
:isShowPagination="false"
|
||||
:tableData="topSaleAmountSkcList"
|
||||
:col-configs="skcColConfigs"
|
||||
style="margin-top: 8px;">
|
||||
<el-table-column slot="saleAmount" label="销售额">
|
||||
<template slot-scope="scope">
|
||||
<div style="color: red">{{ scope.row.saleAmount }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column slot="profitAmount" label="利润">
|
||||
<template slot-scope="scope">
|
||||
<div>{{ scope.row.profitAmount }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column slot="saleCount" label="单量">
|
||||
<template slot-scope="scope">
|
||||
<div>{{ scope.row.saleCount }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
</ai-card>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<ai-card title="SKC利润TOP10排行">
|
||||
<ai-table
|
||||
ref="table1"
|
||||
:isShowPagination="false"
|
||||
:tableData="topSaleProfitSkcList"
|
||||
:col-configs="skcColConfigs"
|
||||
style="margin-top: 8px;">
|
||||
<el-table-column slot="saleAmount" label="销售额">
|
||||
<template slot-scope="scope">
|
||||
<div>{{ scope.row.saleAmount }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column slot="profitAmount" label="利润">
|
||||
<template slot-scope="scope">
|
||||
<div style="color: red">{{ scope.row.profitAmount }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column slot="saleCount" label="单量">
|
||||
<template slot-scope="scope">
|
||||
<div>{{ scope.row.saleCount }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
</ai-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<ai-card title="SKC单量TOP10排行">
|
||||
<ai-table
|
||||
ref="table2"
|
||||
:isShowPagination="false"
|
||||
:tableData="topSaleCountSkcList"
|
||||
:col-configs="skcColConfigs"
|
||||
style="margin-top: 8px;">
|
||||
<el-table-column slot="saleAmount" label="销售额">
|
||||
<template slot-scope="scope">
|
||||
<div>{{ scope.row.saleAmount }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column slot="profitAmount" label="利润">
|
||||
<template slot-scope="scope">
|
||||
<div>{{ scope.row.profitAmount }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column slot="saleCount" label="单量">
|
||||
<template slot-scope="scope">
|
||||
<div style="color: red">{{ scope.row.saleCount }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
</ai-card>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<ai-card title="SKU销售额TOP10排行">
|
||||
<ai-table
|
||||
ref="table3"
|
||||
:isShowPagination="false"
|
||||
:tableData="topSaleAmountSkuList"
|
||||
:col-configs="skuColConfigs"
|
||||
style="margin-top: 8px;">
|
||||
<el-table-column slot="skuExtCode" label="SKC属性/SKU属性" width="250px" :show-overflow-tooltip="true">
|
||||
<template slot-scope="scope">
|
||||
<div>{{ scope.row.skcExtCode + '/' + scope.row.skuExtCode }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column slot="saleAmount" label="销售额">
|
||||
<template slot-scope="scope">
|
||||
<div style="color: red">{{ scope.row.saleAmount }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column slot="profitAmount" label="利润">
|
||||
<template slot-scope="scope">
|
||||
<div>{{ scope.row.profitAmount }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column slot="saleCount" label="单量">
|
||||
<template slot-scope="scope">
|
||||
<div>{{ scope.row.saleCount }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
</ai-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<ai-card title="SKU利润TOP10排行">
|
||||
<ai-table
|
||||
ref="table4"
|
||||
:isShowPagination="false"
|
||||
:tableData="topSaleProfitSkuList"
|
||||
:col-configs="skuColConfigs"
|
||||
style="margin-top: 8px;">
|
||||
<el-table-column slot="skuExtCode" label="SKC属性/SKU属性" width="250px" :show-overflow-tooltip="true">
|
||||
<template slot-scope="scope">
|
||||
<div>{{ scope.row.skcExtCode + '/' + scope.row.skuExtCode }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column slot="saleAmount" label="销售额">
|
||||
<template slot-scope="scope">
|
||||
<div>{{ scope.row.saleAmount }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column slot="profitAmount" label="利润">
|
||||
<template slot-scope="scope">
|
||||
<div style="color: red">{{ scope.row.profitAmount }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column slot="saleCount" label="单量">
|
||||
<template slot-scope="scope">
|
||||
<div>{{ scope.row.saleCount }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
</ai-card>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<ai-card title="SKU单量TOP10排行">
|
||||
<ai-table
|
||||
ref="table5"
|
||||
:isShowPagination="false"
|
||||
:tableData="topSaleCountSkuList"
|
||||
:col-configs="skuColConfigs"
|
||||
style="margin-top: 8px;">
|
||||
<el-table-column slot="skuExtCode" label="SKC属性/SKU属性" width="250px" :show-overflow-tooltip="true">
|
||||
<template slot-scope="scope">
|
||||
<div>{{ scope.row.skcExtCode + '/' + scope.row.skuExtCode }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column slot="saleAmount" label="销售额">
|
||||
<template slot-scope="scope">
|
||||
<div>{{ scope.row.saleAmount }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column slot="profitAmount" label="利润">
|
||||
<template slot-scope="scope">
|
||||
<div>{{ scope.row.profitAmount }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column slot="saleCount" label="单量">
|
||||
<template slot-scope="scope">
|
||||
<div style="color: red">{{ scope.row.saleCount }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
</ai-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
</ai-list>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {sendChromeAPIMessage } from '@/api/chromeApi'
|
||||
import JsonExcel from 'vue-json-excel'
|
||||
import { Message } from 'element-ui'
|
||||
import {formatDate} from '@/utils/date'
|
||||
import html2canvas from 'html2canvas'
|
||||
import { DualAxes } from '@antv/g2plot'
|
||||
|
||||
export default {
|
||||
name: 'ExportSaleStatTemu',
|
||||
|
||||
data () {
|
||||
return {
|
||||
mallId: null,
|
||||
storeCode: '',
|
||||
|
||||
dateRange: null,
|
||||
|
||||
currentPage: 1,
|
||||
pageSize: 50,
|
||||
productList: [],
|
||||
productCostList: [],
|
||||
saleAmount: 0.0,
|
||||
saleCount: 0,
|
||||
costAmount: 0.0,
|
||||
profitAmount: 0.0,
|
||||
profitPercent: 0.0,
|
||||
deductionAmount: 0.0,
|
||||
skcList: [],
|
||||
skuList: [],
|
||||
|
||||
leftChartData: [],
|
||||
rightChartData: [],
|
||||
|
||||
isLoading: false,
|
||||
|
||||
skcColConfigs: [
|
||||
{ prop: 'skcExtCode', label: 'SKC货号', width: '250px' },
|
||||
{ slot: 'saleAmount', label: '销售额', align: 'center' },
|
||||
{ slot: 'saleCount', label: '单量', align: 'center' },
|
||||
{ prop: 'costAmount', label: '成本', align: 'center'},
|
||||
{ slot: 'profitAmount', label: '利润', align: 'center' }
|
||||
],
|
||||
skcJsonFields: {
|
||||
"SKC": "productSkcId",
|
||||
"SKC货号": "skcExtCode",
|
||||
"销售额": "saleAmount",
|
||||
"单量": "saleCount",
|
||||
"成本": "costAmount",
|
||||
"利润": "profitAmount"
|
||||
},
|
||||
skuColConfigs: [
|
||||
{ slot: 'skuExtCode', label: 'SKC货号/SKU货号' },
|
||||
{ slot: 'saleAmount', label: '销售额', align: 'center' },
|
||||
{ slot: 'saleCount', label: '单量', align: 'center' },
|
||||
{ prop: 'costAmount', label: '成本', align: 'center'},
|
||||
{ slot: 'profitAmount', label: '利润', align: 'center' }
|
||||
],
|
||||
skuJsonFields: {
|
||||
"SKC": "productSkcId",
|
||||
"SKU": "productSkuId",
|
||||
"SKC货号": "skcExtCode",
|
||||
"SKU货号": "skuExtCode",
|
||||
"销售额": "saleAmount",
|
||||
"单量": "saleCount",
|
||||
"成本": "costAmount",
|
||||
"利润": "profitAmount"
|
||||
},
|
||||
|
||||
chartObj: null
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
topSaleAmountSkcList() {
|
||||
const list = Object.assign([], this.skcList)
|
||||
list.sort((a, b) => b.saleAmount - a.saleAmount)
|
||||
return list.slice(0, 10)
|
||||
},
|
||||
topSaleProfitSkcList() {
|
||||
const list = Object.assign([], this.skcList)
|
||||
list.sort((a, b) => b.profitAmount - a.profitAmount)
|
||||
return list.slice(0, 10)
|
||||
},
|
||||
topSaleCountSkcList() {
|
||||
const list = Object.assign([], this.skcList)
|
||||
list.sort((a, b) => b.saleCount - a.saleCount)
|
||||
return list.slice(0, 10)
|
||||
},
|
||||
topSaleAmountSkuList() {
|
||||
const list = Object.assign([], this.skuList)
|
||||
list.sort((a, b) => b.saleAmount - a.saleAmount)
|
||||
return list.slice(0, 10)
|
||||
},
|
||||
topSaleProfitSkuList() {
|
||||
const list = Object.assign([], this.skuList)
|
||||
list.sort((a, b) => b.profitAmount - a.profitAmount)
|
||||
return list.slice(0, 10)
|
||||
},
|
||||
topSaleCountSkuList() {
|
||||
const list = Object.assign([], this.skuList)
|
||||
list.sort((a, b) => b.saleCount - a.saleCount)
|
||||
return list.slice(0, 10)
|
||||
}
|
||||
},
|
||||
|
||||
components: {
|
||||
JsonExcel
|
||||
},
|
||||
mounted () {
|
||||
this.initChart1()
|
||||
},
|
||||
methods: {
|
||||
initChart1 () {
|
||||
this.chartObj = new DualAxes('chart1', {
|
||||
data: [this.leftChartData, this.rightChartData],
|
||||
xField: 'day',
|
||||
yField: ['value', 'value1'],
|
||||
yAxis: {
|
||||
value: {
|
||||
title: {
|
||||
text: '金额'
|
||||
},
|
||||
label: {
|
||||
formatter: (value) => {
|
||||
return `${value}元`;
|
||||
}
|
||||
}
|
||||
},
|
||||
value1: {
|
||||
max: 100,
|
||||
title: {
|
||||
text: '利润率'
|
||||
},
|
||||
label: {
|
||||
formatter: (value) => {
|
||||
return `${value}%`;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
geometryOptions: [
|
||||
{
|
||||
geometry: 'line',
|
||||
color: ['#FF9A49', '#7A8AA1', '#1EEB73', '#C947AE' ],
|
||||
isGroup: true,
|
||||
smooth: true, // 是否平滑
|
||||
seriesField: 'type'
|
||||
},
|
||||
{
|
||||
geometry: 'line',
|
||||
color: ['red' ],
|
||||
lineStyle: {
|
||||
fill: 'red',
|
||||
fillOpacity: 0.5,
|
||||
stroke: 'red',
|
||||
lineWidth: 4,
|
||||
strokeOpacity: 0.7,
|
||||
shadowColor: 'black',
|
||||
shadowBlur: 10,
|
||||
shadowOffsetX: 5,
|
||||
shadowOffsetY: 5,
|
||||
cursor: 'pointer'
|
||||
},
|
||||
isStack: true,
|
||||
smooth: true, // 是否平滑
|
||||
seriesField: 'type', // 指定使用第二个Y轴字段
|
||||
}],
|
||||
});
|
||||
|
||||
this.chartObj.render();
|
||||
},
|
||||
toBeginStat() {
|
||||
if (!this.dateRange) {
|
||||
Message.error("请选择统计时间范围")
|
||||
return
|
||||
}
|
||||
if (!this.mallId) {
|
||||
Message.error("请选择店铺")
|
||||
return
|
||||
}
|
||||
this.$userCheck(this.mallId).then(() => {
|
||||
this.beginStat()
|
||||
}).catch((err) => {
|
||||
this.mallId = ''
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
async beginStat() {
|
||||
this.currentPage = 1
|
||||
this.isLoading = true
|
||||
this.saleAmount = 0.0
|
||||
this.saleCount = 0
|
||||
this.costAmount = 0.0
|
||||
this.profitAmount = 0.0
|
||||
this.profitPercent = 0.0
|
||||
this.productList = []
|
||||
this.productCostList = []
|
||||
this.skcList = []
|
||||
this.skuList = []
|
||||
this.leftChartData = []
|
||||
this.rightChartData = []
|
||||
this.chartObj.changeData([this.leftChartData, this.rightChartData])
|
||||
await this.getProductList()
|
||||
await this.getSkuCostList()
|
||||
await this.getSkuSaleNumber(0)
|
||||
this.leftChartData.sort((a, b) => {
|
||||
let leftDate = new Date(a.day)
|
||||
let rightDate = new Date(b.day)
|
||||
return leftDate.getTime() - rightDate.getTime()
|
||||
})
|
||||
this.leftChartData.map(item => {
|
||||
if (item.type == '销售额' || item.type == '成本' || item.type == '利润') {
|
||||
item.value = Math.round(item.value * 100) / 100
|
||||
}
|
||||
|
||||
if (item.type == '销售额') {
|
||||
this.leftChartData.map(item1 => {
|
||||
if (item1.type == '成本' && item1.day == item.day) {
|
||||
this.rightChartData.push({
|
||||
day: item1.day,
|
||||
value1: Math.round((item.value - item1.value) / item.value * 10000) / 100,
|
||||
type: '利润率'
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
this.rightChartData.sort((a, b) => {
|
||||
let leftDate = new Date(a.day)
|
||||
let rightDate = new Date(b.day)
|
||||
return leftDate.getTime() - rightDate.getTime()
|
||||
})
|
||||
this.skuList = this.skuList.filter(item => {
|
||||
return item.saleCount > 0
|
||||
})
|
||||
|
||||
this.skuList.map(item => {
|
||||
item.saleAmount = Math.round(item.saleAmount * 100) / 100
|
||||
item.costAmount = Math.round(item.costAmount * 100) / 100
|
||||
item.profitAmount = Math.round(item.profitAmount * 100) / 100
|
||||
})
|
||||
this.skuList.map(item => {
|
||||
let flag = false
|
||||
for (let i = 0; i < this.skcList.length; i++) {
|
||||
if (item.productSkcId == this.skcList[i].productSkcId) {
|
||||
this.skcList[i].saleAmount = this.skcList[i].saleAmount + item.saleAmount
|
||||
this.skcList[i].costAmount = this.skcList[i].costAmount + item.costAmount
|
||||
this.skcList[i].saleCount = this.skcList[i].saleCount + item.saleCount
|
||||
this.skcList[i].profitAmount = this.skcList[i].profitAmount + item.profitAmount
|
||||
flag = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if (!flag) {
|
||||
this.skcList.push({
|
||||
productSkcId: item.productSkcId,
|
||||
skcExtCode: item.skcExtCode,
|
||||
saleAmount: item.saleAmount,
|
||||
saleCount: item.saleCount,
|
||||
costAmount: item.costAmount,
|
||||
profitAmount: item.profitAmount,
|
||||
profitPercent: item.profitPercent
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
this.skcList.map(item => {
|
||||
item.saleAmount = Math.round(item.saleAmount * 100) / 100
|
||||
item.costAmount = Math.round(item.costAmount * 100) / 100
|
||||
item.profitAmount = Math.round(item.profitAmount * 100) / 100
|
||||
})
|
||||
this.leftChartData.map(item => {
|
||||
if (item.type == '销售额') {
|
||||
this.saleAmount = this.saleAmount + item.value
|
||||
}
|
||||
if (item.type == '成本') {
|
||||
this.costAmount = this.costAmount + item.value
|
||||
}
|
||||
if (item.type == '利润') {
|
||||
this.profitAmount = this.profitAmount + item.value
|
||||
}
|
||||
if (item.type == '单量') {
|
||||
this.saleCount = this.saleCount + item.value
|
||||
}
|
||||
})
|
||||
this.saleAmount = Math.round(this.saleAmount * 100) / 100
|
||||
this.costAmount = Math.round(this.costAmount * 100) / 100
|
||||
this.profitAmount = Math.round(this.profitAmount * 100) / 100
|
||||
this.profitPercent = Math.round((this.saleAmount - this.costAmount) / this.saleAmount * 10000) / 100
|
||||
this.chartObj.changeData([this.leftChartData, this.rightChartData])
|
||||
this.isLoading = false
|
||||
},
|
||||
getPorductList() {
|
||||
this.$http.post(`/api/skuCost/listAll`, null, {
|
||||
params: {
|
||||
mallId: this.storeCode
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.productList = res.data
|
||||
}
|
||||
})
|
||||
},
|
||||
async getProductList() {
|
||||
let res = await sendChromeAPIMessage({
|
||||
url: 'marvel-mms/cn/api/kiana/venom/sales/management/listWarehouse',
|
||||
needMallId: true,
|
||||
mallId: this.mallId,
|
||||
data: {
|
||||
pageNo: this.currentPage,
|
||||
pageSize: this.pageSize,
|
||||
isLack: 0,
|
||||
priceAdjustRecentDays: 7
|
||||
}})
|
||||
|
||||
if (res.errorCode == 1000000) {
|
||||
for(let i = 0;i < res.result.subOrderList.length; i++) {
|
||||
let item = res.result.subOrderList[i]
|
||||
let data = {}
|
||||
data.productName = item.productName
|
||||
data.productId = item.productId
|
||||
data.productSkcId = item.productSkcId
|
||||
data.skcExtCode = item.skcExtCode
|
||||
for(let j = 0;j < item.skuQuantityDetailList.length; j++) {
|
||||
data = {...data,
|
||||
skuExtCode: item.skuQuantityDetailList[j].skuExtCode,
|
||||
supplierPrice: item.skuQuantityDetailList[j].supplierPrice / 100,
|
||||
productSkuId: item.skuQuantityDetailList[j].productSkuId,
|
||||
className: item.skuQuantityDetailList[j].className
|
||||
}
|
||||
this.productList.push(data)
|
||||
}
|
||||
}
|
||||
|
||||
if ((this.currentPage * this.pageSize) < res.result.total) {
|
||||
this.currentPage ++
|
||||
await this.getProductList()
|
||||
}
|
||||
} else {
|
||||
await this.getProductList()
|
||||
}
|
||||
},
|
||||
async getSkuSaleNumber (page) {
|
||||
let tempSkuId = []
|
||||
let i = page * 500
|
||||
let j = 0
|
||||
for (; i < this.productList.length; i++) {
|
||||
tempSkuId.push(this.productList[i].productSkuId)
|
||||
j ++
|
||||
if (j == 500) break
|
||||
}
|
||||
if (tempSkuId.length == 0) return
|
||||
let res = await sendChromeAPIMessage({
|
||||
url: 'oms/bg/venom/api/supplier/sales/management/querySkuSalesNumber',
|
||||
needMallId: true,
|
||||
mallId: this.mallId,
|
||||
data: {
|
||||
productSkuIds: tempSkuId,
|
||||
startDate: this.dateRange[0],
|
||||
endDate: this.dateRange[1]
|
||||
}})
|
||||
if (res.errorCode == 1000000) {
|
||||
for (let i = 0; i < res.result.length; i++) {
|
||||
let cost = this.getCost(res.result[i].prodSkuId)
|
||||
|
||||
let flag = false
|
||||
// 计算每日销售额
|
||||
let skuObj = 0
|
||||
for (let k = 0; k < this.productList.length; k++) {
|
||||
if (this.productList[k].productSkuId == res.result[i].prodSkuId) {
|
||||
skuObj = this.productList[k]
|
||||
break
|
||||
}
|
||||
}
|
||||
for (let j = 0; j < this.leftChartData.length; j++) {
|
||||
if (this.leftChartData[j].type == '销售额' && this.leftChartData[j].day == res.result[i].date) {
|
||||
this.leftChartData[j].value = this.leftChartData[j].value + skuObj.supplierPrice * res.result[i].salesNumber
|
||||
flag = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if (!flag) {
|
||||
this.leftChartData.push({
|
||||
type: '销售额',
|
||||
value: skuObj.supplierPrice * res.result[i].salesNumber,
|
||||
day: res.result[i].date
|
||||
})
|
||||
}
|
||||
|
||||
// 计算每日销量
|
||||
flag = false
|
||||
for (let j = 0; j < this.leftChartData.length; j++) {
|
||||
if (this.leftChartData[j].type == '单量' && this.leftChartData[j].day == res.result[i].date) {
|
||||
this.leftChartData[j].value = this.leftChartData[j].value + res.result[i].salesNumber
|
||||
flag = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if (!flag) {
|
||||
this.leftChartData.push({
|
||||
type: '单量',
|
||||
value: res.result[i].salesNumber,
|
||||
day: res.result[i].date
|
||||
})
|
||||
}
|
||||
|
||||
// 计算每日成本
|
||||
flag = false
|
||||
for (let j = 0; j < this.leftChartData.length; j++) {
|
||||
if (this.leftChartData[j].type == '成本' && this.leftChartData[j].day == res.result[i].date) {
|
||||
this.leftChartData[j].value = this.leftChartData[j].value + cost * res.result[i].salesNumber
|
||||
flag = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if (!flag) {
|
||||
this.leftChartData.push({
|
||||
type: '成本',
|
||||
value: cost * res.result[i].salesNumber,
|
||||
day: res.result[i].date
|
||||
})
|
||||
}
|
||||
|
||||
// 计算每日利润
|
||||
flag = false
|
||||
for (let j = 0; j < this.leftChartData.length; j++) {
|
||||
if (this.leftChartData[j].type == '利润' && this.leftChartData[j].day == res.result[i].date) {
|
||||
this.leftChartData[j].value = this.leftChartData[j].value + (skuObj.supplierPrice - cost) * res.result[i].salesNumber
|
||||
flag = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if (!flag) {
|
||||
this.leftChartData.push({
|
||||
type: '利润',
|
||||
value: (skuObj.supplierPrice - cost) * res.result[i].salesNumber,
|
||||
day: res.result[i].date
|
||||
})
|
||||
}
|
||||
|
||||
// 计算SKU维度销售额
|
||||
flag = false
|
||||
for (let j = 0; j < this.skuList.length; j++) {
|
||||
if (this.skuList[j].productSkuId == res.result[i].prodSkuId) {
|
||||
this.skuList[j].saleAmount = this.skuList[j].saleAmount + skuObj.supplierPrice * res.result[i].salesNumber
|
||||
this.skuList[j].costAmount = this.skuList[j].costAmount + cost * res.result[i].salesNumber
|
||||
this.skuList[j].saleCount = this.skuList[j].saleCount + res.result[i].salesNumber
|
||||
this.skuList[j].profitAmount = this.skuList[j].profitAmount + (skuObj.supplierPrice - cost) * res.result[i].salesNumber
|
||||
flag = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if (!flag) {
|
||||
this.skuList.push({
|
||||
productSkcId: skuObj.productSkcId,
|
||||
productSkuId: skuObj.productSkuId,
|
||||
skcExtCode: skuObj.skcExtCode,
|
||||
skuExtCode: skuObj.skuExtCode,
|
||||
saleAmount: skuObj.supplierPrice * res.result[i].salesNumber,
|
||||
costAmount: cost * res.result[i].salesNumber,
|
||||
profitAmount: (skuObj.supplierPrice - cost) * res.result[i].salesNumber,
|
||||
saleCount: res.result[i].salesNumber,
|
||||
profitPercent: Math.round((skuObj.supplierPrice - cost) / skuObj.supplierPrice * 10000) / 100
|
||||
})
|
||||
}
|
||||
}
|
||||
await this.getSkuSaleNumber(page + 1)
|
||||
} else {
|
||||
await this.getSkuSaleNumber(page)
|
||||
}
|
||||
},
|
||||
async getSkuCostList() {
|
||||
let res = await this.$http.post(`/api/skuCost/listAll`, null, {
|
||||
params: {
|
||||
mallId: this.mallId
|
||||
}
|
||||
})
|
||||
if (res.code == 0) {
|
||||
this.productCostList = res.data
|
||||
}
|
||||
},
|
||||
getCost(sku) {
|
||||
for (let i = 0; i < this.productCostList.length; i++) {
|
||||
if (sku == this.productCostList[i].sku) {
|
||||
return this.productCostList[i].costPrice
|
||||
}
|
||||
}
|
||||
return 0
|
||||
},
|
||||
sleepSync(milliseconds) {
|
||||
return new Promise(resolve => setTimeout(resolve, milliseconds));
|
||||
},
|
||||
async downloadPicture() {
|
||||
try {
|
||||
const element = document.getElementById('app-content');
|
||||
const canvas = await html2canvas(element);
|
||||
// 创建一个图片元素
|
||||
const img = new Image();
|
||||
img.src = canvas.toDataURL('image/png');
|
||||
// 添加到body中以便下载
|
||||
document.body.appendChild(img);
|
||||
// 触发下载
|
||||
const a = document.createElement('a');
|
||||
a.style.display = 'none'
|
||||
a.href = img.src;
|
||||
a.download = '销售统计.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>
|
||||
418
src/view/sale/LogisticFee.vue
Normal file
@@ -0,0 +1,418 @@
|
||||
<template>
|
||||
<ai-list class="list" v-loading="isLoading" element-loading-text="拼命加载中" element-loading-spinner="el-icon-loading">
|
||||
<ai-title
|
||||
slot="title"
|
||||
title="物流统计"
|
||||
tips="数据来源于“履约服务账单->明细->缴费记录”"
|
||||
isShowBottomBorder>
|
||||
</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;">
|
||||
<div>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="6">
|
||||
<div>
|
||||
<el-statistic
|
||||
group-separator=","
|
||||
:precision="2"
|
||||
:value="totalLogisticFee"
|
||||
title="物流总费用"
|
||||
>
|
||||
</el-statistic>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<div>
|
||||
<el-statistic
|
||||
title="备货单总数"
|
||||
:value="totalOrders"
|
||||
>
|
||||
</el-statistic>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<div>
|
||||
<el-statistic
|
||||
title="发货时填写总重量(KG)"
|
||||
:value="totalWriteWeight"
|
||||
>
|
||||
</el-statistic>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<div>
|
||||
<el-statistic
|
||||
title="最终计费总重量(KG)"
|
||||
:value="totalFinalWeight"
|
||||
>
|
||||
</el-statistic>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</ai-card>
|
||||
<ai-card title="店铺分布" style="padding-bottom: 40px;">
|
||||
<ai-table
|
||||
:isShowPagination="false"
|
||||
:tableData="tableData"
|
||||
:col-configs="colConfigs"
|
||||
:total="tableData.length"
|
||||
height="500"
|
||||
style="margin-top: 8px;"
|
||||
@getList="() => {}">
|
||||
</ai-table>
|
||||
</ai-card>
|
||||
<ai-card title="运费分布" style="padding-bottom: 40px;">
|
||||
<ai-table
|
||||
:isShowPagination="false"
|
||||
:tableData="logisticTableData"
|
||||
:col-configs="logisticColConfigs"
|
||||
:total="tableData.length"
|
||||
height="500"
|
||||
style="margin-top: 8px;"
|
||||
@getList="() => {}">
|
||||
</ai-table>
|
||||
</ai-card>
|
||||
</div>
|
||||
</template>
|
||||
</ai-list>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Message } from 'element-ui'
|
||||
import {sendChromeAPIMessage } from '@/api/chromeApi'
|
||||
|
||||
export default {
|
||||
name: 'LogisticFee',
|
||||
|
||||
data () {
|
||||
return {
|
||||
searchDate: [],
|
||||
reqData: {
|
||||
pageNum: 1,
|
||||
pageSize: 100
|
||||
},
|
||||
totalLogisticFee: 0.0,
|
||||
totalOrders: 0,
|
||||
totalWriteWeight: 0.0,
|
||||
totalFinalWeight: 0.0,
|
||||
colConfigs: [
|
||||
{ prop: 'mallName', label: '店铺名称', align: 'left' },
|
||||
{ prop: 'wayBillCount', label: '备货单数', align: 'left', sortable: true, 'sort-method': (a, b) => a.wayBillCount - b.wayBillCount },
|
||||
{ prop: 'writeWeight', label: '填写重量(KG)', align: 'left', sortable: true, 'sort-method': (a, b) => a.writeWeight - b.writeWeight },
|
||||
{ prop: 'weight', label: '实际重量(KG)', align: 'left', sortable: true, 'sort-method': (a, b) => a.weight - b.weight },
|
||||
{ prop: 'amount', label: '物流费用', align: 'left', sortable: true, 'sort-method': (a, b) => a.amount - b.amount }
|
||||
],
|
||||
logisticColConfigs: [
|
||||
{ prop: 'company', label: '物流公司', align: 'left' },
|
||||
{ prop: 'writeWeight', label: '填写总重量(KG)', align: 'left', sortable: true, 'sort-method': (a, b) => a.writeWeight - b.writeWeight },
|
||||
{ prop: 'weight', label: '实际总重量(KG)', align: 'left', sortable: true, 'sort-method': (a, b) => a.weight - b.weight },
|
||||
{ prop: 'amount', label: '物流费用', align: 'left', sortable: true, 'sort-method': (a, b) => a.amount - b.amount }
|
||||
],
|
||||
isLoading: false,
|
||||
tableData: [],
|
||||
logisticTableData: [],
|
||||
transList: [],
|
||||
mallWayBillList: [],
|
||||
logisticFeeList: []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
beforeGetList() {
|
||||
this.$userCheck().then(() => {
|
||||
this.toLoad()
|
||||
}).catch((err) => {
|
||||
})
|
||||
},
|
||||
async toLoad() {
|
||||
if (!this.searchDate) {
|
||||
Message.error("请选择时间范围")
|
||||
return
|
||||
}
|
||||
this.reqData.pageNum = 1
|
||||
this.tableData = []
|
||||
this.logisticTableData = []
|
||||
this.isLoading = true
|
||||
this.totalLogisticFee = 0.0
|
||||
this.totalOrders = 0
|
||||
this.totalWriteWeight = 0.0
|
||||
this.totalFinalWeight = 0.0
|
||||
this.transList = []
|
||||
this.mallWayBillList = []
|
||||
this.logisticFeeList = []
|
||||
|
||||
let startTime = this.searchDate[0].getTime()
|
||||
let endTime = this.searchDate[1].getTime() + 86400000 - 1
|
||||
await this.getLogisticFee(startTime, endTime)
|
||||
|
||||
this.totalLogisticFee = Math.round(this.totalLogisticFee * 100)/100
|
||||
this.totalFinalWeight = Math.round(this.totalFinalWeight * 100)/100
|
||||
|
||||
this.isLoading = false
|
||||
|
||||
},
|
||||
async getLogisticFee(startTime, endTime) {
|
||||
let res = await sendChromeAPIMessage({
|
||||
url: `api/merchant/warehouse/express/pay/bill/list`,
|
||||
needMallId: true,
|
||||
mallId: this.$store.state.mallList[0].mallId,
|
||||
data: {
|
||||
...this.reqData,
|
||||
sucTimeStart: startTime,
|
||||
sucTimeEnd: endTime
|
||||
}})
|
||||
if (res.errorCode == 1000000) {
|
||||
for (let i = 0; i < res.result.list.length; i++) {
|
||||
let item = res.result.list[i]
|
||||
this.totalLogisticFee += item.amount
|
||||
|
||||
this.transList.push({ptransId: item.ptransId, chargeType: item.chargeType} )
|
||||
}
|
||||
if ((this.reqData.pageSize * this.reqData.pageNum) < res.result.total) {
|
||||
this.reqData.pageNum ++
|
||||
await this.getLogisticFee(startTime, endTime)
|
||||
} else {
|
||||
await this.getLogisticDetail()
|
||||
await this.getLogisticWeightDetail()
|
||||
this.calcLogiticData()
|
||||
}
|
||||
}
|
||||
},
|
||||
async getLogisticDetail() {
|
||||
for (let i = 0; i < this.transList.length; i++) {
|
||||
let res = await sendChromeAPIMessage({
|
||||
url: `api/merchant/warehouse/express/pay/bill/detail/list`,
|
||||
needMallId: true,
|
||||
mallId: this.$store.state.mallList[0].mallId,
|
||||
data: {
|
||||
chargeType: this.transList[i].chargeType,
|
||||
pageSize: 100,
|
||||
pageNum: 1,
|
||||
ptransId: this.transList[i].ptransId
|
||||
}})
|
||||
if (res.errorCode == 1000000) {
|
||||
for (let k = 0; k < res.result.list.length; k++) {
|
||||
let item = res.result.list[k]
|
||||
let flag = false
|
||||
for (let j = 0; j < this.tableData.length; j++) {
|
||||
if (this.tableData[j].mallId == item.mallId) {
|
||||
flag = true
|
||||
this.tableData[j].amount += item.amount
|
||||
this.tableData[j].wayBillCount += item.wayBillCount
|
||||
|
||||
this.tableData[j].amount = Math.round(this.tableData[j].amount * 100)/100
|
||||
|
||||
this.totalOrders += item.wayBillCount
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (!flag) {
|
||||
this.tableData.push({
|
||||
mallId: item.mallId,
|
||||
mallName: item.mallName,
|
||||
amount: item.amount,
|
||||
wayBillCount: item.wayBillCount,
|
||||
weight: 0.0,
|
||||
writeWeight: 0.0
|
||||
})
|
||||
this.totalOrders += item.wayBillCount
|
||||
}
|
||||
|
||||
await this.getWayBillList(item.transId, item.mallId)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
async getWayBillList(transId, mallId) {
|
||||
let pageNum = 1
|
||||
let pageSize = 100
|
||||
while(true) {
|
||||
let res = await sendChromeAPIMessage({
|
||||
url: `api/merchant/warehouse/express/bill/detail/list`,
|
||||
needMallId: true,
|
||||
mallId: this.$store.state.mallList[0].mallId,
|
||||
data: {
|
||||
pageNum: pageNum,
|
||||
pageSize: pageSize,
|
||||
billStatus: 2,
|
||||
mallId: mallId,
|
||||
transId: transId
|
||||
}})
|
||||
if (res.errorCode == 1000000) {
|
||||
let flag = false
|
||||
for (let i = 0; i < this.logisticFeeList.length; i++) {
|
||||
if (this.logisticFeeList[i].mallId == mallId) {
|
||||
flag = true
|
||||
for (let j = 0; j < res.result.list.length; j++) {
|
||||
this.logisticFeeList[i].billList.push({
|
||||
sn: res.result.list[j].mainWayBillSn,
|
||||
amount: res.result.list[j].amount,
|
||||
company: null,
|
||||
waight: 0.0
|
||||
})
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (!flag) {
|
||||
let temp = {
|
||||
mallId: mallId,
|
||||
billList: []
|
||||
}
|
||||
for (let j = 0; j < res.result.list.length; j++) {
|
||||
temp.billList.push({
|
||||
sn: res.result.list[j].mainWayBillSn,
|
||||
amount: res.result.list[j].amount,
|
||||
company: null,
|
||||
weight: 0.0,
|
||||
writeWeight: 0.0
|
||||
})
|
||||
}
|
||||
this.logisticFeeList.push(temp)
|
||||
}
|
||||
|
||||
if (pageNum * pageSize < res.result.total) {
|
||||
pageNum ++
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
async getLogisticWeightDetail() {
|
||||
for (let i = 0; i < this.logisticFeeList.length; i++) {
|
||||
let page = 1
|
||||
let weight = 0.0
|
||||
let writeWeight = 0.0
|
||||
while(true) {
|
||||
let tempList = []
|
||||
for (let j = (page-1)*20; j < this.logisticFeeList[i].billList.length; j++) {
|
||||
tempList.push(this.logisticFeeList[i].billList[j].sn)
|
||||
|
||||
if (tempList.length % 20 == 0) {
|
||||
break
|
||||
}
|
||||
}
|
||||
if (tempList.length == 0) break
|
||||
|
||||
let res = await sendChromeAPIMessage({
|
||||
url: `bgSongbird-api/supplier/delivery/feedback/queryWaitConfirmWeightExpressList`,
|
||||
needMallId: true,
|
||||
mallId: this.logisticFeeList[i].mallId,
|
||||
anti: true,
|
||||
data: {
|
||||
pageNo: 1,
|
||||
pageSize: 20,
|
||||
platformExpressMainSnList: tempList,
|
||||
displayStatus: 100
|
||||
}})
|
||||
if (res.errorCode == 1000000) {
|
||||
for (let ii = 0; ii < res.result.list.length; ii++) {
|
||||
for (let jj = 0; jj < this.logisticFeeList[i].billList.length; jj++) {
|
||||
if (this.logisticFeeList[i].billList[jj].sn == res.result.list[ii].expressDeliverySn) {
|
||||
this.logisticFeeList[i].billList[jj].company = res.result.list[ii].expressCompany
|
||||
this.logisticFeeList[i].billList[jj].weight = res.result.list[ii].realExpressWeight / 1000
|
||||
this.logisticFeeList[i].billList[jj].writeWeight = res.result.list[ii].predictTotalPackageWeight / 1000
|
||||
|
||||
this.totalFinalWeight += res.result.list[ii].realExpressWeight / 1000
|
||||
this.totalWriteWeight += res.result.list[ii].predictTotalPackageWeight / 1000
|
||||
|
||||
writeWeight += res.result.list[ii].predictTotalPackageWeight / 1000
|
||||
weight += res.result.list[ii].realExpressWeight / 1000
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
page++
|
||||
}
|
||||
}
|
||||
|
||||
for (let kk = 0; kk < this.tableData.length; kk++) {
|
||||
if (this.tableData[kk].mallId == this.logisticFeeList[i].mallId) {
|
||||
this.tableData[kk].weight = Math.round(weight * 100)/100
|
||||
this.tableData[kk].writeWeight = Math.round(writeWeight * 100)/100
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
calcLogiticData() {
|
||||
for (let i = 0; i < this.logisticFeeList.length; i++) {
|
||||
for (let j = 0; j < this.logisticFeeList[i].billList.length; j++) {
|
||||
let flag = false
|
||||
for (let x = 0; x < this.logisticTableData.length; x++) {
|
||||
if (this.logisticTableData[x].company == this.logisticFeeList[i].billList[j].company) {
|
||||
flag = true
|
||||
this.logisticTableData[x].writeWeight += this.logisticFeeList[i].billList[j].writeWeight
|
||||
this.logisticTableData[x].weight += this.logisticFeeList[i].billList[j].weight
|
||||
this.logisticTableData[x].amount += this.logisticFeeList[i].billList[j].amount
|
||||
break
|
||||
}
|
||||
}
|
||||
if (!flag) {
|
||||
console.log(this.logisticFeeList[i].mallId, this.logisticFeeList[i].billList[j], this.logisticFeeList[i].billList[j].company)
|
||||
this.logisticTableData.push({
|
||||
company: this.logisticFeeList[i].billList[j].company,
|
||||
writeWeight: this.logisticFeeList[i].billList[j].writeWeight,
|
||||
weight: this.logisticFeeList[i].billList[j].weight,
|
||||
amount: this.logisticFeeList[i].billList[j].amount,
|
||||
weightPercent: 0.0,
|
||||
amountPercent: 0.0
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
for (let j = 0; j < this.logisticTableData.length; j++) {
|
||||
this.logisticTableData[j].weight = Math.round(this.logisticTableData[j].weight * 100)/100
|
||||
this.logisticTableData[j].amount = Math.round(this.logisticTableData[j].amount * 100)/100
|
||||
|
||||
this.logisticTableData[j].company = this.logisticTableData[j].company || '退回服务费'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</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>
|
||||
256
src/view/sale/PriceAdjustment.vue
Normal file
@@ -0,0 +1,256 @@
|
||||
<template>
|
||||
<ai-list class="list" v-loading="isLoading" element-loading-text="拼命加载中" element-loading-spinner="el-icon-loading">
|
||||
<ai-title
|
||||
slot="title"
|
||||
title="调价管理"
|
||||
tips="每页为100条商品数据"
|
||||
isShowBottomBorder>
|
||||
<template #rightBtn>
|
||||
<div class="title-right">
|
||||
<div>
|
||||
<label style="width:90px">店铺:</label>
|
||||
<el-select v-model="form.mallId" placeholder="请选择" size="small">
|
||||
<el-option
|
||||
v-for="item in $store.state.mallList"
|
||||
:key="item.mallId"
|
||||
:label="item.mallName"
|
||||
:value="item.mallId">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</ai-title>
|
||||
<template slot="content">
|
||||
<div class="content">
|
||||
<ai-search-bar>
|
||||
<template #left>
|
||||
<div class="search-item">
|
||||
<label>起始页:</label>
|
||||
<el-input size="small" placeholder="请输入起始页" type="number" v-model="startPage"></el-input>
|
||||
</div>
|
||||
<div class="search-item">
|
||||
<label>结束页:</label>
|
||||
<el-input size="small" placeholder="请输入起始页" type="number" v-model="endPage"></el-input>
|
||||
</div>
|
||||
</template>
|
||||
<template #right>
|
||||
<el-button type="primary" @click="toLoad">加载</el-button>
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-card title="数据明细" style="padding-bottom: 40px;">
|
||||
<template #right>
|
||||
<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="250px" :show-overflow-tooltip='true' label="商品名称" fixed="left">
|
||||
<template slot-scope="scope">
|
||||
<div>
|
||||
<el-image :src="scope.row.image" style="width: 40px; height: 40px" class="image" :preview-src-list="[scope.row.image]" />
|
||||
{{ 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: 'MyNormalOrder',
|
||||
|
||||
data () {
|
||||
return {
|
||||
form: {
|
||||
mallId: ''
|
||||
},
|
||||
startPage: 1,
|
||||
endPage: 10,
|
||||
reqData: {
|
||||
pageInfo: {
|
||||
pageSize: 100,
|
||||
pageNo: 1
|
||||
},
|
||||
status: 2
|
||||
},
|
||||
colConfigs: [
|
||||
{ slot: 'productName', label: '商品名称', width: '250px', align: 'left', fixed: 'left' },
|
||||
{ prop: 'priceOrderSn', label: '调价单号', width: '140px', align: 'left', fixed: 'left' },
|
||||
{ prop: 'skcId', label: 'SKC ID', width: '120px', align: 'left' },
|
||||
{ prop: 'skcExtCode', label: 'SKC货号', width: '100px', align: 'left' },
|
||||
{ prop: 'productSkuId', label: 'SKU ID', width: '120px', align: 'left' },
|
||||
{ prop: 'skuExtCode', label: 'SKU货号', width: '100px', align: 'left' },
|
||||
{ prop: 'spec', label: 'SKU属性', width: '100px', align: 'left' },
|
||||
{ prop: 'priceBeforeExchange', label: '原申报价格', width: '100px', align: 'left' },
|
||||
{ prop: 'newSupplyPrice', label: '调整后申报价格', width: '100px', align: 'left' },
|
||||
{ prop: 'operateUserName', label: '操作人', width: '100px', align: 'left' },
|
||||
{ prop: 'operateSourceName', label: '操作页面', width: '100px', align: 'left' },
|
||||
{ prop: 'operateTime', label: '操作时间', width: '100px', align: 'left' },
|
||||
{ prop: 'source', label: '申请来源', width: '120px', align: 'left' },
|
||||
{ prop: 'adjustReason', label: '调价原因', align: 'left' }
|
||||
],
|
||||
isLoading: false,
|
||||
tableData: [],
|
||||
jsonFields: {
|
||||
"商品名称": "productName",
|
||||
"图片": "image",
|
||||
"调价单号": "priceOrderSn",
|
||||
"SKC ID": "skcId",
|
||||
"SKC货号": "skcExtCode",
|
||||
"SKU ID": "productSkuId",
|
||||
"SKU货号": "skuExtCode",
|
||||
"SKU属性": "spec",
|
||||
"原申报价格": "priceBeforeExchange",
|
||||
"调整后申报价格": "newSupplyPrice",
|
||||
"操作人": "operateUserName",
|
||||
"操作页面": "operateSourceName",
|
||||
"操作时间": "operateTime",
|
||||
"申请来源": "source",
|
||||
"调价原因": "adjustReason"
|
||||
},
|
||||
currentIndex: 0
|
||||
}
|
||||
},
|
||||
components: {
|
||||
JsonExcel
|
||||
},
|
||||
created () {
|
||||
},
|
||||
methods: {
|
||||
beforeGetList() {
|
||||
this.$userCheck(this.form.mallId).then(() => {
|
||||
this.toLoad()
|
||||
}).catch((err) => {
|
||||
this.form.mallId = ''
|
||||
})
|
||||
},
|
||||
toLoad() {
|
||||
if (!this.form.mallId) {
|
||||
Message.error("请选择店铺")
|
||||
return
|
||||
}
|
||||
if (!this.startPage || (this.startPage < 1)) {
|
||||
Message.error("起始页不能为空,且不能小于1")
|
||||
return
|
||||
}
|
||||
if (!this.endPage || (this.startPage < 1)) {
|
||||
Message.error("结束页不能为空")
|
||||
return
|
||||
}
|
||||
if (this.startPage > this.endPage) {
|
||||
Message.error("起始页不能大于结束页")
|
||||
return
|
||||
}
|
||||
this.reqData.pageInfo.pageNo = this.startPage
|
||||
this.tableData = []
|
||||
this.currentIndex = 0
|
||||
this.isLoading = true
|
||||
this.load()
|
||||
},
|
||||
async load() {
|
||||
let res = await sendChromeAPIMessage({
|
||||
url: 'marvel-mms/cn/api/kiana/magneto/price-adjust/page-query',
|
||||
needMallId: true,
|
||||
mallId: this.form.mallId,
|
||||
anti: true,
|
||||
data: this.reqData})
|
||||
if (res.errorCode == 1000000) {
|
||||
for(let i = 0;i < res.result.list.length; i++) {
|
||||
let item = res.result.list[i];
|
||||
let data = {};
|
||||
data.id = item.id
|
||||
data.productName = item.productName
|
||||
data.image = item.image
|
||||
data.priceOrderSn = item.priceOrderSn
|
||||
data.skcId = item.skcId
|
||||
data.skcExtCode = item.skcExtCode
|
||||
data.source = item.source
|
||||
data.adjustReason = item.adjustReason
|
||||
data.newSupplyPrice = item.newSupplyPrice / 100
|
||||
|
||||
for(let k = 0; k < item.skuInfoItemList.length; k++) {
|
||||
data = {...data,
|
||||
productSkuId: item.skuInfoItemList[k].productSkuId,
|
||||
priceBeforeExchange: item.skuInfoItemList[k].priceBeforeExchange / 100,
|
||||
skuExtCode: item.skuInfoItemList[k].skuExtCode,
|
||||
spec: item.skuInfoItemList[k].spec,
|
||||
operateUserName: null,
|
||||
operateTime: null,
|
||||
operateSourceName: null
|
||||
}
|
||||
|
||||
this.tableData.push(data)
|
||||
}
|
||||
|
||||
}
|
||||
if (res.result.list.length == this.reqData.pageInfo.pageSize && this.reqData.pageInfo.pageNo < this.endPage) {
|
||||
this.reqData.pageInfo.pageNo ++
|
||||
await this.load()
|
||||
} else {
|
||||
await this.getPriceAdjustLog()
|
||||
this.isLoading = false
|
||||
}
|
||||
}
|
||||
},
|
||||
async getPriceAdjustLog() {
|
||||
for (let i = 0; i < this.tableData.length; i++) {
|
||||
let res = await sendChromeAPIMessage({
|
||||
url: 'marvel-mms/cn/api/kiana/gmp/bg/magneto/api/price/adjust/log',
|
||||
needMallId: true,
|
||||
mallId: this.form.mallId,
|
||||
anti: true,
|
||||
data: {priceOrderId: this.tableData[i].id}})
|
||||
if (res.errorCode == 1000000) {
|
||||
if (res.result.list && res.result.list.length > 0) {
|
||||
this.tableData[i].operateSourceName = res.result.list[res.result.list.length - 1].operateSourceName
|
||||
this.tableData[i].operateTime = timestampToTime(res.result.list[res.result.list.length - 1].operateTime)
|
||||
this.tableData[i].operateUserName = res.result.list[res.result.list.length - 1].operateUserName
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</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>
|
||||
166
src/view/selection/AliExpressCopy.vue
Normal file
@@ -0,0 +1,166 @@
|
||||
<template>
|
||||
<div>
|
||||
<ai-list class="list">
|
||||
<ai-title
|
||||
slot="title"
|
||||
title="速卖通采集"
|
||||
tips="请先在当前浏览器登录“拼多多跨境卖家中心”,期间保持登录状态"
|
||||
isShowBottomBorder>
|
||||
</ai-title>
|
||||
<template slot="content">
|
||||
<div class="content">
|
||||
<ai-search-bar>
|
||||
<template #left>
|
||||
<div class="search-item">
|
||||
<label style="width:80px">店铺:</label>
|
||||
<el-select v-model="search.mallId" :clearable="true" @change="search.current =1, getList()" 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>
|
||||
</template>
|
||||
<template #right>
|
||||
<el-button type="primary" @click="search.current =1, getList()">查询</el-button>
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-search-bar>
|
||||
<template #left>
|
||||
<el-button type="button" :class="'el-button el-button--primary'" @click="beforeCopy()">开始采集</el-button>
|
||||
</template>
|
||||
</ai-search-bar>
|
||||
<ai-table
|
||||
:tableData="tableData"
|
||||
:col-configs="colConfigs"
|
||||
:total="total"
|
||||
style="margin-top: 8px;"
|
||||
:current.sync="search.current" :size.sync="search.size"
|
||||
@getList="getList">
|
||||
<el-table-column slot="url" label="商品地址" align="left">
|
||||
<template slot-scope="scope">
|
||||
<div v-if="scope.row.url.startsWith('http')"><a class="el-link el-link--primary" :href="scope.row.url" target="_blank">{{ scope.row.url }}</a></div>
|
||||
<div v-else><a class="el-link el-link--primary" :href="'https://www.temu.com/goods.html?goods_id=' + scope.row.url" target="_blank">{{ scope.row.url }}</a></div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column slot="type" label="来源" width="100px" align="left">
|
||||
<template slot-scope="scope">
|
||||
速卖通
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ai-table>
|
||||
</div>
|
||||
</template>
|
||||
</ai-list>
|
||||
|
||||
<ai-dialog
|
||||
title="速卖通采集"
|
||||
:visible.sync="copyFromDlgShow"
|
||||
:close-on-click-modal="false"
|
||||
width="790px"
|
||||
customFooter
|
||||
@close="handleClose">
|
||||
<ai-copy-from-ali-express v-if="copyFromDlgShow" @onClose="handleClose" @onSuccess="handleSuccess"></ai-copy-from-ali-express>
|
||||
</ai-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AiCopyFromAliExpress from "@/components/AiCopyFromAliExpress.vue";
|
||||
import {sendAliexpressAPIMessage} from '@/api/chromeApi'
|
||||
|
||||
export default {
|
||||
name: 'NiubiCopy',
|
||||
components: {AiCopyFromAliExpress},
|
||||
|
||||
data() {
|
||||
return {
|
||||
search: {
|
||||
current: 1,
|
||||
size: 10,
|
||||
type: '2',
|
||||
mallId: ''
|
||||
},
|
||||
|
||||
colConfigs: [
|
||||
{slot: 'url', label: '商品地址', align: 'left'},
|
||||
{slot: 'type', label: '来源', width: '100px', align: 'left'},
|
||||
{prop: 'mallName', label: '店铺名称', width: '200px', align: 'left'},
|
||||
{prop: 'createTime', label: '复制时间', width: '180px'}
|
||||
],
|
||||
tableData: [],
|
||||
total: 0,
|
||||
copyFromDlgShow: false,
|
||||
}
|
||||
},
|
||||
|
||||
created() {
|
||||
this.getList()
|
||||
},
|
||||
|
||||
methods: {
|
||||
async getList() {
|
||||
/*const image = 'http://temu.jjcp52.com/dist/test.png'
|
||||
let res2 = await getImageMd5(image), res4
|
||||
Promise.all([
|
||||
sendChromeAPIMessage({
|
||||
url: 'marvel-mms/cn/api/kiana/gmp/bg/phoenix/api/material/create',
|
||||
needMallId: true,
|
||||
mallId: '634418212443160',
|
||||
data: {
|
||||
folderId: 0,
|
||||
createDetailList: [
|
||||
{
|
||||
materialType: 1,
|
||||
materialMd5: res2.md5,
|
||||
materialName: "test"
|
||||
}
|
||||
]
|
||||
}
|
||||
}),
|
||||
sendChromeAPIMessage({
|
||||
url: 'galerie/business/get_signature?sdk_version=js-0.0.16-alpha.0&tag_name=product-material-tag',
|
||||
needMallId: true,
|
||||
mallId: '634418212443160',
|
||||
data: {
|
||||
bucket_tag: "product-material-tag"
|
||||
}
|
||||
}).then(res => res4 = res)
|
||||
]).then(() => sendChromeAPIMessage({
|
||||
url: 'https://kuajing-file.pinduoduo.com/api/galerie/v3/store_image?sdk_version=js-0.0.16-alpha.0&tag_name=product-material-tag',
|
||||
isFormData: true,
|
||||
data: {
|
||||
url_width_height: true,
|
||||
image,
|
||||
upload_sign: res4.result.signature
|
||||
}
|
||||
}))*/
|
||||
|
||||
this.$http.post('/api/copyProduct/myPage', null, {
|
||||
params: {
|
||||
...this.search
|
||||
}
|
||||
}).then(res => {
|
||||
this.tableData = res.data.records
|
||||
this.total = res.data.total
|
||||
})
|
||||
},
|
||||
beforeCopy() {
|
||||
this.copyFromDlgShow = true
|
||||
},
|
||||
handleClose() {
|
||||
this.copyFromDlgShow = false
|
||||
},
|
||||
// 添加模板成功
|
||||
handleSuccess() {
|
||||
this.copyFromDlgShow = false
|
||||
this.getList()
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
</style>
|
||||