Commit 53a40167 by 黑潮

Merge remote-tracking branch 'origin/feature/门店签到需求' into master

# Conflicts:
#	index.html
#	src/router/routes.js
parents 75dce083 57c7174f
......@@ -6,7 +6,8 @@ module.exports = {
parser: 'babel-eslint'
},
env: {
browser: true
browser: true,
"node": true
},
extends: [
// https://github.com/vuejs/eslint-plugin-vue#priority-a-essential-error-prevention
......@@ -28,7 +29,7 @@ module.exports = {
],
// allow async-await
'generator-star-spacing': 'off',
'no-console': 0,
'no-console': 0,
'no-alert': process.env.NODE_ENV === 'production' ? 2 : 0, //禁止使用alert confirm prompt
'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
// --------------------静态检测-----------------------------
......
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
!function(e){var n=window.webpackJsonp;window.webpackJsonp=function(r,c,o){for(var f,i,d,u=0,s=[];u<r.length;u++)i=r[u],t[i]&&s.push(t[i][0]),t[i]=0;for(f in c)Object.prototype.hasOwnProperty.call(c,f)&&(e[f]=c[f]);for(n&&n(r,c,o);s.length;)s.shift()();if(o)for(u=0;u<o.length;u++)d=a(a.s=o[u]);return d};var r={},t={16:0};function a(n){if(r[n])return r[n].exports;var t=r[n]={i:n,l:!1,exports:{}};return e[n].call(t.exports,t,t.exports,a),t.l=!0,t.exports}a.e=function(e){var n=t[e];if(0===n)return new Promise(function(e){e()});if(n)return n[2];var r=new Promise(function(r,a){n=t[e]=[r,a]});n[2]=r;var c=document.getElementsByTagName("head")[0],o=document.createElement("script");o.type="text/javascript",o.charset="utf-8",o.async=!0,o.timeout=12e4,a.nc&&o.setAttribute("nonce",a.nc),o.src=a.p+"static/js/"+({0:"card",1:"game",2:"wechat",3:"message",4:"ewash",5:"scan",6:"ecm",7:"evaluation",8:"activity",9:"cdKey",10:"recharge",11:"msg",12:"calllog",13:"signIn"}[e]||e)+"."+{0:"c713da56138b5476aad3",1:"398009c91a7388812f00",2:"1aad863c428279c5a169",3:"83c06aa714fa01a48b43",4:"2aea6e7dfdf4a40cb08d",5:"cbb700e6d6c4f353b03b",6:"4bc7117a17765999514d",7:"ecf8f42559b898ee9c01",8:"5ddb72b68fcdf6943011",9:"52134b24fc8b9e9e0f7a",10:"fd4ef6af3cd790ec9e39",11:"00a6edc9657c9e4c34fa",12:"f1c9fa1ccd0d36ae0602",13:"d1e25de5691f789d26f4"}[e]+".js";var f=setTimeout(i,12e4);function i(){o.onerror=o.onload=null,clearTimeout(f);var n=t[e];0!==n&&(n&&n[1](new Error("Loading chunk "+e+" failed.")),t[e]=void 0)}return o.onerror=o.onload=i,c.appendChild(o),r},a.m=e,a.c=r,a.d=function(e,n,r){a.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:r})},a.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return a.d(n,"a",n),n},a.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},a.p="/marketing/",a.oe=function(e){throw console.error(e),e}}([]);
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -42,6 +42,7 @@
<script src="//web-1251519181.file.myqcloud.com/components/activity-select.1.0.2.1.js"></script><!-- 数据对话 -->
<script src="//web-1251519181.file.myqcloud.com/components/upload-file.1.0.6.js"></script><!-- 文件上传 -->
<script src="//web-1251519181.file.myqcloud.com/components/card.2.0.20.js"></script><!-- 卡券弹窗 -->
<script src="//web-1251519181.file.myqcloud.com/components/radio-transfer.1.0.13.js"></script><!-- 单选穿梭框 -->
</body>
</html>
......@@ -103,5 +103,8 @@
"> 1%",
"last 2 versions",
"not ie <= 8"
]
],
"env": {
"node": true
}
}
......@@ -41,7 +41,7 @@ export default {
},
{
path: 'data-view/:id',
name: '数据对话数据概览',
name: '数据概览',
component: () => import(/* webpackChunkName: "activity" */ '../../views/activity/data-view.vue'),
meta: {
path: '/activity/list'
......
// 签到
export default {
path: 'sign',
name: '门店签到管理',
component: () => import(/* webpackChunkName: "signIn" */ '../../views/sign/index.vue'),
redirect: '/sign/list',
children: [
{
path: 'setting',
name: '门店签到设置',
component: () => import(/* webpackChunkName: "signIn" */ '../../views/sign/setting.vue'),
meta: {
path: '/sign/setting'
}
},
{
path: 'list',
name: '门店签到记录',
component: () => import(/* webpackChunkName: "signIn" */ '../../views/sign/list.vue'),
meta: {
path: '/sign/list'
}
}
]
};
......@@ -32,13 +32,15 @@ import cdKey from './modules/cdKey';
//弹窗推广
import pop from './modules/pop';
//签到
import signIn from './modules/signIn';
export default [
{
path: '/',
name: 'layout',
component: Layout,
redirect: '/wechat/record',
children: [card, ecm, scan, game, message, wechat, msg, calllog, recharge, evaluation, ewash, activity, cdKey, pop]
children: [card, ecm, scan, game, message, wechat, msg, calllog, recharge, evaluation, ewash, activity, cdKey, pop, signIn]
},
{
path: '/401',
......
......@@ -75,6 +75,9 @@ export const exportBackCoupExcel = config.api + PREFIX + 'export-back-coup-excel
//卡券营销--卡券记录--投放记录--删除记录
export const deleteCardPuton = params => requests(PREFIX + 'delete-card-puton', params);
//卡券营销--卡券记录--投放记录--刷新记录
export const refreshPutOnCount = params => requests(PREFIX + 'refresh-put-on-count', params);
//卡券营销--卡券记录--领取记录--核销--(1)获取满足核销条件的订单
export const listCoupcardOrder = params => requests(PREFIX + 'list-coupcard-order', params);
......
......@@ -42,3 +42,5 @@ export const exportBatchSendDetails = config.api + PREFIX + 'export-batch-send-d
// 智能营销--实时人员列表--导出csv
export const exportCurrentSendDetails = config.api + PREFIX + 'export-current-send-details';
export const getUseStoredFalg = params => requests(PREFIX + 'get-ecm-store-flag', params);
......@@ -41,3 +41,15 @@ export const rechargeStep2 = params => requests(PREFIX + 'recharge-step-3', para
//获取账户状态 是否欠费
export const getAccountStateInfo = params => requests(PREFIX + 'account-state-info', params);
//计费中心--消费详情-视频列表
export const videoPage = params => requests('api-mall/' + 'get-traffic-cost-page', params);
//计费中心--视频流量
export const todayVideoTraffic = params => requests('api-mall/' + 'today-traffic', params);
//计费中心--消费详情-视频折线图
export const videoChartData = params => requests('api-mall/' + 'get-traffic-cost-picture', params);
//计费中心--消费详情-视频列表-导出
export const downloadTrafficCostListExcel = config.api + 'api-mall/' + 'download-traffic-cost-list-execl';
import { requests } from './index';
const PREFIX = 'api-marketing/store-sign/';
import config from '@/config';
export const url = config.api + PREFIX;
// 获取门店签到记录分页列表
export const getPageSignLog = params => requests(PREFIX + 'page-sign-log', params);
// 门店签到配置保存
export const saveStoreSignSetting = params => requests(PREFIX + 'save', params);
// 门店签到配置查询
export const getStoreSignDetail = params => requests(PREFIX + 'get-detail', params);
......@@ -180,7 +180,7 @@ export default {
},
created() {
this.$store.commit('aside_handler', false);
this.$store.commit('mutations_breadcrumb', [{ name: '数据对话', path: '/activity/list' }, { name: '数据概览', path: '' }]); // eslint-disable-line
this.$store.commit('mutations_breadcrumb', [{ name: '数据对话', path: '/activity/list' }, { name: '数据概览', path: '' }]); // eslint-disable-line
}
};
</script>
......
......@@ -20,7 +20,8 @@
</div>
</el-form-item>
<el-form-item label="门店范围">
<vue-gic-store-new :options="options" :isAdd="isAdd" :creatorId="creatorId" :scenesVal="scenes" scenes="auth" :uuid.sync="ruleForm.storeGroup" ref="storeNew" @store-change="storeChange"></vue-gic-store-new>
<!-- ruleForm.storeGroup:{{ ruleForm.storeGroup }}==info.storeGroup:{{ info.storeGroup }} -->
<vue-gic-store-new :options="options" :isAdd="isAdd" :creatorId="creatorId" :scenesVal="scenes" scenes="auth" :uuid="ruleForm.storeGroup" ref="storeNew" @store-change="storeChange"></vue-gic-store-new>
<div v-if="disabled && info.storeGroup != ruleForm.storeGroup" class="gray fz12"><i class="el-icon-warning mr5 red fz12"></i>数据对话已生效,门店修改无效</div>
</el-form-item>
<el-form-item>
......@@ -159,10 +160,8 @@ export default {
});
},
// *********门店选择器********
storeChange() {
return;
// if (this.disabled) {
// }
storeChange(storeId) {
this.ruleForm.storeGroup = storeId;
},
// *********会员分组**********
handleDataTransferred(data) {
......
......@@ -41,8 +41,9 @@
</template>
</el-table-column>
<el-table-column min-width="100" align="left" prop="creatorName" label="创建人" v-if="$store.state.marketing.openFlag"></el-table-column>
<el-table-column label="操作" align="left" width="150px" fixed="right">
<el-table-column label="操作" align="left" width="180px" fixed="right">
<template slot-scope="scope">
<el-button type="text" @click="refreshPutOnCount(scope.row.putonId)" v-if="scope.row.issuingQuantity - scope.row.getedQuantity > 0">刷新</el-button>
<el-button type="text" v-if="scope.row.putonStatus === 2 || scope.row.putonStatus === 3" @click="$router.push('/card/groupinfo/' + scope.row.putonId)">详情</el-button>
<el-button type="text" v-if="scope.row.putonStatus !== 2 && scope.row.putonStatus !== 3 && scope.row.canEdit !== false && scope.row.putonStatus !== 5 && scope.row.putonStatus !== 6" @click="$router.push('/card/groupsend/' + scope.row.putonId)">编辑</el-button>
<el-button type="text" v-if="scope.row.putonTime > nowDate" @click="$router.push('/card/record/sendInfo/' + scope.row.putonId)">记录</el-button>
......@@ -56,7 +57,7 @@
</section>
</template>
<script>
import { cardRecordPage, deleteCardPuton } from '@/service/api/cardApi.js';
import { cardRecordPage, deleteCardPuton, refreshPutOnCount } from '@/service/api/cardApi.js';
import { formatDateTimeByType } from '@/utils/index.js';
import timeCounts from '@/components/timeCount/index.vue';
import tableMethods from '@/mixins/tableMethods.js';
......@@ -159,6 +160,17 @@ export default {
this.$tips({ type: 'error', message: '删除失败!' });
});
},
// 刷新当条营销记录
refreshPutOnCount(putonId) {
refreshPutOnCount({ cardPutOnId: putonId }).then(res => {
if (res.errorCode === 0) {
this.$tips({ type: 'success', message: '更新成功!' });
this.getTableList();
} else {
this.$tips({ type: 'error', message: '更新失败!' });
}
});
},
filterStatus(val) {
let result = { label: '执行错误', type: 'danger' };
switch (val) {
......
......@@ -5,6 +5,7 @@
<el-select class="dm-select" clearable v-model="listParams.success" placeholder="所有条件" @change="search">
<el-option v-for="(v, i) in successOptions" :key="i" :label="v.label" :value="v.value"></el-option>
</el-select>
<!-- <el-button type="text" @click="goHistory"> 历史记录</el-button> -->
<el-button icon="iconfont icon-icon_yunxiazai" class="fr" type="primary" @click="exportCurrentSendDetails"> 导出列表</el-button>
</div>
<div class="dm-wrap">
......@@ -185,6 +186,9 @@ export default {
this.listParams.ecmMarketingTypeRelationIds = list;
this.ecmCurrentSendDetails();
},
// goHistory() {
// },
search() {
this.listParams.currentPage = 1;
this.ecmCurrentSendInfos();
......
import { _debounce } from '@/utils/index';
import { getEcmInfo, saveEcmInfo } from '@/service/api/ecmApi.js';
import { getEcmInfo, saveEcmInfo, getUseStoredFalg } from '@/service/api/ecmApi.js';
import { getCardManualSetting } from '@/service/api/cardApi.js';
import { listTemplateVariables } from '@/service/api/msgApi.js';
import { klflStrategy } from '@/service/api/gameApi.js'; // 会员等级列表接口
......@@ -19,7 +19,7 @@ export default {
creatorId: '',
code: '1001',
loading: false,
effectActionOptions: [{ value: 'subscribe', label: '关注触发' }, { value: 'authentication', label: '认证触发' }, { value: 'consume', label: '消费触发' }, { value: 'upgrade', label: '会员卡升级触发' }, { value: 'degrade', label: '会员卡降级触发' }], // eslint-disable-line
effectActionOptions: [{ value: 'subscribe', label: '关注触发' }, { value: 'authentication', label: '认证触发' }, { value: 'consume', label: '消费触发' }, { value: 'upgrade', label: '会员卡升级触发' }, ], // eslint-disable-line
marketingTimesTypeOptions: [{ value: 0, label: '总共触发' }, { value: 1, label: '每天触发' }, { value: 2, label: '每周触发' }, { value: 3, label: '每月触发' }, { value: 4, label: '每年触发' }, { value: -1, label: '无限次触发' }], // eslint-disable-line
execDateType: [
{ label: '每天', value: 1 },
......@@ -79,7 +79,9 @@ export default {
lowest_cost_count: '',
max_cost_count: '',
// store_mode: 0,
order_store: ''
order_store: '',
storedLowest: 0,
storedMax: 0
},
template: {
headerColor: '#173177',
......@@ -146,7 +148,9 @@ export default {
count: false, // 消费件数
good: false // 消费商品
},
discount_limit: { type: 1, count: undefined, flag: false } // 适用商品折扣
storedChecked: false,
discount_limit: { type: 1, count: undefined, flag: false }, // 适用商品折扣
useStoredFlag: 0 //显示储值触发和会员卡升级事件
};
},
components: {
......@@ -390,6 +394,13 @@ export default {
}
});
}
if (this.form.effectAction === 'stored' && result.effectTriggerJson) {
let cost = JSON.parse(result.effectTriggerJson) || {};
this.storedChecked = true;
this.form.storedLowest = cost.lowest_cost;
this.form.storedMax = cost.max_cost;
}
}
if (!this.form.templateUseEnable) return;
let template = null;
......@@ -620,6 +631,17 @@ export default {
return;
}
}
// 如果是储值触发
if (this.form.effectAction === 'stored') {
if (this.storedChecked && !this.form.storedLowest && !this.form.storedMax) {
this.$tips({ type: 'warning', message: '请填写储值金额区间值' });
return;
}
if (this.storedChecked && this.form.storedLowest && this.form.storedMax && this.form.storedLowest > this.form.storedMax) {
this.$tips({ type: 'warning', message: '储值金额区间值填写错误' });
return;
}
}
this.$refs[formName].validate(valid => {
if (valid) {
let params = {
......@@ -703,6 +725,9 @@ export default {
}
params = Object.assign(params, consumeObj); // 合并消费触发数据
}
if (this.form.effectAction === 'stored' && this.storedChecked) {
params.effectTriggerJson = JSON.stringify({ lowest_cost: this.form.storedLowest || 0, max_cost: this.form.storedMax || 0 });
}
params.marketingActivityId = this.form.marketingActivityId || ''; // 否 String 营销场景
// 如果适用人群-人群筛选器可编辑:需要调用await this.$refs.threshold.triggerPeopleSet(); 强制触发回显,否则数据保存有错误
// await this.triggerPeopleSet();
......@@ -1006,6 +1031,12 @@ export default {
);
},
created() {
getUseStoredFalg().then(res => {
this.useStoredFlag = res.result.useStoredFlag;
if (this.useStoredFlag) {
this.effectActionOptions.push({ value: 'stored', label: '储值触发' });
}
});
// 设置面包屑
let breadcrumbName = '智能营销编辑';
if (this.isAdd) {
......
......@@ -124,7 +124,7 @@
<el-button type="primary" @click="handleXxSyspClick" class="fl mt5" size="mini">{{ !isAdd ? '查看' : '编辑' }}</el-button>
<el-button v-show="xxSysp.filterAbbrInfo.length && isAdd" @click="handleXxSyspReset" class="fl mt5" size="mini">清空</el-button>
</div>
<div v-show="consumeChecked.good" class="fz12 gray">勾选消费商品后,消费金额、消费件数仅指适用消费商品的金额和件数。</div>
<div v-show="consumeChecked.good" class="fz12 gray" style="color:#f5222d">勾选消费商品后,消费金额、消费件数仅指适用消费商品的金额和件数。</div>
</div>
</div>
</el-form-item>
......@@ -143,7 +143,7 @@
<el-input-number controls-position="right" :disabled="!isAdd" v-model="discount_limit.count" :precision="2" :min="0" :max="10" class="w150"></el-input-number>&nbsp;&nbsp;
</div>
<span class="fz14 gray" v-else>不限制消费商品折扣</span>
<div v-if="discount_limit.flag" class="fz12 gray">* 商品折扣=订单实付/订单总金额</div>
<div v-if="discount_limit.flag" class="fz12 gray">* 商品折扣 = 订单项实付金额 / 订单项应付金额</div>
</div>
</div>
</el-form-item>
......@@ -187,6 +187,30 @@
</el-select>
</el-form-item>
</section>
<!-- 储值触发配置 -->
<section class="dm-form__wrap" v-if="form.effectType == 0 && form.effectAction === 'stored'">
<h3 class="dm-title__label">
储值触发配置
<i class="dm-title__label--icon iconfont icon-xinxixianshi"></i>
<span class="gray fz13">仅适用于线下单笔充值场景;消费、退款等不会触发</span>
</h3>
<p class="fz14 gray mb20 ml10">同时满足以下条件即可触发</p>
<el-form-item>
<div class="no_label_form_label">
<el-checkbox class="el-form-item__label align-left" :disabled="!isAdd" v-model="storedChecked">储值金额</el-checkbox>
<div>
<span class="fz14 gray" v-show="!storedChecked">任意储值金额</span>
<div v-show="storedChecked">
<el-input-number :disabled="!isAdd" controls-position="right" min="" :max="1000000" style="width:150px;" v-model="form.storedLowest"></el-input-number>
<span class="ml5 mr5"></span>
<el-input-number :disabled="!isAdd" controls-position="right" min="" :max="1000000" style="width:150px;" v-model="form.storedMax"></el-input-number>
<span class="pl5"></span>
<el-popover placement="right" title="" width="200" trigger="hover" content="最大值最小值可选填其一或两个都填写,包含边界值"><i class="el-icon-info ml5 gray" slot="reference"></i></el-popover>
</div>
</div>
</div>
</el-form-item>
</section>
<!-- 营销次数配置 重复 -->
<section class="dm-form__wrap" v-if="form.effectType == 1">
<h3 class="dm-title__label">
......@@ -251,7 +275,7 @@
<section class="dm-form__wrap">
<h3 class="dm-title__label">营销事件</h3>
<!-- 只有实时才是单图文 -->
<marketing-event :readOnly="isInfo" show-out-coupon-icon ref="marketingEvent" @has-card="hasCard" v-if="ecmPlanId" :singleFlag="form.effectType === 0" :integralMultiple="form.effectAction === 'consume'" :ecmPlanId="ecmPlanId" :isSupportVar="form.effectType === 0" :code="code" :enabledMessageState="enabledMessageState" :cardLimitType="-1"></marketing-event>
<marketing-event :readOnly="isInfo" show-out-coupon-icon ref="marketingEvent" @has-card="hasCard" v-if="ecmPlanId" :singleFlag="form.effectType === 0" :integralMultiple="form.effectAction === 'consume'" :ecmPlanId="ecmPlanId" :isSupportVar="form.effectType === 0" :code="code" :enabledMessageState="enabledMessageState" :cardLimitType="-1" :use-stored="useStoredFlag"></marketing-event>
<!-- 只有非实时&&选择卡券了展示提示 -->
<div v-if="currentCard.comName && form.effectType != 0 && couponAutoGetFlag" class="fz13 regular-font-color line-height2" style="margin-left:120px;margin-top:30px;">
* 用户在领取卡券后需要<b class="bold">同步至ERP</b>,如果关闭用户<b class="bold">手动领取</b>,卡券在<b class="bold">批量投放</b>时会需要将卡券信息批量同步至ERP。 <br />
......
......@@ -44,7 +44,7 @@
</template>
<script>
import activitySelect from '@/components/activity-select/index.vue';
import { loadEcmList, deleteEcm, offlineEcmPlan } from '@/service/api/ecmApi.js';
import { loadEcmList, deleteEcm, offlineEcmPlan, getUseStoredFalg } from '@/service/api/ecmApi.js';
import { formatDateTimeByType } from '@/utils/index.js';
const marketingTypeOptions = [{ value: '', label: '所有发送类型' }, { value: 'card', label: '卡券营销' }, { value: 'message', label: '短信营销' }, { value: 'teletext', label: '图文营销' }, { value: 'text', label: '文本营销' }, { value: 'teltask', label: '话务' }, { value: 'image', label: '微信图片' }]; // eslint-disable-line
export default {
......@@ -130,6 +130,11 @@ export default {
activitySelect
},
created() {
getUseStoredFalg().then(res => {
if (res.result.useStoredFlag) {
this.marketingTypeOptions.push({ value: 'grade', label: '会员卡升级' });
}
});
this.loadEcmList();
this.$store.commit('aside_handler', false);
this.$store.commit('mutations_breadcrumb', [{ name: '营销管理', path: '' }, { name: '智能营销', path: '/ecm' }]); // eslint-disable-line
......
......@@ -164,3 +164,6 @@ export const deleteMarketingType = params => requests(PREFIX + 'delete-marketing
//模板库--分页列表 (有效)
export const LoadTempList = params => requests(PREFIX + 'load-message-templateList', params);
//会员等级
export const getCardLevelList = params => requests('api-plug/member-grade-list', params);
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1616486164284" class="icon" viewBox="0 0 1025 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7879" xmlns:xlink="http://www.w3.org/1999/xlink" width="200.1953125" height="200"><defs><style type="text/css"></style></defs><path d="M833.532723 837.12H22.524723c-7.168 0-14.848-4.096-18.432-9.728-4.608-6.144-5.12-13.824-2.56-20.992l168.96-604.16c3.584-9.216 11.776-14.848 21.504-14.848h810.496c7.168 0 14.848 4.096 18.432 9.728 4.608 6.144 5.12 13.824 2.56 20.992l-168.96 604.16c-3.072 8.704-11.264 14.848-20.992 14.848z m-777.728-46.08h761.856l152.064-558.592H207.868723L55.804723 791.04z" fill="#606266" p-id="7880"></path><path d="M833.532723 837.12H22.524723c-7.168 0-14.848-4.096-18.432-9.728-4.608-6.144-5.12-13.824-2.56-20.992l168.96-604.16c3.584-9.216 11.776-14.848 21.504-14.848h810.496c7.168 0 14.848 4.096 18.432 9.728 4.608 6.144 5.12 13.824 2.56 20.992l-168.96 604.16c-3.072 8.704-11.264 14.848-20.992 14.848z m-777.728-46.08h761.856l152.064-558.592H207.868723L55.804723 791.04z" fill="#606266" p-id="7881"></path><path d="M478.204723 393.216L372.732723 634.88H320.508723L219.132723 393.216H276.988723l70.656 182.272 72.192-182.272h58.368z m25.088 241.664V393.216h51.712V634.88H503.292723z m152.064-83.968V634.88h-51.712V393.216h120.832c22.016 0 37.888 1.536 47.104 4.608 15.872 5.12 28.672 16.384 37.888 33.28 6.656 12.288 10.24 26.624 10.24 40.96 0 12.288-2.048 24.064-6.656 34.816-4.608 11.264-10.752 20.48-18.432 27.136-7.168 6.144-15.36 10.752-23.04 12.8-7.68 2.048-18.944 3.584-33.28 3.584H655.868723l-0.512 0.512z m0-43.52h70.144c12.288 0 21.504-1.536 26.624-5.632 7.168-6.144 11.264-16.384 11.264-31.744 0-16.384-5.632-26.624-16.896-30.72-4.096-1.536-10.752-2.56-19.456-2.56H655.868723v70.656h-0.512z" fill="#606266" p-id="7882"></path></svg>
\ No newline at end of file
......@@ -189,16 +189,6 @@
min-width: 950px;
}
.dm-marketing__content__item::after {
content: '';
height: 1px;
width: 100%;
background: #E4E7ED;
display: block;
margin-left: 48px;
margin-top: 20px;
}
.dm-marketing__content--index{
display:inline-block;
width:24px;
......@@ -458,4 +448,12 @@
border-radius:4px;
display: inline-block;
position: relative;
}
\ No newline at end of file
}
.dm-grade__item__wrap {
width: 300px;
padding: 18px 20px;
border: 1px solid rgba(228,231,237,1);
border-radius:4px;
display: inline-block;
position: relative;
}
<template>
<div class="dm-grade__item__wrap">
<div class="fz16">会员卡升级</div>
<p class="mt15 fz24 primary-font-color">
{{ item.title }}
</p>
<p class="minor-font-color mt10 line-height1_5 fz12">*若当前会员卡等级超过该等级,则不会进行会员升级。</p>
</div>
</template>
<script>
export default {
name: 'item-grade',
props: {
item: {
type: Object,
default() {
return {};
}
}
}
};
</script>
File mode changed from 100755 to 100644
<template>
<el-dialog title="会员卡升级" :visible.sync="show" width="340px" @closed="close">
等级:
<el-select style="width:220px" v-model="cardLevel" placeholder="等级选择">
<el-option v-for="(el, i) in cardLevelList" :key="i" :label="el.value" :value="el.key"></el-option>
</el-select>
<p class="minor-font-color mt10 line-height1_5 fz12">*若当前会员卡等级超过该等级,则不会进行会员升级。</p>
<span slot="footer" class="dialog-footer">
<el-button @click="close">关 闭</el-button>
<el-button type="primary" @click="addItem">确 定</el-button>
</span>
</el-dialog>
</template>
<script>
import { getCardLevelList } from '../assets/api.js';
export default {
name: 'lib-grade',
props: {
item: {
type: Object,
default() {
return {};
}
},
show: {
type: Boolean,
default: false
}
},
data() {
return {
cardLevelList: [],
cardLevel: ''
};
},
mounted() {
getCardLevelList({ requestProject: 'marketing', key: 'memberGrade' }).then(res => {
if (res.errorCode === 0) {
this.cardLevelList = res.result;
} else {
this.$message({ type: 'warning', message: '接口异常' });
}
});
},
watch: {
show(val) {
if (val) {
this.cardLevel = this.item.relationId || '';
} else {
this.cardLevel = '';
}
}
},
methods: {
close() {
this.$emit('update:show', false);
},
addItem() {
if (!this.cardLevel) {
return this.$message({ type: 'warning', message: '未选择会员卡等级' });
}
let title = this.cardLevelList.find(item => item.key === this.cardLevel).value;
this.$emit('sendItem', { title, relationId: this.cardLevel, comName: 'grade' });
this.close();
}
}
};
</script>
......@@ -51,6 +51,7 @@ import itemImage from './components/item-image.vue';
import itemMessage from './components/item-Message.vue';
import itemTeltask from './components/item-teltask.vue';
import itemIntegral from './components/item-integral.vue';
import itemGrade from './components/item-grade';
//弹窗组件
import libTeletext from './components/lib-teletext.vue';
import libMessage from './components/lib-Message.vue';
......@@ -60,6 +61,7 @@ import libWxa from './components/lib-wxa.vue';
import libImage from './components/lib-image.vue';
import libTeltask from './components/lib-teltask.vue';
import libIntegral from './components/lib-integral.vue';
import libGrade from './components/lib-grade';
// 全部的操作项
// eslint-disable-next-line
......@@ -86,7 +88,9 @@ export default {
'lib-wxa': libWxa,
'lib-image': libImage,
'lib-teltask': libTeltask,
'lib-integral': libIntegral
'lib-integral': libIntegral,
'item-grade': itemGrade,
'lib-grade': libGrade
},
props: {
// 页面编码——- 1001-智能引擎; 1002-微信营销; 1003-被关注回复; 1004-关键字回复
......@@ -130,6 +134,10 @@ export default {
showOutCouponIcon: {
type: Boolean,
default: false
},
useStored: {
type: Number,
default: 0
}
},
data() {
......@@ -145,6 +153,9 @@ export default {
};
},
created() {
if (this.useStored) {
allOptions.push({ name: '会员卡升级', value: 'grade', key: 9, img: require('./assets/img/grade.svg') }); //eslint-disable-line
}
this.init();
},
methods: {
......@@ -206,6 +217,9 @@ export default {
this.list.push({ comName: 'item-integral', item: { multipleNum: v.multipleNum, integralType: v.integralType, integralCount: v.integralCount, ecmMarketingTypeRelationId: v.ecmMarketingTypeRelationId, relationId: v.relationId, ecmPlanId: v.ecmPlanId } });
// this.list.push({ comName: 'item-teltask', item: { ...v.teltask, ecmMarketingTypeRelationId: v.ecmMarketingTypeRelationId, relationId: v.relationId, ecmPlanId: v.ecmPlanId } });
break;
case 'grade': // 8 积分
this.list.push({ comName: 'item-grade', item: { title: v.title } });
break;
}
});
this.hasReturnCard();
......@@ -290,6 +304,12 @@ export default {
params.title = `${val.multipleNum}倍积分`;
}
}
//9.会员卡升级
if (val.comName === 'grade') {
params.title = val.title;
params.relationId = val.relationId;
}
// 接口请求 保存
saveUpdateMarketingType({ marketingType: JSON.stringify(params) })
.then(res => {
......@@ -305,6 +325,10 @@ export default {
this.$message({ type: 'warning', message: `最多只能添加${this.maxEventCount}个营销事件` });
return;
}
if (this.list.some(item => item.comName === 'item-grade')) {
this.$message({ type: 'warning', message: `已添加会员卡升级营销事件` });
return;
}
// 判断是否欠费
if (v.value === 'message' && this.checkAccountState()) return;
this.dialogCom = 'lib-' + v.value;
......
<template>
<el-dialog title="拼图配置" :visible.sync="show" width="40%" :before-close="close">
<div v-loading="loading">
<div class="layout--tips" style="margin-top:0">
<i class="el-icon-info"></i>
免费赠送游戏前提:需要在前一天玩过游戏
</div>
<div style="margin-top:20px" v-loading="loading">
<h3 class="fz16 pb20">机制设置</h3>
<h4 class="fz14 gray pb20">用户免费体力数</h4>
<el-radio v-model="form.sysGiveValueType" :label="1">
......
......@@ -89,6 +89,22 @@
</div>
</div>
</el-col>
<!-- <el-col :span="5">
<div class="recharge-today-item border2 clearfix">
<div class="text-center fl">
<div class="icon-box color6">
<i class="iconfont icon-shipinliuliang fz26"></i>
</div>
<p>视频流量</p>
</div>
<div class="text-center fr">
<p class="text-right">
<span class="fz30">{{ videoTraffic.traffic || 0 }}</span> GB
</p>
<p class="regular-font-color">合计费用:¥{{ videoTraffic.trafficCost | amount }}</p>
</div>
</div>
</el-col> -->
</el-row>
</div>
<div class="dm-wrap" v-loading="loading">
......@@ -102,8 +118,11 @@
<el-table-column align="left" prop="name" label="计费项目"></el-table-column>
<el-table-column align="left" prop="count" label="时长/条数">
<template slot-scope="scope">
<span>{{ scope.row.count }}</span>
{{ scope.row.type === 'call' || scope.row.type === 'record' ? '分钟' : '条' }}
<template v-if="scope.row.type === 'video'">{{ scope.row.count || 0 }} G</template>
<template v-else>
<span>{{ scope.row.count }}</span>
{{ scope.row.type === 'call' || scope.row.type === 'record' ? '分钟' : '条' }}
</template>
</template>
</el-table-column>
<el-table-column align="left" prop="fee" label="费用">
......@@ -130,7 +149,7 @@
</template>
<script>
import { rechargeCenter, consumeRecord } from '@/service/api/rechargeApi.js';
import { rechargeCenter, consumeRecord, todayVideoTraffic } from '@/service/api/rechargeApi.js';
import { formatDateTimeByType } from '@/utils/index.js';
export default {
......@@ -145,6 +164,7 @@ export default {
beginTime: '',
endTime: ''
},
videoTraffic: {},
pickerOptions: {
disabledDate(val) {
return Date.now() >= val.getTime() + 6 * 30 * 24 * 60 * 60 * 1000;
......@@ -156,6 +176,7 @@ export default {
this.$store.commit('aside_handler', false);
this.rechargeCenter();
this.consumeRecord();
// this.getTodayVideoTraffic();
this.$store.commit('mutations_breadcrumb', [{ name: '企业管理', path: '' }, { name: '计费中心', path: '' }]); // eslint-disable-line
},
filters: {
......@@ -167,6 +188,15 @@ export default {
}
},
methods: {
// 视频流量资费
async getTodayVideoTraffic() {
try {
let res = await todayVideoTraffic();
this.videoTraffic = res.result || {};
} catch (err) {
console.log(err);
}
},
async rechargeCenter() {
try {
let res = await rechargeCenter();
......@@ -187,6 +217,7 @@ export default {
try {
let res = await consumeRecord(this.listParams);
const result = res.result;
// , { name: '视频流量', type: 'video', fee: result.allTraffic, count: result.allTrafficCost }
this.tableList = [{ name: '短信营销', type: 'marketing', fee: result.messageFee, count: result.messageCount }, { name: '短信验证码', type: 'sms', fee: result.smsFee, count: result.smsCount }, { name: '语音验证码', type: 'voice', fee: result.voiceFee, count: result.voiceCount }, { name: '双向呼叫', type: 'call', fee: result.callFee, count: result.callTime }, { name: '通话录音', type: 'record', fee: result.recordCallfee, count: result.recordCallTime }]; // eslint-disable-line
} catch (err) {
console.log(err);
......@@ -225,6 +256,9 @@ export default {
&.color5 {
background: #f39925;
}
&.color6 {
background: #52c41a;
}
i {
line-height: 60px;
color: #fff;
......
<template>
<section class="recharge">
<div class="dm-wrap">
日期:<el-date-picker :pickerOptions="pickerOptions" v-model="dateTime" type="daterange" range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" @change="loadAll(false)"></el-date-picker>
日期:<el-date-picker :clearable="false" :pickerOptions="pickerOptions" v-model="dateTime" type="daterange" range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" @change="loadAll(false)"></el-date-picker>
<span class="fz12 gray">* 此处仅支持筛选近半年的统计数据</span>
</div>
<div class="dm-form__wrap">
<h3 class="dm-title__label">趋势分析图</h3>
<div class="text-center fz16" v-if="$route.params.type === 'record'">{{ formatDateTimeByType(dateTime[0], 'yyyy-MM-dd') }}{{ formatDateTimeByType(dateTime[1], 'yyyy-MM-dd') }} 成功存储:{{ sumCount || 0 }} 分钟 总计消费:{{ (sumFee / 100).toFixed(2) }}</div>
<div class="text-center fz16" v-if="$route.params.type === 'video'">{{ formatDateTimeByType(dateTime[0], 'yyyy-MM-dd') }}{{ formatDateTimeByType(dateTime[1], 'yyyy-MM-dd') }} 共消耗流量{{ sumCount }}MB 累计支出{{ sumFee }}</div>
<div class="text-center fz16" v-else>{{ formatDateTimeByType(dateTime[0], 'yyyy-MM-dd') }}{{ formatDateTimeByType(dateTime[1], 'yyyy-MM-dd') }} 成功发送:{{ sumCount || 0 }} 条 总计消费:{{ (sumFee / 1000).toFixed(2) }}</div>
<div>
<div id="mountNode" ref="mountNode" v-show="list.length"></div>
......@@ -14,7 +15,14 @@
</div>
</div>
<div class="dm-form__wrap" v-loading="loading">
<div class="pb22" style="overflow:hidden;line-height:40px;">
<div class="pb22" style="overflow:hidden;line-height:40px;" v-if="$route.params.type === 'video'">
<!-- 视频资费 -->
<el-date-picker :clearable="false" v-model="dateTimeVideo" type="daterange" range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" @change="changeVideoTime"></el-date-picker>
<span class="fz12 gray">* 此处时间跨度不超过7天</span>
<el-button type="primary" class="fr" icon="iconfont icon-icon_yunxiazai fz14 mr5" @click="downloadTrafficCostListExcel">导出记录</el-button>
</div>
<div v-else class="pb22" style="overflow:hidden;line-height:40px;">
<!-- 非视频资费 -->
<!-- <el-select v-if="$route.params.type === 'call'" class="dm-select" v-model="taskType" placeholder="选择发送状态" @change="loadAll(true)">
<el-option v-for="item in taskTypeOptions" :key="item.taskType" :label="item.ecmName" :value="item.taskType"></el-option>
</el-select> -->
......@@ -187,12 +195,29 @@
<template slot-scope="scope"> {{ Number(scope.row.storageFee / 100).toFixed(2) }}</template>
</el-table-column>
</el-table>
<!-- 视频资费 -->
<el-table tooltipEffect="light" :data="tableList" style="width:100%" v-if="$route.params.type === 'video'">
<el-table-column align="left" prop="createTime" label="时间">
<template slot-scope="scope">
<p class="cell-time">
{{ formatDateTimeByType(scope.row.time, 'yyyy-MM-dd-HH-mm-ss') }}
</p>
</template>
</el-table-column>
<el-table-column align="left" prop="traffic" label="流量消耗统计">
<template slot-scope="scope"> {{ scope.row.traffic }}GB </template>
</el-table-column>
<el-table-column align="left" prop="trafficCost" label="流量费用支出">
<template slot-scope="scope"> ¥ {{ scope.row.trafficCost }} </template>
</el-table-column>
</el-table>
<dm-pagination v-show="tableList.length" background class="dm-pagination" @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="listParams.currentPage" :page-sizes="[20, 40, 60, 80]" :page-size="listParams.pageSize" layout="total, sizes, prev, pager, next" :total="total"></dm-pagination>
</div>
<vue-gic-export-excel :dialogVisible.sync="dialogVisible" :dataArr="tableList" :type="2" :excelUrl="excelUrl" :params="params" :projectName="projectName"></vue-gic-export-excel>
</section>
</template>
<script>
import { messageMarketingChart, messageMarketingPage, smsData, voiceData, callData, recordData } from '@/service/api/rechargeApi.js';
import { messageMarketingChart, messageMarketingPage, smsData, voiceData, callData, recordData, videoPage, videoChartData, downloadTrafficCostListExcel } from '@/service/api/rechargeApi.js';
import { formatDateTimeByType } from '@/utils/index.js';
import G2 from '@antv/g2';
export default {
......@@ -204,6 +229,8 @@ export default {
defaultAvatar: require('../../assets/img/head_default.png'),
formatDateTimeByType,
dateTime: [Date.now() - 30 * 24 * 60 * 60 * 1000, Date.now()],
dateTimeVideo: [Date.now() - 7 * 24 * 60 * 60 * 1000, Date.now()],
dateTimeVideoCopy: [Date.now() - 7 * 24 * 60 * 60 * 1000, Date.now()],
loading: false,
tableList: [],
listParams: {
......@@ -223,7 +250,18 @@ export default {
disabledDate(val) {
return Date.now() >= val.getTime() + 6 * 30 * 24 * 60 * 60 * 1000;
}
}
},
videoListParams: {
currentPage: 1,
pageSize: 20,
requestProject: 'marketing',
startTime: '',
endTime: ''
},
projectName: 'marketing', // 当前项目名
dialogVisible: false,
excelUrl: '', // 下载数据的地址
params: {} // 传递的参数
};
},
created() {
......@@ -282,6 +320,12 @@ export default {
}
this.recordData('list');
}
if (this.$route.params.type === 'video') {
if (!onlyList) {
this.videoPage('charts');
}
this.videoPage('list');
}
},
async marketingList() {
this.loading = true;
......@@ -406,6 +450,62 @@ export default {
} catch (err) {}
this.loading = false;
},
// 视频资费相关接口
async videoPage(type = 'list') {
this.loading = true;
try {
this.videoListParams.startTime = formatDateTimeByType(this.dateTimeVideo[0], 'yyyy-MM-dd');
this.videoListParams.endTime = formatDateTimeByType(this.dateTimeVideo[1], 'yyyy-MM-dd');
if (type === 'list') {
let res = await videoPage(this.videoListParams);
if (res.errorCode === 0 && res.result.result) {
this.tableList = res.result.result || [];
this.total = res.result.totalCount;
} else {
this.tableList = [];
}
} else if (type === 'charts') {
const params = { ...this.listParams, startTime: this.listParams.beginTime };
let res = await videoChartData(params);
this.sumCount = res.result.sumCount;
this.sumFee = res.result.sumFee;
let chartList = res.result.chartList || [];
let list = [];
chartList.map(v => {
list.push({ day: v.chartsDate, name: '支出费用', temperature: v.trafficCost || 0 });
});
list.sort((a, b) => {
return a.temperature - b.temperature;
});
this.list = list;
this.$nextTick(_ => {
this.initCharts(list, 'mountNode');
});
}
} catch (err) {}
this.loading = false;
},
// 修改视频时间 范围不能超过7天
changeVideoTime(date) {
// 单张卡券可以设置领取n久
if (new Date(this.dateTimeVideo[1]).getTime() - new Date(this.dateTimeVideo[0]).getTime() > 7 * 24 * 60 * 60 * 1000) {
this.$tips({ message: '领取时间段范围不能超过7天', type: 'warning' });
this.dateTimeVideo = [...this.dateTimeVideoCopy];
return;
}
this.dateTimeVideoCopy = [...this.dateTimeVideo];
this.videoPage('list');
},
// 导出
downloadTrafficCostListExcel() {
this.dialogVisible = true;
this.excelUrl = downloadTrafficCostListExcel;
this.params = {
startTime: formatDateTimeByType(this.dateTimeVideo[0], 'yyyy-MM-dd'),
endTime: formatDateTimeByType(this.dateTimeVideo[1], 'yyyy-MM-dd'),
requestProject: 'marketing'
};
},
async recordData(type = 'list') {
this.loading = true;
try {
......
import qs from 'qs';
import axios from 'axios';
const host = window.location.origin;
const PREFIX = '/api-marketing/';
const PLUG_PREFIX = '/api-plug/';
// eslint-disable-next-line
const router = new VueRouter();
// 加载最小时间
const MINI_TIME = 300;
// 超时时间
let TIME_OUT_MAX = 20000;
// 环境value
// 请求接口host
let _apiHost = host.indexOf('localhost') !== -1 ? 'http://gicdev.demogic.com' : host;
// 请求组(判断当前请求数)
let _requests = [];
//创建一个请求实例
const instance = axios.create({
baseURL: _apiHost,
timeout: TIME_OUT_MAX,
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
withCredentials: true // 允许携带cookie
});
/**
* 添加请求,显示loading
* @param {请求配置} config
*/
function pushRequest(config) {
console.log(`${config.url}--begin`);
_requests.push(config);
}
/**
* 移除请求,无请求时关闭loading
* @param {请求配置} config
*/
function popRequest(config) {
console.log(`${config.url}--end`);
let _index = _requests.findIndex(r => {
return r === config;
});
if (_index > -1) {
_requests.splice(_index, 1);
}
}
/**
* 错误的处理
* @param {*} code
* @param {string} [message='请求错误']
*/
function handlerErr(code, message = '请求错误') {
switch (code) {
case 404:
message = '404,错误请求';
router.push('/404');
break;
case 401:
message = '登录失效';
break;
case 403:
message = '禁止访问';
router.push('/403');
break;
case 408:
message = '请求超时';
break;
case 500:
message = '服务器内部错误';
// router.push('/500')
break;
case 501:
message = '功能未实现';
break;
case 503:
message = '服务不可用';
break;
case 504:
message = '网关错误';
break;
}
this.$message({ type: 'warning', message: message });
}
/**
* 请求地址,请求数据,是否静默,请求方法
*/
const requests = (url, data = {}, contentTypeIsJSON = false, isSilence = false, method = 'POST') => {
let _opts = { method, url };
const _query = {};
let _timer = null;
if (method.toLocaleUpperCase() === 'POST') {
if (contentTypeIsJSON) {
_opts.data = data;
_opts.headers = { 'Content-Type': 'application/json' };
_opts.url += '?requestProject=marketing';
} else {
_opts.data = qs.stringify(Object.assign({ requestProject: 'gic-web' }, data));
}
} else {
_opts.params = _query;
}
return new Promise((resolve, reject) => {
let _random = { stamp: Date.now(), url: `${_apiHost + url}` };
if (!isSilence) {
_timer = setTimeout(() => {
pushRequest(_random);
}, MINI_TIME);
}
instance(_opts)
.then(res => {
clearTimeout(_timer);
popRequest(_random);
if (res.data.errorCode !== 0) {
reject(res);
handlerErr(res.data.errorCode, res.data.message);
} else {
resolve(res.data);
}
})
.catch(res => {
clearTimeout(_timer);
popRequest(_random);
if (res) {
handlerErr(res.response.status, '接口异常');
}
reject(res);
});
});
};
// 获取营销事件配置信息(类型, 最大条数)
export const getMarketingEvent = params => requests(PREFIX + 'get-marketing-event', params);
//素材库 图文 图文分页列表
export const loadImgTextList = params => requests(PREFIX + 'page-marketing-wechat-image-text', params);
//获取卡券列表
export const getCardList = params => requests(PLUG_PREFIX + 'get-coupon-list', params);
//素材库--图片--图片分页列表
export const loadImgList = params => requests(PREFIX + 'page-marketing-wechat-image', params);
//素材库--图片--编辑图片名称
export const updateImgName = params => requests(PREFIX + 'update-marketing-wechat-image-titlename', params);
//素材库--图片--新建图片分组
export const addGroupService = params => requests(PREFIX + 'save-marketing-wechat-image-group', params);
//素材库--图片--修改图片分组
export const updateGroupName = params => requests(PREFIX + 'update-marketing-wechat-image-group', params);
//素材库--图片--删除图片分组
export const deleteGroupService = params => requests(PREFIX + 'delete-marketing-wechat-image-group', params);
// 智能营销--ECM营销引擎-- 新建/修改 --回显营销事件类型详情
export const getMarketingTypeDetails = params => requests(PREFIX + 'get-marketing-type-details', params);
// 智能营销--新增/修改营销事件类型
export const saveUpdateMarketingType = params => requests(PREFIX + 'save-update-marketing-type', params);
// 智能营销 --删除营销事件
export const deleteMarketingType = params => requests(PREFIX + 'delete-marketing-Type', params);
//模板库--分页列表 (有效)
export const LoadTempList = params => requests(PREFIX + 'load-message-templateList', params);
'use strict';
/* eslint-disable */
exports.__esModule = true;
function _broadcast(componentName, eventName, params) {
this.$children.forEach(function(child) {
var name = child.$options.componentName;
if (name === componentName) {
child.$emit.apply(child, [eventName].concat(params));
} else {
_broadcast.apply(child, [componentName, eventName].concat([params]));
}
});
}
exports.default = {
methods: {
dispatch: function dispatch(componentName, eventName, params) {
var parent = this.$parent || this.$root;
var name = parent.$options.componentName;
while (parent && (!name || name !== componentName)) {
parent = parent.$parent;
if (parent) {
name = parent.$options.componentName;
}
}
if (parent) {
parent.$emit.apply(parent, [eventName].concat(params));
}
},
broadcast: function broadcast(componentName, eventName, params) {
_broadcast.call(this, componentName, eventName, params);
}
}
};
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg fill="#909399" class="icon" width="200px" height="200.00px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M180.224 610.304c0 76.8-56.32 142.336-132.608 153.088v134.144h928.256v-134.144c-76.288-10.752-133.12-76.288-133.12-153.088s56.32-142.336 133.12-153.088V323.072H47.616v134.144c76.288 10.752 132.608 76.288 132.608 153.088zM3.584 477.696V300.544c0-6.144 2.048-11.264 6.656-15.872 4.096-4.096 9.728-6.656 15.872-6.656H998.4c6.144 0 11.264 2.048 15.872 6.656 4.096 4.096 6.656 9.728 6.656 15.872v176.64c0 6.144-2.048 11.264-6.656 15.872-4.096 4.096-9.728 6.656-15.872 6.656-60.928 0-110.592 49.664-110.592 110.592s49.664 110.592 110.592 110.592c6.144 0 11.264 2.048 15.872 6.656 4.096 4.096 6.656 9.728 6.656 15.872v176.64c0 6.144-2.048 11.264-6.656 15.872-4.096 4.096-9.728 6.656-15.872 6.656H25.6c-6.144 0-11.264-2.048-15.872-6.656-4.096-4.096-6.656-9.728-6.656-15.872v-176.64c0-6.144 2.048-11.264 6.656-15.872 4.096-4.096 9.728-6.656 15.872-6.656 60.928 0 110.592-49.664 110.592-110.592 0-60.928-49.664-110.592-110.592-110.592-6.144 0-11.264-2.048-15.872-6.656-4.096-4.096-6.144-9.728-6.144-15.36z m377.856-223.744c-11.776 3.072-24.064-4.096-27.136-15.872-3.072-11.776 4.096-24.064 15.872-27.136l467.968-124.928c11.776-3.072 24.064 4.096 27.136 15.872l26.112 98.304c3.072 11.776-4.096 24.064-15.872 27.136-11.776 3.072-24.064-4.096-27.136-15.872l-20.48-76.8-446.464 119.296zM666.112 389.12c0-12.288 9.728-22.016 22.016-22.016s22.016 9.728 22.016 22.016v88.576c0 12.288-9.728 22.016-22.016 22.016s-22.016-9.728-22.016-22.016V389.12z m0 176.64c0-12.288 9.728-22.016 22.016-22.016s22.016 9.728 22.016 22.016v88.576c0 12.288-9.728 22.016-22.016 22.016s-22.016-9.728-22.016-22.016v-88.576z m0 176.64c0-12.288 9.728-22.016 22.016-22.016s22.016 9.728 22.016 22.016v88.576c0 12.288-9.728 22.016-22.016 22.016s-22.016-9.728-22.016-22.016V742.4z" /></svg>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 204.9 200" style="enable-background:new 0 0 204.9 200;" xml:space="preserve">
<style type="text/css">
.st0{fill:#909399;}
</style>
<path class="st0" d="M204,139c0-10-7.5-19-21-26V95.5v-1V93c0-1.5,0-3-0.5-4.5c14-7,21.5-16.5,21.5-26v-18v-1V42
c0-22.5-39-39.5-90.5-39.5c-52,0-91,17-91,39.5v20c0,1.5,0,3,0.5,4.5C9,73.5,1.5,83,1.5,92.5v20c0,10,7.5,19,21,26v20
c0,22.5,39,39.5,90.5,39.5s90.5-17,90.5-39.5v-18v-1C204,140,204,139.5,204,139L204,139z M190.5,43c-1,4-4,7.5-9.5,11
c-14.5,9.5-40,15-68,15c-47,0-75-14.5-77.5-25.5v-1C35.5,29,73,16,113,16s77.5,13,77.5,26.5L190.5,43L190.5,43z M41.5,67
c1.5,1,3,1.5,5,2.5l1,0.5c1.5,0.5,2.5,1,4,2l1.5,0.5l4.5,1.5l1,0.5c2,0.5,4,1,6,2L66,77c1.5,0.5,3.5,1,5,1l2,0.5
c1.5,0.5,3.5,0.5,5,1l2,0.5c2.5,0.5,4.5,0.5,7,1h1.5c2,0,4,0.5,6,0.5H97c1.5,0,3.5,0,5.5,0.5h21c1.5,0,3.5,0,5-0.5h3
c2,0,3.5-0.5,5.5-0.5h2c2.5-0.5,4.5-0.5,7-1l2.5-0.5c1.5-0.5,3-0.5,4.5-1l2.5-0.5c1.5-0.5,3-0.5,4.5-1l2-0.5l6-1.5l1-0.5l4.5-1.5
l1.5-0.5c1.5-0.5,3-1,4-2l1-0.5c3.5-1.5,6.5-3.5,9.5-5l1-0.5c0,0,0.5,0,0.5-0.5c-0.5,5.5-7.5,11.5-19.5,16c-15,6.5-36,9.5-58,9.5
C73,89.5,44,78,37.5,67c-1-1.5-1.5-2.5-1.5-3.5c0,0,0.5,0,0.5,0.5l1,0.5C38.5,65,40,66,41.5,67L41.5,67z M113,165.5h-11.5
c-1.5,0-3.5,0-5-0.5l-4-0.5c-1,0-2.5,0-3.5-0.5h-2l-2.5-0.5c-1,0-2,0-3-0.5c-0.5,0-1,0-2-0.5l-2-0.5c-1,0-2-0.5-3-0.5
c-0.5,0-1,0-1.5-0.5l-2-0.5c-1,0-2-0.5-3-0.5h-1.5c-1,0-2-0.5-2.5-0.5l-3-1c-1-0.5-1.5-0.5-2.5-1l-2.5-1c-0.5-0.5-1.5-0.5-2-1l-2-1
c-0.5-0.5-1.5-0.5-2-1l-1.5-1c-0.5-0.5-1.5-1-2-1L44,150c-0.5-0.5-1-1-2-1.5l-1.5-1c-0.5-0.5-1-0.5-1-1L39,146c0.5,0,0.5,0,1,0.5
l2.5,0.5c1.5,0.5,3,1,5,1.5l3,0.5c1.5,0.5,3,0.5,5,1c1,0,2,0.5,3,0.5c1.5,0.5,3.5,0.5,5,1l3,0.5c1.5,0,3.5,0.5,5.5,0.5l3,0.5
c1.5,0,3.5,0,5.5,0.5h23c2,0,3.5,0,5.5-0.5l3-0.5c1.5,0,3-0.5,5-0.5l3-0.5c1.5,0,3-0.5,4.5-0.5l3-0.5c1.5,0,3-0.5,4.5-1l3-0.5
c1.5-0.5,2.5-0.5,4-1c1,0,2-0.5,2.5-0.5c1.5-0.5,2.5-0.5,4-1l2.5-0.5c1.5-0.5,2.5-1,3.5-1.5c0.5-0.5,1.5-0.5,2-1
c1.5-0.5,2.5-1,4-1.5c0.5,0,1-0.5,1.5-0.5c1.5-0.5,2.5-1,4-2l1.5-0.5c3.5-2,6-3.5,8.5-5.5l0.5-0.5l3-3l1-1c0.5-1,1.5-1.5,2-2.5
c0,0,0.5-0.5,0.5-1c7.5,4.5,12,9,12,13.5v1.5C188.5,151,160.5,165.5,113,165.5L113,165.5z M143,100c1,0,2-0.5,3.5-0.5s2.5-0.5,4-0.5
c1,0,2.5-0.5,3.5-0.5c1.5-0.5,2.5-0.5,4-1c1-0.5,2.5-0.5,3.5-1c1.5-0.5,2.5-0.5,3.5-1c1-0.5,2-0.5,3-1c0.5,0,1-0.5,1.5-0.5v0.5
c0,1-0.5,2-1.5,3.5c-7,11-35.5,22-75.5,22c-26,0-49.5-4.5-64.5-12.5c-7.5-4-12-8.5-13-13v-1c0-5,5.5-10.5,14.5-15L31,80l0.5,0.5
c1,1,2,1.5,3,2.5l1,1c1,0.5,1.5,1,2.5,2l1.5,1c1,0.5,2,1,2.5,1.5h2l3,1.5c0.5,0.5,1.5,0.5,2,1c1,0.5,2,1,3,1c0.5,0.5,1.5,0.5,2,1
c1,0.5,2,0.5,3,1l2.5,1c1,0.5,2,0.5,3.5,1c1,0,1.5,0.5,2.5,0.5c1,0.5,2,0.5,3.5,1l3,0.5c1,0,2.5,0.5,4,1l2.5,0.5c1,0,2,0.5,3.5,0.5
c1,0,2,0.5,3,0.5c1,0,2,0,3,0.5l8.5,1H131c1,0,2.5,0,3.5-0.5h1.5c1,0,2,0,3-0.5c1.5,0,2.5-0.5,4-0.5 M20,117.5l0.5,0.5
c1.5,1,3,1.5,4.5,2.5l1.5,0.5c1,0.5,2.5,1,3.5,1.5l2,0.5l4.5,1.5L38,125c2,0.5,4,1,6,2l1.5,0.5c1.5,0.5,3,1,5,1l2,0.5
c1.5,0.5,3.5,0.5,5,1l2,0.5c2.5,0.5,4.5,0.5,7.5,1h1c2,0,4,0.5,6,0.5h2.5c2,0,3.5,0,5.5,0.5h20.5c2,0,3.5,0,5.5-0.5h2.5
c2,0,4-0.5,6-0.5h1.5c2.5-0.5,4.5-0.5,7-1l2-0.5c1.5-0.5,3.5-0.5,5-1l2.5-0.5c1.5-0.5,3-0.5,4.5-1l2-0.5l6-1.5l1.5-0.5
c1.5-0.5,3-1,4-1.5l2-1c1-0.5,2.5-1,3.5-1.5c0.5,0,1-0.5,1.5-0.5c1.5-0.5,3-1.5,4.5-2.5l1-0.5c1-0.5,2-1.5,3-2c0.5-0.5,1-0.5,1.5-1
v1c-2.5,10.5-31,25-77,25c-15,0-29.5-1.5-42.5-5c-6.5-1.5-12.5-3.5-17.5-5.5c-10.5-4.5-17-10.5-17.5-15.5c0,0,0.5,0,0.5,0.5H16
C17.5,116,18.5,117,20,117.5L20,117.5z M36.5,160.5l1,0.5c1,1,2.5,1.5,4.5,2.5c1.5,1,3,1.5,4.5,2.5l1.5,0.5c1,0.5,2.5,1,4,1.5l2,0.5
c1.5,0.5,3,1,5,1.5l1,0.5l6,1.5l1.5,0.5c1.5,0.5,3,1,5,1L74,175c1.5,0.5,3,0.5,5,1l2,0.5c2.5,0.5,4.5,0.5,7,1h2c2,0,3.5,0.5,5.5,0.5
h3c1.5,0,3,0,5,0.5h21c1.5,0,3,0,4.5-0.5h3c1.5,0,3-0.5,5-0.5l2.5-0.5c2.5-0.5,4.5-0.5,6.5-1l2.5-0.5c1.5-0.5,3-0.5,4.5-1l2.5-0.5
c1.5-0.5,3-0.5,4.5-1l2-0.5l6-1.5l1.5-0.5l4.5-1.5c0.5,0,1-0.5,1.5-0.5c1.5-0.5,2.5-1,4-2l1-0.5c1.5-1,3.5-1.5,5-2.5s3-1.5,4.5-2.5
l1-0.5h0.5c-1,11-30.5,26-77.5,26S37.5,171.5,36.5,160.5C36,160,36,160.5,36.5,160.5L36.5,160.5z"/>
</svg>
// eslint-disable-next-line
module.exports = [
{ number: '{1}', name: '{姓名}' },
{ number: '{2}', name: '{姓名+先生/女士}' },
{ number: '{3}', name: '{生日日期}' },
{ number: '{4}', name: '{生日天数}' },
{ number: '{5}', name: '{关注日期}' },
{ number: '{6}', name: '{关注天数}' },
{ number: '{7}', name: '{主门店品牌名称}' },
{ number: '{8}', name: '{主门店名称}' },
{ number: '{9}', name: '{主门店电话}' },
{ number: '{10}', name: '{专属导购姓名}' },
{ number: '{11}', name: '{专属导购手机号}' },
{ number: '{12}', name: '{开卡日期}' },
{ number: '{13}', name: '{开卡天数}' },
{ number: '{14}', name: '{开卡门店名称}' },
{ number: '{15}', name: '{会员卡号}' },
{ number: '{16}', name: '{会员等级名称}' },
{ number: '{17}', name: '{主门店地址}' },
{ number: '{18}', name: '{会员等级剩余有效天数}' },
{ number: '{19}', name: '{积分余额}' },
{ number: '{20}', name: '{30天内将过期积分额度}' },
{ number: '{21}', name: '{储值余额}' },
{ number: '{22}', name: '{消费总额}' },
{ number: '{23}', name: '{消费次数}' },
{ number: '{24}', name: '{最近消费日期}' },
{ number: '{25}', name: '{最近消费间隔}' },
{ number: '{26}', name: '{最高单笔消费}' },
{ number: '{27}', name: '{最近消费门店名称}' },
{ number: '{28}', name: '{最近消费品牌名称}' }
];
/* reset样式 */
.w100 {
width: 100px;
}
.w200 {
width: 200px;
}
.w240 {
width: 240px;
}
.w400 {
width: 400px;
}
.w500 {
width: 500px;
}
.inline-block {
/* vertical-align: middle; */
display: inline-block !important;
}
.block {
display: block !important;
}
.gray-color,
.gray {
color: #909399;
}
.pb22 {
padding-bottom: 22px;
}
.pb10 {
padding-bottom: 10px;
}
.pl20 {
padding-left: 20px;
}
.pl10 {
padding-left: 10px;
}
.pr10 {
padding-right: 10px;
}
.fz13 {
font-size: 13px;
}
.fz12 {
font-size: 12px;
}
.fl {
float: left;
}
.fr {
float: right;
}
.clearfix:after {
display: block;
clear: both;
content: '';
visibility: hidden;
height: 0;
}
.clearfix {
zoom: 1;
}
.vertical-middle {
vertical-align: middle;
}
.block {
display: block;
overflow: hidden;
}
.ellipsis {
max-height: 20px;
line-height: 20px;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 1;
-webkit-box-orient: vertical;
}
.ellipsis-l2 {
max-height: 40px;
line-height: 20px;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
.ellipsis-l3 {
max-height: 60px;
line-height: 20px;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
}
.blue {
color: #1890ff;
cursor: pointer;
}
.label-hidden .el-checkbox__label,
.label-hidden .el-radio__label {
opacity: 0;
position: absolute;
}
.dm-pagination {
text-align: right;
margin: 24px 0 10px 0;
}
.text-left {
text-align: left;
}
/* reset样式end */
.dm-marketing {
min-width: 200px;
display: inline-block;
}
.dm-marketing__opt {
background: #ffffff;
border: 1px solid rgba(235, 238, 245, 1);
-webkit-box-shadow: 0px 1px 20px 0px rgba(0, 0, 0, 0.15);
box-shadow: 0px 1px 20px 0px rgba(0, 0, 0, 0.15);
padding: 0 20px;
}
.dm-marketing__opt--label {
vertical-align: middle;
color: #303133;
font-size: 14px;
}
.dm-marketing__opt--icon,
.dm-marketing__opt--icon--bottom {
display: inline-block;
font-size: 20px;
padding: 8px;
margin: 0 10px;
color: #909399;
border: 1px solid #e4e7ed;
border-radius: 50%;
vertical-align: middle;
cursor: pointer;
}
.dm-marketing__opt--icon {
margin-left: 0;
}
.dm-marketing__opt--icon:hover,
.dm-marketing__opt--icon--bottom:hover {
color: #1890ff;
border: 1px solid #1890ff;
}
.dm-marketing__opt--icon.el-icon-delete:hover {
color: #f56c6c;
border: 1px solid #f56c6c;
}
.dm-marketing__opt--icon--bottom {
margin: 20px 0 0 60px;
}
.dm-marketing__opt__item {
display: inline-block;
height: 36px;
line-height: 36px;
margin-right: 30px;
cursor: pointer;
}
.dm-marketing__opt__item > img {
vertical-align: middle;
height: 17px;
width: auto;
overflow: hidden;
color: #909399;
}
.dm-marketing__opt__item > span {
vertical-align: middle;
color: #606266;
font-size: 14px;
}
.dm-marketing__content--label {
position: relative;
top: 40px;
left: 0;
}
.dm-marketing__content__item {
margin: 20px 0;
}
.dm-marketing__content--index {
display: inline-block;
width: 24px;
height: 24px;
line-height: 24px;
text-align: center;
vertical-align: middle;
border: 1px solid #e4e7ed;
border-radius: 50%;
padding: 4px;
color: #606266;
}
/* item */
/* card */
.dm-card__item__wrap {
position: relative;
display: inline-block;
width: 280px;
margin: 0 10px 0 0;
vertical-align: middle;
box-sizing: border-box;
border: 1px solid rgba(228, 231, 237, 1);
border-radius: 4px;
}
.dm-card__item {
padding: 0 15px;
background: rgba(72, 170, 3, 0.85);
height: 106px;
line-height: 106px;
}
.dm-card__item__avatar {
width: 60px;
height: 60px;
border-radius: 50%;
vertical-align: middle;
}
.dm-card__item__title {
vertical-align: middle;
margin-left: 8px;
max-width: 180px;
font-size: 16px;
font-weight: 500;
line-height: 30px;
color: #fff;
overflow: hidden;
text-overflow: ellipsis;
}
.dm-card__item__desc {
vertical-align: middle;
margin-left: 8px;
max-width: 200px;
font-size: 12px;
line-height: 20px;
color: #fff;
overflow: hidden;
text-overflow: ellipsis;
}
.dm-card__item--bottom {
vertical-align: middle;
line-height: 106px;
color: #909399;
font-size: 12px;
line-height: 36px;
padding-left: 15px;
}
/* integral */
.dm-integral__item__wrap {
box-sizing: border-box;
width: 280px;
padding: 18px 20px;
margin: 0 10px 0 0;
border: 1px solid rgba(228, 231, 237, 1);
border-radius: 4px;
display: inline-block;
position: relative;
}
.el-dialog__footer {
border: none;
}
/**
* 补零
* @param {String/Number} num
*/
export const fillZero = num => {
num = num * 1;
if (num < 10) {
return '0' + num;
} else {
return num;
}
};
/**
* @param {*时间} date
* @param {*转换的格式} type
*/
export const formatDateTimeByType = (date, type = 'yyyy-MM-dd-HH-mm-ss') => {
if (!date) {
return '';
}
if (typeof date === 'number') {
date = new Date(date);
}
if (typeof date === 'string') {
return date;
} else {
let year = type.indexOf('yyyy') >= 0 ? fillZero(date.getFullYear()) : '';
let month = type.indexOf('MM') >= 0 ? '-' + fillZero(date.getMonth() + 1) : '';
let day = type.indexOf('dd') >= 0 ? '-' + fillZero(date.getDate()) + '' : '';
let hours = type.indexOf('HH') >= 0 ? ' ' + fillZero(date.getHours()) : '';
let min = type.indexOf('mm') >= 0 ? ':' + fillZero(date.getMinutes()) : '';
let sec = type.indexOf('ss') >= 0 ? ':' + fillZero(date.getSeconds()) : '';
// console.log(year+month+day+hours+min+sec);
return year + month + day + hours + min + sec;
}
};
/*
* 限制字数用, 一个汉字算一个字,两个英文/字母算一个字
*/
export const getByteVal = (val, max) => {
let returnValue = '';
let byteValLen = 0;
for (let i = 0; i < val.length; i++) {
if (val[i].match(/[^\x00-\xff]/gi) != null) byteValLen += 1;
else byteValLen += 0.5;
if (byteValLen > max) break;
returnValue += val[i];
}
return returnValue;
};
/*
* 一个汉字算一个字,一个英文字母或数字算半个字
*/
export const getZhLen = val => {
let len = 0;
for (let i = 0; i < val.length; i++) {
let a = val.charAt(i);
if (a.match(/[^\x00-\xff]/gi) != null) {
len += 1;
} else {
len += 0.5;
}
}
return Math.ceil(len);
};
/*
* 一个汉字算一个字,两个英文/字母算一个字
*/
export const getByteVal2 = val => {
let returnValue = '';
// eslint-disable-next-line
let byteValLen = 0;
for (let i = 0; i < val.length; i++) {
if (val[i].match(/[^\x00-\xff]/gi) != null) byteValLen += 1;
else byteValLen += 0.5;
returnValue += val[i];
}
return returnValue;
};
<template>
<el-popover class="el-button el-button--text" placement="top" width="160" v-model="visible">
<p style="line-height:1.5;padding:10px 10px 20px;color:#606266;">{{ tips }}</p>
<div style="text-align: right; margin: 0">
<el-button size="mini" type="text" @click="cancel">取消</el-button>
<el-button type="primary" size="mini" @click="confirm">确定</el-button>
</div>
<span slot="reference"><slot></slot></span>
</el-popover>
</template>
<script>
export default {
name: 'dm-delete',
props: {
tips: {
type: String,
default: '是否删除?'
}
},
data() {
return {
visible: false
};
},
methods: {
cancel() {
this.visible = false;
},
confirm() {
this.visible = false;
this.$emit('confirm');
}
}
};
</script>
<template>
<div class="dm-card__item__wrap">
<img v-if="item.status === 0" :src="require('../assets/img/delete_icon.png')" draggable="false" class="flag" />
<img v-else-if="item.couponStock <= 0" :src="require('../assets/img/stock_icon.png')" draggable="false" class="flag" />
<div class="dm-card__item" :style="{ background: item.cardColor }">
<img class="dm-card__item__avatar" :src="item.brandLogo || loadErrorImg" alt="" />
<div class="inline-block">
<el-tooltip open-delay="200" effect="dark" :content="item.coupCardId" placement="top-start">
<p class="dm-card__item__title">{{ item.cardName }}</p>
</el-tooltip>
<p class="dm-card__item__desc" v-if="item.cardEffectiveMode !== 0">领取后{{ (item.startDay === 0 ? '当' : '第' + item.startDay) + '天,有效天数' + item.limitDay }}</p>
<p class="dm-card__item__desc" v-if="item.cardEffectiveMode === 0">{{ formatDateTimeByType(item.beginDate, 'yyyy-MM-dd') }}{{ formatDateTimeByType(item.endDate, 'yyyy-MM-dd') }}</p>
</div>
</div>
<p class="dm-card__item--bottom">
<span>适用{{ item.storeMode === 0 ? '所有门店' : item.storeMode === 1 ? '部分分组' : '部分门店' }}</span>
</p>
<div v-if="overdue" class="danger-color fz12 mt5"><i class="el-icon-warning mr5 fz12"></i>超过投放期限</div>
</div>
</template>
<script>
import { formatDateTimeByType } from '../assets/utils.js';
export default {
name: 'item-card',
data() {
return {
formatDateTimeByType,
// eslint-disable-next-line
loadErrorImg: require('../assets/img/loaderror.png')
};
},
props: {
item: {
type: Object,
default() {
return {};
}
}
},
computed: {
overdue() {
const { putEndDate, putBeginDate, putEffectiveMode } = this.item;
if (putEffectiveMode == 0) {
return new Date() > new Date(putEndDate) || new Date() < new Date(putBeginDate);
}
return false;
}
},
mounted() {
console.log(this.item);
}
};
</script>
<style lang="scss" scoped>
@import '../assets/style/index.css';
.dm-card__item__wrap {
position: relative;
img.flag {
position: absolute;
right: 0px;
top: -2px;
z-index: 5;
width: 70px;
}
}
</style>
<template>
<div class="dm-integral__item__wrap">
<!-- {{ item.integralType }} -->
<template>
<span class="fz16">赠送积分<span class="fz12 gray ml20">* 仅支持给开卡会员赠送积分</span></span>
<p class="mt15">
<span class="fz24 mr5 primary-font-color">{{ item.integralCount }}</span>
<span>积分</span>
</p>
</template>
</div>
</template>
<script>
export default {
name: 'item-integral',
props: {
item: {
type: Object,
default() {
return {};
}
}
}
};
</script>
<template>
<el-dialog title="选择卡券" :visible.sync="show" width="800px" :before-close="close">
<div class="clearfix pb10">
<div class="fl">
<el-input v-model="listParams.searchParam" class="w200 mr10" clearable placeholder="请输入卡券名/备注名" @change="refresh"><i slot="prefix" class="el-input__icon el-icon-search"></i></el-input>
<el-select style="width:120px;margin-right:10px;" v-model="listParams.cardTypes" placeholder="卡券类型" @change="refresh">
<el-option v-for="item in cardTypesList" :key="item.value" :label="item.label" :value="item.value"></el-option>
</el-select>
<span class="fz12 gray">{{ limitTips }}{{ total }}张。 </span>
</div>
<!-- <div class="fr">
<el-button type="primary" @click="add">新建卡券</el-button>
<el-button @click="refresh">刷新列表</el-button>
</div> -->
</div>
<div style="font-size:12px;color:#909399;line-height:30px;">* 仅能选择卡券模板投放期限有效的卡券</div>
<el-table tooltipEffect="light" :data="tableList" row-class-name="cursor-pointer" style="width: 100%" v-loading="loading" @row-click="rowClick">
<el-table-column :show-overflow-tooltip="false" width="60" align="center" prop="coupCardId">
<template slot-scope="scope">
<div class="sms-record_left label-hidden">
<el-radio v-model="selectedData" :label="scope.row" class="pr10"></el-radio>
</div>
</template>
</el-table-column>
<el-table-column :show-overflow-tooltip="true" width="140" align="left" prop="cardName" label="卡券名称">
<template slot-scope="scope">
<p style="line-height:22px;">{{ scope.row.cardName }}</p>
<p style="line-height:20px;color:#909399;font-size:13px;">{{ scope.row.subName }}</p>
</template>
</el-table-column>
<el-table-column :show-overflow-tooltip="false" min-width="120" align="left" prop="createTime" label="卡券模板投放期限">
<template slot-scope="scope">
<span v-if="scope.row.putEffectiveMode == 0"> 固定日期:{{ formatDateTimeByType(scope.row.putBeginDate, 'yyyy-MM-dd') }}{{ formatDateTimeByType(scope.row.putEndDate, 'yyyy-MM-dd') }} </span>
<span v-else>长期有效</span>
</template>
</el-table-column>
<el-table-column prop="" label="用户使用有效期" :min-width="120" :show-overflow-tooltip="false">
<template slot-scope="scope">
<div v-if="scope.row.cardEffectiveMode == 0">固定日期:{{ formatDateTimeByType(scope.row.beginDate, 'yyyy-MM-dd') + '至' + formatDateTimeByType(scope.row.endDate, 'yyyy-MM-dd') }}</div>
<div v-if="scope.row.cardEffectiveMode == 1">领取后{{ (scope.row.startDay === 0 ? '当' : '第' + scope.row.startDay) + '天,有效天数' + scope.row.limitDay }}</div>
</template>
</el-table-column>
<el-table-column prop="cardLimit" :show-overflow-tooltip="false" label="领取限制" width="90">
<template slot-scope="scope"> {{ scope.row.cardLimit }}张/人 </template>
</el-table-column>
<el-table-column :show-overflow-tooltip="false" :width="90" align="left" prop="storeMode" label="适用门店">
<template slot-scope="scope">
{{ scope.row.storeMode === 0 ? '所有门店' : scope.row.storeMode === 1 ? '部分分组' : '部分门店' }}
</template>
</el-table-column>
<el-table-column :show-overflow-tooltip="false" :width="100" align="left" prop="couponStock" label="库存"></el-table-column>
</el-table>
<dm-pagination v-show="tableList.length" class="dm-pagination" @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="listParams.currentPage" :page-sizes="[20, 40, 60, 80]" :page-size="listParams.pageSize" layout="prev, pager, next" :total="total"></dm-pagination>
<span slot="footer" class="dialog-footer">
<el-button @click="close">关 闭</el-button>
<el-button type="primary" @click="addItem">确 定</el-button>
</span>
</el-dialog>
</template>
<script>
import { getCardList } from '../assets/api.js';
import { formatDateTimeByType } from '../assets/utils.js';
export default {
name: 'lib-card',
props: {
show: {
type: Boolean,
default: false
},
cardLimitType: {
type: Number,
default: 3
}
},
computed: {
limitTips() {
if (this.cardLimitType === 2) {
return '领取限制领取1~100的卡券,系统已过滤,符合条件共';
} else if (this.cardLimitType === 3) {
return '领取限制领取<100的卡券不支持选择,系统已过滤,符合条件共';
} else if (this.cardLimitType === -1) {
return '该选择器可筛选所有领取限制卡券,共';
} else {
return '领取限制>1的卡券不支持选择,系统已过滤,符合条件共';
}
}
},
data() {
return {
formatDateTimeByType,
cardTypesList: [
{ value: null, label: '全部' },
{ value: 0, label: '抵金券' },
{ value: 1, label: '折扣券' },
{ value: 2, label: '兑换券' }
],
listParams: {
searchParam: '',
currentPage: 1,
pageSize: 5,
cardTypes: '', // 0:抵金券,1:折扣券,2:兑换券
requestProject: 'gic-web',
cardLimitType: 3,
cardType: ''
},
total: 0,
tableList: [],
selectedData: {}
};
},
created() {
this.getCardList();
},
methods: {
handleSizeChange(val) {
this.listParams.pageSize = val;
this.getCardList();
},
handleCurrentChange(val) {
this.listParams.currentPage = val;
this.getCardList();
},
getCardList() {
this.loading = true;
getCardList(this.listParams).then(res => {
if (res.errorCode === 0) {
this.tableList = res.result.result || [];
this.total = res.result.totalCount;
}
this.loading = false;
});
},
reset() {
this.listParams.searchParams = '';
this.getCardList();
},
close() {
this.$emit('update:show', false);
},
rowClick(row) {
row.comName = 'card';
this.selectedData = row;
},
addItem() {
if (!this.selectedData.comName) {
this.$message({ type: 'warning', message: '未选择卡券' });
return;
}
this.$emit('sendItem', this.selectedData);
this.close();
},
add() {
window.open('/marketing/#/card/add');
},
refresh() {
this.listParams.currentPage = 1;
this.getCardList();
}
}
};
</script>
<template>
<el-dialog title="赠送积分" :visible.sync="show" width="420px" @closed="close" :close-on-click-modal="false">
<el-form :model="form" :rules="rules" ref="form" label-width="0">
<template v-if="form.integralType === 1">
<p class="regular-font-color mb20">请输入需要赠送的积分<span class="fz12 gray ml10">* 仅支持给认证会员赠送积分</span></p>
<el-form-item prop="integralCount">
<el-input v-model.number="form.integralCount" maxLength="7" />
</el-form-item>
</template>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="close">关 闭</el-button>
<el-button type="primary" @click="addItem">确 定</el-button>
</span>
</el-dialog>
</template>
<script>
export default {
name: 'lib-integral',
props: {
item: {
type: Object,
default() {
return {};
}
},
show: {
type: Boolean,
default: false
},
integralMultiple: {
// 积分 是否需要倍数(场景:消费触发)
type: Boolean,
default: false
}
},
data() {
const validInteral = (rule, value, callback) => {
if (!Number.isInteger(value)) {
callback(new Error('积分值为数字值'));
} else if (value <= 0) {
callback(new Error('积分值最小为1'));
} else if (value > 1000000) {
callback(new Error('单次赠送值最大值为1000000'));
} else {
callback();
}
};
return {
ecmMarketingTypeRelationId: '',
old: {}, // 旧数据
form: {
integralCount: '',
comName: 'integral',
integralType: 1, // 1固定积分 2订单金额倍数
multipleNum: undefined // 倍数值
},
rules: {
integralCount: [{ required: true, message: '请输入积分值', trigger: 'blur' }, { validator: validInteral, trigger: 'blur' }], // eslint-disable-line
multipleNum: [{ required: true, message: '请输入倍数', trigger: 'blur' }] // eslint-disable-line
},
loading: false
};
},
watch: {
reset() {
this.$refs.form.resetFields();
},
show(val) {
if (val) {
this.old = { ...this.item };
this.form.integralCount = this.item.integralCount;
this.form.multipleNum = this.item.multipleNum || undefined;
this.form.integralType = this.item.integralType || 1;
this.ecmMarketingTypeRelationId = this.item.ecmMarketingTypeRelationId;
} else {
this.old = {};
this.form.integralCount = '';
this.form.multipleNum = undefined;
this.form.integralType = 1;
this.ecmMarketingTypeRelationId = '';
}
}
},
methods: {
close() {
this.$refs.form.resetFields();
this.$emit('update:show', false);
},
addItem() {
this.$refs['form'].validate(valid => {
if (valid) {
if (this.integralMultiple) {
this.integralType = this.integralType || 1; // 设置默认1 防止''
}
this.$emit('sendItem', { ...this.form, ...{ ecmMarketingTypeRelationId: this.ecmMarketingTypeRelationId } });
this.close();
}
});
}
}
};
</script>
<template>
<div class="inline-block dm-marketing__opt">
<span v-for="(v, i) in options" :key="i" class="dm-marketing__opt__item" @click="addItem(v)" style="display: inline-block;height: 36px;line-height: 36px;margin-right: 30px;cursor: pointer;">
<img :src="v.img" alt="" srcset="" style="vertical-align: middle; height: 17px; width: auto; overflow: hidden; color: #909399;" /><span style=" vertical-align: middle;color: #606266;font-size: 14px;"> {{ v.name }}</span>
</span>
</div>
</template>
<script>
export default {
name: 'opt',
props: {
options: {
type: Array,
default() {
return [];
}
}
},
methods: {
addItem(item) {
this.$emit('addItem', item);
}
}
};
</script>
<style lang="scss" scoped>
.dm-marketing__opt {
background: #ffffff;
border: 1px solid rgba(235, 238, 245, 1);
-webkit-box-shadow: 0px 1px 20px 0px rgba(0, 0, 0, 0.15);
box-shadow: 0px 1px 20px 0px rgba(0, 0, 0, 0.15);
padding: 0 20px;
}
.dm-marketing__opt__item {
display: inline-block;
height: 36px;
line-height: 36px;
margin-right: 30px;
cursor: pointer;
}
.dm-marketing__opt__item > img {
vertical-align: middle;
height: 17px;
width: auto;
overflow: hidden;
color: #909399;
}
.dm-marketing__opt__item > span {
vertical-align: middle;
color: #606266;
font-size: 14px;
}
</style>
<template>
<div>
<router-view></router-view>
</div>
</template>
<script>
export default {
name: 'signIn',
data() {
return {};
},
created() {
this.$store.commit('mutations_breadcrumb', [{ name: '门店签到', path: '/signIn' }]);
this.$store.commit('aside_handler', false);
this.$nextTick(_ => {
this.$store.commit('aside_handler', true);
});
}
};
</script>
<template>
<section class="dm-wrap" v-loading="loading">
<div class="pb20 clearfix">
<el-input v-model="pageParams.memberInfo" class="w300" placeholder="请输入会员姓名/手机号" clearable @change="refresh"><i slot="prefix" class="el-input__icon el-icon-search"></i></el-input>
<el-date-picker class="w250" v-model="pageParams.time" type="daterange" range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" @change="refresh"></el-date-picker>
<el-input v-model="pageParams.storeName" class="w300" placeholder="请输入门店" clearable @change="refresh"><i slot="prefix" class="el-input__icon el-icon-search"></i></el-input>
</div>
<el-table tooltipEffect="light" :data="tableList" style="width: 100%">
<el-table-column :show-overflow-tooltip="true" align="left" prop="createTime" label="签到时间">
<template slot-scope="scope">
<p class="cell-time">
{{ formatDateTimeByType(scope.row.signTime, 'yyyy-MM-dd-HH-mm', true).y }}<br />
<span>{{ formatDateTimeByType(scope.row.signTime, 'yyyy-MM-dd-HH-mm', true).h }}</span>
</p>
</template>
</el-table-column>
<el-table-column :show-overflow-tooltip="true" align="left" label="签到用户">
<template slot-scope="scope">
<div class="memberInfo">
<img :src="scope.row.memberImage || ''" alt="" />
<div>
<p class="cell-memberInfo">{{ scope.row.memberName || ' - ' }}</p>
<p class="cell-memberInfo">{{ scope.row.memberPhone || ' - ' }}</p>
</div>
</div>
</template>
</el-table-column>
<el-table-column :show-overflow-tooltip="true" align="left" label="福利类型">
<template slot-scope="scope"> {{ scope.prizeType === '1' ? '积分' : '卡券' }}</template>
</el-table-column>
<el-table-column :show-overflow-tooltip="true" align="left" prop="prizeTxt" label="签到福利"></el-table-column>
<el-table-column :show-overflow-tooltip="true" align="left" prop="storeName" label="签到门店"></el-table-column>
</el-table>
<dm-pagination v-show="tableList.length" background class="dm-pagination" @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="pageParams.currentPage" :page-sizes="[20, 40, 60, 80]" :page-size="pageParams.pageSize" layout="total, sizes, prev, pager, next" :total="total"></dm-pagination>
</section>
</template>
<script>
import { getPageSignLog } from '@/service/api/storeSign.js';
import { formatDateTimeByType } from '@/utils/index.js';
export default {
name: 'sign-record',
data() {
return {
loading: false,
projectName: 'gic-web',
pageParams: {
currentPage: 1,
pageSize: 20
},
total: 0,
tableList: [],
// 门店单选
storeName: '',
storeDialog: false
};
},
created() {
this.$store.commit('mutations_breadcrumb', [{ name: '门店签到' }, { name: '门店签到记录', path: '' }]);
this.fetch();
},
methods: {
async fetch() {
try {
this.loading = true;
const params = { ...this.pageParams };
if (this.pageParams.time) {
params.startTime = formatDateTimeByType(params.time[0], 'yyyy-MM-dd');
params.endTime = formatDateTimeByType(params.time[1], 'yyyy-MM-dd');
delete params.time;
}
let res = await getPageSignLog(params);
if (res.errorCode === 0 && res.result) {
this.tableList = res.result.result || [];
this.total = res.result.totalCount;
} else {
this.tableList = [];
this.total = 0;
}
this.loading = false;
} catch (err) {
this.loading = false;
}
},
refresh() {
this.pageParams.currentPage = '1';
this.fetch();
},
// 显示门店弹窗
showStoreDialog() {
this.storeDialog = true;
},
clearStoreInfo() {
delete this.pageParams.storeId;
this.storeName = '';
this.refresh();
},
// 门店回显
selectStore(val) {
// 模拟检查数据
this.pageParams.storeId = val.storeId;
this.storeName = val.storeName || `(门店代码:${val.storeCode})`;
this.storeDialog = false;
this.refresh();
},
formatDateTimeByType
},
handleSizeChange(val) {
this.pageParams.pageSize = val;
this.fetch();
},
handleCurrentChange(val) {
this.pageParams.currentPage = val;
this.fetch();
}
};
</script>
<style lang="scss" scoped>
.memberInfo {
display: flex;
justify-content: flex-start;
align-items: center;
img {
display: block;
width: 40px;
height: 40px;
margin-right: 10px;
border-radius: 5px;
}
.cell-memberInfo {
color: #606266;
line-height: 20px;
font-size: 14px;
}
}
</style>
This source diff could not be displayed because it is too large. You can view the blob instead.
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