Commit 605e7ae2 by 黑潮

Merge branch 'feature/销售线索4'

parents 94623c21 c1ae3030
......@@ -11,10 +11,10 @@
</el-breadcrumb>
<h3>
<div>
<span>{{ contentTitle }}</span>
<span class="content-title">{{ contentTitle }}</span>
<div v-html="layoutTips" class="layout--tips--wrap"></div>
</div>
<div v-if="showDescription" class="intro_wrap"><img :src="require('@/assets/img/introlIcon.png')" class="introlIcon" alt="" /><span class="intro" @click="() => (drawer = true)">指标说明</span></div>
<div v-if="showDescription" class="intro_wrap"><i class="iconfont icon-zhibiaoshuoming introlIcon" alt="" /><span class="intro" @click="() => (drawer = true)">指标说明</span></div>
</h3>
</div>
<div class="layout-content__wrap">
......@@ -64,7 +64,7 @@ export default {
return this.$store.state.marketing.layoutTips;
},
showDescription() {
return (this.$route.path.indexOf('ecm/list') >= 0 && this.$store.state.marketing.xsxsFlag) || this.$route.path.indexOf('ecm/clue') >= 0 || this.$route.path.indexOf('ecm/touch') >= 0;
return (this.$route.path.indexOf('ecm/list') >= 0 && this.$store.state.marketing.xsxsFlag) || this.$route.path.indexOf('ecm/touch') >= 0;
}
},
// watch:{
......@@ -152,14 +152,14 @@ export default {
display: flex;
align-items: center;
.introlIcon {
width: 20px;
height: 20px;
margin-right: 8px;
color: #1890ff;
font-size: 16px;
margin-right: 5px;
}
.intro {
width: 64px;
height: 22px;
font-size: 16px;
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #1890ff;
......@@ -215,4 +215,11 @@ export default {
.el-popover.user-header-pop {
min-width: 95px;
}
.content-title {
font-size: 20px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 600;
color: #303133;
line-height: 28px;
}
</style>
<template>
<el-tooltip placement="top">
<template slot="content">
<p class="tip-popover">{{ text }}</p>
</template>
<i class="iconfont icon-xinxixianshi"></i>
</el-tooltip>
</template>
<script>
export default {
name: 'tip',
props: {
text: String
}
};
</script>
<style scoped>
i {
margin-left: 5px;
font-size: 13px;
color: #909399;
}
.tip-popover {
max-width: 400px;
color: #ffffff;
}
</style>
......@@ -9,7 +9,7 @@ export const ecmTypes = [
{ value: 'integral', label: '积分', visible: true },
{ value: 'grade', label: '会员卡升级', visible: false },
{ value: 'qywx', label: '企微任务', visible: false },
{ value: 'qfxx', label: '群发消息', visible: false },
{ value: 'qfxx', label: '群发任务', visible: false },
{ value: 'teltask-fail', label: '群发失败-话务', visible: false },
{ value: 'message-fail', label: '群发失败-短信', visible: false }
];
export default {
computed: {
formatterNum() {
return val => (!val ? '0' : parseInt(val).toLocaleString());
},
formatterToFixed() {
return val => (!val ? '0.00' : parseFloat(val).toFixed(2));
},
formatterRate() {
return val => (!val ? '0.00%' : parseFloat(val).toFixed(2) + '%');
},
formatterNumAndFixed() {
return val => parseFloat(val || 0).toLocaleString('zh', { minimumFractionDigits: 2 });
}
}
};
......@@ -49,35 +49,26 @@ export const exportCurrentSendDetails = config.api + PREFIX + 'export-current-se
// 智能营销--触达效果
export const ecmTouchEffectColumnDiagram = params => requests(PREFIX + 'ecmTouchEffectColumnDiagram', params);
export const ecmTouchEffectTable = params => requests(PREFIX + 'ecmTouchEffectTable', params);
export const ecmTouchEffectFunnelChart = params => requests(PREFIX + 'ecmTouchEffectFunnelChart', params);
export const ecmTouchTypeTableList = params => requests(PREFIX + 'ecmTouchTypeTableList', params); // 获取(1 群发任务、2 群发失败-话务、3 群发失败-短信、4 话务、5 短信、6 微信)列表
export const ecmPlanTouchConfig = params => requests(PREFIX + 'ecmPlanTouchConfig', params);
export const getCardLeads = params => requests(PREFIX + 'getCardLeads', params); // 卡券收益
export const getCardLeadsList = params => requests(PREFIX + 'getCardLeadsList', params); // 卡券收益表格
// 智能营销--导购线索
export const ecmGuideCluesColumnDiagram = params => requests(PREFIX + 'ecmGuideCluesColumnDiagram', params);
export const ecmGuideCluesTable = params => requests(PREFIX + 'ecmGuideCluesTable', params);
export const ecmGuideCluesTaskTable = params => requests(PREFIX + 'ecmGuideCluesTaskTable', params); // 任务完成情况表格
export const ecmGuideCluesTouchEffectTotalTab = params => requests(PREFIX + 'ecmGuideCluesTouchEffectTotalTab', params); // 触达效果-整体转化-表格
export const ecmGuideCluesTouchEffectTab = params => requests(PREFIX + 'ecmGuideCluesTouchEffectTab', params); // 触达效果-其他tab-表格
// 智能营销--后台线索
export const ecmHeadCluesColumnDiagram = params => requests(PREFIX + 'ecmHeadCluesColumnDiagram', params);
export const ecmHeadGuideCluesTable = params => requests(PREFIX + 'ecmHeadGuideCluesTable', params);
export const ecmHeadCluesTaskTab = params => requests(PREFIX + 'ecmHeadCluesTaskTab', params); // 表格
// 智能营销--表格的合计和计划整体数据
export const ecmGuideCluesTouchEffectTotalTabHead = params => requests(PREFIX + 'ecmGuideCluesTouchEffectTotalTabHead', params); // 导购线索-触达效果整体计划表头
export const ecmGuideCluesTouchEffectTabHead = params => requests(PREFIX + 'ecmGuideCluesTouchEffectTabHead', params); //导购线索--触达效果其他表格表头
export const ecmGuideCluesTaskTableHead = params => requests(PREFIX + 'ecmGuideCluesTaskTableHead', params); // 触达效果-导购线索-任务完成情况表头
export const ecmHeadCluesTaskTabHead = params => requests(PREFIX + 'ecmHeadCluesTaskTabHead', params); // 总部线索表头
// 计划整体详情
export const overAllList = params => requests(PREFIX + 'ecmOverAllTable', params); // 单独数据
export const overAllTable = params => requests(PREFIX + 'ecmOverAllPage', params); // 下钻表格
export const overAllTableExport = config.api + PREFIX + 'ecmOverAllPageExport'; // 导出数据
// 话务详情
export const telTaskDiagram = params => requests(PREFIX + 'ecmTelTaskColumnDiagram', params); // 柱线图
export const telTaskList = params => requests(PREFIX + 'ecmTelTaskTable', params); // 单独数据
export const telTaskTable = params => requests(PREFIX + 'ecmTelTaskPage', params); // 下钻表格
export const telTaskTableExport = config.api + PREFIX + 'ecmTelTaskPageExport'; // 导出数据
// 群发详情
export const massDiagram = params => requests(PREFIX + 'ecmMassColumnDiagram', params); // 柱线图
export const massList = params => requests(PREFIX + 'ecmMassTaskTable', params); // 单独数据
export const massTable = params => requests(PREFIX + 'ecmMassTaskPage', params); // 下钻表格
export const massTableExport = config.api + PREFIX + 'ecmMassTaskPageExport'; // 导出数据
// 智能营销线索页tree
export const getGroupTree = params => requests(PREFIX + 'getGroupTree', params);
// export
export const getTabList = params => requests(PREFIX + 'ecmGuideCluesTableLabel', params);
// 智能营销导出表格
export const otherTableExoport = config.api + PREFIX + 'ecmGuideCluesTouchEffectTabExport'; // // 触达效果-其他tab-表格
export const allConvTableExport = config.api + PREFIX + 'ecmGuideCluesTouchEffectTotalTabExport'; // 触达效果-整体转化-表格
export const taskTableExport = config.api + PREFIX + 'ecmGuideCluesTaskTableExport'; // 触达效果-任务完成情况表格
export const headClueTableExport = config.api + PREFIX + 'ecmHeadCluesTaskTabExport'; // 触达效果-后台线索表格
export const getUseStoredFalg = params => requests(PREFIX + 'get-ecm-store-flag', params);
......
......@@ -366,7 +366,7 @@
<div class="btn-wrap_fixed" :class="{ on: asideShow }">
<el-button v-if="form.useCustomCode === 0 && form.giveFlag" :disabled="!preview.disabled" @click="preview.visible = true">转赠预览</el-button>
<el-button type="primary" @click="submitForm('form')" v-loading="submitLoading" v-show="!isInfo && canEdit && $store.state.marketing.appletEnable">保存</el-button>
<el-button @click="$router.go(-1)"> </el-button>
<el-button @click="$router.push('/card/list')"> </el-button>
</div>
</el-form>
......
......@@ -57,7 +57,7 @@
<el-form-item label="通知方式" class="is-required" prop="noticeType">
<el-radio v-model="form.noticeType" :label="0" :disabled="!isEditTemplate || isInfo"
>不通知
<el-tooltip class="item" effect="dark" content="不通知用户,但用户可以在GIC卡券包查看到该卡券。建议线下发券使用,或使用其他通知方式代替(如小程序、短信等)" placement="top-start">
<el-tooltip class="item" effect="dark" content="不会通知用户,但是卡券会放入用户账户" placement="top-start">
<i class="iconfont icon-xinxixianshi pl5 gray"></i>
</el-tooltip>
</el-radio>
......
......@@ -64,7 +64,7 @@
import { ecmCurrentSendInfos, ecmCurrentSendDetails, exportCurrentSendDetails } from '@/service/api/ecmApi.js';
import { formatDateTimeByType } from '@/utils/index.js';
import memberInfo from '@/components/member-info/index.vue';
const typeOptions = [{ value: '', label: '所有类型' }, { value: 'teletext', label: '图文' }, { value: 'text', label: '文本' }, { value: 'image', label: '图片' }, { value: 'card', label: '卡券' }, { value: 'wxa', label: '小程序' }, { value: 'message', label: '短信' }, { value: 'teltask', label: '话务' }, { value: 'integral', label: '积分' }, { value: 'qywx', label: '企微任务' }, { value: 'qfxx', label: '群发消息' }, { value: 'grade', label: '会员卡升级' }, { value: 'teltask-fail', label: '群发失败-话务' }, { value: 'message-fail', label: '群发失败-短信' }]; // eslint-disable-line
const typeOptions = [{ value: '', label: '所有类型' }, { value: 'teletext', label: '图文' }, { value: 'text', label: '文本' }, { value: 'image', label: '图片' }, { value: 'card', label: '卡券' }, { value: 'wxa', label: '小程序' }, { value: 'message', label: '短信' }, { value: 'teltask', label: '话务' }, { value: 'integral', label: '积分' }, { value: 'qywx', label: '企微任务' }, { value: 'qfxx', label: '群发任务' }, { value: 'grade', label: '会员卡升级' }, { value: 'teltask-fail', label: '群发失败-话务' }, { value: 'message-fail', label: '群发失败-短信' }]; // eslint-disable-line
export default {
name: 'ecm-current-list',
components: {
......
......@@ -807,7 +807,7 @@ export default {
return this.$tips({ type: 'warning', message: '所选的营销事件中,存在已失效或被删除模板的营销事件,请先将失效的营销事件删除后再保存!' });
}
if (this.$refs.marketingEvent.hasMaterialDeleted) {
return this.$tips({ type: 'warning', message: '所选的群发消息中,存在已失效或被删除的营销素材,请先将失效的营销素材删除后再保存!' });
return this.$tips({ type: 'warning', message: '所选的群发任务中,存在已失效或被删除的营销素材,请先将失效的营销素材删除后再保存!' });
}
}
this.$refs[formName].validate(valid => {
......
......@@ -349,7 +349,7 @@
<el-form-item label="通知方式" class="is-required" prop="cardNoticeType">
<el-radio v-model="form.cardNoticeType" :label="0"
>不通知
<el-tooltip open-delay="200" placement="top-start" content="不通知用户,但用户可以在GIC卡券包查看到该卡券。建议线下发券使用,或使用其他通知方式代替(如小程序、短信等)">
<el-tooltip open-delay="200" placement="top-start" content="不会通知用户,但是卡券会放入用户账户">
<i class="iconfont icon-xinxixianshi pl5 gray"></i>
</el-tooltip>
</el-radio>
......@@ -445,13 +445,14 @@
<div class="mt20">
<div class="w150 text-right inline-block mr10">
<label class="cursor required">
<span>设置营销效果时长</span>
<span>分析天数</span>
<el-tooltip slot="label" open-delay="200" placement="top">
<i style="cursor:pointer;color:#909399;font-size:14px;" class="iconfont icon-xinxixianshi"></i>
<div slot="content" style="width:376px;line-height: 22px;">设置线索在被营销触达之后的{{ analyseConfig.marke_days || '--' }}天内,客户所产生的消费纳入到该线索收益统计</div>
<div slot="content" style="width:340px;line-height: 22px;">设置从触达到客户的那天起,{{ analyseConfig.marke_days || '--' }}天以内会被纳入到数据分析</div>
</el-tooltip>
</label>
</div>
<span class="mr10">触达日期起</span>
<el-input-number :disabled="!isAdd" controls-position="right" class="w150" :min="1" :max="31" step-strictly v-model="analyseConfig.marke_days"></el-input-number>
<span class="ml10">天之内</span>
</div>
......
......@@ -48,7 +48,7 @@
</el-form-item>
</el-form>
</div>
<el-table tooltipEffect="light" :data="tableList" style="width: 100%" element-loading-text="拼命加载中">
<el-table tooltipEffect="dark" :data="tableList" style="width: 100%" element-loading-text="拼命加载中">
<el-table-column align="left" fixed="left" :min-width="200" show-overflow-tooltip label="计划名称">
<template slot-scope="scope">
<el-button v-if="xsxsFlag && isOpenFlag(scope.row.analyseJson)" style="vertical-align: middle;text-overflow: ellipsis;overflow: hidden;white-space: nowrap;width: 100%;text-align:left" type="text" @click="toTouch(scope.row)">
......@@ -90,18 +90,20 @@
<!-- <dm-delete v-if="scope.row.effectType !== 2 && scope.row.onlineStatus === 1 && scope.row.canEdit !== false" @confirm="offlineEcmPlan(scope.row)" tips="是否下线该计划?">
<el-button type="text">下线</el-button>
</dm-delete> -->
<template v-if="scope.row.putonStatus !== 2 && scope.row.canEdit !== false">
<el-button type="text" @click="toRecord(scope.row)">记录</el-button>
<!-- <template v-if="scope.row.putonStatus !== 2 && scope.row.canEdit !== false">
<el-button v-if="xsxsFlag && isOpenFlag(scope.row.analyseJson)" type="text" @click="onDelete(scope.row)">删除</el-button>
<dm-delete v-else @confirm="delData(scope.row)" tips="是否删除该计划?">
<el-button type="text">删除</el-button>
</dm-delete>
</template>
</template> -->
<!-- <el-button type="text" @click="toRecord(scope.row)">记录</el-button>
<el-button type="text" @click="toTouch(scope.row)" v-if="xsxsFlag && isOpenFlag(scope.row.analyseJson)">触达效果</el-button> -->
<el-dropdown style="margin-left:8px" trigger="click" @command="onCommand($event, scope.row)">
<el-button type="text">更多<i class="el-icon-arrow-down el-icon--right"></i></el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item :command="1">记录</el-dropdown-item>
<!-- <el-dropdown-item :command="1">记录</el-dropdown-item> -->
<el-dropdown-item v-if="scope.row.putonStatus !== 2 && scope.row.canEdit !== false" :command="1">删除</el-dropdown-item>
<el-dropdown-item v-if="scope.row.effectType !== 2 && scope.row.onlineStatus === 1 && scope.row.canEdit !== false" @confirm="offlineEcmPlan(scope.row)" :command="2">下线</el-dropdown-item>
<el-dropdown-item v-if="xsxsFlag && isOpenFlag(scope.row.analyseJson)" :command="3">触达效果</el-dropdown-item>
<!-- <el-dropdown-item :command="4">复制新建</el-dropdown-item> -->
......@@ -248,7 +250,7 @@ export default {
}
},
{
label: '线索转化收益',
label: '转化收益',
prop: 'ecmTranIncome',
minWidth: '120',
align: 'left',
......@@ -338,7 +340,7 @@ export default {
},
// 触达效果
toTouch(row) {
this.$router.push({ path: `/ecm/touch/${row.ecmPlanId}`, query: { name: row.ecmPlanName, createTime: row.createTime } });
this.$router.push({ path: `/ecm/touch/${row.ecmPlanId}`, query: { name: row.ecmPlanName, createTime: row.createTime, effectType: row.effectType } });
},
// 删除
async delData(row) {
......@@ -395,7 +397,21 @@ export default {
},
async onCommand(command, row) {
if (command == 1) {
this.toRecord(row);
// this.toRecord(row);
if (this.xsxsFlag && this.isOpenFlag(row.analyseJson)) {
await this.$confirm('是否删除该计划?删除后触达效果数据会一起被删除', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
});
} else {
await this.$confirm('是否删除该计划?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
});
}
this.delData(row);
} else if (command == 2) {
await this.$confirm('是否下线该计划?', '提示', {
confirmButtonText: '确定',
......
<template>
<div>
<el-dialog custom-class="dialogClass" :title="isEdit && !readOnly ? '编辑群发消息' : '群发消息'" :visible.sync="show" width="680px" @closed="close">
<el-dialog custom-class="dialogClass" :title="isEdit && !readOnly ? '编辑群发任务' : '群发任务'" :visible.sync="show" width="680px" @closed="close">
<el-form ref="form" :model="form" :rules="rules" label-width="130px">
<el-form-item label="选择企业" prop="qfxxEnterpriseId">
<el-select v-model="form.qfxxEnterpriseId" @change="onChangeEnterprise" :disabled="isEdit || readOnly">
......@@ -39,7 +39,7 @@
<div slot="content" style="width:376px;line-height: 22px;">计划创建保存后,若修改群发内容,该计划历史已下发任务的群发内容不变,仅影响后续新下发的任务</div>
</el-tooltip>
</template>
<div style="font-size:12px;color:#6B6D71;margin-bottom:10px">建议以文本+其他类型组合创建群发内容;文本内容最多只能添加 1 个</div>
<div style="font-size:12px;color:#6B6D71;margin-bottom:10px">须添加 1 条文本内容,以文本+其他类型的组合创建群发内容</div>
<div style="margin-bottom:16px;display:flex;flex-wrap:wrap;margin-top:12px">
<material-item class="card-item" v-for="item in materials" :key="item.relation_id" :item="item" @delete="onDeleteMaterial" :read-only="readOnly"></material-item>
<div v-show="materials.length < 3 && !readOnly" class="chat-item card-item" @click="openMaterialDialog">
......@@ -69,16 +69,20 @@
<div style="margin-top:12px;color:#606266">{{ form.teltask.content }}</div>
</div>
</div>
<div class="task-wrapper" style="margin-top:16px;padding-top:14px;">
<div class="task-wrapper" :style="{ 'border-color': showWarning ? '#F5222D' : '' }" style="margin-top:16px;padding-top:14px;">
<el-row style="margin-bottom:12px" type="flex" align="middle" justify="space-between">
<el-checkbox label="短信" style="margin-bottom:0" :value="form.smsFlag" :true-label="1" :false-label="0" :disabled="readOnly" @change="onChangeSms"></el-checkbox>
<el-button v-if="form.gicSmsTemplateId && !readOnly" type="text" @click="messageDialogShow = true">重新选择</el-button>
</el-row>
<div style="margin-bottom:14px" v-if="form.gicSmsTemplateId">
<div class="teltask-title" style="font-size:16px;color:#303133">{{ sms.title }}<template v-if="form.gicSmsTemplateId == -1">( 短信模板已删除 )</template></div>
<el-tag v-if="form.gicSmsTemplateId == -1" class="delete-tag" type="danger" style="float:right">短信模板已删除</el-tag>
<div class="teltask-title" style="font-size:16px;color:#303133">{{ sms.title }}</div>
<div v-if="form.gicSmsTemplateId != -1" style="margin-top:12px;color:#606266">{{ sms.content }}</div>
</div>
</div>
<transition name="el-zoom-in-top">
<div v-if="showWarning" style="font-size:12px;color:#F5222D;line-height:1.5;margin-top:8px;position:absolute">您选中的短信模板已被删除,请重新选择</div>
</transition>
</div>
</el-form-item>
</el-form>
......@@ -151,7 +155,8 @@ export default {
telTaskItem: {},
teltaskDialogShow: false,
sms: {},
messageDialogShow: false
messageDialogShow: false,
showWarning: false
};
},
created() {
......@@ -176,6 +181,7 @@ export default {
this.form.gicSmsTemplateId = item.gicSmsTemplateId;
this.form.smsFlag = 1;
this.messageDialogShow = false;
this.showWarning = false;
this.onChangeFailSetting(true);
},
openMaterialDialog() {
......@@ -201,6 +207,7 @@ export default {
this.materials = [];
this.sms = {};
this.telTaskItem = {};
this.showWarning = false;
this.$refs.form.resetFields();
this.$emit('update:show', false);
},
......@@ -216,7 +223,7 @@ export default {
return;
}
if (this.form.failSetting === '') {
return this.$message.warning('请选择是否开启群发消息失败设置');
return this.$message.warning('请选择是否开启群发任务失败设置');
}
if (this.form.failSetting == 1 && this.form.smsFlag == 0 && this.form.telFlag == 0) {
return this.$message.warning('请至少设置一种群发失败方式');
......@@ -225,6 +232,12 @@ export default {
qfxx.telFlag = 0;
qfxx.smsFlag = 0;
}
if (qfxx.gicSmsTemplateId == -1 && qfxx.smsFlag !== 0) {
this.showWarning = true;
return;
} else {
this.showWarning = false;
}
if (qfxx.telFlag == 0) {
delete qfxx.teltask;
}
......@@ -235,6 +248,7 @@ export default {
qfxx.chatContent = JSON.stringify(this.materials.map(el => ({ relation_id: el.relation_id })));
this.$emit('sendItem', { title: this.form.title, qfxx, comName: 'qfxx', ecmMarketingTypeRelationId: this.ecmMarketingTypeRelationId });
this.close();
this.showWarning = false;
},
getEntepriseList() {
getEntepriseList()
......@@ -351,6 +365,17 @@ export default {
</style>
<style lang="scss" scoped>
.delete-tag {
float: right;
font-size: 12px;
line-height: 22px;
height: 22px;
border-radius: 2px;
padding: 0 7px;
color: #f5222d;
border-color: 1px solid #ffa393;
background-color: #fff1f0;
}
.chat-item {
width: 240px;
height: 100px;
......
......@@ -71,7 +71,7 @@ import libQfxx from './components/lib-qfxx';
// 全部的操作项
// eslint-disable-next-line
let allOptions = [{ name: '企微任务', value: 'qywx', key: 10, img: require('./assets/img/qywx.svg'), hoverImg: require('./assets/img/qywx-1.svg'), show: true }, { name: '群发消息', value: 'qfxx', key: 11, img: require('./assets/img/qfxx.svg'), hoverImg: require('./assets/img/qfxx-1.svg'), disabledImg: require('./assets/img/qfxx-2.svg'), show: false, disabled: false }, { name: '图文', value: 'teletext', key: 1, img: require('./assets/img/teletext.svg'), hoverImg: require('./assets/img/teletext-1.svg'), show: true }, { name: '文本', value: 'text', key: 2, img: require('./assets/img/text.svg'), hoverImg: require('./assets/img/text-1.svg'), show: true }, { name: '小程序', value: 'wxa', key: 3, img: require('./assets/img/wxa.svg'), hoverImg: require('./assets/img/wxa-1.svg'), show: true }, { name: '图片', value: 'image', key: 4, img: require('./assets/img/image.svg'), hoverImg: require('./assets/img/image-1.svg'), show: true }, { name: '卡券', value: 'card', key: 5, img: require('./assets/img/card.svg'), hoverImg: require('./assets/img/card-1.svg'), show: true }, { name: '短信', value: 'message', key: 6, img: require('./assets/img/message.svg'), hoverImg: require('./assets/img/message-1.svg'), show: true }, { name: '话务', value: 'teltask', key: 7, img: require('./assets/img/teltask.svg'), hoverImg: require('./assets/img/teltask-1.svg'), show: true }, { name: '积分', value: 'integral', key: 8, img: require('./assets/img/integral.svg'), hoverImg: require('./assets/img/integral-1.svg'), show: true },{ name: '会员卡升级', value: 'grade', key: 9, img: require('./assets/img/grade.svg'), hoverImg: require('./assets/img/grade-1.svg'), disabledImg: require('./assets/img/grade-2.svg'), show: false, disabled: false }];
let allOptions = [{ name: '企微任务', value: 'qywx', key: 10, img: require('./assets/img/qywx.svg'), hoverImg: require('./assets/img/qywx-1.svg'), show: true }, { name: '群发任务', value: 'qfxx', key: 11, img: require('./assets/img/qfxx.svg'), hoverImg: require('./assets/img/qfxx-1.svg'), disabledImg: require('./assets/img/qfxx-2.svg'), show: false, disabled: false }, { name: '图文', value: 'teletext', key: 1, img: require('./assets/img/teletext.svg'), hoverImg: require('./assets/img/teletext-1.svg'), show: true }, { name: '文本', value: 'text', key: 2, img: require('./assets/img/text.svg'), hoverImg: require('./assets/img/text-1.svg'), show: true }, { name: '小程序', value: 'wxa', key: 3, img: require('./assets/img/wxa.svg'), hoverImg: require('./assets/img/wxa-1.svg'), show: true }, { name: '图片', value: 'image', key: 4, img: require('./assets/img/image.svg'), hoverImg: require('./assets/img/image-1.svg'), show: true }, { name: '卡券', value: 'card', key: 5, img: require('./assets/img/card.svg'), hoverImg: require('./assets/img/card-1.svg'), show: true }, { name: '短信', value: 'message', key: 6, img: require('./assets/img/message.svg'), hoverImg: require('./assets/img/message-1.svg'), show: true }, { name: '话务', value: 'teltask', key: 7, img: require('./assets/img/teltask.svg'), hoverImg: require('./assets/img/teltask-1.svg'), show: true }, { name: '积分', value: 'integral', key: 8, img: require('./assets/img/integral.svg'), hoverImg: require('./assets/img/integral-1.svg'), show: true },{ name: '会员卡升级', value: 'grade', key: 9, img: require('./assets/img/grade.svg'), hoverImg: require('./assets/img/grade-1.svg'), disabledImg: require('./assets/img/grade-2.svg'), show: false, disabled: false }];
export default {
name: 'vue-gic-marketing-event',
components: {
......@@ -303,9 +303,9 @@ export default {
if (res.errorCode === 0) {
this.maxEventCount = Number(res.result.maxEventCount || 0);
let list = res.result.list || [];
let optionNameList = list.map(v => v.eventName);
let optionNameList = list.map(v => v.eventType);
this.allOptions.map(v => {
if (optionNameList.indexOf(v.name) >= 0) {
if (optionNameList.indexOf(v.value) >= 0) {
this.options.push(v);
}
});
......@@ -359,8 +359,8 @@ export default {
case 'qywx': // 10 企微任务
this.list.push({ name: '企微任务', comName: 'item-qywx', item: { title: v.title, qywx: v.qywx, ecmMarketingTypeRelationId: v.ecmMarketingTypeRelationId, relationId: v.relationId, ecmPlanId: v.ecmPlanId } });
break;
case 'qfxx': // 11 群发消息
this.list.push({ name: '群发消息', comName: 'item-qfxx', item: { title: v.title, qfxx: v.qfxx, ecmMarketingTypeRelationId: v.ecmMarketingTypeRelationId, relationId: v.relationId, ecmPlanId: v.ecmPlanId } });
case 'qfxx': // 11 群发任务
this.list.push({ name: '群发任务', comName: 'item-qfxx', item: { title: v.title, qfxx: v.qfxx, ecmMarketingTypeRelationId: v.ecmMarketingTypeRelationId, relationId: v.relationId, ecmPlanId: v.ecmPlanId } });
break;
}
});
......
......@@ -70,7 +70,7 @@
<el-form-item label="通知方式" class="is-required" prop="cardNoticeType">
<el-radio v-model="form.cardNoticeType" :label="0"
>不通知
<el-tooltip open-delay="200" placement="top-start" content="不通知用户,但用户可以在GIC卡券包查看到该卡券。建议线下发券使用,或使用其他通知方式代替(如小程序、短信等)">
<el-tooltip open-delay="200" placement="top-start" content="不会通知用户,但是卡券会放入用户账户">
<i class="iconfont icon-xinxixianshi pl5 gray"></i>
</el-tooltip>
</el-radio>
......
<!--群发失败-短信总数据-->
<template>
<div class="middle">
<div class="item-bg bg-purper center_flex min-w-173">
<div>
<p>计划触达人数<tip :text="tipText.planMbrNum" /></p>
<p>{{ formatterNum(data.planMbrNum) }}</p>
</div>
</div>
<div class="item-arrow purper center_flex" style="width: 107px;background-size: 100% 100%">
<p style="width: 80px;">发送成功率</p>
<p style="width: 80px;">{{ formatterRate((data.touchMbrNum / data.planMbrNum) * 100) }}</p>
</div>
<div class="item-bg bg-purper center_flex min-w-173">
<div>
<p>实际触达人数<tip :text="tipText.touchMbrNum" /></p>
<p>{{ formatterNum(data.touchMbrNum) }}</p>
</div>
</div>
<div class="item-arrow purper center_flex">
<p>转化率</p>
<p>{{ formatterRate((data.convMbrNum / data.touchMbrNum) * 100) }}</p>
</div>
<div class="item-bg bg-green center_flex min-w-212">
<div>
<p>触达顾客转化人数<tip :text="tipText.convMbrNum" /></p>
<p>{{ formatterNum(data.convMbrNum) }}</p>
</div>
</div>
<div class="item-bg bg-green min-w-489">
<div>
<p>触达顾客订单数 <tip :text="tipText.convOrderCnt" /></p>
<p>{{ formatterNum(data.convOrderCnt) }}</p>
</div>
<div>
<p>触达顾客转化收益(元)<tip :text="tipText.convSalesAmt" /></p>
<p>{{ formatterNumAndFixed(data.convSalesAmt) }}</p>
</div>
</div>
</div>
</template>
<script>
import formatterNum from '@/mixins/validateNum';
import tip from '@/components/tip';
export default {
name: 'batch-fail-msg',
components: { tip },
props: {
data: {
type: Object,
default: () => {}
}
},
data() {
return {
tipText: {
planMbrNum: '计划使用短信触达的顾客人数。如果当前计划在不同时间用短信多次触达同一个顾客,会进行去重统计,仅计算为1个人。',
touchMbrNum: '发送短信成功的顾客人数。如果当前计划在不同时间用短信多次触达同一个顾客,会进行去重统计,仅计算为1个人。',
convMbrNum: '发送短信成功的顾客中,在收益有效期内消费的顾客人数。无论顾客消费了几次,会进行去重统计,仅计算为1个人。',
convOrderCnt: '发送短信成功的顾客中,在收益有效期内消费的顾客订单数。',
convSalesAmt: '发送短信成功的顾客中,在收益有效期内消费的顾客订单金额。'
}
};
},
mixins: [formatterNum]
};
</script>
<style lang="scss" scoped>
.middle {
font-family: PingFangSC-Medium, PingFang SC;
height: 100px;
display: flex;
align-items: center;
justify-content: space-around;
.item-bg {
flex: 1;
height: 100%;
border-radius: 6px;
box-sizing: border-box;
&.bg-green {
background: #e3fff8;
}
&.bg-purper {
background: #f0f5ff;
}
p {
&:nth-child(1) {
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
color: #606266;
line-height: 20px;
padding-top: 4px;
margin-bottom: 6px;
}
&:nth-child(2) {
font-size: 24px;
font-family: DINAlternate-Bold, DINAlternate;
font-weight: bold;
color: #303133;
line-height: 28px;
}
}
}
.item-arrow {
width: 89px;
height: 71px;
margin-right: 9px;
&.purper {
background: url('~@/assets/img/arrow_purper.png');
}
&.green {
background: url('~@/assets/img/arrow_green.png');
}
p {
width: 47px;
font-size: 12px;
line-height: 20px;
color: #606266;
font-family: PingFangSC-Regular, PingFang SC;
&:nth-child(2) {
font-family: DINAlternate-Bold, DINAlternate;
font-weight: bold;
color: #303133;
}
}
}
}
.center_flex {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.min-w-173 {
min-width: 173px;
}
.min-w-212 {
min-width: 212px;
}
.min-w-489 {
min-width: 489px;
margin-left: 5px;
display: flex;
align-items: center;
padding: 0 42px 0 47px;
box-sizing: border-box;
div {
flex: 1;
text-align: left;
}
}
</style>
<!--群发失败-话务总数据-->
<template>
<div class="middle">
<div class="item-bg bg-purper center_flex min-w-173">
<div>
<p class="key">计划触达人数<tip :text="tipText.planMbrNum" /></p>
<p class="value">{{ formatterNum(data.planMbrNum) }}</p>
</div>
<div class="item-arrow purper">
<p>成功率</p>
<p>{{ formatterRate((data.taskExecuteNum / data.planMbrNum) * 100) }}</p>
</div>
</div>
<div class="item-bg bg-purper center_flex min-w-173">
<div>
<p class="key">任务执行顾客数<tip :text="tipText.taskExecuteNum" /></p>
<p class="value">{{ formatterNum(data.taskExecuteNum) }}</p>
</div>
<div class="item-arrow purper">
<p>触达率</p>
<p>{{ formatterRate((data.touchMbrNum / data.taskExecuteNum) * 100) }}</p>
</div>
</div>
<div class="item-bg bg-purper center_flex min-w-173">
<div>
<p class="key">实际触达人数<tip :text="tipText.touchMbrNum" /></p>
<p class="value">{{ formatterNum(data.touchMbrNum) }}</p>
</div>
<div class="item-arrow green">
<p>转化率</p>
<p>{{ formatterRate((data.convMbrNum / data.touchMbrNum) * 100) }}</p>
</div>
</div>
<div class="item-bg bg-green center_flex min-w-200">
<div style="padding-left: 10px">
<p class="key">触达顾客转化人数<tip :text="tipText.convMbrNum" /></p>
<p class="value">{{ formatterNum(data.convMbrNum) }}</p>
</div>
</div>
<div class="item-bg bg-green min-w-403">
<div>
<p class="key">触达顾客订单数<tip :text="tipText.convOrderCnt" /></p>
<p class="value">{{ formatterNum(data.convOrderCnt) }}</p>
</div>
<div>
<p class="key">触达顾客转化收益(元)<tip :text="tipText.convSalesAmt" /></p>
<p class="value">{{ formatterNumAndFixed(data.convSalesAmt) }}</p>
</div>
</div>
</div>
</template>
<script>
import formatterNum from '@/mixins/validateNum';
import tip from '@/components/tip';
export default {
name: 'batch-fail-phone',
components: { tip },
props: {
data: {
type: Object,
default: () => {}
}
},
data() {
return {
tipText: {
planMbrNum: '计划使用话务任务触达的顾客人数。如果当前计划在不同时间,通过不同区域(门店),用话务任务多次触达同一个顾客,会进行去重统计,仅计算为1个人。',
taskExecuteNum: '导购实际执行话务任务的顾客人数,包括“完成”任务和“放弃”任务的人数。如果当前计划在不同时间,通过不同区域(门店),用话务任务多次触达同一个顾客,会进行去重统计,仅计算为1个人。',
touchMbrNum: '导购执行并完成话务任务的顾客人数。如果当前计划在不同时间,通过不同区域(门店),用话务任务多次触达同一个顾客,会进行去重统计,仅计算为1个人。',
convMbrNum: '导购执行并完成话务任务的顾客人数,在收益有效期内消费的顾客人数。无论顾客消费了几次,会进行去重统计,仅计算为1个人。',
convOrderCnt: '导购执行并完成话务任务的顾客中,在收益有效期内消费的顾客订单数。',
convSalesAmt: '导购执行并完成话务任务的顾客中,在收益有效期内消费的顾客订单金额。'
}
};
},
mixins: [formatterNum]
};
</script>
<style lang="scss" scoped>
.middle {
font-family: PingFangSC-Medium, PingFang SC;
height: 100px;
display: flex;
align-items: center;
justify-content: space-around;
.item-bg {
flex: 1;
height: 100%;
border-radius: 6px;
margin-right: 47px;
box-sizing: border-box;
position: relative;
&.bg-green {
background: #e3fff8;
}
&.bg-purper {
background: #f0f5ff;
}
.key {
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
color: #606266;
line-height: 20px;
padding-top: 4px;
margin-bottom: 6px;
}
.value {
font-size: 24px;
font-family: DINAlternate-Bold, DINAlternate;
font-weight: bold;
color: #303133;
line-height: 28px;
}
}
.item-arrow {
width: 78px;
height: 65px;
position: absolute;
display: flex;
flex-direction: column;
justify-content: center;
padding-left: 7px;
box-sizing: border-box;
z-index: 3;
right: -77px;
&.purper {
background: url('~@/assets/img/arrow_purper.png');
background-size: 100% 100%;
}
&.green {
background: url('~@/assets/img/arrow_green.png');
background-size: 100% 100%;
}
p {
width: 47px;
font-size: 12px;
margin-top: -3px;
line-height: 20px;
color: #606266;
font-family: PingFangSC-Regular, PingFang SC;
&:nth-child(2) {
font-family: DINAlternate-Bold, DINAlternate;
font-weight: bold;
color: #303133;
}
}
}
}
.center_flex {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.min-w-173 {
min-width: 173px;
}
.min-w-200 {
min-width: 200px;
margin-right: 7px !important;
}
.min-w-403 {
min-width: 403px;
margin-right: 0 !important;
display: flex;
align-items: center;
padding: 0 34px 0 22px;
box-sizing: border-box;
div {
flex: 1;
text-align: left;
}
}
</style>
<!--群发任务 总数据-->
<template>
<div class="middle">
<div class="item-bg bg-purper center_flex min-w-173">
<div>
<p class="key">计划触达人数<tip :text="tipText.planMbrNum" /></p>
<p class="value">{{ formatterNum(data.planMbrNum) }}</p>
</div>
<div class="item-arrow purper">
<p>成功率</p>
<p>{{ formatterRate((data.taskCreateNum / data.planMbrNum) * 100) }}</p>
</div>
</div>
<div class="item-bg bg-purper center_flex min-w-173">
<div style="padding-left: 20px">
<p class="key">任务创建成功顾客数<tip :text="tipText.taskCreateNum" /></p>
<p class="value">{{ formatterNum(data.taskCreateNum) }}</p>
</div>
<div class="item-arrow purper">
<p>执行率</p>
<p>{{ formatterRate((data.massExecuteNum / data.taskCreateNum) * 100) }}</p>
</div>
</div>
<div class="item-bg bg-purper center_flex min-w-173">
<div>
<p class="key">群发执行顾客数<tip :text="tipText.taskExecuteNum" /></p>
<p class="value">{{ formatterNum(data.massExecuteNum) }}</p>
</div>
<div class="item-arrow purper">
<p>触达率</p>
<p>{{ formatterRate((data.touchMbrNum / data.massExecuteNum) * 100) }}</p>
</div>
</div>
<div class="item-bg bg-purper center_flex min-w-173">
<div>
<p class="key">实际触达人数<tip :text="tipText.touchMbrNum" /></p>
<p class="value">{{ formatterNum(data.touchMbrNum) }}</p>
</div>
<div class="item-arrow green">
<p>转化率</p>
<p>{{ formatterRate((data.convMbrNum / data.touchMbrNum) * 100) }}</p>
</div>
</div>
<div class="item-bg bg-green center_flex min-w-188 h143">
<div style="padding-left: 10px">
<p class="key">触达顾客转化人数<tip :text="tipText.convMbrNum" /></p>
<p class="value">{{ formatterNum(data.convMbrNum) }}</p>
</div>
</div>
<div class="item-bg bg-green min-w-235 h143">
<div class="center_wrap">
<div>
<p class="key">触达顾客订单数<tip :text="tipText.convOrderCnt" /></p>
<p class="value">{{ formatterNum(data.convOrderCnt) }}</p>
</div>
<div>
<p class="key">触达顾客转化收益(元)<tip :text="tipText.convSalesAmt" /></p>
<p class="value">{{ formatterNumAndFixed(data.convSalesAmt) }}</p>
</div>
</div>
</div>
</div>
</template>
<script>
import formatterNum from '@/mixins/validateNum';
import tip from '@/components/tip';
export default {
name: 'batch-send-sum',
components: { tip },
props: {
data: {
type: Object,
default: () => {}
}
},
data() {
return {
tipText: {
planMbrNum: '计划使用群发任务触达的顾客人数。如果当前计划在不同时间,通过不同区域(门店),用群发多次触达同一个顾客,会进行去重统计,仅计算为1个人。',
taskCreateNum: '成功创建群发任务的人数。若该计划在不同时间通过不同区域(门店)用群发多次触达同一个顾客,会进行去重统计,仅计算为1个人。导致群发任务创建不成功的原因可能是:①非所选企业下的客户好友;②该好友每月群发消息接收次数已达上限',
taskExecuteNum: '导购使用企业微信执行群发的顾客人数。如果当前计划在不同时间,通过不同区域(门店),用群发多次触达同一个顾客,会进行去重统计,仅计算为1个人。点击“查看详情”可以找到群发任务执行率较低的门店,推动门店导购在企业微信中执行群发。',
touchMbrNum: '导购执行群发后,群发消息发送成功的顾客数,按照顾客人数进行统计。如果当前计划在不同时间,通过不同区域(门店),用群发多次触达同一个顾客,会进行去重统计,仅计算为1个人。可能导致群发消息发送失败的原因是:①群发任务下发后,到导购执行群发的时间段内,顾客删除了企业微信好友,使得发送失败。②顾客是多个门店导购的企微好友,已经有某一导购群发成功,其他导购执行群发会发送失败',
convMbrNum: '导购执行群发消息发送成功的顾客中,在收益有效期内消费的顾客人数。无论顾客消费了几次,会进行去重统计,仅计算为1个人。',
convOrderCnt: '导购执行群发消息发送成功的顾客中,在收益有效期内消费的顾客订单数。',
convSalesAmt: '导购执行群发消息发送成功的顾客中,在收益有效期内消费的顾客订单金额。'
}
};
},
mixins: [formatterNum]
};
</script>
<style lang="scss" scoped>
.middle {
font-family: PingFangSC-Medium, PingFang SC;
height: 143px;
display: flex;
align-items: center;
justify-content: space-around;
.item-bg {
flex: 1;
height: 100px;
border-radius: 6px;
margin-right: 47px;
box-sizing: border-box;
position: relative;
&.bg-green {
background: #e3fff8;
}
&.bg-purper {
background: #f0f5ff;
}
.key {
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
color: #606266;
line-height: 20px;
padding-top: 4px;
margin-bottom: 6px;
}
.value {
font-size: 24px;
font-family: DINAlternate-Bold, DINAlternate;
font-weight: bold;
color: #303133;
line-height: 28px;
}
}
.item-arrow {
width: 78px;
height: 65px;
position: absolute;
display: flex;
flex-direction: column;
justify-content: center;
padding-left: 7px;
box-sizing: border-box;
z-index: 3;
right: -77px;
&.purper {
background: url('~@/assets/img/arrow_purper.png');
background-size: 100% 100%;
}
&.green {
background: url('~@/assets/img/arrow_green.png');
background-size: 100% 100%;
}
p {
width: 47px;
font-size: 12px;
margin-top: -3px;
line-height: 20px;
color: #606266;
font-family: PingFangSC-Regular, PingFang SC;
&:nth-child(2) {
font-family: DINAlternate-Bold, DINAlternate;
font-weight: bold;
color: #303133;
}
}
}
}
.center_flex {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.h143 {
height: 143px !important;
}
.min-w-173 {
min-width: 173px;
}
.min-w-188 {
min-width: 188px;
margin-right: 7px !important;
}
.min-w-235 {
min-width: 235px;
margin-right: 0 !important;
display: flex;
justify-content: center;
padding: 7px 0;
.center_wrap {
display: flex;
flex-direction: column;
justify-content: space-between;
}
}
</style>
<!--群发消息总数居-->
<template>
<div class="dm-wrap batch_list">
<div class="title flex_between">
<div class="flex_between">
<img :src="require('@/assets/img/icon-send.png')" class="img" />
<h2>群发任务</h2>
</div>
<el-link type="primary" :underline="false" style="color: #1890ff" @click="$emit('toClue', '群发')">查看详情<i class="el-icon-arrow-right" style="margin-left: 10px"></i></el-link>
</div>
<batch-send-sum v-if="taskList" :data="taskList" />
<div class="wrap" v-if="telTrafficList || msgList">
<div v-if="telTrafficList">
<div class="flex_between" style="margin-bottom: 12px;padding-right: 20px">
<h3>群发失败-话务</h3>
<el-link type="primary" :underline="false" style="color: #1890ff" @click="$emit('toClue', '群发转话务')">查看详情<i class="el-icon-arrow-right" style="margin-left: 10px"></i></el-link>
</div>
<div style="padding: 0px 20px"><batch-fail-phone :data="telTrafficList" /></div>
</div>
<div v-if="msgList" :style="{ marginTop: telTrafficList ? '26px' : '0' }">
<h3 style="margin-bottom: 12px">群发失败-短信</h3>
<div style="padding: 0px 20px"><batch-fail-msg :data="msgList" /></div>
</div>
</div>
</div>
</template>
<script>
import formatterNum from '@/mixins/validateNum';
import batchSendSum from './batch-send-sum';
import batchFailPhone from './batch-fail-phone';
import batchFailMsg from './batch-fail-msg';
export default {
name: 'batch-send',
mixins: [formatterNum],
components: { batchSendSum, batchFailPhone, batchFailMsg },
data() {
return {};
},
props: {
taskList: {
type: Object || undefined
},
telTrafficList: {
type: Object || undefined
},
msgList: {
type: Object || undefined
}
}
};
</script>
<style scoped lang="scss">
.batch_list {
padding: 19px 20px 30px !important;
margin-bottom: 10px !important;
font-family: PingFangSC-Regular, PingFang SC;
.title {
height: 22px;
margin-bottom: 10px;
line-height: 22px;
h2 {
font-size: 16px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 700;
color: #303133;
margin-left: 2px;
}
}
.img {
transform: scale(0.5);
}
.flex_between {
display: flex;
justify-content: space-between;
align-items: center;
}
.wrap {
margin-top: 20px;
padding: 20px 0 30px;
border-radius: 2px;
border: 2px dashed #c9dafd;
}
h3 {
width: 139px;
height: 25px;
background: #bad9ff;
line-height: 25px;
text-align: center;
border-radius: 2px;
margin-left: -2px;
color: #303133;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 600;
}
}
</style>
<!--卡券收益总数据-->
<template>
<div class="middle">
<div class="item-bg bg-purper center_flex min-w-173">
<div>
<p>触达人数<tip :text="tipText.touchMbrNum" /></p>
<p>{{ formatterNum(list.touchMbrNum) }}</p>
</div>
</div>
<div class="item-arrow purper center_flex">
<p>领取率</p>
<p>{{ formatterRate((list.getMbrNum / list.touchMbrNum) * 100) }}</p>
</div>
<div class="item-bg bg-purper center_flex min-w-173">
<div>
<p>领取人数<tip :text="tipText.getMbrNum" /></p>
<p>{{ formatterNum(list.getMbrNum) }}</p>
</div>
</div>
<div class="item-arrow purper center_flex">
<p>使用率</p>
<p>{{ formatterRate((list.useMbrNum / list.getMbrNum) * 100) }}</p>
</div>
<div class="item-bg bg-purper center_flex min-w-214">
<div>
<p>使用人数<tip :text="tipText.useMbrNum" /></p>
<p>{{ formatterNum(list.useMbrNum) }}</p>
</div>
</div>
<div class="item-bg bg-purper min-w-527">
<div>
<p>销售单数 <tip :text="tipText.orderCnt" /></p>
<p>{{ formatterNum(list.orderCnt) }}</p>
</div>
<div>
<p>销售单金额(元)<tip :text="tipText.salesAmt" /></p>
<p>{{ formatterNumAndFixed(list.salesAmt) }}</p>
</div>
</div>
</div>
</template>
<script>
import formatterNum from '@/mixins/validateNum';
import tip from '@/components/tip';
export default {
name: 'card-profit-sum',
components: { tip },
props: {
list: {
type: Array,
default: () => {}
}
},
data() {
return {
tipText: {
touchMbrNum: '当前智能营销计划发出优惠券的顾客数,如果对同一个顾客发送了超过1张优惠券,仅计算为1个人。',
getMbrNum: '当前智能营销计划发出优惠券后,领取优惠券的顾客人数。如果同一个顾客领取了超过1张优惠券,仅计算为1个人。',
useMbrNum: '"当前智能营销计划发出优惠券后,使用优惠券的顾客人数。如果同一个顾客使用了超过1张优惠券,仅计算为1个人。由于是单独从“卡券”维度统计,因此只要是使用了该计划所发送优惠券的都会计入,即使顾客使用该优惠券的订单超过了收益有效期"',
orderCnt: '"当前智能营销计划发出优惠券后,使用优惠券的订单数。如果一个订单使用了超过1张优惠券,仅计算为1个订单。由于是单独从“卡券”维度统计,因此只要是使用了该计划所发送优惠券的订单都会计入,即使该订单超过了收益有效期,也会将该订单计入销售单数。"',
salesAmt: '"当前智能营销计划发出优惠券后,使用优惠券的订单金额。如果一笔订单使用了超过1张优惠券,该金额仅计算一次。由于是单独从“卡券”维度统计,因此只要是使用了该计划所发送优惠券的订单都会计入,即使该订单超过了收益有效期,也会将该订单金额计入。"'
}
};
},
mixins: [formatterNum]
};
</script>
<style lang="scss" scoped>
.middle {
font-family: PingFangSC-Medium, PingFang SC;
height: 100px;
display: flex;
align-items: center;
justify-content: space-around;
.item-bg {
flex: 1;
height: 100%;
border-radius: 6px;
box-sizing: border-box;
&.bg-green {
background: #e3fff8;
}
&.bg-purper {
background: #f0f5ff;
}
p {
&:nth-child(1) {
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
color: #606266;
line-height: 20px;
padding-top: 4px;
margin-bottom: 6px;
}
&:nth-child(2) {
font-size: 24px;
font-family: DINAlternate-Bold, DINAlternate;
font-weight: bold;
color: #303133;
line-height: 28px;
}
}
}
.item-arrow {
width: 89px;
height: 71px;
margin-right: 14px;
&.purper {
background: url('~@/assets/img/arrow_purper.png');
}
&.green {
background: url('~@/assets/img/arrow_green.png');
}
p {
width: 47px;
font-size: 12px;
line-height: 20px;
color: #606266;
font-family: PingFangSC-Regular, PingFang SC;
&:nth-child(2) {
font-family: DINAlternate-Bold, DINAlternate;
font-weight: bold;
color: #303133;
}
}
}
}
.center_flex {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.min-w-173 {
min-width: 173px;
}
.min-w-214 {
min-width: 214px;
}
.min-w-527 {
min-width: 527px;
margin-left: 5px;
display: flex;
align-items: center;
padding: 0 42px 0 47px;
box-sizing: border-box;
div {
flex: 1;
text-align: left;
}
}
</style>
......@@ -4,38 +4,9 @@
<h2>卡券收益</h2>
<span>计划中的卡券,计划中卡券触达的人群使用该卡券消费的收益,包含已过计划收益有效期的数据</span>
</div>
<template v-if="tableData.length">
<div class="list">
<div class="list_left">
<div>
<p>触达人数</p>
<p>{{ formatterNum(list.touchMbrNum) }}</p>
</div>
<div>
<p>
领取人数<span> (领取率 {{ formatterRate((list.getMbrNum / list.touchMbrNum) * 100) }}</span>
</p>
<p>{{ formatterNum(list.getMbrNum) }}</p>
</div>
<div>
<p>
使用人数<span> (使用率 {{ formatterRate((list.useMbrNum / list.getMbrNum) * 100) }}</span>
</p>
<p>{{ formatterNum(list.useMbrNum) }}</p>
</div>
</div>
<div class="list_right">
<div>
<p>销售单数</p>
<p>{{ formatterNum(list.orderCnt) }}</p>
</div>
<div>
<p>销售单金额(元)</p>
<p>{{ parseFloat(list.salesAmt || 0).toLocaleString('zh', { minimumFractionDigits: 2 }) }}</p>
</div>
</div>
</div>
<el-table :data="tableData" v-if="tableData.length > 1" style="margin-bottom:47px" max-height="710">
<template>
<card-profit-sum :list="list" />
<el-table :data="tableData" v-if="tableData.length > 1" style="margin:20px 0 20px" max-height="710" header-cell-class-name="card-profit-header">
<el-table-column :prop="cardName" label="卡券名称" min-width="150">
<template slot-scope="scope">
<div class="name" v-if="scope.row.cardName">
......@@ -59,16 +30,12 @@
</el-table-column>
</el-table>
</template>
<div class="empty" v-else>
<div class="content">
<span class="icon iconfont">&#xe76e;</span>
<span class="none-tip">本计划未使用卡券营销</span>
</div>
</div>
</div>
</template>
<script>
import formatterNum from '@/mixins/validateNum';
import cardProfitSum from './card-profit-sum.vue';
export default {
name: 'card-profit',
props: {
......@@ -81,6 +48,8 @@ export default {
default: () => []
}
},
mixins: [formatterNum],
components: { cardProfitSum },
data() {
return {
tableHeader: [
......@@ -90,7 +59,7 @@ export default {
{ label: '使用人数', prop: 'useMbrNum', minWidth: '160', align: 'left', fixed: 'left', formatter: row => this.formatterNum(row.useMbrNum) },
{ label: '使用率', prop: 'useRate', minWidth: '160', align: 'left', fixed: 'left', formatter: row => this.formatterRate((row.useMbrNum / row.getMbrNum) * 100) },
{ label: '销售单数', prop: 'orderCnt', minWidth: '160', align: 'left', fixed: 'left', formatter: row => this.formatterNum(row.orderCnt) },
{ label: '销售单金额', prop: 'salesAmt', minWidth: '160', align: 'left', fixed: 'left', formatter: row => parseFloat(row.salesAmt || 0).toLocaleString('zh', { minimumFractionDigits: 2 }) }
{ label: '销售单金额', prop: 'salesAmt', minWidth: '160', align: 'left', fixed: 'left', formatter: row => this.formatterNumAndFixed(row.salesAmt) }
]
};
},
......@@ -99,21 +68,13 @@ export default {
if (row.status == 0) return;
window.open(window.location.origin + `/marketing/#/card/edit/${row.cardId}`);
}
},
computed: {
formatterNum() {
return val => (!val ? '0' : parseInt(val).toLocaleString());
},
formatterRate() {
return val => (!val ? '0.00%' : parseFloat(val).toFixed(2) + '%');
}
}
};
</script>
<style scoped lang="scss">
.card_profit {
padding: 19px 34px 7px 28px !important;
padding: 20px !important;
margin-bottom: 10px !important;
font-family: PingFangSC-Regular, PingFang SC;
.title {
......@@ -134,59 +95,6 @@ export default {
color: #909399;
}
}
.list {
display: flex;
justify-content: space-between;
margin-bottom: 20px;
.list_left {
margin-right: 10px;
}
.list_left,
.list_right {
background: #f0f5ff;
border-radius: 6px;
flex: 1;
height: 115px;
padding-left: 40px;
box-sizing: border-box;
display: flex;
div {
flex: 1;
padding-top: 26px;
&:nth-of-type(1) {
flex: 0.8;
}
p {
&:nth-child(1) {
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #606266;
line-height: 20px;
padding-top: 4px;
margin-bottom: 6px;
}
&:nth-child(2) {
font-size: 24px;
font-family: DINAlternate-Bold, DINAlternate;
font-weight: bold;
color: #303133;
line-height: 28px;
}
.active {
color: #f5222d;
margin-left: 4px;
}
span {
color: #303133;
}
}
}
}
.list_right div {
text-align: center;
}
}
.name {
color: #303133;
line-height: 22px;
......@@ -226,25 +134,8 @@ export default {
line-height: 22px;
}
}
.empty {
display: flex;
align-items: center;
justify-content: center;
height: 200px;
color: #909399;
font-size: 16px;
.content {
display: flex;
align-items: center;
.icon {
font-size: 30px;
margin-right: 10px;
}
.none-tip {
color: #c0c4cc;
font-size: 14px;
}
}
/deep/ .card-profit-header .cell {
font-family: PingFangSC-Medium, PingFang SC;
}
}
</style>
<template>
<div class="dm-wrap phone-traffic">
<div class="title flex_between">
<div class="flex_between">
<img :src="require('@/assets/img/icon-phone.png')" class="img" />
<h2>话务</h2>
</div>
<el-link type="primary" :underline="false" style="color: #1890ff" @click="$emit('toClue', '话务')">查看详情<i class="el-icon-arrow-right" style="margin-left: 10px"></i></el-link>
</div>
<phone-traffic-sum v-bind="$attrs" />
</div>
</template>
<script>
import phoneTrafficSum from './phone-traffic-sum';
export default {
name: 'phone-traffic',
components: { phoneTrafficSum },
inheritAttrs: false
};
</script>
<style lang="scss" scoped>
.phone-traffic {
padding: 22px 20px 30px !important;
font-family: PingFangSC-Regular, PingFang SC;
.title {
height: 22px;
margin-bottom: 20px;
line-height: 22px;
h2 {
font-size: 16px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 700;
color: #303133;
margin-left: 2px;
}
}
.img {
transform: scale(0.5);
}
.flex_between {
display: flex;
justify-content: space-between;
align-items: center;
}
}
</style>
<!--话务总数据-->
<template>
<div class="middle">
<div class="item-bg bg-purper center_flex min-w-173">
<div>
<p class="key">计划触达人数<tip :text="tipText.planMbrNum" /></p>
<p class="value">{{ formatterNum(data.planMbrNum) }}</p>
</div>
<div class="item-arrow purper">
<p>执行率</p>
<p>{{ formatterRate((data.taskExecuteNum / data.planMbrNum) * 100) }}</p>
</div>
</div>
<div class="item-bg bg-purper center_flex min-w-173">
<div>
<p class="key">任务执行顾客数<tip :text="tipText.taskExecuteNum" /></p>
<p class="value">{{ formatterNum(data.taskExecuteNum) }}</p>
</div>
<div class="item-arrow purper">
<p>触达率</p>
<p>{{ formatterRate((data.touchMbrNum / data.taskExecuteNum) * 100) }}</p>
</div>
</div>
<div class="item-bg bg-purper center_flex min-w-173">
<div>
<p class="key">实际触达人数<tip :text="tipText.touchMbrNum" /></p>
<p class="value">{{ formatterNum(data.touchMbrNum) }}</p>
</div>
<div class="item-arrow green">
<p>转化率</p>
<p>{{ formatterRate((data.convMbrNum / data.touchMbrNum) * 100) }}</p>
</div>
</div>
<div class="item-bg bg-green center_flex min-w-210">
<div>
<p class="key">触达顾客转化人数<tip :text="tipText.convMbrNum" /></p>
<p class="value">{{ formatterNum(data.convMbrNum) }}</p>
</div>
</div>
<div class="item-bg bg-green min-w-433">
<div>
<p class="key">触达顾客订单数<tip :text="tipText.convOrderCnt" /></p>
<p class="value">{{ formatterNum(data.convOrderCnt) }}</p>
</div>
<div>
<p class="key">触达顾客转化收益(元)<tip :text="tipText.convSalesAmt" /></p>
<p class="value">{{ formatterNumAndFixed(data.convSalesAmt) }}</p>
</div>
</div>
</div>
</template>
<script>
import formatterNum from '@/mixins/validateNum';
import tip from '@/components/tip';
export default {
name: 'phone-traffic-sum',
components: { tip },
props: {
data: {
type: Object,
default: () => {}
}
},
data() {
return {
tipText: {
planMbrNum: '计划使用话务任务触达的顾客人数。如果当前计划在不同时间,通过不同区域(门店),用话务任务多次触达同一个顾客,会进行去重统计,仅计算为1个人。',
taskExecuteNum: '导购实际执行话务任务的顾客人数,包括“完成”任务和“放弃”任务的人数。如果当前计划在不同时间,通过不同区域(门店),用话务任务多次触达同一个顾客,会进行去重统计,仅计算为1个人。',
touchMbrNum: '导购执行并完成话务任务的顾客人数。如果当前计划在不同时间,通过不同区域(门店),用话务任务多次触达同一个顾客,会进行去重统计,仅计算为1个人。',
convMbrNum: '导购执行并完成话务任务的顾客人数,在收益有效期内消费的顾客人数。无论顾客消费了几次,会进行去重统计,仅计算为1个人。',
convOrderCnt: '导购执行并完成话务任务的顾客中,在收益有效期内消费的顾客订单数。',
convSalesAmt: '导购执行并完成话务任务的顾客中,在收益有效期内消费的顾客订单金额。'
}
};
},
mixins: [formatterNum]
};
</script>
<style lang="scss" scoped>
.middle {
font-family: PingFangSC-Medium, PingFang SC;
height: 100px;
display: flex;
align-items: center;
justify-content: space-around;
.item-bg {
flex: 1;
height: 100%;
border-radius: 6px;
margin-right: 47px;
box-sizing: border-box;
position: relative;
&.bg-green {
background: #e3fff8;
}
&.bg-purper {
background: #f0f5ff;
}
.key {
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
color: #606266;
line-height: 20px;
padding-top: 4px;
margin-bottom: 6px;
}
.value {
font-size: 24px;
font-family: DINAlternate-Bold, DINAlternate;
font-weight: bold;
color: #303133;
line-height: 28px;
}
}
.item-arrow {
width: 78px;
height: 65px;
position: absolute;
display: flex;
flex-direction: column;
justify-content: center;
padding-left: 7px;
box-sizing: border-box;
z-index: 3;
right: -77px;
&.purper {
background: url('~@/assets/img/arrow_purper.png');
background-size: 100% 100%;
}
&.green {
background: url('~@/assets/img/arrow_green.png');
background-size: 100% 100%;
}
p {
width: 47px;
font-size: 12px;
margin-top: -3px;
line-height: 20px;
color: #606266;
font-family: PingFangSC-Regular, PingFang SC;
&:nth-child(2) {
font-family: DINAlternate-Bold, DINAlternate;
font-weight: bold;
color: #303133;
}
}
}
}
.center_flex {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.min-w-173 {
min-width: 173px;
}
.min-w-210 {
min-width: 210px;
margin-right: 7px !important;
}
.min-w-433 {
min-width: 433px;
margin-right: 0 !important;
display: flex;
align-items: center;
padding: 0 50px 0 36px;
box-sizing: border-box;
div {
flex: 1;
text-align: left;
}
}
</style>
<template>
<div class="dm-wrap short-msg">
<div class="title flex_between">
<div class="flex_between">
<img :src="require('@/assets/img/icon-talk.png')" class="img" />
<h2>短信</h2>
</div>
</div>
<short-msg-sum v-bind="$attrs" />
</div>
</template>
<script>
import shortMsgSum from './short-msg-sum.vue';
export default {
name: 'short-msg',
components: { shortMsgSum },
inheritAttrs: false
};
</script>
<style lang="scss" scoped>
.short-msg {
padding: 22px 20px 30px !important;
font-family: PingFangSC-Regular, PingFang SC;
.title {
height: 22px;
margin-bottom: 20px;
line-height: 22px;
h2 {
font-size: 16px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 700;
color: #303133;
margin-left: 2px;
}
}
.img {
transform: scale(0.5);
}
.flex_between {
display: flex;
justify-content: space-between;
align-items: center;
}
}
</style>
<!--短信总数据-->
<template>
<div class="middle">
<div class="item-bg bg-purper center_flex min-w-173">
<div>
<p>计划触达人数<tip :text="tipText.planMbrNum" /></p>
<p>{{ formatterNum(data.planMbrNum) }}</p>
</div>
</div>
<div class="item-arrow purper center_flex">
<p>执行率</p>
<p>{{ formatterRate((data.touchMbrNum / data.planMbrNum) * 100) }}</p>
</div>
<div class="item-bg bg-purper center_flex min-w-173">
<div>
<p>实际触达人数<tip :text="tipText.touchMbrNum" /></p>
<p>{{ formatterNum(data.touchMbrNum) }}</p>
</div>
</div>
<div class="item-arrow green center_flex">
<p>转化率</p>
<p>{{ formatterRate((data.convMbrNum / data.touchMbrNum) * 100) }}</p>
</div>
<div class="item-bg bg-green center_flex min-w-214">
<div>
<p>触达顾客转化人数<tip :text="tipText.convMbrNum" /></p>
<p>{{ formatterNum(data.convMbrNum) }}</p>
</div>
</div>
<div class="item-bg bg-green min-w-527">
<div>
<p>触达顾客订单数 <tip :text="tipText.convOrderCnt" /></p>
<p>{{ formatterNum(data.convOrderCnt) }}</p>
</div>
<div>
<p>触达顾客转化收益(元)<tip :text="tipText.convSalesAmt" /></p>
<p>{{ formatterNumAndFixed(data.convSalesAmt) }}</p>
</div>
</div>
</div>
</template>
<script>
import formatterNum from '@/mixins/validateNum';
import tip from '@/components/tip';
export default {
name: 'short-msg-sum',
components: { tip },
props: {
data: {
type: Object,
default: () => {}
}
},
data() {
return {
tipText: {
planMbrNum: '计划使用短信触达的顾客人数。如果当前计划在不同时间用短信多次触达同一个顾客,会进行去重统计,仅计算为1个人。',
touchMbrNum: '发送短信成功的顾客人数。如果当前计划在不同时间用短信多次触达同一个顾客,会进行去重统计,仅计算为1个人。',
convMbrNum: '发送短信成功的顾客中,在收益有效期内消费的顾客人数。无论顾客消费了几次,会进行去重统计,仅计算为1个人。',
convOrderCnt: '发送短信成功的顾客中,在收益有效期内消费的顾客订单数。',
convSalesAmt: '发送短信成功的顾客中,在收益有效期内消费的顾客订单金额。'
}
};
},
mixins: [formatterNum]
};
</script>
<style lang="scss" scoped>
.middle {
font-family: PingFangSC-Medium, PingFang SC;
height: 100px;
display: flex;
align-items: center;
justify-content: space-around;
.item-bg {
flex: 1;
height: 100%;
border-radius: 6px;
box-sizing: border-box;
&.bg-green {
background: #e3fff8;
}
&.bg-purper {
background: #f0f5ff;
}
p {
&:nth-child(1) {
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
color: #606266;
line-height: 20px;
padding-top: 4px;
margin-bottom: 6px;
}
&:nth-child(2) {
font-size: 24px;
font-family: DINAlternate-Bold, DINAlternate;
font-weight: bold;
color: #303133;
line-height: 28px;
}
}
}
.item-arrow {
width: 89px;
height: 71px;
margin-right: 14px;
&.purper {
background: url('~@/assets/img/arrow_purper.png');
}
&.green {
background: url('~@/assets/img/arrow_green.png');
}
p {
width: 47px;
font-size: 12px;
line-height: 20px;
color: #606266;
font-family: PingFangSC-Regular, PingFang SC;
&:nth-child(2) {
font-family: DINAlternate-Bold, DINAlternate;
font-weight: bold;
color: #303133;
}
}
}
}
.center_flex {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.min-w-173 {
min-width: 173px;
}
.min-w-214 {
min-width: 214px;
}
.min-w-527 {
min-width: 527px;
margin-left: 7px;
display: flex;
align-items: center;
padding: 0 51px 0 107px;
box-sizing: border-box;
div {
flex: 1;
text-align: left;
}
}
</style>
......@@ -9,11 +9,11 @@
</template>
<script>
import * as G2 from '@antv/g2';
import { ecmTouchEffectColumnDiagram, ecmGuideCluesColumnDiagram, ecmHeadCluesColumnDiagram } from '@/service/api/ecmApi.js';
import { ecmTouchEffectColumnDiagram, telTaskDiagram, massDiagram } from '@/service/api/ecmApi.js';
export default {
name: 'touch-charts',
props: {
type: String, // 0是触达效果 1导购线索 2后台线索
type: String,
createTime: Number
},
data() {
......@@ -115,16 +115,27 @@ export default {
},
getChartData() {
let meth;
if (this.type == 0) meth = ecmTouchEffectColumnDiagram;
else if (this.type == 1) meth = ecmGuideCluesColumnDiagram;
else meth = ecmHeadCluesColumnDiagram;
meth({ ecmPlanId: this.$route.query.id || this.$route.params.id }).then(res => {
let params = {
ecmPlanId: this.$route.query.id || this.$route.params.id
};
if (!this.type) {
meth = ecmTouchEffectColumnDiagram;
} else if (this.type == '话务') {
meth = telTaskDiagram;
params.convType = 1;
} else if (this.type == '群发转话务') {
meth = telTaskDiagram;
params.convType = 2;
} else if (this.type == '群发') {
meth = massDiagram;
}
meth(params).then(res => {
if (!res.result || !res.result.length) {
// 没数据的情况
this.isNone = true;
} else {
this.chartData = res.result.map(item => {
if (item.name == '线索转化收益') {
if (item.name == '转化收益') {
item.rate = item.vaule ? parseFloat(item.vaule) : 0;
delete item.vaule;
} else {
......@@ -147,7 +158,7 @@ export default {
let obj = [
{ date: item, value: 0, name: '触达人数' },
{ date: item, value: 0, name: '转化人数' },
{ date: item, rate: 0, name: '线索转化收益' }
{ date: item, rate: 0, name: '转化收益' }
];
arr.unshift(...obj);
}
......@@ -158,7 +169,7 @@ export default {
chartData.forEach(item => {
dateArr.forEach(el => {
if (item.date == this.formatterTime(el.date) && item.name == el.name) {
if (el.name == '线索转化收益') el.rate = item.rate;
if (el.name == '转化收益') el.rate = item.rate;
else el.value = item.value;
}
});
......
<template>
<div class="dm-wrap wechat">
<div class="title flex_between">
<div class="flex_between">
<img :src="require('@/assets/img/icon-weixin.png')" class="img" />
<h2>微信</h2>
</div>
</div>
<div v-if="customServiceData">
<h3>{{ $route.query.effectType == 0 ? '客服接口(文本、图文、图片、小程序)' : '客服接口(小程序)' }}</h3>
<wechat-sum :data="customServiceData" :tipText="customText" />
</div>
<div v-if="batchData" style="margin-top: 30px">
<h3>群发接口(文本、图文、图片)</h3>
<wechat-sum :data="batchData" :tipText="batchText" />
</div>
</div>
</template>
<script>
import wechatSum from './wechat-sum.vue';
export default {
name: 'wechat',
components: { wechatSum },
props: {
customServiceData: {
type: Object || undefined
},
batchData: {
type: Object || undefined
}
},
data() {
return {
customText: {
planMbrNum: '计划使用微信客服接口触达的顾客人数。如果当前计划在不同时间用微信客服接口触达多次触达同一个顾客,会进行去重统计,仅计算为1个人。',
touchMbrNum: '使用微信客服接口成功推送触达的顾客人数。如果当前计划在不同时间用微信客服接口触达多次触达同一个顾客,会进行去重统计,仅计算为1个人。微信客服接口成功推送触达需要严格的前置条件,也有相应限制,可能导购触达人数过低。',
convMbrNum: '使用微信客服接口成功推送触达的顾客中,在收益有效期内消费的顾客人数。无论顾客消费了几次,会进行去重统计,仅计算为1个人。',
convOrderCnt: '使用微信客服接口成功推送触达的顾客中,在收益有效期内消费的顾客订单数。',
convSalesAmt: '使用微信客服接口成功推送触达的顾客中,在收益有效期内消费的顾客订单金额。'
},
batchText: {
planMbrNum: '计划使用微信服务号群发接口进行推送触达的顾客人数。如果当前计划在不同时间用微信服务号群发接口多次触达同一个顾客,会进行去重统计,仅计算为1个人。',
touchMbrNum: '使用微信服务号群发接口成功推送的顾客人数。如果当前计划在不同时间用微信服务号群发接口触达多次触达同一个顾客,会进行去重统计,仅计算为1个人。由于微信系统限制,无法获取发送的消息是否成功到达顾客手机,所以只要成功向微信接口发出消息,即视为实际触达。',
convMbrNum: '使用微信服务号群发接口触达的顾客中,在收益有效期内消费的顾客人数。无论顾客消费了几次,会进行去重统计,仅计算为1个人。',
convOrderCnt: '使用微信服务号群发接口触达的顾客中,在收益有效期内消费的顾客订单数。',
convSalesAmt: '使用微信服务号群发接口触达的顾客中,在收益有效期内消费的顾客订单金额。'
}
};
}
};
</script>
<style lang="scss" scoped>
.wechat {
padding: 22px 20px 30px !important;
font-family: PingFangSC-Regular, PingFang SC;
.title {
height: 22px;
margin-bottom: 30px;
line-height: 22px;
h2 {
font-size: 16px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 700;
color: #303133;
margin-left: 2px;
}
}
.img {
transform: scale(0.5);
}
.flex_between {
display: flex;
justify-content: space-between;
align-items: center;
}
h3 {
display: inline-block;
height: 25px;
background: #bad9ff;
line-height: 25px;
text-align: center;
border-radius: 2px;
color: #303133;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 600;
margin-bottom: 20px;
padding: 0 20px;
}
}
</style>
<!--微信总数据-->
<template>
<div class="middle">
<div class="item-bg bg-purper center_flex min-w-173">
<div>
<p>计划触达人数<tip :text="tipText.planMbrNum" /></p>
<p>{{ formatterNum(data.planMbrNum) }}</p>
</div>
</div>
<div class="item-arrow purper center_flex">
<p>执行率</p>
<p>{{ formatterRate((data.touchMbrNum / data.planMbrNum) * 100) }}</p>
</div>
<div class="item-bg bg-purper center_flex min-w-173">
<div>
<p>实际触达人数<tip :text="tipText.touchMbrNum" /></p>
<p>{{ formatterNum(data.touchMbrNum) }}</p>
</div>
</div>
<div class="item-arrow green center_flex">
<p>转化率</p>
<p>{{ formatterRate((data.convMbrNum / data.touchMbrNum) * 100) }}</p>
</div>
<div class="item-bg bg-green center_flex min-w-214">
<div>
<p>触达顾客转化人数<tip :text="tipText.convMbrNum" /></p>
<p>{{ formatterNum(data.convMbrNum) }}</p>
</div>
</div>
<div class="item-bg bg-green min-w-527">
<div>
<p>触达顾客订单数 <tip :text="tipText.convOrderCnt" /></p>
<p>{{ formatterNum(data.convOrderCnt) }}</p>
</div>
<div>
<p>触达顾客转化收益(元)<tip :text="tipText.convSalesAmt" /></p>
<p>{{ formatterNumAndFixed(data.convSalesAmt) }}</p>
</div>
</div>
</div>
</template>
<script>
import formatterNum from '@/mixins/validateNum';
import tip from '@/components/tip';
export default {
name: 'wechat-sum',
components: { tip },
props: {
data: {
type: Object,
default: () => {}
},
tipText: Object
},
mixins: [formatterNum]
};
</script>
<style lang="scss" scoped>
.middle {
font-family: PingFangSC-Medium, PingFang SC;
height: 100px;
display: flex;
align-items: center;
justify-content: space-around;
.item-bg {
flex: 1;
height: 100%;
border-radius: 6px;
box-sizing: border-box;
&.bg-green {
background: #e3fff8;
}
&.bg-purper {
background: #f0f5ff;
}
p {
&:nth-child(1) {
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
color: #606266;
line-height: 20px;
padding-top: 4px;
margin-bottom: 6px;
}
&:nth-child(2) {
font-size: 24px;
font-family: DINAlternate-Bold, DINAlternate;
font-weight: bold;
color: #303133;
line-height: 28px;
}
}
}
.item-arrow {
width: 89px;
height: 71px;
margin-right: 14px;
&.purper {
background: url('~@/assets/img/arrow_purper.png');
}
&.green {
background: url('~@/assets/img/arrow_green.png');
}
p {
width: 47px;
font-size: 12px;
line-height: 20px;
color: #606266;
font-family: PingFangSC-Regular, PingFang SC;
&:nth-child(2) {
font-family: DINAlternate-Bold, DINAlternate;
font-weight: bold;
color: #303133;
}
}
}
}
.center_flex {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.min-w-173 {
min-width: 173px;
}
.min-w-214 {
min-width: 214px;
}
.min-w-527 {
min-width: 527px;
margin-left: 7px;
display: flex;
align-items: center;
padding: 0 51px 0 107px;
box-sizing: border-box;
div {
flex: 1;
text-align: left;
}
}
</style>
......@@ -49,7 +49,7 @@
<el-form-item label="通知方式" class="is-required" prop="noticeType">
<el-radio v-model="form.noticeType" :label="0" :disabled="!isEditTemplate || isInfo"
>不通知
<el-tooltip class="item" effect="dark" content="不通知用户,但用户可以在GIC卡券包查看到该卡券。建议线下发券使用,或使用其他通知方式代替(如小程序、短信等)" placement="top-start">
<el-tooltip class="item" effect="dark" content="不会通知用户,但是卡券会放入用户账户" placement="top-start">
<i class="iconfont icon-xinxixianshi pl5 gray"></i>
</el-tooltip>
</el-radio>
......
......@@ -30,9 +30,10 @@
</div>
<div class="fr">
<el-button type="text" v-if="v.status === 2" @click="$router.push('/message/temp/edit/' + v.gicSmsTemplateId)">修改</el-button>
<dm-delete @confirm="delData(v)" tips="是否删除该短信模板?">
<el-button type="text" @click="onDeleteData(v)">删除</el-button>
<!-- <dm-delete @confirm="delData(v)" tips="模板删除后,所有引用此模板的短信都会停止发送,请确认。">
<el-button type="text">删除</el-button>
</dm-delete>
</dm-delete> -->
</div>
</div>
<span class="sms-lib-item-tips_right danger-color-bg" v-if="v.status === 2">未通过</span>
......@@ -91,6 +92,17 @@ export default {
this.$store.commit('mutations_layoutTips', '');
},
methods: {
onDeleteData(v) {
this.$confirm('确认删除该模板?删除后,所有引用此模板的短信都会停止发送。', '提示', {
confirmButtonText: '确认',
cancelBUttonText: '取消',
type: 'warning'
})
.then(() => {
this.delData(v);
})
.catch(() => {});
},
search() {
this.listParams.currentPage = 1;
this.LoadLibList();
......
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