Commit 92174ce4 by crushh

update: temp

parent 97c2b5b4
......@@ -7,9 +7,9 @@
<title>GIC后台</title>
<link rel="stylesheet" type="text/css" href="<%= htmlWebpackPlugin.options.BASE_URL %>static/fonts/iconfont.css">
<link rel="stylesheet" type="text/css" href="<%= htmlWebpackPlugin.options.BASE_URL %>static/css/common.css">
<link rel="stylesheet" href="//at.alicdn.com/t/font_2996579_93aeeozj35q.css">
<link rel="stylesheet" href="//at.alicdn.com/t/font_3229694_tsgoqwe80mp.css"> <!--GIC3.0营销-->
<link rel="stylesheet" href="//at.alicdn.com/t/font_3229694_tsgoqwe80mp.js"> <!--GIC3.0营销-->
<!-- <link rel="stylesheet" href="//at.alicdn.com/t/font_2996579_93aeeozj35q.css"> -->
<link rel="stylesheet" href="//at.alicdn.com/t/font_3229694_b36vgmw8y2d.css"> <!--GIC3.0营销-->
<link rel="stylesheet" href="//at.alicdn.com/t/font_3229694_b36vgmw8y2d.js"> <!--GIC3.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"> -->
......
......@@ -253,6 +253,9 @@ a:hover {
.w300{
width: 300px!important;
}
.w340{
width: 340px!important;
}
.w350{
width: 350px!important;
}
......@@ -554,3 +557,18 @@ img::after {
color: #096dd9 !important;
}
}
.delIcon {
width: 24px;
display: inline-block;
height: 24px;
border-radius: 2px;
text-align: center;
color: #f5222d;
line-height: 24px;
margin-left: 6px;
cursor: pointer;
&:hover {
background: #f6e1e5;
}
}
\ No newline at end of file
<template>
<div>
<el-button v-for="item in notDropdownList" :disabled="typeof item.disabled === 'function' ? item.disabled(scopeData) : item.disabled" v-bind="{ type: 'text', ...item.props }" :key="item.text" @click="handleCommand(item)">{{ item.text }}</el-button>
<el-dropdown v-if="buttonArray.length > max" v-bind="{ type: 'text', ...dropdownProps }" @click="() => emitEventHandler('click')" @command="handleCommand" @visible-change="bool => emitEventHandler('visible-change', bool)">
<span class="el-dropdown-link">
<i class="iconfont icon-more"></i>
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item v-for="item in dropdownList" :class="{ 'item-disabled': typeof item.disabled === 'function' ? item.disabled(scopeData) : item.disabled }" :command="item" :key="item.text">
<el-button :disabled="typeof item.disabled === 'function' ? item.disabled(scopeData) : item.disabled" v-bind="{ type: 'text', ...item.props }">{{ item.text }}</el-button>
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
</template>
<script>
export default {
name: 'dm-dropdown',
components: {},
props: {
dropdownProps: {
//Dropdown Attributes
type: Object,
default: () => {}
},
configs: {
type: Array,
default: () => []
},
max: {
type: [Number, String],
default: 3
},
scopeData: Object
},
methods: {
emitEventHandler(event) {
this.$emit(event, ...Array.from(arguments).slice(1));
},
handleCommand(config) {
if (typeof config.disabled == 'function' ? config.disabled(this.scopeData) : config.disabled) return;
config.handler && config.handler(this.scopeData);
this.emitEventHandler('command', { config, data: this.scopeData });
}
},
computed: {
buttonArray() {
return this.configs.filter(item => {
let visible = item.visible;
if (typeof visible === 'boolean') {
return item.visible;
} else if (typeof visible === 'function') {
return item.visible(this.scopeData);
} else {
return true;
}
});
},
notDropdownList() {
return this.buttonArray.length > this.max ? this.buttonArray.slice(0, this.max - 1) : this.buttonArray;
},
dropdownList() {
return this.buttonArray.length > this.max ? this.buttonArray.slice(this.max - 1) : [];
}
}
};
</script>
<style lang="scss" scoped>
.el-dropdown-link {
cursor: pointer;
color: #1890ff;
}
.el-button--text + .el-dropdown {
margin-left: 8px;
}
.item-disabled {
cursor: not-allowed;
}
</style>
## 示例
```
<el-table-column
fixed="right"
label="操作"
>
<template slot-scope="scope">
<dm-dropdown :scope-data="scope.row" :configs="btnArr" @command="onCommand"/>
</template>
</el-table-column>
export default {
name: 'btn',
data() {
return {
dropdownAttr: {
// splitButton: true
},
btnArr: [
{
text: '查看',
visible: (row)=>row.status === 2, // 不写visible属性默认为true
handler: (row) =>{
console.log(row)
console.log('查看')
},
},
{
text: '编辑',
handler: (row) =>{
console.log(row)
console.log('编辑')
},
},
{
text: '删除',
handler: (row) =>{
console.log(row)
console.log('删除')
}
},
{
text: '复制',
handler: (row) =>{
console.log(row)
console.log('复制')
},
},
{
text: '禁用',
handler: (row) =>{
console.log(row)
console.log('禁用')
},
}
],
}
},
methods: {
onCommand(item) {
console.log(item)
},
}
}
```
### props
| 参数 | 说明 | 类型 | 可选值 | 默认值 | 是否必传 |
| ------------ | ------------ | ------------ | ------------ | ------------ | ------------ |
| scopeData | - | Object | -- | -- | 否 |
| configs | 按钮数组 | Array | [{text:string(必传), visible: boolean \| function, handler: function,props:按钮属性配置(非必传)}] | -- | 是 |
| dropdownProps | el-dropDown的属性 | Object | -- | -- | 否 |
| max | 最多展示几个按钮 | String/Number | -- | 3 | 否 |
#### events
| 事件名称 | 说明 | 参数 |
| ------------ | ------------ | ------------ |
| command | 按钮触发事件 | {config, data} |
### 更新日志:
- v1.0.0 cr by 黄冷<br>
......@@ -5,6 +5,29 @@ export default {
defaultAvatar: require('../assets/img/head_default.png')
};
},
filters: {
sceneFilter(val) {
let str = '- -';
switch (val) {
case 1:
str = '客户生日';
break;
case 2:
str = '节日活动邀约';
break;
case 3:
str = '加企微好友';
break;
case 4:
str = '客户复购';
break;
case 5:
str = '其它场景';
break;
}
return str;
}
},
methods: {
filterAvatar(img) {
return img ? img.replace(/^http(s)?/, 'https') : this.defaultAvatar;
......
......@@ -3,12 +3,12 @@ export default {
name: 'ai营销',
component: () => import('../../views/ai/index.vue'),
meta: {},
redirect: 'ai/index',
redirect: 'ai/list',
children: [
{
path: 'index',
path: 'list',
name: '列表',
component: () => import('../../views/ai/index.vue'),
component: () => import('../../views/ai/list.vue'),
meta: {}
},
{
......
......@@ -5,3 +5,9 @@ export const pageStatistics = params => requests(PREFIX + 'page-statistics', par
//活动分页查询
export const page = params => requests(PREFIX + 'page', params, true);
//计费中心--获取账号余额, 今日消费
export const rechargeCenter = params => requests('/api-marketing/recharge-center', params);
//查看话术模板列表
export const templateList = params => requests(PREFIX + 'get-template-list', params, true);
......@@ -134,7 +134,7 @@ const requests = (url, data = {}, contentTypeIsJSON = false, isSilence = false,
.then(res => {
clearTimeout(_timer);
popRequest(_random);
if (res.data.errorCode !== 0) {
if (res.data.errorCode !== 0 && res.data.code != 0) {
reject(res);
// handlerErr(res.data.errorCode, res.data.message, alertError);
if (res.data.message.indexOf('抱歉') >= 0) {
......
<template>
<div class="defineTime">
<p class="tips">自定义时段不少于4个小时</p>
<el-form :model="form" ref="couponForm">
<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>
</el-form-item>
</el-form>
<el-button type="text" @click="addTimeRange"> <i class="iconfont icon-Plus"></i> 添加时间段 </el-button>
</div>
</template>
<script>
export default {
data() {
const validateTime = (rule, value, callback) => {
if (!value) {
return callback(new Error('请输入时间'));
} else {
callback();
}
};
return {
validateTime,
form: {
timeRangeList: [{ timeRange: '' }]
}
};
},
methods: {
// 删除兑换时段
delTimeRange(index) {
this.form.timeRangeList.splice(index, 1);
},
// 添加兑换时段
addTimeRange() {
if (this.form.timeRangeList.length >= 5) {
this.$message.error('最多五个时间段');
return false;
}
this.form.timeRangeList.push({ timeRange: '' });
}
}
};
</script>
<style lang="scss" scoped>
.defineTime {
width: 400px;
// height: 164px;
background: #f7f8fa;
border-radius: 4px;
padding: 16px;
box-sizing: border-box;
}
.tips {
font-size: 12px;
font-weight: 400;
color: #909399;
line-height: 17px;
}
</style>
<template>
<div>
活动详情
<el-form class="content" ref="form" :model="form" label-width="100px" :rules="rules" v-loading="loading" element-loading-text="拼命加载中">
<dm-sub-title line>基本信息</dm-sub-title>
<div class="section">
<el-form-item label="活动场景" prop="ecmPlanName">
{{ form.scene | sceneFilter }}
</el-form-item>
<el-form-item label="活动名称" prop="activityName">
<el-input class="w340" :maxlength="30" placeholder="请输入活动名称" show-word-limit v-model="form.activityName"></el-input>
</el-form-item>
<el-form-item label="选择话术" prop="aiTemplateId">
<el-select filterable class="w340" v-model="form.aiTemplateId" placeholder="请选择话术" @change="effectActionChange">
<el-option v-for="item in templateOptions" :key="item.aiTemplateId" :label="item.name" :value="item.aiTemplateId"></el-option>
</el-select>
<span class="tips">仅支持选择已上线的话术,若需要增加话术,请联系运营经理</span>
</el-form-item>
</div>
<dm-sub-title line>活动时间<span class="tips">每天16:00之后不支持创建当天开始的活动</span></dm-sub-title>
<div class="section">
<el-form-item label="生日范围" prop="birthDate">
<el-date-picker value-format="MM-dd" format="MM-dd" v-model="form.birthDate" @change="handleDateChange" :picker-options="pickerOptions" type="daterange" placeholder="请选择生日范围" range-separator="~" start-placeholder="开始日期" end-placeholder="结束日期"> </el-date-picker>
</el-form-item>
<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="外呼时段" 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>
<defineTime />
</el-form-item>
<el-form-item label="活动有效期" required>
<span class="tips" style="font-size: 14px;margin:0">设置【生日范围】和【外呼时间】后自动生成</span>
</el-form-item>
</div>
<dm-sub-title line>人群规则<span class="tips">针对选择的客户仅会执行一次外呼任务。</span></dm-sub-title>
<div class="section">
<el-form-item label="参与人群" prop="memberType" required>
<el-radio v-model="form.memberType" :label="0" @change="onChangeEffectType">客户筛选</el-radio>
<el-radio v-model="form.memberType" :label="1" @change="onChangeEffectType">客户分组</el-radio>
</el-form-item>
<el-form-item label="预计覆盖人数"><span class="bold">23,098</span><span class="tips">不包含无手机号的客户,以最终活动覆盖人数为准</span> </el-form-item>
</div>
<dm-sub-title line>外呼规则配置</dm-sub-title>
<div class="section">
<div class="tagMatch">
<div class="head">
<div class="left">
<div class="title">根据客户意向打标签</div>
<el-switch />
</div>
<el-button type="text">意向等级说明</el-button>
</div>
<div class="tagBody">
<table>
<thead>
<tr>
<th class="tableHead">客户意向等级</th>
<th class="tableHead">选择标签</th>
<th class="tableHead">操作</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in tagMatchList" :key="index">
<td class="tagSelectCell">
<el-select filterable class="w420" v-model="item.options" placeholder="请选择话术" @change="effectActionChange">
<el-option v-for="item in templateOptions" :key="item.aiTemplateId" :label="item.name" :value="item.aiTemplateId"></el-option>
</el-select>
</td>
<td class="tagSelectCell">
<el-button type="text" v-if="!Object.keys(item.labels).length">选择标签</el-button>
<el-tag type="mini" v-else>{{ item.labels.name }}</el-tag>
</td>
<td class="tagSelectCell">
<div class="delIcon" type="text" @click="delTimeRange(item)">
<i class="iconfont icon-Delete"></i>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<div class="footer">
<el-button type="text"> <i class="iconfont icon-Plus"></i> 添加等级 </el-button>
</div>
</div>
</div>
<dm-sub-title line>活动分析设置</dm-sub-title>
<div class="section"></div>
</el-form>
</div>
</template>
<script>
export default {};
import filterAvater from '@/mixins/filterAvater.js';
import { templateList } from '@/service/api/aiApi.js';
import defineTime from './defineTime.vue';
let minTime = null;
let maxTime = null;
export default {
mixins: [filterAvater],
data() {
return {
//ai营销场景,一个活动下只有一个计划,一个计划里有多个事件
form: {
scene: '', //活动场景 「1 客户生日」、「2 节日活动邀约」、「3 加企微好友」、「4 客户复购」、「5 其它场景」
aiTemplateId: '', //话术模板id
birthDate: '', //生日范围
birth_type: 1, //外呼时间 1当天 2当月 3生日前
call_flag: 0, //外呼时段 0 默认 1 自定义
memberType: 0 // 会员类型(0:会员筛选,1:会员分组)
},
templateOptions: [], //话术模板下拉
rules: {
activityName: { required: true, message: '活动名称不能为空' },
aiTemplateId: { required: true, message: '活动名称不能为空' },
birthDate: { required: true, message: '生日范围不能为空' }
},
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; // 6个月
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;
}
}
},
tagMatchList: [
{
options: [],
labels: {
id: 1,
name: '标签名称1'
}
},
{
options: [],
labels: {
id: 2,
name: '标签名称2'
}
}
]
};
},
mounted() {
const { scene } = this.$route.query;
this.form.scene = scene && Number(scene);
this.getTemplateList();
},
components: {
defineTime
},
methods: {
handleDateChange(val) {
if (!val) {
minTime = maxTime = null;
}
},
async getTemplateList() {
const { result } = await templateList({ status: 5 });
this.templateOptions = result || [];
console.log(result);
}
}
};
</script>
<style></style>
<style lang="scss" scoped>
.content {
margin: 10px 20px;
}
.tips {
font-size: 12px;
font-weight: 400;
color: #909399;
line-height: 17px;
margin-left: 20px;
}
.bold {
font-size: 14px;
font-weight: bold;
color: #303133;
line-height: 20px;
}
.section {
padding: 20px 0 40px 0;
}
.tagMatch {
padding: 0 20px;
width: 730px;
height: 243px;
background: #f7f8fa;
border-radius: 4px;
.head {
width: 100%;
height: 60px;
display: flex;
justify-content: space-between;
box-sizing: border-box;
border-bottom: 1px solid #e4e7ed;
.left {
display: flex;
align-items: center;
.title {
width: 173px;
margin-right: 15px;
}
}
}
}
.tagBody {
box-sizing: border-box;
table {
width: 100%;
}
.tagSelectCell {
padding: 0 30px 12px 0;
}
}
.tableHead {
text-align: left;
font-weight: bold;
line-height: 20px;
color: #303133;
font-size: 14px;
height: 52px;
line-height: 52px;
}
</style>
<template>
<div>
<el-tabs v-model="activeName">
<el-tab-pane label="外呼任务" name="first">
<task />
</el-tab-pane>
<el-tab-pane label="话术管理" name="second">
<manage />
</el-tab-pane>
</el-tabs>
<keep-alive>
<router-view v-if="$route.meta.keepAlive" />
</keep-alive>
<router-view v-if="!this.$route.meta.keepAlive" />
</div>
</template>
<script>
import task from './task.vue';
import manage from './manage.vue';
export default {
data() {
return {
activeName: 'first'
};
},
components: {
task,
manage
},
watch: {}
};
</script>
<style></style>
<script></script>
<template>
<div>
<el-tabs v-model="activeName">
<el-tab-pane label="外呼任务" name="first">
<task />
</el-tab-pane>
<el-tab-pane label="话术管理" name="second">
<manage />
</el-tab-pane>
</el-tabs>
</div>
</template>
<script>
import task from './task.vue';
import manage from './manage.vue';
export default {
data() {
return {
activeName: 'first'
};
},
components: {
task,
manage
},
watch: {}
};
</script>
<style></style>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment