397 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
			
		
		
	
	
			397 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
| <template>
 | ||
|   <ai-list class="list" v-loading="isLoading" element-loading-text="拼命加载中" element-loading-spinner="el-icon-loading">
 | ||
|     <ai-title
 | ||
|       slot="title"
 | ||
|       title="成本管理"
 | ||
|       isShowBottomBorder>
 | ||
|     </ai-title>
 | ||
|     <template slot="content">
 | ||
|       <div style="margin-bottom: 5px">
 | ||
|         <el-alert
 | ||
|               title="郑重承诺:由于业务逻辑需要,TEMU助手将会以最小范围内存储SKU成本信息,平台将会做好保密,不泄露、不出售任何数据。使用与成本管理以及利润计算等相关功能,将视为授权TEMU助手存储相关信息。"
 | ||
|               type="error"
 | ||
|               :closable="false">
 | ||
|             </el-alert>
 | ||
|       </div>
 | ||
|       <ai-search-bar>
 | ||
|         <template #left>
 | ||
|           <div class="search-item">
 | ||
|             <el-checkbox v-model="search.unSet">只显示未填写</el-checkbox>
 | ||
|           </div>
 | ||
|           <div class="search-item">
 | ||
|             <label>SKC ID:</label>
 | ||
|             <el-input size="small" clearable placeholder="请输入SKC ID" v-model="search.skc"></el-input>
 | ||
|           </div>
 | ||
|           <div class="search-item">
 | ||
|             <label>SKU ID:</label>
 | ||
|             <el-input size="small" clearable placeholder="请输入SKU ID" v-model="search.sku"></el-input>
 | ||
|           </div>
 | ||
|           <div class="search-item">
 | ||
|             <label>SKC货号:</label>
 | ||
|             <el-input size="small" clearable placeholder="请输入SKC货号" v-model="search.skcCode"></el-input>
 | ||
|           </div>
 | ||
|         </template>
 | ||
|         <template #right>
 | ||
|           <!--<el-button type="primary" @click="toLoad">加载</el-button>-->
 | ||
|         </template>
 | ||
|       </ai-search-bar>
 | ||
|       <ai-card title="SKU明细" style="padding-bottom: 40px;">
 | ||
|         <template #right>
 | ||
|           <el-button type="primary" @click="exportToExcel">导出</el-button>
 | ||
|           <el-button type="primary" @click="toUpload">导入</el-button>
 | ||
|         </template>
 | ||
|         <ai-table
 | ||
|           :isShowPagination="false"
 | ||
|           :tableData="filteredData"
 | ||
|           :col-configs="colConfigs"
 | ||
|           height="600"
 | ||
|           style="margin-top: 8px;"
 | ||
|           @getList="() => {}">
 | ||
|           <el-table-column slot="costPrice" label="成本价格" :sortable="true" :sort-method="(a, b) => a.costPrice - b.costPrice">
 | ||
|             <template slot-scope="{ row }">
 | ||
|               <el-input
 | ||
|                 v-if="row.edit"
 | ||
|                 v-model="row.editValue"
 | ||
|                 type="number"
 | ||
|                 size="small"
 | ||
|               ></el-input>
 | ||
|               <span v-else>{{ row.costPrice }}</span>
 | ||
|             </template>
 | ||
|           </el-table-column>
 | ||
|           <el-table-column slot="options" label="操作" width="80px" show-overflow-tooltip align="center" fixed="right">
 | ||
|             <template slot-scope="{ row }">
 | ||
|               <el-button
 | ||
|                 v-if="!row.edit"
 | ||
|                 size="small"
 | ||
|                 icon="el-icon-edit"
 | ||
|                 @click="row.edit = true"
 | ||
|               ></el-button>
 | ||
|               <el-button
 | ||
|                 v-if="row.edit"
 | ||
|                 size="small"
 | ||
|                 type="success"
 | ||
|                 icon="el-icon-circle-check"
 | ||
|                 @click="handleSave(row)"
 | ||
|               ></el-button>
 | ||
|             </template>
 | ||
|           </el-table-column>
 | ||
|         </ai-table>
 | ||
|       </ai-card>
 | ||
| 
 | ||
|       <AiDialog
 | ||
|         title="成本导入"
 | ||
|         :visible.sync="costDlgShow"
 | ||
|         :close-on-click-modal="false"
 | ||
|         customFooter
 | ||
|         width="1290px">
 | ||
|         <el-form :model="costForm" ref="costForm" label-width="180px" class="form">
 | ||
|           <el-form-item label="上传excel" prop="file" :rules="[{ required: true, message: '请上传文件', trigger: 'blur' }]" style="width: 100%;">
 | ||
|             <ai-uploader isImport v-model="costForm.file" fileType="file" :limit="1"
 | ||
|                         acceptType=".xlsx," :clearable="false">
 | ||
|               <template #trigger>
 | ||
|                 <el-button icon="iconfont iconfangda">选择文件</el-button>
 | ||
|               </template>
 | ||
|               <template #tips>最多上传1个文件,单个文件最大10MB,仅支持Excel格式</template>
 | ||
|             </ai-uploader>
 | ||
|           </el-form-item>
 | ||
|         </el-form>
 | ||
|         <span slot="footer" class="dialog-footer">
 | ||
|           <el-button @click="costDlgShow = false">关 闭</el-button>
 | ||
|           <el-button type="primary" @click="importConfirm">确 定</el-button>
 | ||
|         </span>
 | ||
|       </AiDialog>
 | ||
|     </template>
 | ||
|   </ai-list>
 | ||
| </template>
 | ||
| 
 | ||
| <script>
 | ||
| import {sendGeiwohuoAPIMessage} from '@/api/chromeApi'
 | ||
| import {timestampToTime} from '@/utils/date'
 | ||
| import { Message } from 'element-ui'
 | ||
| import * as XLSX from 'xlsx'
 | ||
| import { saveAs } from 'file-saver'
 | ||
| 
 | ||
|   export default {
 | ||
|     name: 'CostManageShein',
 | ||
| 
 | ||
|     data () {
 | ||
|       return {
 | ||
|         isLoading: false,
 | ||
|         list: [],
 | ||
|         mallId: '',
 | ||
|         colConfigs: [
 | ||
|           { prop: 'skc', label: 'SKC ID', align: 'left' },
 | ||
|           { prop: 'skcCode', label: 'SKC货号', align: 'left' },
 | ||
|           { prop: 'sku', label: 'SKU ID', align: 'left' },
 | ||
|           { prop: 'skuAttr', label: '属性集', align: 'left' },
 | ||
|           { prop: 'skuCode', label: 'SKU货号', align: 'left' },
 | ||
|           { prop: 'price', label: '申报价格', align: 'left', sortable: true, 'sort-method': (a, b) => a.price - b.price },
 | ||
|           { slot: 'costPrice', label: '成本价格', align: 'left' },
 | ||
|           { prop: 'profitPercent', label: '利润率(%)', align: 'left', sortable: true, 'sort-method': (a, b) => a.profitPercent - b.profitPercent }
 | ||
|         ],
 | ||
|         search: {
 | ||
|           unSet: false,
 | ||
|           skc: '',
 | ||
|           sku: '',
 | ||
|           skcCode: ''
 | ||
|         },
 | ||
| 
 | ||
|         tableData: [],
 | ||
|         currentPage: 1,
 | ||
| 
 | ||
|         costList: [],
 | ||
| 
 | ||
|         costDlgShow: false,
 | ||
|         costForm: {
 | ||
|           file: null
 | ||
|         }
 | ||
|       }
 | ||
|     },
 | ||
| 
 | ||
|     computed: {
 | ||
|       filteredData() {
 | ||
|         const filteredData = this.list.filter(item => {
 | ||
|           let flag1 = true, flag2 = true, flag3 = true, flag4 = true
 | ||
|           if (this.search.unSet) {
 | ||
|             if (item.costPrice) flag1 = false
 | ||
|           }
 | ||
|           if (this.search.skc) {
 | ||
|             if (!item.skc.toLowerCase().includes(this.search.skc.toLowerCase())) {
 | ||
|               flag2 = false
 | ||
|             }
 | ||
|           }
 | ||
|           if (this.search.sku) {
 | ||
|             if (!item.sku.toLowerCase().includes(this.search.sku.toLowerCase())) {
 | ||
|               flag3 = false
 | ||
|             }
 | ||
|           }
 | ||
|           if (this.search.skcCode) {
 | ||
|             if (!item.skcCode.toLowerCase().includes(this.search.skcCode.toLowerCase())) {
 | ||
|               flag4 = false
 | ||
|             }
 | ||
|           }
 | ||
| 
 | ||
|           return flag1 && flag2 && flag3 && flag4
 | ||
|         })
 | ||
| 
 | ||
|         return filteredData
 | ||
|       }
 | ||
|     },
 | ||
| 
 | ||
|     mounted () {
 | ||
|       this.$http.post('/api/malluser/info').then(res => {
 | ||
|         if (res.code == 0) {
 | ||
|           this.$store.commit('setUserInfo', res.data)
 | ||
|           if (res.data.flag != 1) {
 | ||
|             Message.error('您的账号未激活或已失效,请激活后使用')
 | ||
|             this.$store.commit('setActiveDlgShow', true)
 | ||
|             return;
 | ||
|           }
 | ||
|           this.getUserInfo()
 | ||
|           this.isLoading = true
 | ||
|         }
 | ||
|       })
 | ||
|     },
 | ||
| 
 | ||
|     methods: {
 | ||
|       async getUserInfo() {
 | ||
|         let res = await sendGeiwohuoAPIMessage({
 | ||
|           url: 'sso-prefix/auth/getUser?uuid=' + Date.now(),
 | ||
|           method: 'GET'
 | ||
|         })
 | ||
|         if (res.code == '0' && res.msg == "OK") {
 | ||
|           this.mallId = res.info.merchantCode
 | ||
|           this.getList([])
 | ||
|         } else if (res.code == 100004 || res.code == 20302) {
 | ||
|           this.isLoading = false
 | ||
|           this.$store.commit("setSheinAlertShow", true)
 | ||
|         }
 | ||
|       },
 | ||
|       async getList (skcList) {
 | ||
|         let res = await sendGeiwohuoAPIMessage({
 | ||
|           url: `idms/goods-skc/list`,
 | ||
|           method: 'POST',
 | ||
|           data: {
 | ||
|             pageNumber: this.currentPage,
 | ||
|             pageSize: 100,
 | ||
|             sortBy7dSaleCnt: 2
 | ||
|           }})
 | ||
|         if (res.code == '0') {
 | ||
|           for(let i = 0;i < res.info.list.length; i++) {
 | ||
|             let item = res.info.list[i];
 | ||
|             let data = {skc: item.skc,
 | ||
|               skcCode: item.supplierCode
 | ||
|             }
 | ||
| 
 | ||
|             skcList.push(item.skc)
 | ||
|             
 | ||
|             for (let j = 0; j < item.skuList.length; j++) {
 | ||
|               let sku = item.skuList[j]
 | ||
|               if (sku.attr == '合计') continue
 | ||
|               data = {...data, sku: sku.skuCode,
 | ||
|                 skuAttr: sku.attr,
 | ||
|                 skuCode: sku.supplierSku,
 | ||
|                 price: null,
 | ||
|                 costPrice: '',
 | ||
|                 profitPercent: null,
 | ||
|                 edit: false,
 | ||
|                 editValue: null
 | ||
|               }
 | ||
| 
 | ||
|               this.list.push(data)
 | ||
|             }
 | ||
|           }
 | ||
|           if (res.info.list.length == 100 && (res.info.count > 100*this.currentPage)) {
 | ||
|             this.currentPage++
 | ||
|             await this.sleepSync(200)
 | ||
|             await this.getList(skcList)
 | ||
|           } else {
 | ||
|             await this.getPriceInfo(skcList)
 | ||
|             this.getSkuCostList()
 | ||
|           }
 | ||
|         } else if (res.code == 100004 || res.code == 20302) {
 | ||
|           this.isLoading = false
 | ||
|           this.$store.commit("setSheinAlertShow", true)
 | ||
|         }
 | ||
|       },
 | ||
|       async getPriceInfo(skcList) {
 | ||
|         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
 | ||
|                 }
 | ||
|               }
 | ||
|             }
 | ||
|           }
 | ||
|         }
 | ||
|       },
 | ||
|       sleepSync(milliseconds) {
 | ||
|         return new Promise(resolve => setTimeout(resolve, milliseconds));
 | ||
|       },
 | ||
|       getSkuCostList() {
 | ||
|         this.$http.post(`/api/skuCost/listAll`, null, {
 | ||
|           params: {
 | ||
|             mallId: this.mallId
 | ||
|           }
 | ||
|         }).then(res => {
 | ||
|           if (res.code == 0) {
 | ||
|             this.costList = res.data
 | ||
|             for (let i = 0; i < this.costList.length; i++) {
 | ||
|               for (let j = 0; j < this.list.length; j++) {
 | ||
|                 if (this.costList[i].sku == this.list[j].sku) {
 | ||
|                   this.list[j].costPrice = this.costList[i].costPrice
 | ||
|                   this.list[j].editValue = this.costList[i].costPrice
 | ||
|                   this.list[j].profitPercent = Math.round((this.list[j].price - this.list[j].costPrice) / this.list[j].price * 10000) /100
 | ||
|                 }
 | ||
|               }
 | ||
|             }
 | ||
|             this.isLoading = false
 | ||
|           }
 | ||
|         })
 | ||
|       },
 | ||
|       handleSave(row) {
 | ||
|         this.$http.post(`/api/skuCost/addOrUpdate`, [{
 | ||
|           mallId: this.mallId,
 | ||
|           costPrice: row.editValue,
 | ||
|           skc: row.skc,
 | ||
|           sku: row.sku
 | ||
|         }]).then((res) => {
 | ||
|           if (res.code == 0) {
 | ||
|             row.edit = false
 | ||
|             row.costPrice = row.editValue
 | ||
|             row.profitPercent = Math.round((row.price - row.costPrice) / row.price * 10000) / 100
 | ||
|             Message.success("修改成功")
 | ||
|           }
 | ||
|         })
 | ||
|       },
 | ||
|       toUpload() {
 | ||
|         this.costDlgShow = true
 | ||
|       },
 | ||
|       importConfirm() {
 | ||
|         this.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.$message.success('导入成功')
 | ||
|               this.currentPage = 1
 | ||
|               this.list = []
 | ||
|               this.isLoading = false
 | ||
|               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>
 |