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
ce98716a
Commit
ce98716a
authored
Mar 21, 2022
by
crushh
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
udpate: dist
parent
b09e2e93
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
358 additions
and
13 deletions
+358
-13
aiApi.js
src/service/api/aiApi.js
+6
-0
index.js
src/service/api/index.js
+1
-1
birthSense.vue
src/views/ai/birthSense.vue
+154
-0
card.vue
src/views/ai/card.vue
+140
-0
defineTime.vue
src/views/ai/defineTime.vue
+46
-11
form.vue
src/views/ai/form.vue
+0
-0
task.vue
src/views/ai/task.vue
+11
-1
No files found.
src/service/api/aiApi.js
View file @
ce98716a
...
...
@@ -11,3 +11,9 @@ export const rechargeCenter = params => requests('/api-marketing/recharge-center
//查看话术模板列表
export
const
templateList
=
params
=>
requests
(
PREFIX
+
'get-template-list'
,
params
,
true
);
//营销活动场景/客户意向等级/重拨状态
export
const
aiDictList
=
params
=>
requests
(
'/api-marketing/ai-dict-list'
,
params
,
true
,
false
,
'get'
);
//新建ai活动
export
const
initActivity
=
params
=>
requests
(
PREFIX
+
'/init-activity'
,
params
,
true
);
src/service/api/index.js
View file @
ce98716a
...
...
@@ -110,7 +110,7 @@ const requests = (url, data = {}, contentTypeIsJSON = false, isSilence = false,
_opts
.
data
=
qs
.
stringify
(
Object
.
assign
({
requestProject
:
'gic-web'
},
data
));
}
}
else
{
_opts
.
params
=
_query
;
_opts
.
params
=
Object
.
assign
({
requestProject
:
'gic-web'
},
data
)
;
}
let
key
=
JSON
.
stringify
(
_opts
);
...
...
src/views/ai/birthSense.vue
0 → 100644
View file @
ce98716a
<
template
>
<el-form
:model=
"form"
ref=
"form"
label-width=
"100px"
:rules=
"rules"
>
<el-form-item
label=
"外呼时间"
required
>
<el-radio
v-model=
"form.birth_type"
:label=
"1"
@
change=
"onChangeEffectType"
>
生日当天
</el-radio>
<el-radio
v-model=
"form.birth_type"
:label=
"2"
@
change=
"onChangeEffectType"
>
生日当月
</el-radio>
<el-radio
v-model=
"form.birth_type"
:label=
"3"
@
change=
"onChangeEffectType"
>
生日前
<el-input
class=
"w100"
style=
"margin:0 5px;"
v-model=
"form.birth_days"
/>
天
</el-radio>
</el-form-item>
<el-form-item
label=
"生日范围"
prop=
"birthDate1"
v-show=
"form.birth_type == 1 || form.birth_type == 3"
>
<el-date-picker
value-format=
"timestamp"
format=
"MM-dd"
v-model=
"form.birthDate1"
@
change=
"handleDateChange"
:picker-options=
"pickerOptions"
type=
"daterange"
placeholder=
"请选择生日范围"
range-separator=
"~"
start-placeholder=
"开始日期"
end-placeholder=
"结束日期"
>
</el-date-picker>
</el-form-item>
<el-form-item
label=
"生日范围"
prop=
"birthDate2"
v-show=
"form.birth_type == 2"
>
<el-date-picker
type=
"monthrange"
value-format=
"timestamp"
format=
"MM月"
v-model=
"form.birthDate2"
@
change=
"handleDateMonthChange"
:picker-options=
"pickerOptionsMonth"
placeholder=
"请选择生日范围"
range-separator=
"~"
start-placeholder=
"开始月份"
end-placeholder=
"结束月份"
>
</el-date-picker>
</el-form-item>
<el-form-item
label=
"外呼时段"
required
>
<el-radio
v-model=
"form.call_flag"
:label=
"0"
@
change=
"onChangeEffectType"
>
默认时段
</el-radio>
<el-radio
v-model=
"form.call_flag"
:label=
"1"
@
change=
"onChangeEffectType"
>
自定义时段
</el-radio>
<div
v-show=
"form.call_flag == 0"
style=
"line-height: 20px;"
>
每天 09:00-20:00
</div>
<defineTime
v-show=
"form.call_flag == 1"
ref=
"defineTime"
/>
</el-form-item>
<el-form-item
label=
"活动有效期"
required
>
<span
v-if=
"!activeTime"
class=
"tips"
style=
"font-size: 14px;margin:0"
>
设置【生日范围】和【外呼时间】后自动生成
</span>
<span
v-else
>
{{
activeTime
}}
</span>
</el-form-item>
</el-form>
</
template
>
<
script
>
import
defineTime
from
'./defineTime.vue'
;
import
{
formatDateTimeByType
}
from
'@/utils/index'
;
let
minTime
=
null
;
let
maxTime
=
null
;
let
minTimeMonth
=
null
;
let
maxTimeMonth
=
null
;
export
default
{
data
()
{
const
birthDateValidtor
=
(
rule
,
value
,
callback
)
=>
{
if
((
this
.
form
.
birth_type
==
1
||
this
.
form
.
birth_type
==
3
)
&&
!
this
.
form
.
birthDate1
.
length
)
{
return
callback
(
new
Error
(
'生日范围不能为空'
));
}
else
if
(
this
.
form
.
birth_type
==
2
&&
!
this
.
form
.
birthDate2
.
length
)
{
return
callback
(
new
Error
(
'生日范围不能为空'
));
}
callback
();
};
return
{
formatDateTimeByType
,
form
:
{
birthDate1
:
''
,
//生日范围 当天
birthDate2
:
''
,
//生日范围 当月
birth_type
:
1
,
//外呼时间 1当天 2当月 3生日前
call_flag
:
0
//外呼时段 0 默认 1 自定义
},
rules
:
{
birthDate1
:
{
validator
:
birthDateValidtor
},
birthDate2
:
{
validator
:
birthDateValidtor
}
},
pickerOptions
:
{
onPick
(
time
)
{
// 起始时间:仅半年范围内 && 结束时间:跨度最多3个月,即所选起始时间往后+90天为上限;
if
(
!
time
.
maxDate
)
{
const
timeRange
=
90
*
24
*
60
*
60
*
1000
;
// 3个月
minTime
=
time
.
minDate
.
getTime
();
// 最小时间
maxTime
=
time
.
minDate
.
getTime
()
+
timeRange
;
// 最大时间
}
},
disabledDate
:
time
=>
{
const
timeRange
=
30
*
24
*
60
*
60
*
1000
;
// 3个月
if
(
minTime
&&
maxTime
)
{
return
time
.
getTime
()
<
minTime
||
time
.
getTime
()
>
maxTime
;
}
else
{
return
time
.
getTime
()
<
new
Date
().
getTime
()
-
24
*
60
*
60
*
1000
||
time
.
getTime
()
>
new
Date
().
getTime
()
+
timeRange
;
}
}
},
pickerOptionsMonth
:
{
onPick
(
time
)
{
// 起始时间:仅半年范围内 && 结束时间:跨度最多3个月,即所选起始时间往后+90天为上限;
if
(
!
time
.
maxDate
)
{
const
timeRange
=
90
*
24
*
60
*
60
*
1000
;
// 3个月
minTimeMonth
=
time
.
minDate
.
getTime
();
// 最小时间
maxTimeMonth
=
time
.
minDate
.
getTime
()
+
timeRange
;
// 最大时间
}
},
disabledDate
:
time
=>
{
const
timeRange
=
180
*
24
*
60
*
60
*
1000
;
// 3个月
if
(
minTimeMonth
&&
maxTimeMonth
)
{
return
time
.
getTime
()
<
minTimeMonth
||
time
.
getTime
()
>
maxTimeMonth
;
}
else
{
return
time
.
getTime
()
<
new
Date
().
getTime
()
||
time
.
getTime
()
>
new
Date
().
getTime
()
+
timeRange
;
}
}
}
};
},
computed
:
{
activeTime
()
{
let
str
=
''
;
if
(
this
.
form
.
birth_type
==
1
&&
this
.
form
.
birthDate1
.
length
)
{
str
=
formatDateTimeByType
(
this
.
form
.
birthDate1
[
0
],
'yyyy-MM-dd'
)
+
' 至 '
+
formatDateTimeByType
(
this
.
form
.
birthDate1
[
1
],
'yyyy-MM-dd'
);
}
else
if
(
this
.
form
.
birth_type
==
2
&&
this
.
form
.
birthDate2
.
length
)
{
str
=
formatDateTimeByType
(
this
.
form
.
birthDate2
[
0
],
'yyyy-MM-dd'
)
+
' 至 '
+
formatDateTimeByType
(
this
.
form
.
birthDate2
[
1
],
'yyyy-MM-dd'
);
}
return
str
;
}
},
components
:
{
defineTime
},
methods
:
{
submit
()
{
return
new
Promise
(
async
resolve
=>
{
const
res
=
await
this
.
$refs
.
defineTime
.
submit
();
let
arr
=
[];
if
(
!
res
)
return
;
res
.
timeRangeList
.
forEach
(
item
=>
{
arr
.
push
(
`
${
item
.
startTime
}
-
${
item
.
endTime
}
`
);
});
this
.
$refs
.
form
.
validate
(
val
=>
{
if
(
val
)
{
const
{
birth_type
,
call_flag
,
birthDate1
,
birthDate2
}
=
this
.
form
;
const
obj
=
{
startDate
:
birth_type
==
2
?
birthDate2
[
0
]
:
birthDate1
[
0
],
endDate
:
birth_type
==
2
?
birthDate2
[
1
]
:
birthDate1
[
1
],
call_flag
,
birth_type
};
if
(
arr
.
length
)
{
obj
.
callTime
=
arr
;
}
resolve
(
obj
);
}
else
{
resolve
(
false
);
}
});
});
},
handleDateChange
(
val
)
{
console
.
log
(
val
);
if
(
!
val
)
{
minTime
=
maxTime
=
null
;
}
},
handleDateMonthChange
(
val
)
{
console
.
log
(
val
);
if
(
!
val
)
{
minTimeMonth
=
maxTimeMonth
=
null
;
}
}
}
};
</
script
>
<
style
></
style
>
src/views/ai/card.vue
0 → 100644
View file @
ce98716a
<
template
>
<!--根据客户意向打标签 -->
<div
class=
"card"
>
<div
class=
"tagHead"
>
<div
class=
"left"
>
<div
class=
"title"
>
{{
text
.
title
}}
</div>
<el-switch
v-model=
"form.labelFlag"
/>
<div
class=
"tips"
v-show=
"text.tips"
>
{{
text
.
tips
}}
</div>
</div>
<el-button
type=
"text"
>
{{
text
.
explanation
}}
</el-button>
</div>
<div
v-show=
"form.labelFlag"
>
<div
class=
"tagBody"
>
<table>
<thead>
<tr>
<th
class=
"tableHead"
v-for=
"(item, index) in tableColumn"
:key=
"index"
>
{{
item
.
text
}}
</th>
</tr>
</thead>
<tbody>
<tr
v-for=
"(item, index) in tableData"
:key=
"index"
>
<td
class=
"tagSelectCell"
style=
"width:420px"
>
<el-select
filterable
v-model=
"item.options"
placeholder=
"请选择意向等级(多选)"
@
change=
"effectActionChange"
>
<el-option
v-for=
"item in options"
:key=
"item.aiTemplateId"
:label=
"item.name"
:value=
"item.aiTemplateId"
></el-option>
</el-select>
</td>
<td
class=
"tagSelectCell"
style=
"width:170px"
>
<el-button
type=
"text"
v-if=
"!Object.keys(item.labels).length"
@
click=
"openTagsDialog(index)"
>
选择标签
</el-button>
<el-tag
type=
"mini"
v-else
closable
@
close=
"handleTagClose(item.id)"
>
{{
item
.
labels
.
name
}}
</el-tag>
</td>
<td
class=
"tagSelectCell"
>
<div
class=
"delIcon"
type=
"text"
@
click=
"delTagList(index)"
>
<i
class=
"iconfont icon-Delete"
></i>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<div
class=
"tagFooter"
>
<el-button
type=
"text"
@
click=
"addGrade"
>
<i
class=
"iconfont icon-Plus"
></i>
{{
text
.
addText
}}
</el-button>
</div>
</div>
</div>
</
template
>
<
script
>
export
default
{
props
:
{
tableData
:
{
type
:
Array
,
default
:
()
=>
[]
},
options
:
{
type
:
Array
,
default
:
()
=>
[]
},
text
:
{
type
:
Object
,
default
:
()
=>
{
return
{
title
:
'客户意向等级'
,
tips
:
'开启后,可提高接通率'
,
explanation
:
'意向等级说明'
,
addText
:
'添加等级'
};
}
},
tableColumn
:
{
type
:
Array
,
default
:
()
=>
[
{
text
:
'客户意向等级'
,
prop
:
'options'
},
{
text
:
'选择标签'
,
prop
:
'select'
},
{
text
:
'操作'
,
prop
:
'operate'
}
]
}
}
};
</
script
>
<
style
lang=
"scss"
scoped
>
.card
{
width
:
730px
;
background
:
#f7f8fa
;
border-radius
:
4px
;
box-sizing
:
border-box
;
margin-top
:
20px
;
&:first-child
{
margin-top
:
0
;
}
.tagHead
{
width
:
100%
;
height
:
60px
;
display
:
flex
;
justify-content
:
space-between
;
box-sizing
:
border-box
;
padding
:
0
20px
;
.left
{
display
:
flex
;
align-items
:
center
;
.title
{
width
:
173px
;
margin-right
:
15px
;
}
}
}
.tagBody
{
border-top
:
1px
solid
#e4e7ed
;
box-sizing
:
border-box
;
padding
:
0
20px
;
table
{
width
:
100%
;
}
.tagSelectCell
{
padding
:
0
30px
12px
0
;
}
}
.tagFooter
{
padding
:
0
20px
17px
20px
;
}
.tableHead
{
text-align
:
left
;
font-weight
:
bold
;
line-height
:
20px
;
color
:
#303133
;
font-size
:
14px
;
height
:
52px
;
line-height
:
52px
;
}
}
</
style
>
src/views/ai/defineTime.vue
View file @
ce98716a
<
template
>
<div
class=
"defineTime"
>
<p
class=
"tips"
>
自定义时段不少于4个小时
</p>
<el-form
:model=
"form"
ref=
"
couponForm
"
>
<el-form
:model=
"form"
ref=
"
defineTime
"
>
<el-form-item
class=
"mt10"
v-for=
"(v, i) in form.timeRangeList"
:key=
"i"
:prop=
"'timeRangeList.' + i + '.timeRange'"
:rules=
"[
{ validator: validateTime, trigger: 'change' }]">
<el-time-picker
class=
"w280"
is-range
v-model=
"v.timeRange"
range-separator=
"~"
start-placeholder=
"开始时间"
end-placeholder=
"结束时间"
value-format=
"HH:mm"
format=
"HH:mm"
placeholder=
"选择时间范围"
/>
<div
class=
"delIcon"
type=
"text"
@
click=
"delTimeRange(i)"
>
<i
class=
"iconfont icon-Delete"
></i>
<div
style=
"display: flex;align-items: center;"
>
<el-time-select
placeholder=
"起始时间"
v-model=
"v.startTime"
:picker-options=
"
{
start: '09:00',
step: '00:30',
end: '20:00'
}"
>
</el-time-select>
<el-time-select
placeholder=
"结束时间"
v-model=
"v.endTime"
:picker-options=
"
{
start: '09:00',
step: '00:30',
end: '20:00',
minTime: startTime
}"
>
</el-time-select>
<div
class=
"delIcon"
type=
"text"
@
click=
"delTimeRange(i)"
>
<i
class=
"iconfont icon-Delete"
></i>
</div>
</div>
</el-form-item>
</el-form>
...
...
@@ -17,16 +40,17 @@
export
default
{
data
()
{
const
validateTime
=
(
rule
,
value
,
callback
)
=>
{
if
(
!
value
)
{
return
callback
(
new
Error
(
'请输入时间'
));
}
else
{
callback
();
}
// if (!value) {
// return callback(new Error('请输入时间'));
// } else {
// callback();
// }
callback
();
};
return
{
validateTime
,
form
:
{
timeRangeList
:
[{
timeRange
:
''
}]
timeRangeList
:
[{}]
}
};
},
...
...
@@ -41,7 +65,18 @@ export default {
this
.
$message
.
error
(
'最多五个时间段'
);
return
false
;
}
this
.
form
.
timeRangeList
.
push
({
timeRange
:
''
});
this
.
form
.
timeRangeList
.
push
({});
},
submit
()
{
return
new
Promise
(
resolve
=>
{
this
.
$refs
.
defineTime
.
validate
(
val
=>
{
if
(
val
)
{
resolve
(
this
.
form
);
}
else
{
resolve
(
false
);
}
});
});
}
}
};
...
...
src/views/ai/form.vue
View file @
ce98716a
This diff is collapsed.
Click to expand it.
src/views/ai/task.vue
View file @
ce98716a
...
...
@@ -309,7 +309,17 @@ export default {
},
methods
:
{
create
({
scene
})
{
this
.
$router
.
push
({
path
:
'/ai/form'
,
query
:
{
scene
}
});
if
(
this
.
money
==
0
)
{
this
.
$confirm
(
'当前账户已无可用余额,请充值后再创建外呼任务'
,
'提示'
,
{
confirmButtonText
:
'去充值'
,
cancelButtonText
:
'取消'
,
type
:
'warning'
}).
then
(()
=>
{
this
.
recharge
();
});
}
else
{
this
.
$router
.
push
({
path
:
'/ai/form'
,
query
:
{
scene
}
});
}
},
recharge
()
{
window
.
open
(
`
${
window
.
location
.
origin
}
/marketing/#/recharge/do`
,
'_blank'
);
...
...
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