Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
M
marketing
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
marketing-web
marketing
Commits
15027b9e
Commit
15027b9e
authored
Mar 31, 2022
by
caoyanzhi
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
update: ai营销数据统计
parent
084ced0a
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
303 additions
and
19 deletions
+303
-19
index.html
index.html
+1
-0
aiApi.js
src/service/api/aiApi.js
+7
-0
activity-info.vue
src/views/ai/ai-data-report/activity-info.vue
+11
-5
ai-data.vue
src/views/ai/ai-data-report/ai-data.vue
+230
-7
conversion.vue
src/views/ai/ai-data-report/conversion.vue
+54
-7
No files found.
index.html
View file @
15027b9e
...
...
@@ -13,6 +13,7 @@
<script
src=
"//at.alicdn.com/t/font_3229694_vfjtu9hqyrc.js"
></script>
<!--GIC3.0营销-->
<link
rel=
"stylesheet"
href=
"//at.alicdn.com/t/font_2996579_875h3lycepk.css"
>
<!-- 3.0企业 -->
<script
src=
"//at.alicdn.com/t/font_2996579_875h3lycepk.js"
></script>
<!-- 3.0企业 -->
<script
src=
"//at.alicdn.com/t/font_2859043_i7b45sfe90d.js"
></script>
<!--3.0组件库-->
<!-- <link rel="stylesheet" href="//web-1251519181.file.myqcloud.com/components/element.2.12.0.css"> -->
<!-- element 皮肤 -->
<!-- <link rel="stylesheet" type="text/css" href="http://web-1251519181.file.myqcloud.com/lib/elementUI/theme.1.0.1/index.css"> -->
...
...
src/service/api/aiApi.js
View file @
15027b9e
...
...
@@ -53,6 +53,13 @@ export const getActivityInfo = params => requests('/api-marketing/statistics/get
// 获取AI数据统计外呼数据
export
const
getOutBound
=
params
=>
requests
(
'/api-marketing/statistics/out-bound'
,
params
,
true
,
false
,
'get'
);
export
const
getIntentionLabel
=
params
=>
requests
(
'/api-marketing/statistics/intention-label'
,
params
,
true
,
false
,
'get'
);
export
const
getBillAnalysis
=
params
=>
requests
(
'/api-marketing/statistics/bill-quality-analysis'
,
params
,
true
,
false
,
'get'
);
export
const
getCallDuration
=
params
=>
requests
(
'/api-marketing/statistics/call-duration'
,
params
,
true
,
false
,
'get'
);
// 人群规则回显
export
const
getMemberCrowd
=
params
=>
requests
(
'/api-plug/query-member-crowd-new'
,
params
,
true
);
export
const
getGroupByIds
=
params
=>
requests
(
'/gic-member-tag-web/member-tag-group/queryGroupByIds'
,
params
);
// 活动转化数据
export
const
getPlanStatistics
=
params
=>
requests
(
'/api-marketing/statistics/plan-statistics'
,
params
,
true
,
false
,
'get'
);
src/views/ai/ai-data-report/activity-info.vue
View file @
15027b9e
...
...
@@ -45,9 +45,10 @@
<
script
>
import
{
formatDateTimeByType
}
from
'@/utils/index.js'
;
import
{
getActivityInfo
,
getMemberCrowd
}
from
'@/service/api/aiApi.js'
;
import
{
getActivityInfo
,
getMemberCrowd
,
getGroupByIds
}
from
'@/service/api/aiApi.js'
;
import
gicNewMemberGroup
from
'@/components/dm-new-member-group/index.vue'
;
// TODO 回显人群规则
export
default
{
name
:
'ActivityInfo'
,
components
:
{
gicNewMemberGroup
},
...
...
@@ -87,11 +88,16 @@ export default {
});
},
getMemberCrowd
()
{
getMemberCrowd
({
memberCrowdWidgetId
:
this
.
activityInfo
.
filterJson
}).
then
(
res
=>
{
if
(
res
.
result
)
{
const
{
memberType
,
filterJson
,
sceneJson
}
=
this
.
activityInfo
;
if
(
memberType
==
0
)
{
getMemberCrowd
({
memberCrowdWidgetId
:
filterJson
}).
then
(
res
=>
{
this
.
memberRule
=
res
.
result
.
filterFrontShow
;
}
});
});
}
else
if
(
memberType
==
1
)
{
getGroupByIds
({
memberTagGroupIds
:
sceneJson
}).
then
(
res
=>
{
this
.
memberRule
=
res
.
result
.
filterFrontShow
;
});
}
}
}
};
...
...
src/views/ai/ai-data-report/ai-data.vue
View file @
15027b9e
...
...
@@ -8,16 +8,35 @@
<el-row
class=
"chart-group"
>
<el-col
:span=
"8"
>
<div
class=
"chart-title"
>
意向标签
</div>
<div
class=
"chart-box"
id=
"chart-tag"
></div>
<div
class=
"chart-box"
id=
"chart-tag"
>
<svg
aria-hidden=
"true"
class=
"no-data-icon"
>
<use
xlink:href=
"#icon-cp-no-data"
></use>
</svg>
</div>
</el-col>
<el-col
:span=
"8"
>
<div
class=
"chart-title"
>
话单质量分析
</div>
<div
class=
"chart-box"
id=
"chart-record"
></div>
<div
class=
"chart-box"
id=
"chart-record"
>
<svg
aria-hidden=
"true"
class=
"no-data-icon"
>
<use
xlink:href=
"#icon-cp-no-data"
></use>
</svg>
</div>
</el-col>
<el-col
:span=
"8"
>
<div
class=
"chart-title"
>
通话时长
</div>
<div
class=
"chart-box"
>
<div
id=
"chart-time"
></div>
<div
id=
"chart-duration"
></div>
<div
v-if=
"talkTimeData.length > 0"
>
<div
class=
"talk-legend"
v-for=
"el in talkTimeData"
:key=
"el.color"
>
<i
class=
"talk-legend-icon"
:style=
"
{ background: el.color }">
</i>
<span
class=
"talk-legend-label"
>
{{
el
.
label
}}
</span>
<span
class=
"talk-legend-count"
>
{{
numFormat
(
el
.
count
)
}}
</span>
<span
class=
"talk-legend-percent"
>
{{
el
.
percent
}}
</span>
</div>
</div>
<svg
v-else
aria-hidden=
"true"
class=
"no-data-icon"
>
<use
xlink:href=
"#icon-cp-no-data"
></use>
</svg>
</div>
</el-col>
</el-row>
...
...
@@ -25,9 +44,12 @@
</
template
>
<
script
>
import
G2
from
'@antv/g2'
;
import
DataSet
from
'@antv/data-set'
;
import
{
numFormat
}
from
'@/utils/index.js'
;
import
{
getOutBound
}
from
'@/service/api/aiApi.js'
;
import
{
getOutBound
,
getIntentionLabel
,
getBillAnalysis
,
getCallDuration
}
from
'@/service/api/aiApi.js'
;
import
TargetGroup
from
'./target-group.vue'
;
export
default
{
name
:
'AiData'
,
components
:
{
TargetGroup
},
...
...
@@ -39,6 +61,7 @@ export default {
},
data
()
{
return
{
numFormat
,
activityId
:
''
,
planId
:
''
,
// type number:数字、time:时间、amount:金额、rate:百分比
...
...
@@ -142,7 +165,10 @@ export default {
}
]
],
targetData
:
{}
// 外呼数据
targetData
:
{},
// 通话时长数据
talkTimeData
:
[]
};
},
computed
:
{
...
...
@@ -168,7 +194,7 @@ export default {
item
.
value
=
typeof
value
==
'number'
?
numFormat
(
value
)
:
'--'
;
break
;
case
'rate'
:
item
.
value
=
typeof
value
==
'string'
?
value
:
'--'
;
item
.
value
=
value
==
null
?
'--'
:
value
;
break
;
}
// 活动不发送挂机短信时,数据指标不展示短信发送总数的字段
...
...
@@ -183,11 +209,171 @@ export default {
this
.
activityId
=
this
.
$route
.
params
.
id
;
this
.
planId
=
this
.
$route
.
query
.
planId
;
this
.
getOutBound
();
this
.
getIntentionLabel
();
this
.
getBillAnalysis
();
this
.
getCallDuration
();
},
methods
:
{
getOutBound
()
{
getOutBound
({
activityId
:
this
.
activityId
,
planId
:
this
.
planId
}).
then
(
res
=>
{
this
.
targetData
=
res
.
result
;
this
.
targetData
=
Array
.
isArray
(
res
.
result
)
&&
res
.
result
.
length
>
0
?
res
.
result
[
0
]
:
{};
});
},
getIntentionLabel
()
{
getIntentionLabel
({
activityId
:
this
.
activityId
,
planId
:
this
.
planId
}).
then
(
res
=>
{
if
(
!
Array
.
isArray
(
res
.
result
)
||
res
.
result
.
length
==
0
)
{
return
;
}
const
originData
=
res
.
result
[
0
];
const
levels
=
[
'A'
,
'B'
,
'C'
,
'D'
,
'E'
,
'F'
];
const
data
=
levels
.
map
(
el
=>
{
return
{
label
:
`
${
el
}
级`
,
count
:
originData
[
'count_'
+
el
],
percent
:
originData
[
el
+
'_proportion'
]
};
});
const
chart
=
new
G2
.
Chart
({
container
:
'chart-tag'
,
forceFit
:
true
,
height
:
220
,
padding
:
10
});
chart
.
source
(
data
);
chart
.
coord
(
'theta'
);
chart
.
legend
(
false
);
chart
.
intervalStack
()
.
position
(
'count'
)
.
color
(
'percent'
,
[
'#2d4dd1'
,
'#239EFF'
,
'#14C9C9'
,
'#05B770'
,
'#F69F3E'
,
'#7D59E0'
])
.
label
(
'percent'
,
val
=>
{
return
{
offset
:
-
40
,
textStyle
:
{
fontSize
:
10
,
textAlign
:
'center'
,
shadowBlur
:
2
,
shadowColor
:
'rgba(0, 0, 0, .45)'
,
fill
:
'#fff'
},
formatter
:
(
text
,
item
)
=>
{
return
item
.
point
.
label
+
'
\
n'
+
item
.
point
.
percent
;
}
};
})
.
tooltip
(
'label*count*percent'
,
(
label
,
count
,
percent
)
=>
{
return
{
title
:
label
,
name
:
count
,
value
:
percent
};
})
.
style
({
lineWidth
:
1
,
stroke
:
'#fff'
});
chart
.
render
();
});
},
getBillAnalysis
()
{
getBillAnalysis
({
activityId
:
this
.
activityId
,
planId
:
this
.
planId
}).
then
(
res
=>
{
if
(
!
Array
.
isArray
(
res
.
result
)
||
res
.
result
.
length
==
0
)
{
return
;
}
const
originData
=
res
.
result
[
0
];
const
data
=
[
{
label
:
'已接通'
,
count
:
originData
[
'count_3'
],
percent
:
originData
[
'3_proportion'
]
},
{
label
:
'线路问题'
,
count
:
originData
[
'count_4'
],
percent
:
originData
[
'4_proportion'
]
},
{
label
:
'被叫问题'
,
count
:
originData
[
'count_5'
],
percent
:
originData
[
'5_proportion'
]
}
];
const
chart
=
new
G2
.
Chart
({
container
:
'chart-record'
,
forceFit
:
true
,
height
:
220
,
padding
:
10
});
chart
.
source
(
data
);
chart
.
coord
(
'theta'
);
chart
.
legend
(
false
);
chart
.
intervalStack
()
.
position
(
'count'
)
.
color
(
'percent'
,
[
'#2d4dd1'
,
'#239EFF'
,
'#14C9C9'
])
.
label
(
'percent'
,
()
=>
{
return
{
offset
:
-
40
,
textStyle
:
{
fontSize
:
10
,
textAlign
:
'center'
,
shadowBlur
:
2
,
shadowColor
:
'rgba(0, 0, 0, .45)'
,
fill
:
'#fff'
},
formatter
:
(
text
,
item
)
=>
{
return
item
.
point
.
label
+
'
\
n'
+
item
.
point
.
percent
;
}
};
})
.
tooltip
(
'label*count*percent'
,
(
label
,
count
,
percent
)
=>
{
return
{
title
:
label
,
name
:
count
,
value
:
percent
};
})
.
style
({
lineWidth
:
1
,
stroke
:
'#fff'
});
chart
.
render
();
});
},
getCallDuration
()
{
getCallDuration
({
activityId
:
this
.
activityId
,
planId
:
this
.
planId
}).
then
(
res
=>
{
if
(
!
Array
.
isArray
(
res
.
result
)
||
res
.
result
.
length
==
0
)
{
return
;
}
const
originData
=
res
.
result
[
0
];
this
.
talkTimeData
=
[
{
label
:
'<10秒'
,
color
:
'#2d4dd1'
,
count
:
originData
[
'less_than_10'
],
percent
:
originData
[
'10_proportion'
]
},
{
label
:
'10-59秒'
,
color
:
'#D6B38C'
,
count
:
originData
[
'10_to_59'
],
percent
:
originData
[
'10_to_59_proportion'
]
},
{
label
:
'60-119秒'
,
color
:
'#14C9C9'
,
count
:
originData
[
'60_to_119'
],
percent
:
originData
[
'60_to_119_proportion'
]
},
{
label
:
'>120秒'
,
color
:
'#05B770'
,
count
:
originData
[
'greater_than_120'
],
percent
:
originData
[
'120_proportion'
]
}
];
this
.
talkTimeData
.
splice
(
3
,
1
);
const
data
=
[
this
.
talkTimeData
.
reduce
(
(
result
,
el
)
=>
{
result
[
el
.
label
]
=
el
.
count
;
return
result
;
},
{
type
:
'通话时长'
}
)
];
const
ds
=
new
DataSet
();
const
dv
=
ds
.
createView
().
source
(
data
);
dv
.
transform
({
type
:
'fold'
,
fields
:
this
.
talkTimeData
.
map
(
el
=>
el
.
label
),
// 展开字段集
key
:
'通话时长'
,
// key字段
value
:
'通话数量'
,
// value字段
retains
:
[
'type'
]
// 保留字段集,默认为除fields以外的所有字段
});
const
chart
=
new
G2
.
Chart
({
container
:
'chart-duration'
,
forceFit
:
true
,
height
:
84
,
padding
:
0
});
chart
.
source
(
dv
);
chart
.
coord
().
transpose
();
chart
.
legend
(
false
);
chart
.
axis
(
false
);
chart
.
intervalStack
()
.
size
(
24
)
.
position
(
'type*通话数量'
)
.
color
(
'通话时长'
,
this
.
talkTimeData
.
map
(
el
=>
el
.
color
)
);
chart
.
render
();
});
}
}
...
...
@@ -207,6 +393,43 @@ export default {
.chart-box
{
width
:
100%
;
height
:
220px
;
text-align
:
center
;
.no-data-icon
{
width
:
80px
;
height
:
auto
;
margin-top
:
20px
;
}
.talk-legend
{
display
:
flex
;
justify-content
:
space-between
;
align-items
:
center
;
margin
:
0
auto
;
max-width
:
400px
;
font-size
:
12px
;
font-weight
:
400
;
color
:
#606266
;
line-height
:
17px
;
+
.talk-legend
{
margin-top
:
10px
;
}
.talk-legend-icon
{
flex-shrink
:
0
;
margin-right
:
10px
;
width
:
9px
;
height
:
9px
;
border-radius
:
9px
;
}
.talk-legend-label
{
width
:
100%
;
text-align
:
left
;
}
.talk-legend-count
,
.talk-legend-percent
{
flex-shrink
:
0
;
width
:
120px
;
text-align
:
right
;
}
}
}
}
</
style
>
src/views/ai/ai-data-report/conversion.vue
View file @
15027b9e
...
...
@@ -15,12 +15,16 @@
</
template
>
<
script
>
import
{
getPlanStatistics
}
from
'@/service/api/aiApi.js'
;
import
{
numFormat
}
from
'@/utils/index.js'
;
import
TargetGroup
from
'./target-group.vue'
;
export
default
{
name
:
'Conversion'
,
components
:
{
TargetGroup
},
data
()
{
return
{
activityId
:
''
,
planId
:
''
,
contrast
:
[
{
label
:
'会员类型'
,
value
:
'type'
},
{
label
:
'会员等级'
,
value
:
'level'
},
...
...
@@ -32,16 +36,22 @@ export default {
{
label
:
'活动目标(销售额)'
,
unit
:
'元'
,
value
:
'200,000'
value
:
''
,
key
:
'activityTargetSale'
,
type
:
'amount'
},
{
label
:
'实际达成(销售额)'
,
unit
:
'元'
,
value
:
'200,000'
value
:
''
,
key
:
'actualSale'
,
type
:
'amount'
},
{
label
:
'实际达成率'
,
value
:
'200.00%'
value
:
''
,
key
:
'actualReachRate'
,
type
:
'rate'
}
],
[
...
...
@@ -49,26 +59,63 @@ export default {
label
:
'活动费用'
,
tips
:
'不包含短信发送失败退回金额'
,
unit
:
'元'
,
value
:
'2,276.1'
value
:
''
,
key
:
'activityCost'
,
type
:
'amount'
},
{
label
:
'ROI'
,
value
:
'1:88'
value
:
'1:88'
,
key
:
'ROI'
,
type
:
'rate'
}
],
[
{
label
:
'客单价'
,
unit
:
'元'
,
value
:
'196.39'
value
:
''
,
key
:
'perCustomerTransaction'
,
type
:
'amount'
},
{
label
:
'连带率'
,
value
:
'1.2'
value
:
''
,
key
:
'associatedPurchaseRate'
,
type
:
'number'
}
]
]
};
},
created
()
{
this
.
activityId
=
this
.
$route
.
params
.
id
;
this
.
planId
=
this
.
$route
.
query
.
planId
;
this
.
getPlanStatistics
();
},
methods
:
{
getPlanStatistics
()
{
getPlanStatistics
({
activityId
:
this
.
activityId
,
planId
:
this
.
planId
}).
then
(
res
=>
{
const
targetData
=
Array
.
isArray
(
res
.
result
)
&&
res
.
result
.
length
>
0
?
res
.
result
[
0
]
:
{};
this
.
targetList
=
this
.
targetList
.
map
(
el
=>
{
return
el
.
map
(
item
=>
{
const
value
=
targetData
[
item
.
key
];
switch
(
item
.
type
)
{
case
'number'
:
item
.
value
=
typeof
value
==
'number'
?
numFormat
(
value
)
:
'--'
;
break
;
case
'amount'
:
item
.
value
=
typeof
value
==
'number'
?
numFormat
(
value
)
:
'--'
;
break
;
case
'rate'
:
item
.
value
=
value
==
null
?
'--'
:
value
;
break
;
}
return
item
;
});
});
});
}
}
};
</
script
>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment