478 lines
17 KiB
Vue
478 lines
17 KiB
Vue
<template>
|
||
<div style="display:flex;justify-content:space-between">
|
||
<div class="content_xwl">
|
||
<div class="header_xwl" style="background: white">
|
||
<div class="root_xwl">
|
||
<div class="main_xwl">
|
||
<a-tooltip placement="right" style="cursor: pointer">
|
||
<template slot="title">
|
||
<span>以某段时间做过初始事件的用户为样本,查看在指定日期后用户进行回访事件的留存情况</span>
|
||
</template>
|
||
<span class="title_xwl" style="color: #202d3f"> 留存分析 <a-icon
|
||
type="question-circle"
|
||
/>
|
||
<template v-if="reportTableName!=''">
|
||
{{ reportTableName }}
|
||
</template>
|
||
</span>
|
||
</a-tooltip>
|
||
</div>
|
||
<div class="actions_xwl">
|
||
<a-tooltip placement="top" style="cursor: pointer">
|
||
<template slot="title">
|
||
<span>以页面格式下载全量数据</span>
|
||
</template>
|
||
<a-button type="link" class="actions_xwl_btn" icon="download" @click="download" />
|
||
</a-tooltip>
|
||
<report-table-list :rt_type="Number(2)" />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<split-pane :min-percent="0" :default-percent="22" split="vertical" @resize="onResize">
|
||
<template slot="paneL">
|
||
<div
|
||
id="scollL"
|
||
style="height: 95%;width: 100px;display: inline-block; height: 100%;vertical-align: top;width: 100%;background: white;"
|
||
>
|
||
<div style="width: 100%;height: calc(100% - 140px); overflow-x: hidden; overflow-y: auto;">
|
||
<div style="width: 100%; padding-bottom: 8px;border-bottom: 1px solid #f0f2f5">
|
||
<div
|
||
style="line-height: 18px;font-weight: 500; font-size: 13px; padding: 10px 16px 12px;font-weight: bolder"
|
||
>
|
||
初始事件
|
||
</div>
|
||
<div class="xwl_main">
|
||
<div v-for="(v,index) in form.zhibiaoArr" v-if="index == 0">
|
||
<div class="row___xwl" style="padding: 10px;">
|
||
<el-row>
|
||
<el-col :span="2">
|
||
<el-tag type="warning" class="drageTag">{{ index + 1 }}</el-tag>
|
||
</el-col>
|
||
<el-col :span="18">
|
||
<el-row :span="15" class="zhibiao">
|
||
<a-tooltip placement="topLeft" style="cursor: pointer">
|
||
<template slot="title">
|
||
<span>点击修改指标名称</span>
|
||
</template>
|
||
<a-input
|
||
:ref="('getFocus'+index).toString()"
|
||
v-model:value="form.zhibiaoArr[index].eventNameDisplay"
|
||
class="eventNameDisplayInput"
|
||
placeholder="请输入..."
|
||
autofocus="autofocus"
|
||
allow-clear
|
||
@change="getFocus1('getFocus'+index)"
|
||
/>
|
||
</a-tooltip>
|
||
</el-row>
|
||
<el-row style="padding-top: 5px" :span="6">
|
||
<a-select
|
||
v-model="form.zhibiaoArr[index].eventName"
|
||
dropdown-match-select-width
|
||
show-search
|
||
default-active-first-option
|
||
style="width: 120px"
|
||
@change="changeEventNameDisplay(index)"
|
||
>
|
||
|
||
<a-select-option
|
||
v-for="(v,k,index) in metaEventList"
|
||
:key="index"
|
||
:value="v.event_name"
|
||
>
|
||
{{ v.show_name == '' ? v.event_name : v.show_name }}
|
||
</a-select-option>
|
||
|
||
</a-select>
|
||
</el-row>
|
||
</el-col>
|
||
</el-row>
|
||
<div class="filters_xwl">
|
||
<filter-where
|
||
v-model="form.zhibiaoArr[index].relation"
|
||
table-typ="2"
|
||
:data-type-map="attrMap"
|
||
:options="eventAttrOptions"
|
||
/>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div style="width: 100%; padding-bottom: 8px;border-bottom: 1px solid #f0f2f5">
|
||
<div
|
||
style="line-height: 18px;font-weight: 500; font-size: 13px; padding: 10px 16px 12px;font-weight: bolder"
|
||
>
|
||
回访事件
|
||
</div>
|
||
<div class="xwl_main">
|
||
|
||
<div v-for="(v,index) in form.zhibiaoArr" v-if="index == 1">
|
||
|
||
<div class="row___xwl" style="padding: 10px;">
|
||
|
||
<el-row>
|
||
<el-col :span="2">
|
||
<el-tag type="warning" class="drageTag">{{ index + 1 }}</el-tag>
|
||
</el-col>
|
||
<el-col :span="18">
|
||
<el-row :span="15" class="zhibiao">
|
||
<a-tooltip placement="topLeft" style="cursor: pointer">
|
||
<template slot="title">
|
||
<span>点击修改指标名称</span>
|
||
</template>
|
||
<a-input
|
||
:ref="('getFocus'+index).toString()"
|
||
v-model:value="form.zhibiaoArr[index].eventNameDisplay"
|
||
class="eventNameDisplayInput"
|
||
placeholder="请输入..."
|
||
autofocus="autofocus"
|
||
allow-clear
|
||
@change="getFocus1('getFocus'+index)"
|
||
/>
|
||
</a-tooltip>
|
||
</el-row>
|
||
<el-row style="padding-top: 5px" :span="6">
|
||
<a-select
|
||
v-model="form.zhibiaoArr[index].eventName"
|
||
dropdown-match-select-width
|
||
show-search
|
||
default-active-first-option
|
||
style="width: 120px"
|
||
@change="changeEventNameDisplay(index)"
|
||
>
|
||
|
||
<a-select-option
|
||
v-for="(v,k,index) in metaEventList"
|
||
:key="index"
|
||
:value="v.event_name"
|
||
>
|
||
{{ v.show_name == '' ? v.event_name : v.show_name }}
|
||
</a-select-option>
|
||
|
||
</a-select>
|
||
</el-row>
|
||
</el-col>
|
||
|
||
</el-row>
|
||
<div class="filters_xwl">
|
||
<filter-where
|
||
v-model="form.zhibiaoArr[index].relation"
|
||
table-typ="2"
|
||
:data-type-map="attrMap"
|
||
:options="eventAttrOptions"
|
||
/>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div style="width: 100%; padding-bottom: 8px;border-bottom: 1px solid #f0f2f5">
|
||
<div
|
||
style="line-height: 18px;font-weight: 500; font-size: 13px; padding: 10px 16px 10px;font-weight: bolder"
|
||
>
|
||
全局筛选事件维度
|
||
</div>
|
||
|
||
<filter-where
|
||
v-model="form.whereFilter"
|
||
:data-type-map="attrMap"
|
||
table-typ="2"
|
||
:options="eventAttrOptions"
|
||
/>
|
||
</div>
|
||
|
||
<div style="width: 100%; padding-bottom: 8px;border-bottom: 1px solid #f0f2f5">
|
||
<div
|
||
style="line-height: 18px;font-weight: 500; font-size: 13px; padding: 10px 16px 10px;font-weight: bolder"
|
||
>
|
||
全局筛选用户维度
|
||
</div>
|
||
<filter-where
|
||
v-model="form.whereFilterByUser"
|
||
:data-type-map="attrMap"
|
||
table-typ="1"
|
||
:options="userAttrOptions"
|
||
/>
|
||
</div>
|
||
|
||
<div style="width: 100%; padding-bottom: 8px;border-bottom: 1px solid #f0f2f5">
|
||
<filter-user-group v-model="form.userGroup" />
|
||
</div>
|
||
</div>
|
||
|
||
<div
|
||
style="width: 100%;height: 50px;margin-bottom: 0px;z-index: 10000;border-top: 1px solid #f0f2f5;background: white;display: flex;align-items: center;justify-content: center"
|
||
>
|
||
<add-report-table
|
||
:rt-type="Number(2)"
|
||
:name="currentReportTable.name"
|
||
:remark="currentReportTable.remark"
|
||
:data="this.form"
|
||
style="width: 200px;height: 50px;line-height: 50px;margin: 0px auto"
|
||
@go="go"
|
||
/>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
<template slot="paneR">
|
||
<a-spin tip="计算中..." :spinning="spinning">
|
||
<div class="spin-content">
|
||
<retention-result
|
||
v-if="retentionResShow"
|
||
ref="retentionRes"
|
||
v-model="form.date"
|
||
:window-time="form.windowTime"
|
||
style="padding: 20px"
|
||
:table-header="tableHeader"
|
||
:retention-res="retentionRes"
|
||
@changeWindowTime="changeWindowTime"
|
||
@go="go"
|
||
/>
|
||
</div>
|
||
</a-spin>
|
||
|
||
</template>
|
||
</split-pane>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
import { debounce } from 'lodash'
|
||
|
||
import moment from 'moment'
|
||
|
||
import { GetConfigs, RetentionList } from '@/api/analysis'
|
||
import { FindRtById } from '@/api/pannel'
|
||
|
||
export default {
|
||
name: 'Retention',
|
||
components: {
|
||
'FilterWhere': () => import('@/components/AnalyseTools/FilterWhere/index'),
|
||
'FilterGroup': () => import('@/components/AnalyseTools/FilterGroup/index'),
|
||
'RetentionResult': () => import('@/views/behavior-analysis/components/RetentionResult'),
|
||
'ReportTableList': () => import('@/views/behavior-analysis/components/ReportTableList'),
|
||
'AddReportTable': () => import('@/views/behavior-analysis/components/AddReportTable'),
|
||
'FilterUserGroup': () => import('@/components/AnalyseTools/FilterUserGroup')
|
||
},
|
||
data() {
|
||
return {
|
||
currentReportTable: {
|
||
name: '',
|
||
remark: ''
|
||
},
|
||
spinning: false,
|
||
drawerShow: false,
|
||
tableHeader: [],
|
||
retentionRes: [],
|
||
retentionResShow: true,
|
||
prevCount: 0,
|
||
metaEventList: [],
|
||
userAttr: [],
|
||
eventAttr: [],
|
||
reportTableName: '',
|
||
form: {
|
||
zhibiaoArr: [],
|
||
groupBy: [],
|
||
|
||
whereFilter: {
|
||
filterType: 'COMPOUND',
|
||
filts: [],
|
||
relation: '且'
|
||
},
|
||
|
||
whereFilterByUser: {
|
||
filterType: 'COMPOUND',
|
||
filts: [],
|
||
relation: '且'
|
||
},
|
||
windowTime: 1,
|
||
windowTimeFormat: '天',
|
||
date: [
|
||
moment().startOf('day').subtract(1, 'days').format('YYYY-MM-DD'),
|
||
moment().startOf('day').subtract(1, 'days').format('YYYY-MM-DD')
|
||
]
|
||
},
|
||
|
||
eventAttrOptions: [],
|
||
allAttrOptions: [],
|
||
userAttrOptions: [],
|
||
attrMap: [],
|
||
debounceHandleSizeChange: undefined
|
||
}
|
||
},
|
||
async beforeMount() {
|
||
await this.initReportData()
|
||
this.debounceHandleSizeChange = debounce(this.refreshRes, 500)
|
||
},
|
||
mounted() {
|
||
this.init()
|
||
},
|
||
methods: {
|
||
download() {
|
||
this.$refs['retentionRes'].download('全量数据')
|
||
},
|
||
changeWindowTime(windowTime, windowTimeFormat) {
|
||
this.form.windowTime = windowTime
|
||
this.form.windowTimeFormat = windowTimeFormat
|
||
},
|
||
refreshRes() {
|
||
this.$nextTick(() => {
|
||
this.retentionResShow = true
|
||
})
|
||
},
|
||
onResize() {
|
||
this.retentionResShow = false
|
||
this.debounceHandleSizeChange()
|
||
},
|
||
changeEventNameDisplay(index) {
|
||
let eventNameDisplay = ''
|
||
for (const v of this.metaEventList) {
|
||
if (v.event_name == this.form.zhibiaoArr[index].eventName) {
|
||
eventNameDisplay = v.show_name == '' ? v.event_name : v.show_name
|
||
}
|
||
}
|
||
|
||
this.form.zhibiaoArr[index].eventNameDisplay = eventNameDisplay
|
||
},
|
||
async initReportData() {
|
||
const id = this.$route.params.id
|
||
if (id != ':id' && Number(id) != 0) {
|
||
const res = await FindRtById({ id: Number(id), 'appid': this.$store.state.baseData.EsConnectID })
|
||
if (res.code != 0) {
|
||
this.$message({
|
||
offset: 60,
|
||
type: 'error',
|
||
message: res.msg
|
||
})
|
||
return
|
||
}
|
||
this.reportTableName = res.data.name
|
||
this.currentReportTable.name = res.data.name
|
||
this.currentReportTable.remark = res.data.remark
|
||
this.form = JSON.parse(res.data.data)
|
||
this.form.date = [
|
||
moment().startOf('day').subtract(1, 'days').format('YYYY-MM-DD'),
|
||
moment().startOf('day').subtract(1, 'days').format('YYYY-MM-DD')
|
||
]
|
||
this.go()
|
||
}
|
||
},
|
||
|
||
async init() {
|
||
await this.getMetaEventList()
|
||
if (this.form.zhibiaoArr.length == 0) {
|
||
this.addZhibiao()
|
||
this.addZhibiao()
|
||
}
|
||
},
|
||
|
||
async getMetaEventList() {
|
||
const res = await GetConfigs({ 'appid': this.$store.state.baseData.EsConnectID })
|
||
|
||
if (res.code != 0) {
|
||
this.$message({
|
||
type: 'error',
|
||
offset: 60,
|
||
message: res.msg
|
||
})
|
||
|
||
return
|
||
}
|
||
this.metaEventList = res.data.event_name_list
|
||
|
||
const attributeMap = res.data.attributeMap
|
||
const allAttrOptions = []
|
||
const eventAttrOptions = []
|
||
const userAttrOptions = []
|
||
this.attrMap = []
|
||
this.attrMap = attributeMap
|
||
const eventData = { label: '事件', options: [] }
|
||
const userData = { label: '用户', options: [] }
|
||
if (attributeMap.hasOwnProperty('2')) {
|
||
for (const v of attributeMap['2']) {
|
||
eventData.options.push({
|
||
value: v.attribute_name,
|
||
label: v.show_name == '' ? v.attribute_name : v.show_name
|
||
})
|
||
}
|
||
}
|
||
if (attributeMap.hasOwnProperty('1')) {
|
||
for (const v of attributeMap['1']) {
|
||
userData.options.push({
|
||
value: v.attribute_name,
|
||
label: v.show_name == '' ? v.attribute_name : v.show_name
|
||
})
|
||
}
|
||
}
|
||
|
||
eventAttrOptions.push(eventData)
|
||
userAttrOptions.push(userData)
|
||
allAttrOptions.push(eventData, userData)
|
||
this.userAttrOptions = userAttrOptions
|
||
this.eventAttrOptions = eventAttrOptions
|
||
this.allAttrOptions = allAttrOptions
|
||
},
|
||
moment,
|
||
addZhibiao() {
|
||
if (this.form.zhibiaoArr.length >= 30) return
|
||
|
||
this.form.zhibiaoArr.push({
|
||
'eventName': this.metaEventList[0].event_name,
|
||
'eventNameDisplay': this.metaEventList[0].show_name != '' ? this.metaEventList[0].show_name : this.metaEventList[0].event_name,
|
||
'relation': {
|
||
filterType: 'COMPOUND',
|
||
filts: [],
|
||
relation: '且'
|
||
}
|
||
})
|
||
},
|
||
getFocus1(f) {
|
||
this.$nextTick(function() {
|
||
this.$refs[f][0].focus()
|
||
})
|
||
},
|
||
async go() {
|
||
this.retentionResShow = false
|
||
this.spinning = true
|
||
|
||
const form = this.form
|
||
form['appid'] = this.$store.state.baseData.EsConnectID
|
||
const res = await RetentionList(form)
|
||
if (res.code != 0) {
|
||
this.$message({
|
||
type: 'error',
|
||
offset: 60,
|
||
message: res.msg
|
||
})
|
||
this.retentionRes = []
|
||
} else {
|
||
this.retentionRes = res.data.alldata
|
||
}
|
||
this.spinning = false
|
||
this.$nextTick(() => {
|
||
this.retentionResShow = true
|
||
})
|
||
}
|
||
}
|
||
|
||
}
|
||
</script>
|
||
|
||
<style scoped src="@/styles/retention.css"/>
|
||
|
||
<style>
|
||
.eventNameDisplayInput .ant-input {
|
||
resize: none;
|
||
border: none;
|
||
}
|
||
|
||
.eventNameDisplayInput .ant-input:focus {
|
||
border: none;
|
||
box-shadow: none;
|
||
}
|
||
</style>
|