提交 fc396ea6 编写于 作者: huangwensu's avatar huangwensu

添加数据分析页面

上级 42890d80
......@@ -2767,6 +2767,14 @@
"safer-buffer": "^2.1.0"
}
},
"echarts": {
"version": "4.9.0",
"resolved": "http://192.168.110.93:4873/echarts/-/echarts-4.9.0.tgz",
"integrity": "sha1-qbm6oD8Doqcx5jQMVb77V6nhNH0=",
"requires": {
"zrender": "4.3.2"
}
},
"editorconfig": {
"version": "0.13.3",
"resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-0.13.3.tgz",
......@@ -8766,6 +8774,11 @@
"dev": true
}
}
},
"zrender": {
"version": "4.3.2",
"resolved": "http://192.168.110.93:4873/zrender/-/zrender-4.3.2.tgz",
"integrity": "sha1-7HQy+UFcgsc1hLa3uMR+GwFiCcY="
}
}
}
......@@ -12,6 +12,7 @@
"dependencies": {
"axios": "^0.18.0",
"babel-polyfill": "^6.23.0",
"echarts": "^4.9.0",
"element-ui": "^2.7.2",
"vue": "^2.3.2",
"vue-core-image-upload": "2.1.11",
......
......@@ -5,9 +5,10 @@ import router from './router';
import store from './vuex/store'
import axios from 'axios';
import ElementUI from 'element-ui';
import echarts from 'echarts';
import 'element-ui/lib/theme-chalk/index.css'; // 默认主题
import {getAddress, loadCommonFilter} from './common/env'
import vueFilter from './common/filter'
import vueFilter from './common/filter';
//加载环境变量
......@@ -15,6 +16,7 @@ getAddress();
loadCommonFilter();
//加载elementUi
Vue.use(ElementUI);
Vue.prototype.$echarts = echarts;
// Vue.use(vueXlsxTable, {rABS: false})
if (localStorage.getItem("token")) {
......
......@@ -39,6 +39,10 @@ export default new Router({
path: '/add-funnel',
component: resolve => require(['../views/user-path/add-funnel.vue'], resolve)
},
{ // 用户路径分析--查看数据
path: '/path-data',
component: resolve => require(['../views/user-path/funnel-data.vue'], resolve)
},
]
},
{ // 短信中的 数据查看页面
......
......@@ -21,37 +21,35 @@
<div class="add-step">
<p>请以用户逐步触发的事件为依据,构造漏斗、系统会自动计算整个过程的转化率。如果事件之间不连续,转化率为0!</p>
</div>
<div class="step-content">
<div v-for="(item,index) in stepArray" :key="index">
<span>步骤{{index + 1}}</span>
<el-form
ref="form"
class="step-form"
:model="item"
label-suffix=":"
style="width:100%;">
<el-col :span="11">
<el-form-item label="步骤名称">
<el-input v-model="item.name" maxlength="20" placeholder="请输入步骤名称" style="width:200px;"></el-input>
</el-form-item>
</el-col>
<el-col :span="11">
<el-form-item label="触发事件">
<el-select v-model="item.event" placeholder="请选择用户触发事件" style="width:200px">
<el-option
v-for="(eItem,eIndex) in eventSelect"
:key="eIndex"
:label="eItem.label"
:value="eItem.value">
</el-option>
</el-select>
</el-form-item>
</el-col>
</el-form>
<i v-if="index == 0" class="el-icon-remove-outline"></i>
<i v-if="index > 0" class="el-icon-remove-outline"></i>
<i class="el-icon-circle-plus-outline"></i>
</div>
<div class="step-content" v-for="(item,index) in stepArray" :key="index">
<span>步骤{{index + 1}}</span>
<el-form
ref="form"
class="step-form"
:model="item"
label-suffix=":"
style="width:100%;">
<el-col :span="11">
<el-form-item label="步骤名称">
<el-input v-model="item.name" maxlength="20" placeholder="请输入步骤名称" style="width:200px;"></el-input>
</el-form-item>
</el-col>
<el-col :span="11">
<el-form-item label="触发事件">
<el-select v-model="item.event" placeholder="请选择用户触发事件" style="width:200px">
<el-option
v-for="(eItem,eIndex) in eventSelect"
:key="eIndex"
:label="eItem.label"
:value="eItem.value">
</el-option>
</el-select>
</el-form-item>
</el-col>
</el-form>
<i v-if="index == 0" class="el-icon-remove-outline disable-step"></i>
<i v-if="index > 0" class="el-icon-remove-outline delete-step" @click="deleteSteps(index)"></i>
<i class="el-icon-circle-plus-outline add-step" @click="addSteps"></i>
</div>
</div>
</div>
......@@ -74,8 +72,20 @@ export default {
}
},
methods: {
// 保存
saveAddAndEdit() {
},
// 删除步骤
deleteSteps(i) {
this.stepArray.splice(i,1);
},
// 增加步骤
addSteps() {
this.stepArray.push({
name: '',
event: ''
});
}
}
}
......@@ -114,7 +124,7 @@ export default {
font-size: 14px;
color: #58ADE8;
padding: 5px;
margin: 20px 0 0 20px;
margin: 20px 20px 0 20px;
border: 1px solid #58ADE8;
border-radius: 3px;
}
......@@ -122,9 +132,19 @@ export default {
width: 80% !important;
padding: 15px 0 0 30px;
}
}
i.disable {
color: #CFCED0;
i {
padding: 10px 20px;
font-size: 20px;
}
.disable-step {
color: #D2D2D3;
}
.delete-step {
color: #58ADE8;
}
.add-step {
color: #58ADE8;
}
}
}
}
......
<template>
<div class="data-container">
<el-breadcrumb separator="/" class="data-title">
<el-breadcrumb-item :to="{ path: '/user-path' }">漏斗分析</el-breadcrumb-item>
<el-breadcrumb-item><a href="/path-data">{{name}}详情</a></el-breadcrumb-item>
</el-breadcrumb>
<div class="data-content">
<div class="con">
<el-row :gutter="30" class="row search" type="flex" style="margin-bottom:0;">
<el-form ref="form" :model="searchParam" label-suffix=":" style="width:100%;">
<el-col :span="10">
<el-form-item label="时间">
<el-date-picker
v-model="searchParam.time"
type="daterange"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期">
</el-date-picker>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="版本">
<el-select v-model="searchParam.version" placeholder="请选择版本" style="width:200px">
<el-option
v-for="(eItem,eIndex) in versionSelect"
:key="eIndex"
:label="eItem.label"
:value="eItem.value">
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="6" style="padding:0;text-align:right;padding-right:15px;">
<el-button type="default" size="small">下载</el-button>
<el-button type="default" size="small" @click="reset">重置</el-button>
<el-button type="primary" size="small">筛选</el-button>
</el-col>
</el-form>
</el-row>
<div class="data-num">
<div class="num-text first-num">
<span>总人数</span>
<p>543233<span></span></p>
</div>
<div class="num-text">
<span>总转化率</span>
<p>20.47%</p>
</div>
<div class="num-text">
<span>达成目标人数</span>
<p>234<span></span></p>
</div>
<div class="num-text num">
<span>转化率最低步骤</span>
<p>点击【相关推荐内容】</p>
</div>
</div>
<div class="data-analysis">
<div class="map-title">转化漏斗详情</div>
<div ref="chart" class="echart"></div>
<el-table
class="data-table"
:data="tableData"
style="width: 100%">
<el-table-column prop="step" label="步骤" min-width="140" align="center"></el-table-column>
<el-table-column prop="name" label="步骤名称" min-width="140" align="center"></el-table-column>
<el-table-column prop="userNum" label="用户数" min-width="150" align="center"></el-table-column>
<el-table-column prop="pre" label="较上一步转化率" min-width="150" align="center"></el-table-column>
<el-table-column prop="all" label="总转化率" min-width="150" align="center"></el-table-column>
</el-table>
</div>
</div>
</div>
</div>
</template>
<script>
let url = 'image://data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAARCAMAAACLgl7OAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAaVBMVEUAAADBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcEAAAD45xibAAAAInRSTlMAmT6WJYwSfBMGZAFHmEgtkBeCCW0KAlI1k5QeiA10A1tc7ah1owAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAB7SURBVCjPtZDZDoAgDAQXvA+8bwX1/3/SGKIBEd+cx07TdgtIiAF0/mygDvnAoYDr2b3nnjP8wOaDUG6J4ncfR9cdScpMzbJECZEXT1/kesyy0n1VPv6AulF908Kg6+9DWN/hjWGUfhpgYV5Ov8ywwgUhguODddtXvXIAjuUEs/70/t4AAAAldEVYdGRhdGU6Y3JlYXRlADIwMTktMTItMTZUMTU6MzM6MDkrMDg6MDCzL2BEAAAAJXRFWHRkYXRlOm1vZGlmeQAyMDE5LTEyLTE2VDE1OjMzOjA5KzA4OjAwwnLY+AAAAABJRU5ErkJggg==';
export default {
data() {
return {
name: '测试',
searchParam: {
time: '',
version: ''
},
versionSelect: [], // 版本下拉数据
tableData: [{
step: '步骤1',
name: '点击【微专业】',
userNum: 54343,
pre: 98.00,
all: 67.34
},{
step: '步骤2',
name: '点击【课程】',
userNum: 54343,
pre: 98.00,
all: 67.34
}]
}
},
mounted() {
this.initCharts();
},
methods: {
// 初始化图标
initCharts() {
let lineargroup = [{
value: 200,
oriname: "点击【微专业】",
number: 98756,
color: ["rgba(29,211,137,0.8)", "rgba(29,211,137,0)"]
},
{
value: 150,
oriname: "点击【课程】",
number: 88756,
pointValue: 69.23,
color: ["rgba(102,142,255,0.7)", "rgba(102,142,255,0)"]
},
{
value: 100,
oriname: "点击【相关推荐内容】",
number: 78756,
pointValue: 35.21,
color: ["rgba(255,198,82,0.6)", "rgba(255,198,82,0)"]
},
{
value: 60,
oriname: "点击【健康漫画】",
number: 456,
pointValue: 15.21,
color: ["rgba(255,198,82,0.6)", "rgba(255,198,82,0)"]
},
{
value:30,
oriname: "点击【更多】",
number: 56,
pointValue: 5.21,
color: ["rgba(255,198,82,0.6)", "rgba(255,198,82,0)"]
},
];
let len = lineargroup.length;
let colorObj = {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [{
offset: 0,
color: '#1cd389' // 0% 处的颜色
}, {
offset: 1,
color: '#668eff' // 100% 处的颜色
}],
global: false // 缺省为 false
};
let data1 = [], dataArr = [], valueArr = [], lineArr = [], linksArr = [];
for (let i = 0; i < lineargroup.length; i++) {
let obj1 = {
value: lineargroup[i].value,
num: lineargroup[i].number,
name: lineargroup[i].oriname
};
data1.push(obj1);
if(i != (lineargroup.length - 1)) {
dataArr.push('转化率');
valueArr.push({value: '100'}); // 步骤箭头
linksArr.push({ // 转化率线
source: lineargroup[i].oriname,
target: lineargroup[i + 1].oriname,
value: lineargroup[i + 1].pointValue,
lineStyle: {
normal: {
curveness: parseInt(len - i) + 1,
color: colorObj
}
}
})
}
lineArr.push({
name: lineargroup[i].oriname,
x: 400,
y: 0 + i*15
});
}
let option = {
backgroundColor: '#ffffff',
grid: {
top: 110 - len * 5, // 箭头距离顶部高度
left: "-34%",
right: 20,
height: 115 + len * 15, // 箭头之间的距离
bottom: '0'
},
xAxis: {
show: false
},
yAxis: [{
show: false,
boundaryGap: false,
type: "category",
data: dataArr
}],
series: [{ // 内容块
top: 0,
type: 'funnel',
height: 300 + len * 20, // 块高度
gap: 40, // 块间距
minSize: 150, // 块两边斜度
left: '15%', // 块左边距离
width: '35%', // 块宽度
label: {
show: true,
position: 'inside',
fontSize: '14',
formatter: function(d) {
var ins = d.name + '{aa|}\n' + d.data.num;
return ins
},
rich: {
aa: {
padding: [8, 0, 6, 0]
}
}
},
data: data1
},
{
type: 'pictorialBar', // 步骤箭头
name: '',
symbolSize: ['32', '17'],
symbolPosition: 'center',
symbol: url,
animation: true,
symbolClip: true,
z: 10,
data: valueArr
},
{ // 转化率线
z: 1,
top: 20,
left: 500,
height: 286,
type: 'graph',
layout: 'none',
symbolSize: 0,
roam: false,
edgeSymbol: ['circle', 'arrow'],
lineStyle: {
normal: {
width: 4,
}
},
edgeLabel: { // 转化率数字
normal: {
show: true,
rotate: 90,
position: 'middle',
borderRadius: 4,
color: '#333',
verticalAlign: 'middle',
fontSize: 14,
legendHoverLink: true,
padding: [30, 20, 5, 10],
formatter: function(d) {
if (d.value) {
var ins = '{img1|} ' + '{words|' + d.value + '%}';
return ins;
}
},
rich: {
img1: {
width: 18,
height: 16
},
words: {
color: '#333',
position: 'right',
fontSize: 14,
lineHeight: 20,
padding: [0, 0, 5, 0],
}
}
}
},
data: lineArr,
links: linksArr
}
]
};
let myChart = this.$echarts.init(this.$refs.chart);
myChart.setOption(option);
},
reset() {
}
}
}
</script>
<style lang="less" scoped>
.data-container {
margin: -20px -40px;
.data-title {
height: 60px;
line-height: 60px;
padding-left: 40px;
}
.data-content {
background: #F2F2F4;
padding: 20px 0 0 20px;
min-height: 85vh;
padding-bottom: 20px;
.con {
min-height: 82vh;
background: #fff;
padding-bottom: 50px;
.search {
padding: 20px 20px 0;
margin: 0 !important;
border-bottom: 1px solid #EDEDEE;
}
.data-num {
display: flex;
padding: 20px 20px 0 30px;
.num-text {
width: 15%;
border-right: 1px solid #EDEDEE;
text-align: center;
span {
font-size: 12px;
color: #b2b2b3;
}
p {
padding-top: 8px;
}
}
.first-num {
width: 10%;
text-align: left;
}
.num {
width: 20%;
border: none;
}
}
.data-analysis {
// overflow: hidden;
margin: 20px 20px 0 30px;
padding: 0px 20px 30px;
border: 1px solid #EDEDEE;
box-shadow: 5px 0px 30px #EDEDEE;
.map-title {
height: 60px;
line-height: 60px;
border-bottom: 1px solid #EDEDEE;
}
.echart {
padding-top: 20px;
width: 100%;
min-height: 400px;
}
.data-table {
margin-top: 20px;
}
}
}
}
}
</style>
\ No newline at end of file
......@@ -7,7 +7,7 @@
<el-form ref="form" :model="searchParam" label-suffix=":" style="width:100%;">
<el-col :span="21">
<el-form-item label="漏斗名称">
<el-input v-model="searchParam.name" maxlength="20" placeholder="请输入漏斗名称" style="width:288px;"></el-input>
<el-input v-model="searchParam.searchName" maxlength="20" placeholder="请输入漏斗名称" style="width:288px;"></el-input>
</el-form-item>
</el-col>
<el-col :span="3" style="padding:0;text-align:right;padding-right:15px;">
......@@ -25,13 +25,13 @@
:data="tableData"
style="width: 100%">
<el-table-column prop="name" label="漏斗名称" min-width="140" align="center"></el-table-column>
<el-table-column prop="begin" label="起始步骤" min-width="140" align="center"></el-table-column>
<el-table-column prop="target" label="转化目标" min-width="150" align="center"></el-table-column>
<el-table-column prop="stepStartName" label="起始步骤" min-width="140" align="center"></el-table-column>
<el-table-column prop="stepEndName" label="转化目标" min-width="150" align="center"></el-table-column>
<el-table-column label="操作" fixed="right" align="center" min-width="200">
<template slot-scope="scope">
<el-button type="primary" size="small" @click="visitData(scope.row)">查看数据</el-button>
<el-button type="primary" size="small" @click="editColumn(scope.row)">编辑</el-button>
<el-button type="primary" size="small" @click="deleteConfirm(scope.row)">删除</el-button>
<el-button type="danger" size="small" @click="deleteConfirm(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
......@@ -57,7 +57,7 @@
<span class="tip">删除该转化漏斗数据将不会保留</span>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false">取 消</el-button>
<el-button type="primary" @click="dialogVisible = false">确 定</el-button>
<el-button type="primary" @click="confirm">确 定</el-button>
</span>
</el-dialog>
</div>
......@@ -66,40 +66,77 @@
</div>
</template>
<script>
import { openLoading, closeLoading } from "../../common/utils";
export default {
data() {
return {
searchParam: {
name: '',
searchName: '',
pageNo: 1,
pageSize: 15
},
totalRows: 0,
tableData: [
{name: '测试', begin: '点击微专业', target: '点击播放'}
],
dialogVisible: false
tableData: [],
dialogVisible: false,
deleteId: ''
}
},
mounted() {
this.search();
},
methods: {
// 封装一下请求通用的方法
getData(type, url, req, callback) {
openLoading(this);
this.$axios[type](localStorage.getItem("lectureUrl") + url, req)
.then(res => {
closeLoading(this);
let data = res.data;
if (data.code == "000000") {
if (callback) callback(data);
} else {
this.$message.error(data.message);
}
})
},
search() {
let req = this.searchParam;
this.getData(
"get", `/session/funnel/list?searchName=${this.searchParam.searchName}&pageNo=${this.searchParam.pageNo}&pageSize=${this.searchParam.pageSize}`, {},
res => {
this.tableData = res.data.data;
this.totalRows = res.data.totalRows;
}
);
},
// 新增漏斗
addData() {
this.$router.push({ path: 'add-funnel' })
this.$router.push({ path: 'add-funnel' });
},
// 查看数据
visitData() {
this.$router.push({ path: 'path-data' });
},
// 编辑
editColumn() {
editColumn(row) {
this.$router.push({ path: 'add-funnel' ,query: {id: row.id}});
},
// 删除确认框
deleteConfirm() {
deleteConfirm(row) {
this.dialogVisible = true;
this.deleteId = row.id;
},
confirm() {
this.getData(
"delete", `/session/funnel/remove/${this.deleteId}`, {},
res => {
if(res.code == '000000') {
this.dialogVisible = false;
this.$message.success('删除成功');
this.search();
}
}
);
},
handleSizeChange(value) {
this.searchParam.pageSize = value;
......
Markdown 格式
0% or
您添加了 0 到此讨论。请谨慎行事。
先完成此消息的编辑!
想要评论请 注册