调整
This commit is contained in:
		| @@ -55,7 +55,6 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { | ||||
|         headers['Content-Type'] = 'application/json'; | ||||
|         data = JSON.stringify(request.data) | ||||
|       } else { | ||||
|         console.log(request.data) | ||||
|         const formData = new FormData(); | ||||
|         Object.keys(request.data).forEach(key => { | ||||
|           const value = request.data[key] | ||||
|   | ||||
| @@ -34,7 +34,8 @@ | ||||
|     "declarativeNetRequest", | ||||
|     "declarativeNetRequestWithHostAccess", | ||||
|     "declarativeNetRequestFeedback", | ||||
|     "activeTab" | ||||
|     "activeTab", | ||||
|     "fileSystemProvider" | ||||
|   ], | ||||
|   "declarative_net_request": { | ||||
|     "rule_resources": [{ | ||||
|   | ||||
| @@ -2,7 +2,7 @@ | ||||
|   "manifest_version": 3, | ||||
|   "name": "TEMU助手", | ||||
|   "description": "TEMU助手 - 自动化提高生产效率", | ||||
|   "version": "3.3.0", | ||||
|   "version": "3.3.1", | ||||
|   "background": { | ||||
|     "service_worker": "/background.js" | ||||
|   }, | ||||
| @@ -33,7 +33,8 @@ | ||||
|     "declarativeNetRequest", | ||||
|     "declarativeNetRequestWithHostAccess", | ||||
|     "declarativeNetRequestFeedback", | ||||
|     "activeTab" | ||||
|     "activeTab", | ||||
|     "fileSystemProvider" | ||||
|   ], | ||||
|   "declarative_net_request": { | ||||
|     "rule_resources": [{ | ||||
|   | ||||
| @@ -110,6 +110,11 @@ const router = new VueRouter({ | ||||
|           name: 'copyProductAliExpress', | ||||
|           component: () => import('../view/product/CopyProductAliExpress.vue') | ||||
|         }, | ||||
|         { | ||||
|           path: 'batchUpload', | ||||
|           name: 'batchUpload', | ||||
|           component: () => import('../view/product/BatchUpload.vue') | ||||
|         }, | ||||
|         { | ||||
|           path: 'niubiCopy', | ||||
|           name: 'niubiCopy', | ||||
| @@ -222,6 +227,11 @@ const router = new VueRouter({ | ||||
|           name: 'logisticFee', | ||||
|           component: () => import('../view/sale/LogisticFee.vue') | ||||
|         }, | ||||
|         { | ||||
|           path: 'billStat', | ||||
|           name: 'billStat', | ||||
|           component: () => import('../view/sale/ExportBillStatTemu.vue') | ||||
|         }, | ||||
|         { | ||||
|           path: 'costManageShein', | ||||
|           name: 'costManageShein', | ||||
| @@ -272,6 +282,11 @@ const router = new VueRouter({ | ||||
|           name: 'purchaseOrderListShein', | ||||
|           component: () => import('../view/shein/PurchaseOrderListShein.vue') | ||||
|         }, | ||||
|         { | ||||
|           path: 'syncDataTemu', | ||||
|           name: 'syncDataTemu', | ||||
|           component: () => import('../view/data/SyncDataTemu.vue') | ||||
|         }, | ||||
|          | ||||
|         // { | ||||
|         //   path: 'statistics', | ||||
| @@ -313,6 +328,14 @@ 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) { | ||||
|   | ||||
| @@ -19,8 +19,29 @@ export function getImageMd5(imageUrl) { | ||||
|   }); | ||||
| } | ||||
|  | ||||
| export async function uploadImage(folderId, imageUrl, mallId) { | ||||
|   let res1 = await getImageMd5(imageUrl) | ||||
| 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, | ||||
| @@ -35,6 +56,7 @@ export async function uploadImage(folderId, imageUrl, mallId) { | ||||
|       createDetailList: detailList, | ||||
|       folderId: folderId | ||||
|   }}) | ||||
|   await sleepSync(200) | ||||
|  | ||||
|   if (res2.success) { | ||||
|     if (res2.result.responseDetailList[0].alreadyExists) { | ||||
| @@ -48,6 +70,7 @@ export async function uploadImage(folderId, imageUrl, mallId) { | ||||
|           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', | ||||
| @@ -58,6 +81,7 @@ export async function uploadImage(folderId, imageUrl, mallId) { | ||||
|           upload_sign: res3.result.signature | ||||
|         } | ||||
|       }) | ||||
|       await sleepSync(200) | ||||
|  | ||||
|       let res5 = await sendChromeAPIMessage({ | ||||
|         url: 'marvel-mms/cn/api/kiana/gmp/bg/phoenix/api/material/edit', | ||||
| @@ -76,3 +100,7 @@ export async function uploadImage(folderId, imageUrl, mallId) { | ||||
|   } | ||||
|  | ||||
| } | ||||
|  | ||||
| function sleepSync(milliseconds) { | ||||
|   return new Promise(resolve => setTimeout(resolve, milliseconds)); | ||||
| } | ||||
| @@ -26,7 +26,8 @@ export function transform(leftData) { | ||||
|       propName: leftData.productPropertyList[i].propName, | ||||
|       refPid: leftData.productPropertyList[i].refPid, | ||||
|       vid: leftData.productPropertyList[i].vid, | ||||
|       controlType: 1, | ||||
|       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 | ||||
| @@ -65,7 +66,7 @@ export function transform(leftData) { | ||||
|     rightSkcItem.previewImgUrls = leftSkc[i].previewImgUrls; | ||||
|     rightSkcItem.productSkcCarouselImageI18nReqs = leftSkc[i].productSkcCarouselImageI18nVOList; | ||||
|     rightSkcItem.extCode = leftSkc[i].extCode; | ||||
|     rightSkcItem.mainProductSkuSpecReqs =  [ | ||||
|     rightSkcItem.mainProductSkuSpecReqs = leftSkc[i].mainProductSkuSpec || [ | ||||
|       { | ||||
|       "parentSpecId": 0, | ||||
|       "parentSpecName": "", | ||||
| @@ -83,6 +84,12 @@ export function transform(leftData) { | ||||
|       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, | ||||
| @@ -127,6 +134,7 @@ export function transform(leftData) { | ||||
|   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 = { | ||||
| @@ -139,6 +147,9 @@ export function transform(leftData) { | ||||
|   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({ | ||||
|   | ||||
| @@ -13,6 +13,7 @@ | ||||
|           </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"> | ||||
|             <span>会员信息:</span> | ||||
| @@ -72,6 +73,7 @@ | ||||
|             <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="/batchUpload">批量上品</el-menu-item>--> | ||||
|             <el-menu-item v-if="$store.state.userInfo.phone == '18610967550' || $store.state.userInfo.phone == '18571466720'" index="/draft"> | ||||
|               草稿箱管理 | ||||
|             </el-menu-item> | ||||
| @@ -138,6 +140,7 @@ | ||||
|             <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"> | ||||
| @@ -159,6 +162,13 @@ | ||||
|             </el-menu-item> | ||||
|             <el-menu-item index="/saleStatShein">商家账单统计</el-menu-item> | ||||
|           </el-submenu> | ||||
|           <el-submenu index="/dataManager" 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="/syncDataTemu">数据同步(TEMU)</el-menu-item> | ||||
|           </el-submenu> | ||||
|           <el-menu-item index="/info"> | ||||
|             <i class="el-icon-info"></i> | ||||
|             <span slot="title">弹窗消息</span> | ||||
| @@ -341,6 +351,30 @@ export default { | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     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') | ||||
|     }, | ||||
|   | ||||
| @@ -232,6 +232,11 @@ import BiVueMindmap from "bi-vue-mindmap"; | ||||
|             parentId: "01010104", | ||||
|             title: "物流统计:对应“履约服务账单->明细->缴费记录”,以及“发货单列表->物流计费重核实”,统计一段时期内物流费用,以及货物重量,物流费用分布" | ||||
|           }, | ||||
|           { | ||||
|             id: "0101010408", | ||||
|             parentId: "01010104", | ||||
|             title: "账务明细统计:对应“账户资金->对账中心->账务明细”,真实统计一段时间内的实际收入,以及各种类型的支出,汇总统计" | ||||
|           }, | ||||
|           { | ||||
|             id: "01010105", | ||||
|             parentId: "010101", | ||||
|   | ||||
							
								
								
									
										359
									
								
								src/view/data/SyncDataTemu.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										359
									
								
								src/view/data/SyncDataTemu.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,359 @@ | ||||
| <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 | ||||
|                         } | ||||
|  | ||||
|                         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> | ||||
							
								
								
									
										380
									
								
								src/view/login/Forget.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										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.success('两次密码输入不一致'); | ||||
|               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> | ||||
|   | ||||
							
								
								
									
										305
									
								
								src/view/product/BatchUpload.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										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> | ||||
| @@ -295,14 +295,18 @@ import { saveAs } from 'file-saver' | ||||
|         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 | ||||
|             } | ||||
|           }) | ||||
|         }) | ||||
|   | ||||
							
								
								
									
										428
									
								
								src/view/sale/ExportBillStatTemu.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										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> | ||||
| @@ -376,7 +376,7 @@ import { DualAxes } from '@antv/g2plot' | ||||
|     computed: { | ||||
|       topSaleAmountSkcList() { | ||||
|         const list = Object.assign([], this.skcList) | ||||
|         list.sort((a, b) => b.amount - a.amount) | ||||
|         list.sort((a, b) => b.saleAmount - a.saleAmount) | ||||
|         return list.slice(0, 10) | ||||
|       }, | ||||
|       topSaleProfitSkcList() { | ||||
| @@ -805,7 +805,7 @@ import { DualAxes } from '@antv/g2plot' | ||||
|           const a = document.createElement('a'); | ||||
|           a.style.display = 'none' | ||||
|           a.href = img.src; | ||||
|           a.download = '近60天销售统计.png'; | ||||
|           a.download = '销售统计.png'; | ||||
|           a.click(); | ||||
|           document.body.removeChild(img); | ||||
|         } catch (error) { | ||||
|   | ||||
| @@ -3,7 +3,7 @@ | ||||
|     <ai-title | ||||
|       slot="title" | ||||
|       title="物流统计" | ||||
|       tips="请先在当前浏览器登录“拼多多跨境卖家中心”,期间保持登录状态" | ||||
|       tips="数据来源于“履约服务账单->明细->缴费记录" | ||||
|       isShowBottomBorder> | ||||
|     </ai-title> | ||||
|     <template slot="content"> | ||||
|   | ||||
| @@ -255,16 +255,26 @@ import { saveAs } from 'file-saver' | ||||
|         } | ||||
|       }, | ||||
|       async getPriceInfo(skcList) { | ||||
|         let res = await sendGeiwohuoAPIMessage({ | ||||
|           url: `idms/goods-skc/price`, | ||||
|           method: 'POST', | ||||
|           data: skcList}) | ||||
|         if (res.code == '0') { | ||||
|           for (let key in res.info) { | ||||
|             for (let i = 0; i < this.list.length; i++) { | ||||
|               if (key == this.list[i].sku) { | ||||
|                 this.list[i].price = res.info[key] | ||||
|                 break | ||||
|         let i = 0, len = 100 | ||||
|         while(i < skcList.length) { | ||||
|           let tempSkcList = [] | ||||
|           for (; i < skcList.length; i++) { | ||||
|             tempSkcList.push(skcList[i]) | ||||
|             if (tempSkcList.length % len == 0) { | ||||
|               break | ||||
|             } | ||||
|           } | ||||
|           let res = await sendGeiwohuoAPIMessage({ | ||||
|             url: `idms/goods-skc/price`, | ||||
|             method: 'POST', | ||||
|             data: tempSkcList}) | ||||
|           if (res.code == '0') { | ||||
|             for (let key in res.info) { | ||||
|               for (let i = 0; i < this.list.length; i++) { | ||||
|                 if (key == this.list[i].sku) { | ||||
|                   this.list[i].price = res.info[key] | ||||
|                   break | ||||
|                 } | ||||
|               } | ||||
|             } | ||||
|           } | ||||
| @@ -313,6 +323,7 @@ import { saveAs } from 'file-saver' | ||||
|         this.costDlgShow = true | ||||
|       }, | ||||
|       importConfirm() { | ||||
|         this.isLoading = true | ||||
|         this.$refs.costForm.validate((valid) => { | ||||
|           const data = new FormData() | ||||
|           data.append('file', this.costForm.file[0].raw); | ||||
| @@ -322,8 +333,10 @@ import { saveAs } from 'file-saver' | ||||
|               this.$message.success('导入成功') | ||||
|               this.currentPage = 1 | ||||
|               this.list = [] | ||||
|               this.isLoading = true | ||||
|               this.isLoading = false | ||||
|               this.getList() | ||||
|             } else { | ||||
|               this.isLoading = false | ||||
|             } | ||||
|           }) | ||||
|         }) | ||||
|   | ||||
| @@ -199,7 +199,7 @@ import { saveAs } from 'file-saver' | ||||
|           for(let i = 0;i < res.info.data.length; i++) { | ||||
|             let item = res.info.data[i]; | ||||
|             let data = { | ||||
|               orderNo: item.orderId, | ||||
|               orderNo: item.sellerOrderNo, | ||||
|               supplierCode: item.goods.supplierCode, | ||||
|               statusName: item.statusName, | ||||
|               skc: item.goods.skcName, | ||||
|   | ||||
| @@ -490,6 +490,8 @@ | ||||
|                 Message.error("店铺【" + mallInfo.mallName + "】未设置默认发货地址,将无法自动创建发货单") | ||||
|               } | ||||
|               break | ||||
|             } else if (res.error_msg == '没权限访问') { | ||||
|               break | ||||
|             } | ||||
|           } | ||||
|         } | ||||
| @@ -612,7 +614,23 @@ | ||||
|             } | ||||
|           } | ||||
|         } else { | ||||
|           this.getList(data, mallId, mallName, currentPage) | ||||
|           if (res.error_msg == '没权限访问') { | ||||
|             if (this.loadMode == 1) { | ||||
|               this.loadMallIndex ++ | ||||
|               if (this.loadMallIndex < this.mallList.length) { | ||||
|                 this.getList(data, this.mallList[this.loadMallIndex].mallId, this.mallList[this.loadMallIndex].mallName, 1) | ||||
|               } else { | ||||
|                 this.isLoading = false | ||||
|                 this.isDlgLoading = false | ||||
|                 Message.success("所有店铺备货单已加载完成") | ||||
|               } | ||||
|             } else { | ||||
|               this.isLoading = false | ||||
|               this.isDlgLoading = false | ||||
|             } | ||||
|           } else { | ||||
|             this.getList(data, mallId, mallName, currentPage) | ||||
|           } | ||||
|         } | ||||
|       }, | ||||
|       remove(sn) { | ||||
|   | ||||
| @@ -153,7 +153,6 @@ import { saveAs } from 'file-saver' | ||||
|           url: 'bg-visage-mms/labelcode/pageQuery', | ||||
|           needMallId: true, | ||||
|           mallId: this.form.mallId, | ||||
|           anti: true, | ||||
|           data: this.reqData}).then((res) => { | ||||
|             if (res.errorCode == 1000000) { | ||||
|               for(let i = 0;i < res.result.pageItems.length; i++) { | ||||
|   | ||||
| @@ -194,14 +194,16 @@ import { saveAs } from 'file-saver' | ||||
|           for(let i = 0;i < res.result.deliveryOrderDetails.length; i++) { | ||||
|             let item = res.result.deliveryOrderDetails[i] | ||||
|  | ||||
|             let specArr = item.secondarySpecVOList.map(item => { | ||||
|               return item.specName | ||||
|             }) | ||||
|             let spec = specArr.join(',') | ||||
|  | ||||
|             for(let j = 0; j < this.list.length; j++) { | ||||
|               if (this.list[j].productSkuId == item.productSkuId) { | ||||
|                 this.list[j].specName = spec | ||||
|             if (item.secondarySpecVOList) { | ||||
|               let specArr = item.secondarySpecVOList.map(item => { | ||||
|                 return item.specName | ||||
|               }) | ||||
|               let spec = specArr.join(',') | ||||
|    | ||||
|               for(let j = 0; j < this.list.length; j++) { | ||||
|                 if (this.list[j].productSkuId == item.productSkuId) { | ||||
|                   this.list[j].specName = spec | ||||
|                 } | ||||
|               } | ||||
|             } | ||||
|           } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user