调整
This commit is contained in:
81
src/components/AiSingleProductDetail.vue
Normal file
81
src/components/AiSingleProductDetail.vue
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
<template>
|
||||||
|
<ai-detail class="audit">
|
||||||
|
<template slot="content">
|
||||||
|
<ai-card title="基本信息">
|
||||||
|
<ai-product-drop-down v-if="info" :params="info" slot="right"></ai-product-drop-down>
|
||||||
|
<template #content>
|
||||||
|
<div class="flex">
|
||||||
|
<ai-avatar v-model="info.imgUrl" :editable="false" :preview="true"/>
|
||||||
|
<ai-wrapper
|
||||||
|
label-width="120px" class="fill">
|
||||||
|
<ai-info-item label="价格:" :value="'$' + info.price"></ai-info-item>
|
||||||
|
<ai-info-item label="销量:" :value="info.saleTotal"></ai-info-item>
|
||||||
|
</ai-wrapper>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</ai-card>
|
||||||
|
<ai-card title="趋势信息">
|
||||||
|
<template #content>
|
||||||
|
<div id="dataChart"></div>
|
||||||
|
</template>
|
||||||
|
</ai-card>
|
||||||
|
</template>
|
||||||
|
</ai-detail>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import AiProductDropDown from './AiProductDropDown.vue'
|
||||||
|
import { DualAxes } from '@antv/g2plot'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "AiSingleProductDetail",
|
||||||
|
props: ['params', 'url'],
|
||||||
|
components: {
|
||||||
|
AiProductDropDown
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
info: {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
// this.info = this.params
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.init()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
init() {
|
||||||
|
this.$http.post(this.url ? this.url: '/api/singleGoodsDetail/queryDetail',null,{
|
||||||
|
params: {
|
||||||
|
goodsId: this.params.goodsId,
|
||||||
|
groupId: this.params.groupId
|
||||||
|
}
|
||||||
|
}).then(res => {
|
||||||
|
this.info = res.data
|
||||||
|
|
||||||
|
const dualAxes = new DualAxes('dataChart', {
|
||||||
|
data: [this.info.priceAndSale, this.info.priceAndSale],
|
||||||
|
xField: '日期',
|
||||||
|
yField: ['价格', '销量'],
|
||||||
|
geometryOptions: [
|
||||||
|
{
|
||||||
|
geometry: 'line',
|
||||||
|
color: '#5B8FF9',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
geometry: 'line',
|
||||||
|
color: '#5AD8A6',
|
||||||
|
}
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
dualAxes.render();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style scoped lang="scss">
|
||||||
|
</style>
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
"manifest_version": 3,
|
"manifest_version": 3,
|
||||||
"name": "TEMU助手",
|
"name": "TEMU助手",
|
||||||
"description": "TEMU助手 - 自动化提高生产效率",
|
"description": "TEMU助手 - 自动化提高生产效率",
|
||||||
"version": "3.1.6",
|
"version": "3.1.7",
|
||||||
"background": {
|
"background": {
|
||||||
"service_worker": "/background.js"
|
"service_worker": "/background.js"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -138,7 +138,12 @@ const router = new VueRouter({
|
|||||||
{
|
{
|
||||||
path: 'saleData',
|
path: 'saleData',
|
||||||
name: 'saleData',
|
name: 'saleData',
|
||||||
component: () => import('../view/ExportSaleData.vue')
|
component: () => import('../view/sale/ExportSaleData.vue')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'saleOut',
|
||||||
|
name: 'saleOut',
|
||||||
|
component: () => import('../view/sale/ExportSaleOutData.vue')
|
||||||
},
|
},
|
||||||
|
|
||||||
// {
|
// {
|
||||||
|
|||||||
@@ -98,7 +98,7 @@
|
|||||||
<el-menu-item index="/newProduct">上架新品</el-menu-item>
|
<el-menu-item index="/newProduct">上架新品</el-menu-item>
|
||||||
<el-menu-item index="/newProductGroup">我的分组</el-menu-item>
|
<el-menu-item index="/newProductGroup">我的分组</el-menu-item>
|
||||||
</el-submenu>
|
</el-submenu>
|
||||||
<!-- <el-menu-item index="/singleTrack">单品跟踪</el-menu-item> -->
|
<el-menu-item index="/singleTrack">单品跟踪</el-menu-item>
|
||||||
<el-menu-item index="/bestSellers">7天畅销品</el-menu-item>
|
<el-menu-item index="/bestSellers">7天畅销品</el-menu-item>
|
||||||
<el-menu-item index="/indexTrack">首页商品跟踪</el-menu-item>
|
<el-menu-item index="/indexTrack">首页商品跟踪</el-menu-item>
|
||||||
</el-submenu>
|
</el-submenu>
|
||||||
@@ -115,10 +115,14 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-menu-item>
|
</el-menu-item>
|
||||||
</el-submenu>
|
</el-submenu>
|
||||||
<el-menu-item index="/saleData">
|
<el-submenu index="/saleManager">
|
||||||
<i class="el-icon-s-data"></i>
|
<template slot="title">
|
||||||
<span slot="title">销售数据</span>
|
<i class="el-icon-s-data"></i>
|
||||||
</el-menu-item>
|
<span slot="title">销售管理</span>
|
||||||
|
</template>
|
||||||
|
<el-menu-item index="/saleData">销售管理</el-menu-item>
|
||||||
|
<el-menu-item index="/saleOut">售罄看板</el-menu-item>
|
||||||
|
</el-submenu>
|
||||||
<el-menu-item index="/learning">
|
<el-menu-item index="/learning">
|
||||||
<i class="el-icon-eleme"></i>
|
<i class="el-icon-eleme"></i>
|
||||||
<span slot="title">新手园地</span>
|
<span slot="title">新手园地</span>
|
||||||
|
|||||||
@@ -851,7 +851,7 @@ import { Message } from 'element-ui'
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
let beginDateStr = formatDate(this.skuDownloadForm.date[0])
|
let beginDateStr = formatDate(this.skuDownloadForm.date[0])
|
||||||
let endDateStyr = formatDate(this.skuDownloadForm.date[1])
|
let endDateStr = formatDate(this.skuDownloadForm.date[1])
|
||||||
|
|
||||||
let temp = {}
|
let temp = {}
|
||||||
temp = {
|
temp = {
|
||||||
@@ -872,9 +872,9 @@ import { Message } from 'element-ui'
|
|||||||
let tempSkuList = this.list.filter(item => {
|
let tempSkuList = this.list.filter(item => {
|
||||||
return item.onSalesDurationOffline != '-天'
|
return item.onSalesDurationOffline != '-天'
|
||||||
})
|
})
|
||||||
this.tempSkuIds = []
|
let tempSkuIds = []
|
||||||
tempSkuList.map(i => {
|
tempSkuList.map(i => {
|
||||||
this.tempSkuIds.push(i.productSkuId)
|
tempSkuIds.push(i.productSkuId)
|
||||||
})
|
})
|
||||||
|
|
||||||
this.skuSaleNumberList = []
|
this.skuSaleNumberList = []
|
||||||
@@ -899,33 +899,42 @@ import { Message } from 'element-ui'
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
let reqSkusIds = [], pageSize = 200
|
||||||
|
for (let i = 0; i < tempSkuIds.length; i++) {
|
||||||
|
reqSkusIds.push(tempSkuIds[i])
|
||||||
|
if (reqSkusIds.length % pageSize == 0 || ((i+1) == tempSkuIds.length)) {
|
||||||
|
let res = await sendChromeAPIMessage({
|
||||||
|
url: 'oms/bg/venom/api/supplier/sales/management/querySkuSalesNumber',
|
||||||
|
needMallId: true,
|
||||||
|
mallId: this.mallId,
|
||||||
|
data: {
|
||||||
|
"productSkuIds": reqSkusIds,
|
||||||
|
"startDate": beginDateStr,
|
||||||
|
"endDate": endDateStr
|
||||||
|
}})
|
||||||
|
|
||||||
let res = await sendChromeAPIMessage({
|
if (res.success) {
|
||||||
url: 'oms/bg/venom/api/supplier/sales/management/querySkuSalesNumber',
|
res.result.map(item => {
|
||||||
needMallId: true,
|
for (let i = 0; i < this.skuSaleNumberList.length; i++) {
|
||||||
mallId: this.mallId,
|
if (this.skuSaleNumberList[i].sku == item.prodSkuId) {
|
||||||
data: {
|
this.skuSaleNumberList[i][item.date] = item.salesNumber
|
||||||
"productSkuIds": this.tempSkuIds,
|
break
|
||||||
"startDate": beginDateStr,
|
}
|
||||||
"endDate": endDateStyr
|
|
||||||
}})
|
|
||||||
|
|
||||||
if (res.success) {
|
|
||||||
res.result.map(item => {
|
|
||||||
for (let i = 0; i < this.skuSaleNumberList.length; i++) {
|
|
||||||
if (this.skuSaleNumberList[i].sku == item.prodSkuId) {
|
|
||||||
this.skuSaleNumberList[i][item.date] = item.salesNumber
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
})
|
} else {
|
||||||
document.getElementById('downloadSkuSaleNumber').click()
|
this.isLoading = false
|
||||||
} else {
|
Message.error("获取SKU历史销量数据失败")
|
||||||
Message.error("获取SKU历史销量数据失败")
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((i+1) == tempSkuIds.length) {
|
||||||
|
document.getElementById('downloadSkuSaleNumber').click()
|
||||||
|
this.isLoading = false
|
||||||
|
}
|
||||||
|
reqSkusIds = []
|
||||||
}
|
}
|
||||||
|
}
|
||||||
this.isLoading = false
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
223
src/view/sale/ExportSaleOutData.vue
Normal file
223
src/view/sale/ExportSaleOutData.vue
Normal file
@@ -0,0 +1,223 @@
|
|||||||
|
<template>
|
||||||
|
<ai-list class="list" v-loading="isLoading" element-loading-text="拼命加载中" element-loading-spinner="el-icon-loading">
|
||||||
|
<ai-title
|
||||||
|
slot="title"
|
||||||
|
title="售罄看板"
|
||||||
|
isShowBottomBorder>
|
||||||
|
<template #rightBtn>
|
||||||
|
<div class="title-right">
|
||||||
|
<div>
|
||||||
|
<label style="width:90px">店铺:</label>
|
||||||
|
<el-select v-model="mallId" @change="beforeGetList" placeholder="请选择" size="small">
|
||||||
|
<el-option
|
||||||
|
v-for="item in $store.state.mallList"
|
||||||
|
:key="item.mallId"
|
||||||
|
:label="item.mallName"
|
||||||
|
:value="item.mallId">
|
||||||
|
</el-option>
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</ai-title>
|
||||||
|
<template slot="content">
|
||||||
|
<ai-search-bar>
|
||||||
|
<template #left>
|
||||||
|
<el-radio-group v-model="type" @change="onChange">
|
||||||
|
<el-radio-button label="0">即将售罄</el-radio-button>
|
||||||
|
<el-radio-button label="1">已售罄</el-radio-button>
|
||||||
|
</el-radio-group>
|
||||||
|
</template>
|
||||||
|
<template #right>
|
||||||
|
</template>
|
||||||
|
</ai-search-bar>
|
||||||
|
<ai-card title="数据明细" style="padding-bottom: 40px;">
|
||||||
|
<template #right>
|
||||||
|
<json-excel
|
||||||
|
:data="tableData"
|
||||||
|
:fields="jsonFields"
|
||||||
|
:before-generate = "startDownload"
|
||||||
|
name="即将售罄明细.xls"
|
||||||
|
worksheet="即将售罄明细">
|
||||||
|
<el-button type="primary" :disabled="!mallId || (tableData.length == 0)">导出数据</el-button>
|
||||||
|
</json-excel>
|
||||||
|
</template>
|
||||||
|
<ai-table
|
||||||
|
:isShowPagination="false"
|
||||||
|
:tableData="tableData"
|
||||||
|
:col-configs="colConfigs"
|
||||||
|
:total="tableData.length"
|
||||||
|
height="500"
|
||||||
|
style="margin-top: 8px;"
|
||||||
|
@getList="() => {}">
|
||||||
|
</ai-table>
|
||||||
|
</ai-card>
|
||||||
|
</template>
|
||||||
|
</ai-list>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import {sendChromeAPIMessage} from '@/api/chromeApi'
|
||||||
|
import JsonExcel from 'vue-json-excel'
|
||||||
|
import { Message } from 'element-ui'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'ExportSaleOutData',
|
||||||
|
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
type: '0',
|
||||||
|
isLoading: false,
|
||||||
|
tableData: [],
|
||||||
|
mallId: '',
|
||||||
|
colConfigs: [
|
||||||
|
{ prop: 'productName', label: '商品名称', align: 'left' },
|
||||||
|
{ prop: 'catName', label: '类目', align: 'left' },
|
||||||
|
{ prop: 'productSkcId', label: 'SKC ID', align: 'left' },
|
||||||
|
{ prop: 'skcExtCode', label: 'SKC货号', align: 'left' },
|
||||||
|
{ prop: 'productSkuId', label: 'SKU ID', align: 'left' },
|
||||||
|
{ prop: 'skuExtCode', label: 'SKU货号', align: 'left' },
|
||||||
|
{ prop: 'className', label: 'SKU属性', align: 'left' },
|
||||||
|
{ prop: 'prodSkuPayQtyTotal7d', label: '近7天SKU销量', align: 'left' },
|
||||||
|
{ prop: 'prodSkcPayQtyTotal7d', label: '近7天SKC销量', align: 'left' },
|
||||||
|
{ prop: 'totalStock', label: '仓内可用库存', align: 'left' },
|
||||||
|
{ prop: 'stockNotAvailable', label: '仓内暂不可用库存', align: 'left' },
|
||||||
|
{ prop: 'totalWaitReceiveNum', label: '已发货库存', align: 'left' },
|
||||||
|
{ prop: 'stockAvailable', label: '合计库存', align: 'left' },
|
||||||
|
{ prop: 'stockAvlbDays', label: '库存可售天数', align: 'left' },
|
||||||
|
{ prop: 'p7dSellOutSimuAmount', label: '近7天销售损失(CNY)', align: 'left' },
|
||||||
|
{ prop: 'p7dSellOutSimuAmountRatio', label: '近7天销售损失占比', align: 'left' },
|
||||||
|
{ prop: 'prodSkuPayQtyTotal7d2', label: '近7天sku已支付销量', align: 'left' },
|
||||||
|
{ prop: 'waitDeliverOrderSnList', label: '待发货备货单ID', align: 'left' }
|
||||||
|
],
|
||||||
|
jsonFields: {
|
||||||
|
"商品名称": "productName",
|
||||||
|
"类目": "catName",
|
||||||
|
"SKC ID": "productSkcId",
|
||||||
|
"SKC货号": "skcExtCode",
|
||||||
|
"SKU ID": "productSkuId",
|
||||||
|
"SKU货号": "skuExtCode",
|
||||||
|
"SKU属性": "className",
|
||||||
|
"近7天SKU销量": "prodSkuPayQtyTotal7d",
|
||||||
|
"近7天SKC销量": "prodSkcPayQtyTotal7d",
|
||||||
|
"仓内可用库存": "totalStock",
|
||||||
|
"仓内暂不可用库存": "stockNotAvailable",
|
||||||
|
"已发货库存": "totalWaitReceiveNum",
|
||||||
|
"合计库存": "stockAvailable",
|
||||||
|
"库存可售天数": "stockAvlbDays",
|
||||||
|
"近7天销售损失(CNY)": "p7dSellOutSimuAmount",
|
||||||
|
"近7天销售损失占比": "p7dSellOutSimuAmountRatio",
|
||||||
|
"近7天sku已支付销量": "prodSkuPayQtyTotal7d2",
|
||||||
|
"待发货备货单ID": "waitDeliverOrderSnList"
|
||||||
|
},
|
||||||
|
|
||||||
|
currentPage: 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
},
|
||||||
|
|
||||||
|
components: {
|
||||||
|
JsonExcel
|
||||||
|
},
|
||||||
|
|
||||||
|
created () {
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
onChange (e) {
|
||||||
|
this.tableData = []
|
||||||
|
this.currentPage = 1
|
||||||
|
if (e === '0') {
|
||||||
|
this.getList(1)
|
||||||
|
} else {
|
||||||
|
this.getList(2)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
beforeGetList() {
|
||||||
|
if (!this.mallId) {
|
||||||
|
Message.error("请先选择店铺")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.currentPage = 1
|
||||||
|
this.tableData = []
|
||||||
|
this.$userCheck(this.mallId).then(() => {
|
||||||
|
this.isLoading = true
|
||||||
|
if (this.type == '0') {
|
||||||
|
this.getList(1)
|
||||||
|
} else {
|
||||||
|
this.getList(2)
|
||||||
|
}
|
||||||
|
}).catch((err) => {
|
||||||
|
this.isLoading = false
|
||||||
|
})
|
||||||
|
},
|
||||||
|
getList (detailType) {
|
||||||
|
sendChromeAPIMessage({
|
||||||
|
url: 'marvel-mms/cn/api/kiana/venom/sold/out/querySoldOutDetail',
|
||||||
|
needMallId: true,
|
||||||
|
mallId: this.mallId,
|
||||||
|
anti: true,
|
||||||
|
data: {
|
||||||
|
"pageNo": this.currentPage,
|
||||||
|
"pageSize": 200,
|
||||||
|
"detailType": detailType
|
||||||
|
}}).then((res) => {
|
||||||
|
if (res.errorCode == 1000000) {
|
||||||
|
res.result.soldOutDetailList.map(item => {
|
||||||
|
this.tableData.push({...item,
|
||||||
|
p7dSellOutSimuAmount: item.p7dSellOutSimuAmount/100,
|
||||||
|
p7dSellOutSimuAmountRatio: (item.p7dSellOutSimuAmountRatio * 100).toFixed(2) + '%',
|
||||||
|
waitDeliverOrderSnList: item.waitDeliverOrderSnList.join(',')})
|
||||||
|
})
|
||||||
|
if (200 == res.result.soldOutDetailList.length) {
|
||||||
|
this.currentPage ++
|
||||||
|
setTimeout(() => {
|
||||||
|
this.getList(detailType)
|
||||||
|
}, 1000)
|
||||||
|
} else {
|
||||||
|
this.isLoading = false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setTimeout(() => {
|
||||||
|
this.getList(detailType)
|
||||||
|
}, 1000)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
startDownload() {
|
||||||
|
this.$http.post('/api/malluser/info').then(res => {
|
||||||
|
if (res.code == 0) {
|
||||||
|
this.$store.commit('setUserInfo', res.data)
|
||||||
|
if (res.data.flag != 1) {
|
||||||
|
Message.error('您的账号未激活或已失效,请激活后使用')
|
||||||
|
this.$store.commit('setActiveDlgShow', true)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.list {
|
||||||
|
.title-right {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
& > div:first-child {
|
||||||
|
margin-right: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
::v-deep.ai-list {
|
||||||
|
.ai-list__content--right-wrapper {
|
||||||
|
background: transparent;
|
||||||
|
box-shadow: none;
|
||||||
|
padding: 0!important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -11,7 +11,6 @@
|
|||||||
<script>
|
<script>
|
||||||
import List from './components/List.vue'
|
import List from './components/List.vue'
|
||||||
import Detail from './components/Detail.vue'
|
import Detail from './components/Detail.vue'
|
||||||
import SheinDetail from './components/SheinDetail.vue'
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'SingleTrack',
|
name: 'SingleTrack',
|
||||||
@@ -19,8 +18,7 @@
|
|||||||
|
|
||||||
components: {
|
components: {
|
||||||
List,
|
List,
|
||||||
Detail,
|
Detail
|
||||||
SheinDetail
|
|
||||||
},
|
},
|
||||||
|
|
||||||
data () {
|
data () {
|
||||||
@@ -37,11 +35,6 @@
|
|||||||
this.params = data.params
|
this.params = data.params
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.type === 'SheinDetail') {
|
|
||||||
this.component = 'SheinDetail'
|
|
||||||
this.params = data.params
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.type === 'List') {
|
if (data.type === 'List') {
|
||||||
this.component = 'List'
|
this.component = 'List'
|
||||||
this.params = data.params
|
this.params = data.params
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<ai-list class="list">
|
<ai-list class="list">
|
||||||
<ai-title
|
<ai-title
|
||||||
slot="title"
|
slot="title"
|
||||||
:title="'店铺ID(' + `${content}` + ')商品列表'"
|
:title="'分组(' + `${content}` + ')商品列表'"
|
||||||
isShowBottomBorder isShowBack @onBackClick="cancel(false)">
|
isShowBottomBorder isShowBack @onBackClick="cancel(false)">
|
||||||
</ai-title>
|
</ai-title>
|
||||||
<template slot="content">
|
<template slot="content">
|
||||||
@@ -26,10 +26,6 @@
|
|||||||
<el-input :clearable="true" size="small" style="width: 80px" v-model="search.saleBegin" ></el-input>
|
<el-input :clearable="true" size="small" style="width: 80px" v-model="search.saleBegin" ></el-input>
|
||||||
~
|
~
|
||||||
<el-input :clearable="true" size="small" style="width: 80px" v-model="search.saleEnd" ></el-input>
|
<el-input :clearable="true" size="small" style="width: 80px" v-model="search.saleEnd" ></el-input>
|
||||||
<label style="width:100px">仅显示最新:</label>
|
|
||||||
<ai-select :selectList="$dict.getDict('mall_yesno')" v-model="search.isNew"></ai-select>
|
|
||||||
<label style="width:100px">仅显示下架:</label>
|
|
||||||
<ai-select :selectList="$dict.getDict('mall_yesno')" v-model="search.isOff"></ai-select>
|
|
||||||
</template>
|
</template>
|
||||||
<template #right>
|
<template #right>
|
||||||
<el-button type="primary" @click="search.current =1, getList()">查询</el-button>
|
<el-button type="primary" @click="search.current =1, getList()">查询</el-button>
|
||||||
@@ -37,16 +33,7 @@
|
|||||||
</ai-search-bar>
|
</ai-search-bar>
|
||||||
<div style="display: grid; grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr; gap: 16px;">
|
<div style="display: grid; grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr; gap: 16px;">
|
||||||
<el-card v-for="item in tableData" :key="item.id" :body-style="{ padding: '0px', margin: '5px' }">
|
<el-card v-for="item in tableData" :key="item.id" :body-style="{ padding: '0px', margin: '5px' }">
|
||||||
<div :class="[{'img-background': item.isSelect}, 'img-box']" v-if="item.isOff == '1'">
|
<span class="nav-label labelBadge">
|
||||||
<div>
|
|
||||||
<el-image :src="item.imgUrl" class="mask image" :preview-src-list="[item.imgUrl]" />
|
|
||||||
</div>
|
|
||||||
<span class="icon-box">
|
|
||||||
<img style="width: 50px; height: 50px" src="../../../../assets/off.png">
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<span class="nav-label labelBadge" v-else>
|
|
||||||
<span class="ii" v-if="item.isNew == 1">新</span>
|
|
||||||
<el-image :src="item.imgUrl" class="image" :preview-src-list="[item.imgUrl]" />
|
<el-image :src="item.imgUrl" class="image" :preview-src-list="[item.imgUrl]" />
|
||||||
</span>
|
</span>
|
||||||
<div style="padding: 14px;">
|
<div style="padding: 14px;">
|
||||||
@@ -56,11 +43,8 @@
|
|||||||
<div style="display: inline; margin-right: 5px; float: right;">{{ item.saleTotal }}<sub style="margin-left: 2px;" v-html="getSalePercent(item.saleChange)"></sub></div>
|
<div style="display: inline; margin-right: 5px; float: right;">{{ item.saleTotal }}<sub style="margin-left: 2px;" v-html="getSalePercent(item.saleChange)"></sub></div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div v-if="search.orderBy == '5'" style="display: inline">近3次日均销量: <span style="color: red; font-weight: bold">{{ item.days3AverageSale }}</span></div>
|
<div style="display: inline">日均销量: <span style="color: red; font-weight: bold">{{ item.averageSale }}</span></div>
|
||||||
<div v-else-if="search.orderBy == '6'" style="display: inline">近7次日均销量: <span style="color: red; font-weight: bold">{{ item.days7AverageSale }}</span></div>
|
<ai-product-drop-down :params="item" :isShowDetail="true" :isShowAddFavorite="true" :isShowDelFavorite="false" @onGoDetail="goDetail(item.goodsId, item.groupId)" style="float: right;"></ai-product-drop-down>
|
||||||
<div v-else-if="search.orderBy == '7'" style="display: inline">近15次日均销量: <span style="color: red; font-weight: bold">{{ item.days15AverageSale }}</span></div>
|
|
||||||
<div v-else style="display: inline">日均销量: <span style="color: red; font-weight: bold">{{ item.averageSale }}</span></div>
|
|
||||||
<ai-product-drop-down :params="item" :isShowDetail="true" :isShowAddFavorite="true" :isShowDelFavorite="false" @onGoDetail="goDetail(item.goodsId, item.monitorId)" style="float: right;"></ai-product-drop-down>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -84,23 +68,23 @@
|
|||||||
:close-on-click-modal="false"
|
:close-on-click-modal="false"
|
||||||
width="80%"
|
width="80%"
|
||||||
:before-close="handleClose">
|
:before-close="handleClose">
|
||||||
<ai-product-detail v-if="isShowDetailDlg" :params="detailParams"/>
|
<ai-single-product-detail v-if="isShowDetailDlg" :params="detailParams"/>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import AiProductDetail from "@/components/AiProductDetail.vue";
|
import AiSingleProductDetail from "@/components/AiSingleProductDetail.vue";
|
||||||
import AiProductDropDown from '@/components/AiProductDropDown.vue';
|
import AiProductDropDown from '@/components/AiProductDropDown.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'DetailPage',
|
name: 'DetailPage',
|
||||||
props: ['params'],
|
props: ['params'],
|
||||||
components: {AiProductDetail, AiProductDropDown},
|
components: {AiSingleProductDetail, AiProductDropDown},
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
monitorId: '',
|
groupId: '',
|
||||||
content: '',
|
content: '',
|
||||||
search: {
|
search: {
|
||||||
current: 1,
|
current: 1,
|
||||||
@@ -110,9 +94,7 @@ import AiProductDropDown from '@/components/AiProductDropDown.vue';
|
|||||||
priceBegin: '',
|
priceBegin: '',
|
||||||
priceEnd: '',
|
priceEnd: '',
|
||||||
saleBegin: '',
|
saleBegin: '',
|
||||||
saleEnd: '',
|
saleEnd: ''
|
||||||
isNew: '',
|
|
||||||
isOff: ''
|
|
||||||
},
|
},
|
||||||
orderBys: [{
|
orderBys: [{
|
||||||
value: '0',
|
value: '0',
|
||||||
@@ -129,15 +111,6 @@ import AiProductDropDown from '@/components/AiProductDropDown.vue';
|
|||||||
},{
|
},{
|
||||||
value: '4',
|
value: '4',
|
||||||
label: '按日均销量排序'
|
label: '按日均销量排序'
|
||||||
},{
|
|
||||||
value: '5',
|
|
||||||
label: '按近3次采集平均销售量排序'
|
|
||||||
},{
|
|
||||||
value: '6',
|
|
||||||
label: '按近7次采集平均销售量排序'
|
|
||||||
},{
|
|
||||||
value: '7',
|
|
||||||
label: '按近15次采集平均销售量排序'
|
|
||||||
}],
|
}],
|
||||||
tableData: [],
|
tableData: [],
|
||||||
total: 0,
|
total: 0,
|
||||||
@@ -147,17 +120,16 @@ import AiProductDropDown from '@/components/AiProductDropDown.vue';
|
|||||||
},
|
},
|
||||||
|
|
||||||
created () {
|
created () {
|
||||||
this.$dict.load('mall_yesno');
|
this.groupId = this.params.id
|
||||||
this.monitorId = this.params.id
|
|
||||||
this.content = this.params.content
|
this.content = this.params.content
|
||||||
this.getList()
|
this.getList()
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
getList () {
|
getList () {
|
||||||
this.$http.post('/api/monitorDetail/myPageNew',null,{
|
this.$http.post('/api/singleGoodsDetail/myPageNew',null,{
|
||||||
params: {
|
params: {
|
||||||
monitorId: this.monitorId,
|
groupId: this.groupId,
|
||||||
...this.search
|
...this.search
|
||||||
}
|
}
|
||||||
}).then(res => {
|
}).then(res => {
|
||||||
@@ -190,8 +162,8 @@ import AiProductDropDown from '@/components/AiProductDropDown.vue';
|
|||||||
handleClose() {
|
handleClose() {
|
||||||
this.isShowDetailDlg = false
|
this.isShowDetailDlg = false
|
||||||
},
|
},
|
||||||
goDetail (goodsId, monitorId) {
|
goDetail (goodsId, groupId) {
|
||||||
this.detailParams = {goodsId: goodsId, monitorId: monitorId}
|
this.detailParams = {goodsId: goodsId, groupId: groupId}
|
||||||
this.isShowDetailDlg = true
|
this.isShowDetailDlg = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<ai-list class="list" v-loading="isLoading" element-loading-text="正在采集中……" element-loading-spinner="el-icon-loading">
|
<ai-list class="list" v-loading="isLoading" :element-loading-text="loadingText" element-loading-spinner="el-icon-loading">
|
||||||
<ai-title
|
<ai-title
|
||||||
slot="title"
|
slot="title"
|
||||||
title="单品跟踪"
|
title="单品跟踪"
|
||||||
@@ -11,7 +11,6 @@
|
|||||||
<ai-search-bar>
|
<ai-search-bar>
|
||||||
<template #left>
|
<template #left>
|
||||||
<el-button type="button" :icon="'el-icon-delete'" :class="'el-button el-button--primary'" @click="batchRemove()">删除</el-button>
|
<el-button type="button" :icon="'el-icon-delete'" :class="'el-button el-button--primary'" @click="batchRemove()">删除</el-button>
|
||||||
<el-button type="button" :class="'el-button el-button--primary'" @click="batchCollect()">批量采集</el-button>
|
|
||||||
<el-button type="button" :class="'el-button el-button--primary'" @click="addGroup()">添加分组</el-button>
|
<el-button type="button" :class="'el-button el-button--primary'" @click="addGroup()">添加分组</el-button>
|
||||||
</template>
|
</template>
|
||||||
<template #right>
|
<template #right>
|
||||||
@@ -26,12 +25,13 @@
|
|||||||
@selection-change="onChooseChange"
|
@selection-change="onChooseChange"
|
||||||
:current.sync="search.current" :size.sync="search.size"
|
:current.sync="search.current" :size.sync="search.size"
|
||||||
@getList="getList">
|
@getList="getList">
|
||||||
<el-table-column slot="options" label="操作" width="240px" show-overflow-tooltip align="center" fixed="right">
|
<el-table-column slot="options" label="操作" width="280px" show-overflow-tooltip align="center" fixed="right">
|
||||||
<template slot-scope="{ row }">
|
<template slot-scope="{ row }">
|
||||||
<div class="table-options">
|
<div class="table-options">
|
||||||
<el-button type="text" @click="deleteGroup(row.id)">删除</el-button>
|
<el-button type="text" @click="deleteGroup(row.id)">删除</el-button>
|
||||||
<el-button type="text" @click="toUpdateGroup(row)">修改</el-button>
|
<el-button type="text" @click="toUpdateGroup(row)">修改</el-button>
|
||||||
<el-button type="text" @click="toDetail(row.id, row.content, row.source)">详情</el-button>
|
<el-button type="text" @click="toAddUrl(row)">添加商品</el-button>
|
||||||
|
<el-button type="text" @click="toDetail(row.id, row.name)">详情</el-button>
|
||||||
<el-button type="text" @click="toBegin(row)">采集数据</el-button>
|
<el-button type="text" @click="toBegin(row)">采集数据</el-button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -82,11 +82,53 @@
|
|||||||
<el-button type="primary" @click="updateGroup">确定</el-button>
|
<el-button type="primary" @click="updateGroup">确定</el-button>
|
||||||
</div>
|
</div>
|
||||||
</ai-dialog>
|
</ai-dialog>
|
||||||
|
|
||||||
|
<ai-dialog
|
||||||
|
title="添加商品"
|
||||||
|
:visible.sync="isAddUrlDlgShow"
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
width="80%"
|
||||||
|
customFooter
|
||||||
|
@close="isDlgShow = false">
|
||||||
|
<el-alert
|
||||||
|
title="每成功添加一个商品,将消耗10金币"
|
||||||
|
type="success"
|
||||||
|
:closable="false" style="margin-bottom: 10px;">
|
||||||
|
</el-alert>
|
||||||
|
<el-form class="ai-form" style="margin-top: 20px" :model="addUrlForm" label-width="120px" ref="addUrlForm">
|
||||||
|
<el-form-item
|
||||||
|
prop="urls"
|
||||||
|
label="商品地址"
|
||||||
|
:rules="[{ required: true, message: '请输入TEMU商品地址,多个用英文,号或换行隔开', trigger: 'blur' }]">
|
||||||
|
<el-input type="textarea" placeholder="请输入TEMU商品地址,多个用英文,号或换行隔开" :rows="20" v-model="addUrlForm.urls"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<div class="dialog-footer" slot="footer">
|
||||||
|
<el-button @click="isAddUrlDlgShow = false">取 消</el-button>
|
||||||
|
<el-button type="primary" @click="addUrl">确定</el-button>
|
||||||
|
</div>
|
||||||
|
</ai-dialog>
|
||||||
|
|
||||||
|
<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="isTipDlgShow = false, isLoading = true, beginCollect()">已验证,继续采集</el-button>
|
||||||
|
<el-button style="width: 180px;" @click="isTipDlgShow = false, isLoading = true, currentIndex ++, beginCollect()">跳过</el-button>
|
||||||
|
<el-button type="primary" @click="gotoValid">前往验证</el-button>
|
||||||
|
</div>
|
||||||
|
</ai-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {sendTemuAPIMessage, sendSheinAPIMessage} from '@/api/chromeApi'
|
import {sendTemuAPIMessage, sendSheinAPIMessage, sendChromeWebReqMessage} from '@/api/chromeApi'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'List',
|
name: 'List',
|
||||||
@@ -101,6 +143,7 @@ import {sendTemuAPIMessage, sendSheinAPIMessage} from '@/api/chromeApi'
|
|||||||
colConfigs: [
|
colConfigs: [
|
||||||
{ type: "selection", width: '70px', align: 'left' },
|
{ type: "selection", width: '70px', align: 'left' },
|
||||||
{ prop: 'name', label: '分组名称', align: 'left' },
|
{ prop: 'name', label: '分组名称', align: 'left' },
|
||||||
|
{ prop: 'total', label: '商品个数', align: 'left' },
|
||||||
{ prop: 'lastUpdateTime', label: '上一次更新时间', align: 'left' },
|
{ prop: 'lastUpdateTime', label: '上一次更新时间', align: 'left' },
|
||||||
{ prop: 'createTime', label: '添加时间', width: '180px', fixed: 'right'}
|
{ prop: 'createTime', label: '添加时间', width: '180px', fixed: 'right'}
|
||||||
],
|
],
|
||||||
@@ -126,7 +169,22 @@ import {sendTemuAPIMessage, sendSheinAPIMessage} from '@/api/chromeApi'
|
|||||||
isLoading: false,
|
isLoading: false,
|
||||||
|
|
||||||
selectRows: [],
|
selectRows: [],
|
||||||
isBatchCollect: false
|
isBatchCollect: false,
|
||||||
|
|
||||||
|
isAddUrlDlgShow: false,
|
||||||
|
addUrlForm: {
|
||||||
|
groupId: '',
|
||||||
|
urls: ''
|
||||||
|
},
|
||||||
|
|
||||||
|
loadingText: '正在采集中……',
|
||||||
|
isTipDlgShow: false,
|
||||||
|
errorUrl: '',
|
||||||
|
collectList: [],
|
||||||
|
currentIndex: 0,
|
||||||
|
collectData: {
|
||||||
|
groupId: ''
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -200,26 +258,6 @@ import {sendTemuAPIMessage, sendSheinAPIMessage} from '@/api/chromeApi'
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
batchCollect () {
|
|
||||||
if (this.selectRows.length <= 0) {
|
|
||||||
this.$message.error('请选择要采集的分组');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.isBatchCollect = true
|
|
||||||
this.isLoading = true
|
|
||||||
this.selectRows.map((item, index) => {
|
|
||||||
setTimeout(() => {
|
|
||||||
this.pageNo = 1
|
|
||||||
|
|
||||||
let data = {}
|
|
||||||
data.monitorId = item.id
|
|
||||||
data.source = item.source
|
|
||||||
data.details = []
|
|
||||||
|
|
||||||
this.beginCollect(item, data, index)
|
|
||||||
}, 1000*(index+1))
|
|
||||||
})
|
|
||||||
},
|
|
||||||
deleteGroup(id) {
|
deleteGroup(id) {
|
||||||
this.$confirm('确定要删除?', '温馨提示', {
|
this.$confirm('确定要删除?', '温馨提示', {
|
||||||
type: 'warning'
|
type: 'warning'
|
||||||
@@ -237,166 +275,182 @@ import {sendTemuAPIMessage, sendSheinAPIMessage} from '@/api/chromeApi'
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
toDetail (id, content, source) {
|
toDetail (id, content) {
|
||||||
if (source == '0') {
|
this.$emit('change', {
|
||||||
this.$emit('change', {
|
type: 'Detail',
|
||||||
type: 'Detail',
|
params: {
|
||||||
params: {
|
id: id || '',
|
||||||
id: id || '',
|
content: content
|
||||||
content: content
|
}
|
||||||
}
|
})
|
||||||
})
|
|
||||||
} else {
|
|
||||||
this.$emit('change', {
|
|
||||||
type: 'SheinDetail',
|
|
||||||
params: {
|
|
||||||
id: id || '',
|
|
||||||
content: content
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
},
|
},
|
||||||
addGroup() {
|
addGroup() {
|
||||||
this.form.mallId = ''
|
this.form.mallId = ''
|
||||||
this.isDlgShow = true
|
this.isDlgShow = true
|
||||||
},
|
},
|
||||||
toBegin(row) {
|
toAddUrl(row) {
|
||||||
this.isBatchCollect = false
|
this.isAddUrlDlgShow = true
|
||||||
this.pageNo = 1
|
this.addUrlForm.groupId = row.id
|
||||||
this.isLoading = true
|
this.addUrlForm.urls = ''
|
||||||
|
|
||||||
let data = {}
|
|
||||||
data.monitorId = row.id
|
|
||||||
data.details = []
|
|
||||||
|
|
||||||
this.beginCollect(row, data, 0)
|
|
||||||
},
|
},
|
||||||
|
addUrl() {
|
||||||
|
this.$refs.addUrlForm.validate((valid) => {
|
||||||
|
if (valid) {
|
||||||
|
let params = []
|
||||||
|
let arr = this.addUrlForm.urls.split(/[\n,]/).map((value) => value.trim());
|
||||||
|
arr.map(url => {
|
||||||
|
let urlParams = this.parseURL(url)
|
||||||
|
let tmpUrl = url.substring(0,url.indexOf(".html"))
|
||||||
|
|
||||||
beginCollect(row, reqData, index) {
|
if (tmpUrl.lastIndexOf("-g-") > 0) {
|
||||||
if (row.source == '0') {
|
tmpUrl = tmpUrl.substring(tmpUrl.lastIndexOf("-g-"), tmpUrl.length);
|
||||||
this.beginTemuCollect(row, reqData, index)
|
tmpUrl = tmpUrl.substring(3, tmpUrl.length);
|
||||||
} else if (row.source == '1') {
|
params.push({
|
||||||
this.beginSheinCollect(row, reqData, index)
|
groupId: this.addUrlForm.groupId,
|
||||||
}
|
goodsUrl: url,
|
||||||
},
|
goodsId: tmpUrl
|
||||||
beginTemuCollect(row, reqData, index) {
|
|
||||||
sendTemuAPIMessage({
|
|
||||||
url: 'api/bg/circle/c/mall/newGoodsList',
|
|
||||||
anti: true,
|
|
||||||
data: {
|
|
||||||
"mall_id": row.content,
|
|
||||||
"filter_items": "0:1",
|
|
||||||
"page_number": this.pageNo,
|
|
||||||
"page_size": this.pageSize
|
|
||||||
}}).then((res) => {
|
|
||||||
if (this.isBatchCollect && (index+1) == this.selectRows.length) {
|
|
||||||
this.isLoading = false
|
|
||||||
this.isBatchCollect = false
|
|
||||||
} else {
|
|
||||||
this.isLoading = false
|
|
||||||
}
|
|
||||||
if (res.errorCode == 1000000) {
|
|
||||||
res.result.data.goods_list.map(item => {
|
|
||||||
let total = 0
|
|
||||||
if (item.sales_tip_text[0]) {
|
|
||||||
total = item.sales_tip_text[0]
|
|
||||||
total = total.replace('+', '')
|
|
||||||
if (total.indexOf('K') != -1) {
|
|
||||||
total = total.replace('K', '')
|
|
||||||
total = total * 1000
|
|
||||||
} else if (total.indexOf('M') != -1) {
|
|
||||||
total = total.replace('M', '')
|
|
||||||
total = total * 1000000
|
|
||||||
}
|
|
||||||
}
|
|
||||||
reqData.details.push({
|
|
||||||
url: 'https://www.temu.com/goods.html?goods_id=' + item.goods_id,
|
|
||||||
price: item.price_info.price_schema,
|
|
||||||
saleTotal: total,
|
|
||||||
goodsId: item.goods_id,
|
|
||||||
imgUrl: item.thumb_url,
|
|
||||||
mallId: item.mall_id
|
|
||||||
})
|
})
|
||||||
})
|
|
||||||
|
|
||||||
if (res.result.data.goods_list.length == this.pageSize) {
|
|
||||||
this.pageNo = this.pageNo + 1
|
|
||||||
this.beginCollect(row, reqData, index)
|
|
||||||
} else {
|
} else {
|
||||||
this.isLoading = false
|
let urlParams = this.parseURL(url)
|
||||||
this.$http.post('/api/monitorDetail/addDetails', reqData
|
if (urlParams.params) {
|
||||||
).then(res => {
|
let goodsId = urlParams.params.goods_id
|
||||||
if (res.code == 0) {
|
if (goodsId) {
|
||||||
this.$message.success('店铺ID【' + row.content + '】数据采集成功!')
|
params.push({
|
||||||
this.getList()
|
groupId: this.addUrlForm.groupId,
|
||||||
|
goodsUrl: url,
|
||||||
|
goodsId: goodsId
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.isLoading = false
|
|
||||||
this.$message.error("采集失败,请检查https://www.temu.com是否能正常访问")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
async beginSheinCollect(row, reqData, index) {
|
|
||||||
let res = await sendSheinAPIMessage({
|
|
||||||
url: 'api/store/items/get',
|
|
||||||
method: 'GET',
|
|
||||||
params: {
|
|
||||||
_ver: '1.1.8',
|
|
||||||
_lang: 'en',
|
|
||||||
scene_id: '10188',
|
|
||||||
rule_poskey: "shoprecommend",
|
|
||||||
requestType: "pageChange",
|
|
||||||
search_type: "store",
|
|
||||||
store_code: row.content,
|
|
||||||
viewed_goods: '',
|
|
||||||
limit: 120,
|
|
||||||
page: this.pageNo
|
|
||||||
}})
|
|
||||||
if (this.isBatchCollect && (index+1) == this.selectRows.length) {
|
|
||||||
this.isLoading = false
|
|
||||||
this.isBatchCollect = false
|
|
||||||
} else {
|
|
||||||
this.isLoading = false
|
|
||||||
}
|
|
||||||
if (res.goods && res.goods.length > 0) {
|
|
||||||
res.goods.map(item => {
|
|
||||||
let total = 0
|
|
||||||
if (item.pretreatInfo?.sellingPointUniversalLabels) {
|
|
||||||
for (let i = 0; i < item.pretreatInfo.sellingPointUniversalLabels.length; i++) {
|
|
||||||
if (item.pretreatInfo.sellingPointUniversalLabels[i].starComment) {
|
|
||||||
total = item.pretreatInfo.sellingPointUniversalLabels[i].starComment?.comment_num || 0
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
reqData.details.push({
|
|
||||||
url: 'https://www.shein.com/'+item.goods_url_name.replace(/ /g, '-')+'-p-'+item.goods_id+'-cat-'+item.cat_id+'.html',
|
|
||||||
price: item.salePrice.amount,
|
|
||||||
saleTotal: total,
|
|
||||||
goodsId: item.goods_id,
|
|
||||||
imgUrl: 'https:'+item.goods_img,
|
|
||||||
mallId: item.store_code
|
|
||||||
})
|
})
|
||||||
})
|
this.$http.post(`/api/singleGroup/saveGoods`, params).then(res => {
|
||||||
|
|
||||||
if (res.goods.length == this.pageSize) {
|
|
||||||
this.pageNo = this.pageNo + 1
|
|
||||||
this.beginCollect(row, reqData, index)
|
|
||||||
} else {
|
|
||||||
this.isLoading = false
|
|
||||||
this.$http.post('/api/monitorDetail/addDetails', reqData
|
|
||||||
).then(res => {
|
|
||||||
if (res.code == 0) {
|
if (res.code == 0) {
|
||||||
this.$message.success('店铺ID【' + row.content + '】数据采集成功!')
|
this.$message.success(res.msg)
|
||||||
this.getList()
|
this.getList()
|
||||||
|
this.isAddUrlDlgShow = false
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
toBegin(row) {
|
||||||
|
this.isLoading = true
|
||||||
|
|
||||||
|
this.collectData.groupId = row.id
|
||||||
|
this.collectData.details = []
|
||||||
|
|
||||||
|
this.$http.post(`/api/singleGroup/getGoodsList`, null, {params: {
|
||||||
|
id: row.id
|
||||||
|
}}).then(res => {
|
||||||
|
if (res.code == 0) {
|
||||||
|
this.collectList = res.data
|
||||||
|
this.currentIndex = 0
|
||||||
|
|
||||||
|
this.beginCollect()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
},
|
||||||
|
async beginCollect() {
|
||||||
|
this.loadingText = `正在采集第(${this.currentIndex}/${this.collectList.length})个商品的商品信息`
|
||||||
|
if (this.currentIndex == this.collectList.length) {
|
||||||
|
let res = await this.$http.post(`/api/singleGoodsDetail/addDetails`, this.collectData)
|
||||||
|
if (res.code == 0) {
|
||||||
|
this.getList()
|
||||||
|
}
|
||||||
|
this.isLoading = false
|
||||||
|
this.$message.success('采集成功')
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
let res = await sendTemuAPIMessage({
|
||||||
|
url: 'api/oak/integration/render',
|
||||||
|
anti: true,
|
||||||
|
data: {
|
||||||
|
goods_id: this.collectList[this.currentIndex].goodsId
|
||||||
|
}})
|
||||||
|
|
||||||
|
if (!res.goods || !res.goods.productName) {
|
||||||
|
res = await sendChromeWebReqMessage({
|
||||||
|
type: 'temu',
|
||||||
|
url: this.collectList[this.currentIndex].goodsUrl,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (res.indexOf("window.rawData") == -1) {
|
||||||
|
this.$message.error("请检查地址是否正确,或者“TEMU”网站是否出现图形验证码")
|
||||||
|
|
||||||
|
this.isLoading = false
|
||||||
|
this.errorUrl = this.collectList[this.currentIndex].goodsUrl
|
||||||
|
this.isTipDlgShow = true
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
let str = res.substring(res.indexOf("window.rawData"))
|
||||||
|
str = str.substring(0, str.indexOf("<\/script>"))
|
||||||
|
str = str.substring(str.indexOf("{"))
|
||||||
|
str = str.substring(0, str.lastIndexOf("}"))
|
||||||
|
str = str + "}"
|
||||||
|
let goodsObj = JSON.parse(str)
|
||||||
|
let goods = goodsObj.store.goods
|
||||||
|
|
||||||
|
this.collectData.details.push({
|
||||||
|
groupId: this.collectData.groupId,
|
||||||
|
price: goods.minOnSalePrice / 100,
|
||||||
|
saleTotal: goods.soldQuantity,
|
||||||
|
goodsId: goods.goodsId,
|
||||||
|
url: 'https://www.temu.com/goods.html?goods_id=' +goods.goodsId,
|
||||||
|
imgUrl: goods.hdThumbUrl,
|
||||||
|
mallId: goods.mallId
|
||||||
|
})
|
||||||
|
|
||||||
|
this.currentIndex ++
|
||||||
|
this.beginCollect()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.collectData.details.push({
|
||||||
|
groupId: this.collectData.groupId,
|
||||||
|
price: res.goods.min_on_sale_price / 100,
|
||||||
|
saleTotal: res.goods.sold_quantity,
|
||||||
|
goodsId: res.goods.goods_id,
|
||||||
|
url: 'https://www.temu.com/goods.html?goods_id=' + res.goods.goods_id,
|
||||||
|
imgUrl: res.goods.hd_thumb_url,
|
||||||
|
mallId: res.goods.mall_id
|
||||||
|
})
|
||||||
|
|
||||||
|
this.currentIndex ++
|
||||||
|
this.beginCollect()
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
gotoValid() {
|
||||||
|
window.open(this.errorUrl, '_blank');
|
||||||
|
},
|
||||||
|
parseURL(url) {
|
||||||
|
let a = document.createElement('a');
|
||||||
|
a.href = url;
|
||||||
|
return {
|
||||||
|
source: url,
|
||||||
|
protocol: a.protocol.replace(':',''),
|
||||||
|
host: a.hostname,
|
||||||
|
port: a.port,
|
||||||
|
query: a.search,
|
||||||
|
params: (function(){
|
||||||
|
var ret = {},
|
||||||
|
seg = a.search.replace(/^\?/,'').split('&'),
|
||||||
|
len = seg.length, i = 0, s;
|
||||||
|
for (;i<len;i++) {
|
||||||
|
if (!seg[i]) { continue; }
|
||||||
|
s = seg[i].split('=');
|
||||||
|
ret[s[0]] = s[1];
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
})(),
|
||||||
|
file: (a.pathname.match(/\/([^\/?#]+)$/i) || [,''])[1],
|
||||||
|
hash: a.hash.replace('#',''),
|
||||||
|
path: a.pathname.replace(/^([^\/])/,'/$1'),
|
||||||
|
relative: (a.href.match(/tps?:\/\/[^\/]+(.+)/) || [,''])[1],
|
||||||
|
segments: a.pathname.replace(/^\//,'').split('/')
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,302 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div>
|
|
||||||
<ai-list class="list">
|
|
||||||
<ai-title
|
|
||||||
slot="title"
|
|
||||||
:title="'店铺ID(' + `${content}` + ')商品列表'"
|
|
||||||
isShowBottomBorder isShowBack @onBackClick="cancel(false)">
|
|
||||||
</ai-title>
|
|
||||||
<template slot="content">
|
|
||||||
<ai-search-bar>
|
|
||||||
<template #left>
|
|
||||||
<label style="width:80px">排序方式:</label>
|
|
||||||
<el-select v-model="search.orderBy" :clearable="true" @change="search.current =1, getList()" placeholder="请选择排序方式" size="small">
|
|
||||||
<el-option
|
|
||||||
v-for="item in orderBys"
|
|
||||||
:key="item.value"
|
|
||||||
:label="item.label"
|
|
||||||
:value="item.value">
|
|
||||||
</el-option>
|
|
||||||
</el-select>
|
|
||||||
<label style="width:80px">价格区间:</label>
|
|
||||||
<el-input :clearable="true" size="small" style="width: 80px" v-model="search.priceBegin" ></el-input>
|
|
||||||
~
|
|
||||||
<el-input :clearable="true" size="small" style="width: 80px" v-model="search.priceEnd" ></el-input>
|
|
||||||
<label style="width:80px">评论数区间:</label>
|
|
||||||
<el-input :clearable="true" size="small" style="width: 80px" v-model="search.saleBegin" ></el-input>
|
|
||||||
~
|
|
||||||
<el-input :clearable="true" size="small" style="width: 80px" v-model="search.saleEnd" ></el-input>
|
|
||||||
<label style="width:100px">仅显示最新:</label>
|
|
||||||
<ai-select :selectList="$dict.getDict('mall_yesno')" v-model="search.isNew"></ai-select>
|
|
||||||
<label style="width:100px">仅显示下架:</label>
|
|
||||||
<ai-select :selectList="$dict.getDict('mall_yesno')" v-model="search.isOff"></ai-select>
|
|
||||||
</template>
|
|
||||||
<template #right>
|
|
||||||
<el-button type="primary" @click="search.current =1, getList()">查询</el-button>
|
|
||||||
</template>
|
|
||||||
</ai-search-bar>
|
|
||||||
<div style="display: grid; grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr; gap: 16px;">
|
|
||||||
<el-card v-for="item in tableData" :key="item.id" :body-style="{ padding: '0px', margin: '5px' }">
|
|
||||||
<div :class="[{'img-background': item.isSelect}, 'img-box']" v-if="item.isOff == '1'">
|
|
||||||
<div>
|
|
||||||
<el-image :src="item.imgUrl" class="mask image" :preview-src-list="[item.imgUrl]" />
|
|
||||||
</div>
|
|
||||||
<span class="icon-box">
|
|
||||||
<img style="width: 50px; height: 50px" src="../../../../assets/off.png">
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<span class="nav-label labelBadge" v-else>
|
|
||||||
<span class="ii" v-if="item.isNew == 1">新</span>
|
|
||||||
<el-image :src="item.imgUrl" class="image" :preview-src-list="[item.imgUrl]" />
|
|
||||||
</span>
|
|
||||||
<div style="padding: 14px;">
|
|
||||||
<div class="bottom clearfix">
|
|
||||||
<div style="margin-bottom: 5px;">
|
|
||||||
<div style="display: inline; margin-left: 5px;">${{ item.price }}<sub style="margin-left: 2px;" v-html="getPricePercent(item.priceChange)"></sub></div>
|
|
||||||
<div style="display: inline; margin-right: 5px; float: right;">{{ item.saleTotal }}<sub style="margin-left: 2px;" v-html="getSalePercent(item.saleChange)"></sub></div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div v-if="search.orderBy == '5'" style="display: inline">近3次日均评论数: <span style="color: red; font-weight: bold">{{ item.days3AverageSale }}</span></div>
|
|
||||||
<div v-else-if="search.orderBy == '6'" style="display: inline">近7次日均评论数: <span style="color: red; font-weight: bold">{{ item.days7AverageSale }}</span></div>
|
|
||||||
<div v-else-if="search.orderBy == '7'" style="display: inline">近15次日均评论数: <span style="color: red; font-weight: bold">{{ item.days15AverageSale }}</span></div>
|
|
||||||
<div v-else style="display: inline">日均评论数: <span style="color: red; font-weight: bold">{{ item.averageSale }}</span></div>
|
|
||||||
<ai-product-drop-down :params="item" :isHideCopy="true" :isShowDetail="true" :isShowAddFavorite="true" :isShowDelFavorite="false" @onGoDetail="goDetail(item.goodsId, item.monitorId)" style="float: right;"></ai-product-drop-down>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</el-card>
|
|
||||||
<el-pagination
|
|
||||||
layout="prev, pager, next"
|
|
||||||
style="position: absolute; bottom: 0px; right: 40px;"
|
|
||||||
:total="total"
|
|
||||||
:page-size.sync="search.size"
|
|
||||||
:current-page.sync="search.current"
|
|
||||||
@current-change="getList">
|
|
||||||
</el-pagination>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</ai-list>
|
|
||||||
|
|
||||||
<div class="productDetail">
|
|
||||||
<el-dialog
|
|
||||||
title="商品详情"
|
|
||||||
:visible="isShowDetailDlg"
|
|
||||||
:close-on-click-modal="false"
|
|
||||||
width="80%"
|
|
||||||
:before-close="handleClose">
|
|
||||||
<ai-product-detail v-if="isShowDetailDlg" :params="detailParams"/>
|
|
||||||
</el-dialog>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import AiProductDetail from "@/components/AiProductDetail.vue";
|
|
||||||
import AiProductDropDown from '@/components/AiProductDropDown.vue';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'DetailPage',
|
|
||||||
props: ['params'],
|
|
||||||
components: {AiProductDetail, AiProductDropDown},
|
|
||||||
data () {
|
|
||||||
return {
|
|
||||||
monitorId: '',
|
|
||||||
content: '',
|
|
||||||
search: {
|
|
||||||
current: 1,
|
|
||||||
type: '1',
|
|
||||||
size: 120,
|
|
||||||
orderBy: '',
|
|
||||||
priceBegin: '',
|
|
||||||
priceEnd: '',
|
|
||||||
saleBegin: '',
|
|
||||||
saleEnd: '',
|
|
||||||
isNew: '',
|
|
||||||
isOff: ''
|
|
||||||
},
|
|
||||||
orderBys: [{
|
|
||||||
value: '0',
|
|
||||||
label: '按评论数涨辐排序'
|
|
||||||
},{
|
|
||||||
value: '1',
|
|
||||||
label: '按价格涨辐排序'
|
|
||||||
},{
|
|
||||||
value: '2',
|
|
||||||
label: '按评论数排序'
|
|
||||||
},{
|
|
||||||
value: '3',
|
|
||||||
label: '按价格排序'
|
|
||||||
},{
|
|
||||||
value: '4',
|
|
||||||
label: '按日均评论数排序'
|
|
||||||
},{
|
|
||||||
value: '5',
|
|
||||||
label: '按近3次采集平均评论数排序'
|
|
||||||
},{
|
|
||||||
value: '6',
|
|
||||||
label: '按近7次采集平均评论数排序'
|
|
||||||
},{
|
|
||||||
value: '7',
|
|
||||||
label: '按近15次采集平均评论数排序'
|
|
||||||
}],
|
|
||||||
tableData: [],
|
|
||||||
total: 0,
|
|
||||||
isShowDetailDlg: false,
|
|
||||||
detailParams: {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
created () {
|
|
||||||
this.$dict.load('mall_yesno');
|
|
||||||
this.monitorId = this.params.id
|
|
||||||
this.content = this.params.content
|
|
||||||
this.getList()
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
|
||||||
getList () {
|
|
||||||
this.$http.post('/api/monitorDetail/myPageNew',null,{
|
|
||||||
params: {
|
|
||||||
monitorId: this.monitorId,
|
|
||||||
...this.search
|
|
||||||
}
|
|
||||||
}).then(res => {
|
|
||||||
res.data.records = res.data.records.map(item => {
|
|
||||||
item.mallId = 'https://www.shein.com/store/home?store_code=' + item.mallId
|
|
||||||
return item
|
|
||||||
})
|
|
||||||
this.tableData = res.data.records
|
|
||||||
this.total = res.data.total
|
|
||||||
})
|
|
||||||
},
|
|
||||||
cancel (isRefresh) {
|
|
||||||
this.$emit('change', {
|
|
||||||
type: 'List',
|
|
||||||
isRefresh: !!isRefresh
|
|
||||||
})
|
|
||||||
},
|
|
||||||
getPricePercent(data) {
|
|
||||||
if (data < 0) {
|
|
||||||
return '<div style="display: inline; color: green">↓' + data + '%</div>'
|
|
||||||
} else if (data > 0) {
|
|
||||||
return '<div style="display: inline; color: red">↑' + data + '%</div>'
|
|
||||||
}
|
|
||||||
return ''
|
|
||||||
},
|
|
||||||
getSalePercent(data) {
|
|
||||||
if (data < 0) {
|
|
||||||
return '<div style="display: inline; color: green">↓' + data + '%</div>'
|
|
||||||
} else if (data > 0) {
|
|
||||||
return '<div style="display: inline; color: red">↑' + data + '%</div>'
|
|
||||||
}
|
|
||||||
return ''
|
|
||||||
},
|
|
||||||
handleClose() {
|
|
||||||
this.isShowDetailDlg = false
|
|
||||||
},
|
|
||||||
goDetail (goodsId, monitorId) {
|
|
||||||
this.detailParams = {goodsId: goodsId, monitorId: monitorId}
|
|
||||||
this.isShowDetailDlg = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped lang="scss">
|
|
||||||
.productDetail {
|
|
||||||
:deep(.el-dialog) {
|
|
||||||
height: 78vh;
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
.time {
|
|
||||||
font-size: 13px;
|
|
||||||
color: #999;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bottom {
|
|
||||||
margin-top: 13px;
|
|
||||||
line-height: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button {
|
|
||||||
padding: 0;
|
|
||||||
float: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
.image {
|
|
||||||
width: 100%;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.clearfix:before,
|
|
||||||
.clearfix:after {
|
|
||||||
display: table;
|
|
||||||
content: "";
|
|
||||||
}
|
|
||||||
|
|
||||||
.clearfix:after {
|
|
||||||
clear: both
|
|
||||||
}
|
|
||||||
.el-dropdown-link {
|
|
||||||
cursor: pointer;
|
|
||||||
color: #409EFF;
|
|
||||||
}
|
|
||||||
.el-icon-arrow-down {
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*徽标*/
|
|
||||||
.labelBadge {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ii {
|
|
||||||
background: #f00;
|
|
||||||
border-radius: 50%;
|
|
||||||
width: 20px;
|
|
||||||
height: 20px;
|
|
||||||
top: -3px;
|
|
||||||
right: -5px;
|
|
||||||
position: absolute;
|
|
||||||
text-align: center;
|
|
||||||
color: #FFF;
|
|
||||||
z-index: 999;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.img-box {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
//父级设置 相对定位,让 icon设置绝对定位时能够以该父级为准。
|
|
||||||
position: relative;
|
|
||||||
// icon 设置 绝对定位 让其固定在你想要的合适位置。 样式可调整,自己定位即可。
|
|
||||||
.icon-box {
|
|
||||||
position: absolute;
|
|
||||||
top: 35%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.mask {
|
|
||||||
background-color: #000;
|
|
||||||
opacity: 0.6;
|
|
||||||
|
|
||||||
.el-image__inner {
|
|
||||||
opacity: 0.6;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
::v-deep .mask > img {
|
|
||||||
opacity: 0.6;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.el-icon {
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
|
|
||||||
</style>
|
|
||||||
Reference in New Issue
Block a user