Commit c9bf843b by liuchenxi

Merge branch 'feature/1月迭代-年后'

parents 3a25db50 9e5ba188
......@@ -3,9 +3,10 @@
<head>
<meta charset="utf-8" />
<link rel="shortcut icon" href="./favicon.ico" />
<script src="//web-1251519181.file.myqcloud.com/lib/vue/2.5.2/vue.min.js"></script>
<style href="//at.alicdn.com/t/font_2996579_ubjq74uy5wj.css"></style>
<!-- <script src="//web-1251519181.file.myqcloud.com/lib/vue/2.5.2/vue.min.js"></script>
<script src="//web-1251519181.file.myqcloud.com/lib/vue-router/3.0.2/vue-router.min.js"></script>
<script src="//web-1251519181.file.myqcloud.com/lib/vuex/3.1.0/vuex.min.js"></script>
<script src="//web-1251519181.file.myqcloud.com/lib/vuex/3.1.0/vuex.min.js"></script> -->
<script src="//web-1251519181.file.myqcloud.com/lib/lodash.min.js"></script>
<title>memberproject</title>
<!-- GrowingIO Analytics code version 2.1 -->
......
......@@ -74,6 +74,9 @@
display: flex;
justify-content: space-between;
align-items: center;
.left {
font-size: 0;
}
.senior-search {
margin-left: 17px;
.el-icon-d-arrow-right,
......
......@@ -31,26 +31,7 @@
@change="onSearch"
clearable
/>
<el-select
v-model="customerTypeLabel"
placeholder="请选择"
multiple
@change="selectChange"
style="width: 300px"
>
<el-option :value="customerType" style="height: auto;padding:0">
<el-tree
:data="treeData"
show-checkbox
node-key="id"
ref="tree"
highlight-current
default-expand-all
:props="defaultProps"
@check="handleCheckChange"
/>
</el-option>
</el-select>
<vue-gic-select-tree :options="selectTreeOptions" @change="onSelectTreeChange" style="display: inline-block;margin-left:10px; height: 32px" />
<el-button type="text" @click="showSearch = !showSearch" class="senior-search">
高级搜索<i
:class="showSearch ? 'el-icon-d-arrow-left' : 'el-icon-d-arrow-right'"
......@@ -62,7 +43,7 @@
v-model="batchValue"
placeholder="批量操作"
@change="handleFocusBatch"
style="width: 150px;margin-right:10px;"
style="width: 150px;margin-right:7px;"
@visible-change="handleVisibleBatch"
>
<template v-for="item in batchOpt">
......@@ -75,6 +56,7 @@
/>
</template>
</el-select>
<el-button v-if="getCodeAuth('memberBatchImport')" :limit-code="getCode('memberBatchImport')" type="primary" @click="batchImport">批量导入修改</el-button>
</div>
</div>
<div v-show="showSearch" class="senior-search-content">
......@@ -122,7 +104,7 @@
>
<template slot-scope="{row}">
<!-- 基本信息 -->
<div v-if="colum == 'name'" class="customer-info-cell">
<div v-if="colum == 'name'" :class="['customer-info-cell', getCodeAuth('memberIntoCustomDetail') && 'pointer']" @click="linkDetail(row.memberId)">
<img :src="row.thirdImgUrl||defaultImg" alt="">
<p class="memberName">
{{ row.memberName || '--' }}
......@@ -309,4 +291,17 @@ export default { ...action };
transform: translateY(0);
}
}
.pointer {
cursor: pointer;
}
.customer-tree .el-tree-node__content {
height: 32px;
line-height: 32px;
&:hover {
background: #F7F8FA;
}
}
.all-coustomer-select .el-select__tags {
height: 29px;
}
</style>
......@@ -71,7 +71,7 @@
z-index: 1;
width: 100%;
height: 34px;
transform: translateY(43px);
transform: translateY(0);
transition: transform 0.5s, -webkit-transform 0.5s;
background: linear-gradient(
180deg,
......@@ -100,11 +100,6 @@
display: block;
width: 100%;
}
&:hover {
.maskOperation {
transform: translateY(0px);
}
}
}
}
.right {
......@@ -177,7 +172,7 @@
padding: 20px 0 0;
transition: height 1s;
.shrink{
height: 47px;
height: 20px;
overflow: hidden;
box-sizing: border-box;
}
......@@ -386,8 +381,8 @@
border: 1px solid #e4e7ed;
box-sizing: border-box;
.el-icon-arrow-right {
align-self: flex-end;
margin-bottom: 9px;
align-self: center;
}
}
}
......@@ -638,7 +633,6 @@
flex-direction: column;
justify-content: center;
align-items: center;
min-height: 80px;
img {
width: 60px;
height: 60px;
......
<template>
<div class="customer-details" v-loading.fullscreen.lock="fullscreenLoading">
<div class="customer-details">
<v-nav :navpath="navpath" />
<div class="customer-contain-wrap">
<div class="customer-contain-wrap" v-loading="fullscreenLoading">
<div class="customer-info-item" v-for="section in customerInfoItemList" :key="section">
<div class="info-item-header">
<h2 class="item-title">
......@@ -24,7 +24,7 @@
<div class="maskOperation">
<!-- <span @click="updateImgUrl">刷新头像</span><i class="vertical-line" /> -->
<router-link tag="span" :to="`/photo-album?memberId=${memberId}&from=1`">
会员相册
客户相册
</router-link>
</div>
<el-image
......@@ -150,7 +150,7 @@
</el-tooltip>
</el-descriptions-item>
</el-descriptions>
</div>
<!-- 会员信息字段 -->
<div :class="[toggleTag?'':'shrink']" v-if="showFieldType===2&&extendInfo.fieldList">
......@@ -167,13 +167,13 @@
{{ item.fieldValue }}
</el-descriptions-item>
</el-descriptions>
</div>
<div
class="empty-block"
v-if="(showFieldType===1&&!extendInfo.openField&&!extendInfo.openChildrenField)||(showFieldType===2&&!extendInfo.fieldList)"
>
<img :src="require('../../../static/img/no-data_icon.png')" alt="">
<!-- <img :src="require('../../../static/img/no-data_icon.png')" alt=""> -->
<p>暂无数据</p>
</div>
<div class="toggleTag" @click="toggleTag=!toggleTag" v-if="toggleShow">
......@@ -250,7 +250,8 @@
{{ memberInfo.cardGivingTime|formatTime }}
</el-descriptions-item>
<el-descriptions-item label="等级到期时间:">
{{ memberInfo.limitTime|formatTime }}
<template v-if="memberInfo.limitTime == -1">永久有效</template>
<template v-else>{{memberInfo.limitTime|formatTime}}</template>
</el-descriptions-item>
</el-descriptions>
</template>
......@@ -319,15 +320,24 @@
<div class="middle">
<div class="label">
{{ item.label }}
<el-tooltip v-if="item.key == 'numOfMarket'" content="只统计近半年的数据" placement="top">
<i class="iconfont icon-QuestionCircleOutlined" style="color: #909399" />
</el-tooltip>
</div>
<div class="num">
{{ memberInfo[item.key]
?(item.key==='storedValue'?(memberInfo[item.key]|storedValue):(memberInfo[item.key]))
:0 }}
{{
memberInfo[item.key]
? item.key === "storedValue"
? memberInfo[item.key] || storedValue
: item.key == "numOfMarket"
? marketingRecordNum
: memberInfo[item.key]
: 0
}}
</div>
</div>
</div>
<div class="el-icon-arrow-right" v-if="item.key==='numOfTel'" />
<div class="el-icon-arrow-right" />
</li>
</ul>
</div>
......
......@@ -38,7 +38,6 @@ export default {
totalCount: 0,
loading: false,
tableData: [],
customerTypeLabel: "", // "非会员,微信会员,POS会员",
customerType: [
// { id: 1, label: "非会员" },
// { id: 3, label: "微信会员" },
......@@ -65,37 +64,52 @@ export default {
{ value: "integral", label: "调整积分", code: "memberBatchSetIntegral" },
{ value: "grade", label: "修改等级", code: "memberBatchSetGrade" },
{ value: "mainstore", label: "修改服务门店", code: "memberBatchSetService" },
{ value: "store", label: "修改协管门店", code: "memberBatchSetCustomer" },
{ value: "batchImport", label: "批量导入", code: "memberBatchImport" }
{ value: "store", label: "修改协管门店", code: "memberBatchSetCustomer" }
],
defaultImg,
integralFlag: "", // 积分调整权限
memberGrade: [], // 商户等级列表
cliqueMemberGrade: [], // 集团等级列表
treeData: [
{
id: 1,
label: "非会员",
disabled: false
selectTreeOptions: {
selectOptions: {
allCheckText: '全部客户',
placeholder: '全部客户',
width: 220
},
{
id: 2,
label: "会员",
disabled: false,
children: [
treeOptions: {
data: [
{
id: 3,
label: "微信会员",
id: 1,
label: "会员",
disabled: false
},
{
id: 4,
label: "POS会员",
disabled: false
id: 2,
label: "会员",
disabled: false,
children: [
{
id: 3,
label: "微信会员",
disabled: false
},
{
id: 4,
label: "POS会员",
disabled: false
}
]
}
]
}
],
],
props: {
label: 'label',
children: 'children',
value: 'id'
}
},
searchAble: false,
multipleAble: true
},
defaultProps: {
children: "children",
label: "label"
......@@ -156,17 +170,7 @@ export default {
watch: {
customerType: {
handler(newV, oldV) {
if (newV.length === 0 && this.$refs.tree) {
this.$message.error("至少选择一个客户类型");
this.$refs.tree.setChecked(oldV[0].id, true, true);
this.$nextTick(_ => {
this.handleCheckChange();
});
} else if (oldV.length === 0) {
return false;
} else {
this.onSearch();
}
this.onSearch();
},
deep: true
},
......@@ -186,44 +190,11 @@ export default {
this.getFindMemberFields();
this.getAjaxMembers();
this.getEnterpriseInfo();
// 默认勾选全部客户类型 1-非会员 notMember 3-微信会员 wxOpenCarMember 4-pos会员 posMember
this.$refs.tree.setCheckedNodes(this.treeData);
this.$nextTick(_ => {
this.handleCheckChange();
});
},
beforUpdate() {},
methods: {
selectChange(e) {
const arrNew = [];
const dataLength = this.customerType.length;
const eleng = e.length;
for (let i = 0; i < dataLength; i++) {
for (let j = 0; j < eleng; j++) {
if (e[j] === this.customerType[i].label) {
arrNew.push(this.customerType[i]);
}
}
}
this.$refs.tree.setCheckedNodes(arrNew);
this.$nextTick(_ => {
this.handleCheckChange();
});
},
handleCheckChange(data, nodes) {
const res = this.$refs.tree.getCheckedNodes(true, true); // 这里两个true,1. 是否只是叶子节点 2. 是否包含半选节点(就是使得选择的时候不包含父节点)
const arrLabel = [];
const arr = [];
res.forEach(item => {
item.disabled = false;
arrLabel.push(item.label);
arr.push(item);
});
if (res.length === 1) {
res[0].disabled = true;
}
this.customerType = [].concat(arr);
this.customerTypeLabel = [].concat(arrLabel);
onSelectTreeChange(data) {
this.customerType = data;
},
initialize() {
this.pageParam.phoneNameCard = sessionStorage.getItem("phoneNameCard")
......@@ -462,11 +433,7 @@ export default {
},
// 批量处理
handleFocusBatch(val) {
if (this.batchValue == "batchImport") {
// 批量导入
this.batchValue = "";
this.openDialogImport();
} else if (this.multipleList.length < 1) {
if (this.multipleList.length < 1) {
this.batchValue = "";
checkFalse("请勾选会员");
return false;
......@@ -482,6 +449,10 @@ export default {
}
this.batchValue = "";
},
// 批量导入修改
batchImport() {
this.openDialogImport();
},
batchRefresh() {
this.getAjaxMembers();
},
......@@ -514,6 +485,7 @@ export default {
});
},
linkDetail(memberId) {
if (!this.getCodeAuth('memberIntoCustomDetail')) return;
this.$router.push({
path: "/customerDetail",
query: { memberId }
......
......@@ -8,7 +8,7 @@ import customerlabelDialog from './components/customerlabelDialog.vue';
import defaultImg from '../../../static/img/default.png';
import { mapState } from 'vuex';
import url from '../../components/axios/url';
import { doFetch, doFetchqs } from '../../components/axios/api';
import { doFetch, doFetchqs, doFetchGet } from '../../components/axios/api';
import authMethods from '@/mixins/auth';
import {
checkFalse,
......@@ -169,7 +169,7 @@ export default {
icon: 'icon-yingxiaojilu',
iconTheme: 'market',
key: 'numOfMarket',
path: '',
path: '/marketing-record',
},
{
label: '通话记录',
......@@ -198,6 +198,7 @@ export default {
},
{ title: '客户日志', name: 'log', class: 'log-info-contain' },
],
marketingRecordNum: 0
};
},
watch: {
......@@ -240,6 +241,7 @@ export default {
created () {
this.$store.commit('mutations-slide', true);
this.memberId = this.$route.query.memberId;
this.getMarketingRecordNum();
},
mounted () {
const rightWrap = document.querySelector('.right-maincontainer');
......@@ -456,6 +458,20 @@ export default {
checkStatus(err);
});
},
async getMarketingRecordNum() {
try {
const param = { memberId: this.memberId };
const res = await doFetchGet(url.getMarketingRecordNum, param);
if (res.data.errorCode == 0) {
this.marketingRecordNum = res.data.result || 0;
console.log(this.marketingRecordNum);
} else {
checkFalse(res.data.message);
}
}catch(err) {
checkStatus(err);
}
}
},
components: {
'v-nav': nav,
......
import axios from 'axios'
import qs from 'qs'
import { checkFalse } from '../../../static/js/checkStatus';
export function fetch(url, options) {
return new Promise((resolve, reject) => {
axios.post(url, options).then(res => {
resolve(res);
if (res.data.errorCode == 0) {
resolve(res);
} else {
checkFalse(res.data.message);
return reject();
}
}).catch(err => {
reject(err);
checkFalse(err);
return reject(err);
});
})
}
export function fetchqs(url,options) {
return new Promise((resolve, reject) => {
axios.post(url, qs.stringify(options)).then(res => {
resolve(res);
if (res.data.errorCode == 0) {
resolve(res);
} else {
checkFalse(res.data.message);
return reject();
}
}).catch(err => {
reject(err);
checkFalse(err);
return reject(err);
});
})
}
......@@ -23,9 +36,15 @@ export function fetchqs(url,options) {
export function fetchGet(url, options) {
return new Promise((resolve, reject) => {
axios.get(url, { params: options }).then(res => {
resolve(res);
if (res.data.errorCode == 0) {
resolve(res);
} else {
checkFalse(res.data.message);
return reject();
}
}).catch(err => {
reject(err);
checkFalse(err);
return reject(err);
})
})
}
\ No newline at end of file
}
......@@ -89,7 +89,12 @@ const urlConfig = {
addToWhiteList: '/api-member/update-member-white-list', // 加入白名单
memberTagGroupDetail: '/api-member/member-tag-group-detail', //会员分组详情
memberStoredRecordList: '/api-member/member-stored-record-list', //储值列表(储值明细列表)
memberStoredTypeList: '/api-member/member-stored-type-list'// 储值列表-储值类型
memberStoredTypeList: '/api-member/member-stored-type-list',// 储值列表-储值类型
ecmLogPage: '/api-marketing/member/ecm-log-page',
cardLogPage: '/api-marketing/member/card-log-page',
messageLogPage: '/api-marketing/member/sms-log-page',
wechatLogPage: '/api-marketing/member/wechat-log-page',
getMarketingRecordNum: '/api-marketing/member/marketing-count'
}
const defaultUrl = Object.assign({}, urlConfig);
......
<template>
<div class="marketing-card mt5">
<div class="search mb10">
投放时间:<el-date-picker :clearable="false" class="w256 mb10 mr10" value-format="yyyy-MM-dd" :pickerOptions="pickerOptions" v-model="launchTime" type="daterange" range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" @change="change"></el-date-picker>
领取时间:<el-date-picker class="mr10 w256 mb10" value-format="yyyy-MM-dd" :pickerOptions="pickerOptions" v-model="collectionTime" type="daterange" range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" @change="change"></el-date-picker>
<el-input
v-model="search.search"
placeholder="请输入卡券券码"
class="w260 mr10 mb10"
prefix-icon="el-icon-search"
@change="change"
clearable
/>
<el-select class="w160 mb10" v-model="search.receiveCode" placeholder="所有投放渠道" clearable @change="change">
<el-option v-for="item in tableData.dictList" :key="item.dictCode" :value="item.dictCode" :label="item.dictName" />
</el-select>
</div>
<div class="table">
<el-table
v-loading="tableData.loading"
:data="tableData.data"
tooltip-effect="dark"
style="width: 100%"
>
<el-table-column
v-for="(v, i) in tableData.tableHeader"
:key="i"
:prop="v.prop"
:min-width="v.minWidth"
:label="v.label"
:formatter="v.formatter"
:fixed="v.fixed"
show-overflow-tooltip
>
<template slot-scope="{ row }">
<span v-if="v.formatter" v-html="v.formatter(row)"></span>
<span v-else>{{ row[v.prop] || "--" }}</span>
</template>
</el-table-column>
</el-table>
<div class="pager" v-if="tableData.total > 0">
<dm-pagination
background
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="tableData.currentPage"
:page-sizes="tableData.pageSizeList"
:page-size="tableData.pageSize"
layout="total, sizes, prev, pager, next"
:total="tableData.total"
>
</dm-pagination>
</div>
</div>
</div>
</template>
<script>
import dickerPickMixin from './mixins/datePickRuleMixin';
import paginationMixins from './mixins/paginationMixins';
const curMonth = new Date().getMonth() + 1;
const halfBefore = new Date().setMonth(curMonth - (6 + 1));
const datePrickerBegin = new Date(halfBefore).setHours(24);
export default {
name: 'card',
props: {
tableData: Object
},
mixins: [ dickerPickMixin, paginationMixins ],
data() {
return {
launchTime: [new Date(datePrickerBegin), new Date()],
collectionTime: [],
search: {
putBeginTime: '', // 投放开始时间
putEndTime: '', // 投放结束时间
receiveBeginTime: '', // 领取开始时间
receiveEndTime: '', // 结束
search: '', // 卡券代码
receiveCode: null, // 投放渠道
}
}
},
methods: {
change() {
const { currentPage, pageSize } = this.tableData;
const { launchTime, collectionTime } = this;
this.search.putBeginTime = launchTime ? ( typeof launchTime[0] == 'string ' ? launchTime[0] : this.dateformat(new Date(launchTime[0]), 'yyyy-MM-dd')) : null;
this.search.putEndTime = launchTime ? ( typeof launchTime[0] == 'string ' ? launchTime[1] : this.dateformat(new Date(launchTime[1]), 'yyyy-MM-dd')) : null;
this.search.receiveBeginTime = collectionTime ? collectionTime[0] : null;
this.search.receiveEndTime = collectionTime ? collectionTime[1] : null;
const commonObj = { currentPage, pageSize };
this.$emit("changeSearch", Object.assign({}, this.search, commonObj));
},
}
};
</script>
<style scoped>
@import './css/all.scss';
</style>
.w160 {
width: 160px;
}
.w256 {
width: 256px;
}
.w260 {
width: 260px;
}
.mb20 {
margin-bottom: 20px;
}
.pb20 {
padding-bottom: 20px;
}
.mt5 {
margin-top: 5px;
}
.ml10 {
margin-left: 10px;
}
.mr10 {
margin-right: 10px;
}
.mb10 {
margin-bottom: 10px !important;
}
.mb25 {
margin-bottom: 25px;
}
.search {
font-size: 0;
margin-bottom: 20px;
}
.pager {
text-align: right;
margin-top: 20px;
}
.min20 {
min-height: 100%;
padding-bottom: 20px;
box-sizing: border-box;
}
.marketing-message, .marketing-wechat, .marketing-card, .marketing-ecm {
height: 100%;
}
.table {
.pager {
text-align: right;
padding: 20px 0;
}
}
<template>
<div class="marketing-ecm mt5">
<div class="search">
<el-input
v-model="search.search"
placeholder="请输入计划名称"
class="w260"
prefix-icon="el-icon-search"
clearable
@change="change"
/>
<el-date-picker class="ml10 w256" value-format="yyyy-MM-dd" :pickerOptions="pickerOptions" v-model="time" type="daterange" range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" @change="change"></el-date-picker>
<el-select class="ml10 w160" v-model="search.marketingType" placeholder="所有营销方式" clearable @change="change">
<el-option v-for="item in ecmTypeList" :key="item.id" :value="item.value" :label="item.label" />
</el-select>
</div>
<div class="table">
<el-table
v-loading="tableData.loading"
:data="tableData.data"
tooltip-effect="dark"
style="width: 100%"
>
<el-table-column
v-for="(v, i) in tableData.tableHeader"
:key="i"
:prop="v.prop"
:min-width="v.minWidth"
:label="v.label"
:formatter="v.formatter"
:fixed="v.fixed"
show-overflow-tooltip
>
<template slot-scope="{ row }">
<span v-if="v.formatter" v-html="v.formatter(row)"></span>
<span v-else>{{ row[v.prop] || "--" }}</span>
</template>
</el-table-column>
</el-table>
<div class="pager" v-if="tableData.total > 0">
<dm-pagination
background
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="tableData.currentPage"
:page-sizes="tableData.pageSizeList"
:page-size="tableData.pageSize"
layout="total, sizes, prev, pager, next"
:total="tableData.total"
>
</dm-pagination>
</div>
</div>
</div>
</template>
<script>
import dickerPickMixin from './mixins/datePickRuleMixin';
import paginationMixins from './mixins/paginationMixins';
export default {
name: "ecm",
props: {
tableData: Object
},
mixins: [ dickerPickMixin, paginationMixins ],
data() {
return {
search: {
search: '',
beginTime: '',
endTime: '',
marketingType: null
},
ecmTypeList: [
{ label: '积分', value: 'integral' },
{ label: '短信', value: 'message' },
{ label: '话务', value: 'teltask' },
{ label: '群发任务', value: 'qfxx' },
{ label: '图文消息', value: 'teletext' },
{ label: '图片', value: 'image' },
{ label: '文本消息', value: 'text' },
{ label: '小程序', value: 'wxa' },
{ label: '卡券', value: 'card' }
]
};
},
methods: {
change() {
const { currentPage, pageSize } = this.tableData;
this.search.beginTime = this.time ? ( typeof this.time[0] == 'string ' ? this.time[0] : this.dateformat(new Date(this.time[0]), 'yyyy-MM-dd')) : null;
this.search.endTime = this.time ? ( typeof this.time[0] == 'string ' ? this.time[1] : this.dateformat(new Date(this.time[1]), 'yyyy-MM-dd')) : null;
const commonObj = { currentPage, pageSize };
this.$emit("changeSearch", Object.assign({}, this.search, commonObj));
},
}
};
</script>
<style scoped>
@import './css/all.scss';
</style>
<template>
<div class="marketing-message mt5">
<div class="search">
<el-date-picker value-format="yyyy-MM-dd" class="w256" :pickerOptions="pickerOptions" v-model="time" type="daterange" range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" @change="change"></el-date-picker>
<el-select class="ml10 w160" v-model="search.smsType" placeholder="所有模板类型" clearable @change="change">
<el-option v-for="item in sysTypeList" :key="item.id" :value="item.value" :label="item.label" />
</el-select>
</div>
<div class="table">
<el-table
v-loading="tableData.loading"
:data="tableData.data"
tooltip-effect="dark"
style="width: 100%"
>
<el-table-column
v-for="(v, i) in tableData.tableHeader"
:key="i"
:prop="v.prop"
:min-width="v.minWidth"
:label="v.label"
:formatter="v.formatter"
:fixed="v.fixed"
show-overflow-tooltip
>
<template slot-scope="{ row }">
<span v-if="v.formatter" v-html="v.formatter(row)"></span>
<span v-else>{{ row[v.prop] || "--" }}</span>
</template>
</el-table-column>
</el-table>
<div class="pager" v-if="tableData.total > 0">
<dm-pagination
background
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="tableData.currentPage"
:page-sizes="tableData.pageSizeList"
:page-size="tableData.pageSize"
layout="total, sizes, prev, pager, next"
:total="tableData.total"
>
</dm-pagination>
</div>
</div>
</div>
</template>
<script>
import dickerPickMixin from './mixins/datePickRuleMixin';
import paginationMixins from './mixins/paginationMixins';
export default {
name: 'message',
props: {
tableData: Object
},
mixins: [ dickerPickMixin, paginationMixins ],
data() {
return {
search: {
beginTime: '',
endTime: '',
smsType: null
},
sysTypeList: [
{ label: '普通短信', value: 0 },
{ label: '营销短信', value: 1 }
]
}
},
methods: {
change() {
const { currentPage, pageSize } = this.tableData;
this.search.beginTime = this.time ? ( typeof this.time[0] == 'string ' ? this.time[0] : this.dateformat(new Date(this.time[0]), 'yyyy-MM-dd')) : null;
this.search.endTime = this.time ? ( typeof this.time[0] == 'string ' ? this.time[1] : this.dateformat(new Date(this.time[1]), 'yyyy-MM-dd')) : null;
const commonObj = { currentPage, pageSize };
this.$emit("changeSearch", Object.assign({}, this.search, commonObj));
}
}
};
</script>
<style scoped>
@import './css/all.scss';
</style>
import { dateformat } from '@/utils/formatTime';
const curMonth = new Date().getMonth() + 1;
const halfBefore = new Date().setMonth(curMonth - (6 + 1));
const datePrickerBegin = new Date(halfBefore).setHours(24);
export default {
data() {
return {
// 四个时间选择器的初始值
time: [new Date(datePrickerBegin), new Date()],
// 四个页面选择器的禁用规则
pickerOptions: {
disabledDate: val => {
// 只能筛选半年之内得数据,并且最大跨度为六个月
const timeArea = new Date().setMonth(curMonth - (6 + 1));
if (this.minDate) {
const curTime = this.minDate.getTime();
const min = curTime - timeArea > halfBefore ? curTime - timeArea : halfBefore;
return val.getTime() > curTime + timeArea || val.getTime() < min || val.getTime() > this.maxDate;
}
return val.getTime() <= halfBefore || val.getTime() > this.maxDate.getTime();
},
onPick: ({ maxDate, minDate }) => {
this.minDate = minDate;
}
},
minDate: null,
maxDate: new Date(),
dateformat: dateformat
}
}
}
export default {
methods: {
handleCurrentChange(val) {
this.tableData.currentPage = val;
this.change();
},
handleSizeChange(val) {
this.tableData.pageSize = val;
this.tableData.currentPage = 1;
this.change();
}
}
};
<template>
<div class="marketing-wechat mt5">
<div class="search">
<el-date-picker value-format="yyyy-MM-dd" class="w256" :pickerOptions="pickerOptions" v-model="time" type="daterange" range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" @change="change"></el-date-picker>
<el-select class="ml10 w160" v-model="search.contentType" placeholder="所有素材类型" clearable @change="change">
<el-option v-for="item in contentTypeList" :key="item.id" :value="item.value" :label="item.label" />
</el-select>
</div>
<div class="table">
<el-table
v-loading="tableData.loading"
:data="tableData.data"
tooltip-effect="dark"
style="width: 100%"
>
<el-table-column
v-for="(v, i) in tableData.tableHeader"
:key="i"
:prop="v.prop"
:min-width="v.minWidth"
:label="v.label"
:formatter="v.formatter"
:fixed="v.fixed"
show-overflow-tooltip
>
<template slot-scope="{ row }">
<span v-if="v.formatter" v-html="v.formatter(row)"></span>
<span v-else>{{ row[v.prop] || "--" }}</span>
</template>
</el-table-column>
</el-table>
<div class="pager" v-if="tableData.total > 0">
<dm-pagination
background
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="tableData.currentPage"
:page-sizes="tableData.pageSizeList"
:page-size="tableData.pageSize"
layout="total, sizes, prev, pager, next"
:total="tableData.total"
>
</dm-pagination>
</div>
</div>
</div>
</template>
<script>
import dickerPickMixin from './mixins/datePickRuleMixin';
import paginationMixins from './mixins/paginationMixins';
export default {
name: 'wechat',
props: {
tableData: Object
},
mixins: [ dickerPickMixin, paginationMixins ],
data() {
return {
search: {
beginTime: '',
endTime: '',
contentType: null
},
contentTypeList: [
{ label: '图文消息', value: 0 },
{ label: '文本消息', value: 1 },
{ label: '图片', value: 2 }
]
}
},
methods: {
change() {
const { currentPage, pageSize } = this.tableData;
this.search.beginTime = this.time ? ( typeof this.time[0] == 'string ' ? this.time[0] : this.dateformat(new Date(this.time[0]), 'yyyy-MM-dd')) : null;
this.search.endTime = this.time ? ( typeof this.time[0] == 'string ' ? this.time[1] : this.dateformat(new Date(this.time[1]), 'yyyy-MM-dd')) : null;
const commonObj = { currentPage, pageSize };
this.$emit("changeSearch", Object.assign({}, this.search, commonObj));
},
}
};
</script>
<style scoped>
@import './css/all.scss';
</style>
<template>
<div class="marketing-record">
<div class="min20">
<nav-path :navpath="navpath"></nav-path>
<div class="marketing-container">
<div class="tabs">
<el-tabs v-model="tabsIndex" @tab-click="handleClick">
<el-tab-pane label="智能营销" name="1">
<ecm-record ref="ecmRecord" :tableData="ecmTableData" @changeSearch="onChange" />
</el-tab-pane>
<el-tab-pane label="卡券营销" name="2">
<card-record :tableData="cardTableData" @changeSearch="onChange" />
</el-tab-pane>
<el-tab-pane label="短信营销" name="3">
<message-record :tableData="messageTableData" @changeSearch="onChange" />
</el-tab-pane>
<el-tab-pane label="微信营销" name="4">
<wechat-record :tableData="wechatTableData" @changeSearch="onChange" />
</el-tab-pane>
</el-tabs>
</div>
</div>
</div>
</div>
</template>
<script>
import NavPath from "@/common/navbar/navbar.vue";
import ecmRecord from "./components/ecm.vue";
import cardRecord from "./components/card.vue";
import wechatRecord from "./components/wechat.vue";
import messageRecord from "./components/message.vue";
import { doFetch, doFetchqs } from "@/components/axios/api";
import { dateformat } from '@/utils/formatTime';
import url from "@/components/axios/url";
const { ecmLogPage, cardLogPage, messageLogPage, wechatLogPage, cardChannelType } = url;
export default {
name: "marketing-record",
components: {
NavPath,
ecmRecord,
cardRecord,
wechatRecord,
messageRecord
},
data() {
return {
navpath: [
{ name: "首页", path: "" },
{ name: "客户列表", path: "/allCustomers" },
{ name: "客户详情", path: '/customerDetail?memberId=' + this.$route.query.memberId || '' },
{ name: "营销记录", path: "" }
],
tabsIndex: "1",
search: {
msg: ""
},
ecmTableData: {
data: [],
currentPage: 1,
pageSizeList: [20, 40, 60, 80],
pageSize: 20,
total: 0,
tableHeader: [],
loading: false
},
wechatTableData: {
data: [],
currentPage: 1,
pageSizeList: [20, 40, 60, 80],
pageSize: 20,
total: 0,
tableHeader: [],
loading: false
},
messageTableData: {
data: [],
currentPage: 1,
pageSizeList: [20, 40, 60, 80],
pageSize: 20,
total: 0,
tableHeader: [],
loading: false
},
cardTableData: {
data: [],
currentPage: 1,
pageSizeList: [20, 40, 60, 80],
pageSize: 20,
total: 0,
tableHeader: [],
dictList: [],
loading: false
},
};
},
created() {
this.getTableHeader();
this.getCardChannelType();
// 触发第一个ecm子组件的change时候。触发自身的onChange
this.$nextTick(() => this.$refs.ecmRecord.change());
this.$store.commit("mutations-slide", true);
},
methods: {
async getTableData(tab, params) {
let res, name;
switch(tab) {
case "1":
name = 'ecmTableData';
this[name].loading = true;
res = await doFetchqs(ecmLogPage, params);
break;
case "2":
name = 'cardTableData';
this[name].loading = true;
res = await doFetchqs(cardLogPage, params);
break;
case "3":
name = 'messageTableData';
this[name].loading = true;
res = await doFetchqs(messageLogPage, params);
break;
case "4":
name = 'wechatTableData';
this[name].loading = true;
res = await doFetchqs(wechatLogPage, params);
break;
}
this.extendTable(this[name], res.data.result); // 赋值对应表格数据
this[name].loading = false;
},
getTableHeader() {
this.ecmTableData.tableHeader = [
{
label: "提交时间",
prop: "createDate",
minWidth: 80,
formatter(row) {
return `${row.createDate ? dateformat(new Date(row.createDate), 'yyyy-MM-dd hh:mm:ss') : '--'}`;
}
},
{ label: "计划名称", prop: "ecmName", minWidth: 120 },
{ label: "营销方式", prop: "marketingType", minWidth: 60, formatter(row) {
const type = row.marketingType;
switch(type) {
case 'integral':
return '积分';
case 'message':
return '短信';
case 'teltask':
return '话务';
case 'qfxx':
return '群发任务';
case 'teletext':
return '图文消息';
case 'image':
return '图片';
case 'text':
return '文本消息';
case 'wxa':
return '小程序';
case 'card':
return '卡券';
}
}
},
{ label: '营销内容', prop: "eventTitle", minWidth: 180 }
];
this.cardTableData.tableHeader = [
{
label: "投放时间",
prop: "createDate",
minWidth: 100,
formatter(row) {
return `${row.createDate ? dateformat(new Date(row.createDate), 'yyyy-MM-dd hh:mm:ss') : '--'}`;
}
},
{
label: "领取时间",
prop: "receiveTime",
minWidth: 100,
formatter(row) {
return `${row.receiveTime ? dateformat(new Date(row.receiveTime), 'yyyy-MM-dd hh:mm:ss') : '--'}`;
}
},
{ label: "卡券名称", prop: "cardName", minWidth: 100, },
{ label: "卡券代码", prop: "cardCode", minWidth: 100, },
{ label: "投放途径", prop: "receiveName", minWidth: 120, },
{ label: "来源明细", prop: "receiveTypeExcel", minWidth: 120, }
];
this.messageTableData.tableHeader = [
{
label: "发送时间",
prop: "createDate",
minWidth: 80,
formatter(row) {
return `${row.createDate ? dateformat(new Date(row.createDate), 'yyyy-MM-dd hh:mm:ss') : '--'}`;
}
},
{ label: "模板类型", prop: "smsType", minWidth: 50, formatter(row) {
return row.smsType == 1 ? '营销短信' : '普通短信'
} },
{ label: "模板名称", prop: "smsTitle", minWidth: 60, },
{ label: "模板内容", prop: "smsContent", minWidth: 220 }
];
this.wechatTableData.tableHeader = [
{
label: "提交时间",
prop: "createDate",
minWidth: 80,
formatter(row) {
return `${row.createDate ? dateformat(new Date(row.createDate), 'yyyy-MM-dd hh-mm-ss') : '--'}`;
}
},
{ label: "素材类型", prop: "contentType",minWidth: 60, formatter(row) {
const type = row.contentType;
switch(type) {
case 0:
return '图文消息';
case 1:
return '文本消息';
case 2:
return '图片';
}
}
},
{ label: "素材标题/文本内容", prop: "title",minWidth: 220,formatter(row) {
return row.title || '--';
}
}
];
},
// 设置表格数据
extendTable(tableObj, remoteData) {
tableObj['total'] = remoteData['totalCount'];
tableObj['currentPage'] = remoteData['currentPage'];
tableObj['data'] = remoteData['result'];
},
handleClick(tab) {
// 获取切换的组件实例重置数据, 注意不要改变el-tab-pane里的组件层级关系
const vm = tab.$children[0];
Object.assign(vm.$data, vm.$options.data.call(vm));
vm.change();
},
// 获取卡券营销所有投放渠道
async getCardChannelType() {
const res = await doFetch(cardChannelType, { businessType: "CARD_RECEIVE_TYPE" })
this.cardTableData.dictList = res.data.result.dictList;
},
// 子组件任何筛选项发生改变, 包括tab切换、父组件初始化都会触发
onChange(params) {
params.memberId = this.$route.query.memberId || '';
this.getTableData(this.tabsIndex, params);
}
}
};
</script>
<style lang="scss" scoped>
.marketing-container {
margin: 20px;
padding: 20px;
background-color: #fff;
}
.table {
.pager {
text-align: right;
padding: 20px 0;
}
}
.w160 {
width: 160px;
}
.w260 {
width: 260px;
}
</style>
......@@ -272,7 +272,7 @@
:current-page="currentPage"
:page-sizes="[20, 50, 75, 100]"
:page-size="pageSize"
layout="total, sizes, prev, pager, next, jumper"
layout="total, sizes, prev, pager, next"
:total="total"
>
</dm-pagination>
......
......@@ -327,6 +327,13 @@ export const constantRouterMap = [
title: '黑名单列表',
},
},
{
path: '/marketing-record',
component: _import('marketingRecord', 'index'),
meta: {
title: '营销记录',
},
},
],
},
];
......
......@@ -277,9 +277,9 @@
content: "\eb4d";
}
.icon-tubiao_tupiankongjian:before {
/* .icon-tubiao_tupiankongjian:before {
content: "\e656";
}
} */
.icon-video1:before {
content: "\e64b";
......@@ -937,9 +937,9 @@
content: "\ea30";
}
.icon-lianjie:before {
/* .icon-lianjie:before {
content: "\e627";
}
} */
.icon-duankailianjie:before {
content: "\e674";
......
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