209 lines
7.2 KiB
Vue
209 lines
7.2 KiB
Vue
<script>
|
|
const getHourRange = hour => `${hour.padStart(2, '0')}:00-${`${Number(hour) + 1}`.padStart(2, '0')}:00`
|
|
export default {
|
|
name: "AppHourSale",
|
|
label: "市场看板-全门店时段销售",
|
|
data() {
|
|
return {
|
|
summary: {},
|
|
tableData: [],
|
|
hourSummary: [],
|
|
hourSummaryStyle: {display: 'none'}
|
|
}
|
|
},
|
|
computed: {
|
|
search: v => v.$marketBoard.search,
|
|
columns: v => {
|
|
let {currentDate, compareDate} = v.search
|
|
const {dayjs} = window
|
|
currentDate = currentDate ? dayjs(currentDate).format("YYYY-MM-DD") : ""
|
|
compareDate = compareDate ? dayjs(compareDate).format("YYYY-MM-DD") : ""
|
|
return [
|
|
{label: "日期", children: [{label: "时段", width: 100, prop: "hour"}]},
|
|
{
|
|
label: compareDate, align: 'center', children: [
|
|
{label: "销售额", prop: "compareSaleAmt", align: 'center'},
|
|
{label: "有效订单数", prop: "compareValidOrderNum", align: 'center'},
|
|
]
|
|
},
|
|
{
|
|
label: currentDate, align: 'center', children: [
|
|
{label: "销售额", prop: "currentSaleAmt", align: 'center'},
|
|
{label: "有效订单数", prop: "currentValidOrderNum", align: 'center'},
|
|
]
|
|
},
|
|
{label: "销售增长率", width: 80, align: 'center', prop: "saleGrowthRate"},
|
|
]
|
|
},
|
|
tableColumns: v => v.columns.map(e => e.children || e).flat(),
|
|
tableConfig: v => {
|
|
return {
|
|
headerBGC: 'rgba(13, 48, 99, 0.6)',
|
|
oddRowBGC: window.evenRowBGC(), evenRowBGC: "transparent",
|
|
header: v.columns.map(e => e.label), rowNum: 16,
|
|
columnWidth: v.columns.map(e => e.width || "0;flex:1;min-width:0;"),
|
|
align: v.columns.map(e => e.align || "left"),
|
|
data: v.tableData.map(e => v.columns.map(column => e[column.prop])),
|
|
}
|
|
},
|
|
summaryRow: v => v.tableColumns.map((column, i) => {
|
|
const isNumber = v => /^-?\d+(\.\d+)?%?$/.test(v)
|
|
const style = {textAlign: column.align}
|
|
if (column.width > 0) {
|
|
style.width = `${column.width}px`
|
|
} else {
|
|
style.flex = 1
|
|
style.minWidth = 0
|
|
}
|
|
return {
|
|
style,
|
|
value: isNumber(v.summary[column.prop]) ? v.summary[column.prop] :
|
|
i == 0 ? v.summary.hour : ""
|
|
}
|
|
}),
|
|
specialRow: v => {
|
|
let {currentDate, compareDate} = v.search
|
|
const {dayjs} = window
|
|
currentDate = currentDate ? dayjs(currentDate).format("YYYY-MM-DD") : ""
|
|
compareDate = compareDate ? dayjs(compareDate).format("YYYY-MM-DD") : ""
|
|
return [
|
|
{value: "日期", width: 100},
|
|
{value: compareDate, align: 'center'},
|
|
{value: currentDate, align: 'center'},
|
|
{width: 80},
|
|
].map(column => {
|
|
const style = {textAlign: column.align}
|
|
if (column.width > 0) {
|
|
style.width = `${column.width}px`
|
|
} else {
|
|
style.flex = 1
|
|
style.minWidth = 0
|
|
}
|
|
return {style, value: column.value}
|
|
})
|
|
},
|
|
},
|
|
methods: {
|
|
getTableData() {
|
|
const {$http, $waitFor} = window
|
|
return $waitFor($http).then(() => $http.post("/data-boot/la/screen/marketBoard/hourSale", {
|
|
...this.search, limit: 999
|
|
})).then(res => {
|
|
if (res?.data) {
|
|
this.summary = res.data.total
|
|
return this.tableData = res.data?.page?.records?.map(e => ({...e, hour: getHourRange(e.hour), index: e.hour})).sort((a, b) => a.index - b.index) || []
|
|
}
|
|
})
|
|
},
|
|
handleSta({hour}) {
|
|
this.handleMouseout()
|
|
const rowIndex = this.tableData.findIndex(e => e.hour == hour)
|
|
const v = this
|
|
const summary = {
|
|
compareSaleAmt: 0, compareValidOrderNum: 0, currentSaleAmt: 0, currentValidOrderNum: 0, saleGrowthRate: 0
|
|
}
|
|
v.tableData.forEach((e, i) => {
|
|
if (i <= rowIndex) {
|
|
summary.compareSaleAmt += Number(e.compareSaleAmt || 0)
|
|
summary.compareValidOrderNum += Number(e.compareValidOrderNum || 0)
|
|
summary.currentSaleAmt += Number(e.currentSaleAmt || 0)
|
|
summary.currentValidOrderNum += Number(e.currentValidOrderNum || 0)
|
|
const {currentSaleAmt, compareSaleAmt} = summary
|
|
summary.saleGrowthRate = Number((currentSaleAmt - compareSaleAmt) / compareSaleAmt * 100 || 0)
|
|
}
|
|
if (i == rowIndex) {
|
|
summary.compareSaleAmt = summary.compareSaleAmt.toFixed(2)
|
|
summary.compareValidOrderNum = summary.compareValidOrderNum.toFixed(2)
|
|
summary.currentSaleAmt = summary.currentSaleAmt.toFixed(2)
|
|
summary.currentValidOrderNum = summary.currentValidOrderNum.toFixed(2)
|
|
summary.saleGrowthRate = summary.saleGrowthRate.toFixed(2) + "%"
|
|
}
|
|
})
|
|
const summaryRow = {}
|
|
v.tableColumns.forEach(({prop}, i) => {
|
|
summaryRow[prop] = i == 0 ? "时段合计" : (summary[prop] || '')
|
|
})
|
|
v.tableData.splice(rowIndex + 1, 0, summaryRow)
|
|
// this.hourSummary = v.tableColumns.map((column, i) => {
|
|
// const isNumber = v => /^-?\d+(\.\d+)?%?$/.test(v)
|
|
// const style = {textAlign: column.align}
|
|
// if (column.width > 0) {
|
|
// style.width = `${column.width}px`
|
|
// } else {
|
|
// style.flex = 1
|
|
// style.minWidth = 0
|
|
// }
|
|
// return {
|
|
// style,
|
|
// value: isNumber(summary[column.prop]) ? summary[column.prop] :
|
|
// i == 0 ? "时段合计" : ""
|
|
// }
|
|
// })
|
|
// this.hourSummaryStyle.display = "flex"
|
|
},
|
|
handleRowStyle({row}) {
|
|
if (row.hour == '时段合计') return 'summary'
|
|
return ''
|
|
},
|
|
handleMouseout() {
|
|
// this.hourSummaryStyle = {display: 'none'}
|
|
const i = this.tableData.findIndex(e => e.hour == '时段合计')
|
|
if (i == -1) return;
|
|
this.tableData.splice(i, 1)
|
|
},
|
|
initHourSta() {
|
|
const {dayjs} = window
|
|
const hour = getHourRange(`${dayjs().hour()}`)
|
|
this.handleSta({hour})
|
|
}
|
|
},
|
|
watch: {
|
|
search: {
|
|
immediate: true, deep: true, handler() {
|
|
this.getTableData().then(() => this.initHourSta())
|
|
}
|
|
}
|
|
},
|
|
mounted() {
|
|
document.addEventListener('click', evt => {
|
|
if (!this.$el.contains(evt.target)) {
|
|
this.initHourSta()
|
|
}
|
|
})
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<section class="AppHourSale">
|
|
<scroll-table :table-data="tableData" :columns="columns" @click="handleSta" @click.native.stop :config="{rowClassName:handleRowStyle}"/>
|
|
<!--<dv-scroll-board :config="tableConfig" @mouseover="handleSta" @mouseout.native="hourSummaryStyle={display:'none'}"/>-->
|
|
<!-- <div class="summary flex hourSummary" :style="hourSummaryStyle">-->
|
|
<!-- <div class="item" v-for="(col,i) in hourSummary" :key="i" v-text="col.value" :style="col.style"/>-->
|
|
<!-- </div>-->
|
|
<div class="summary flex">
|
|
<div class="item" v-for="(col,i) in summaryRow" :key="i" v-text="col.value" :style="col.style"/>
|
|
</div>
|
|
</section>
|
|
</template>
|
|
|
|
<style>
|
|
.AppHourSale {
|
|
color: #fff;
|
|
box-sizing: border-box;
|
|
position: relative;
|
|
}
|
|
|
|
.AppHourSale .dv-scroll-board, .AppHourSale .scrollTable {
|
|
height: calc(100% - 60px) !important;
|
|
border-color: transparent;
|
|
}
|
|
|
|
.hourSummary {
|
|
width: 100%;
|
|
background-color: #07193D;
|
|
position: absolute;
|
|
left: 0;
|
|
}
|
|
</style>
|