Commit 0cf5f54d by caoyanzhi

Merge branch 'feature/3月会员标签' into feature/4月-会员通

parents 7c7d907c 9d71eadb
......@@ -100,7 +100,6 @@
position: relative;
width: 100%;
height: 100%;
background: #f7f8fa;
}
.right-content {
padding-top: 12px;
......
......@@ -3,13 +3,10 @@
<head>
<meta charset="utf-8">
<link rel="shortcut icon" href="./static/img/favicon.ico"/>
<title></title>
<!-- <title>GIC-会员标签</title> -->
<!-- <script type='text/javascript'>
!function(e,t,n,g,i){e[i]=e[i]||function(){(e[i].q=e[i].q||[]).push(arguments)},n=t.createElement("script"),tag=t.getElementsByTagName("script")[0],n.async=1,n.src=('https:'==document.location.protocol?'https://':'http://')+g,tag.parentNode.insertBefore(n,tag)}(window,document,"script","assets.giocdn.com/2.1/gio.js","gio");
gio('init','8be12240a3749eab', {});
gio('send');
</script> -->
<title>金华达摩</title>
<link rel="stylesheet" href="//at.alicdn.com/t/font_688955_99jmfacmlpp.css">
<link rel="stylesheet" href="//at.alicdn.com/t/font_3276801_mkhlaisq2aq.css">
<script src="//at.alicdn.com/t/font_3276801_w3vkjjmzzz.js"></script>
</head>
<body style="background-color: #f0f2f5;min-width: 1400px;">
......
......@@ -12162,10 +12162,9 @@
}
},
"sortablejs": {
"version": "1.10.2",
"resolved": "https://registry.npm.taobao.org/sortablejs/download/sortablejs-1.10.2.tgz?cache=0&sync_timestamp=1610070445944&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsortablejs%2Fdownload%2Fsortablejs-1.10.2.tgz",
"integrity": "sha1-bkA2TZE/mLhaFPZnj5K1wSIfUpA=",
"dev": true
"version": "1.15.0",
"resolved": "https://registry.npmmirror.com/sortablejs/-/sortablejs-1.15.0.tgz",
"integrity": "sha512-bv9qgVMjUMf89wAvM6AxVvS/4MX3sPeN0+agqShejLU5z5GX4C75ow1O2e5k4L6XItUyAK3gH6AxSbXrOM5e8w=="
},
"source-list-map": {
"version": "2.0.1",
......@@ -13514,6 +13513,14 @@
"dev": true,
"requires": {
"sortablejs": "1.10.2"
},
"dependencies": {
"sortablejs": {
"version": "1.10.2",
"resolved": "https://registry.npmmirror.com/sortablejs/-/sortablejs-1.10.2.tgz",
"integrity": "sha512-YkPGufevysvfwn5rfdlGyrGjt7/CRHwvRPogD/lC+TnvcN29jDpCifKP+rBqf+LRldfXSTh+0CGLcSg0VIxq3A==",
"dev": true
}
}
},
"vuex": {
......
......@@ -14,6 +14,7 @@
"element-ui": "^2.15.6",
"file-saver": "^1.3.8",
"moment": "^2.29.1",
"sortablejs": "^1.15.0",
"tinymce": "^4.8.3",
"vue": "2.6.6",
"vue-clipboard2": "^0.2.0",
......
......@@ -36,3 +36,11 @@ export function _throttle(fn, interval) {
}
};
}
// 生成一个永不重复的ID
export function GenNonDuplicateID() {
let str = '';
str = Math.random().toString(36).substr(3);
str += Date.now().toString(16).substr(4);
return str;
}
<template>
<div id="cycleWrap">
<div class="leftWrap">
<div class="left" :style="{ transform: `rotate(${num1}deg)` }"></div>
</div>
<div class="rightWrap">
<div class="right" :style="{ transform: `rotate(${num2}deg)` }"></div>
</div>
<div class="cover"></div>
</div>
</template>
<script>
export default {
name: 'cycleWrap',
data() {
return {
// num1: 0,
// num2: 0,
}
},
props: {
progress: [Number, String]
},
computed: {
degree() {
return this.progress * 3.6
},
num2() {
return this.degree < 180 ? this.degree : 180;
},
num1() {
return this.degree < 180 ? 0 : this.degree - 180;
},
},
// watch: {
// progress() {
// let degree = this.progress * 3.6;
// if(degree < 180) {
// this.num1 = degree;
// this.num2 = 0;
// } else {
// this.num1 = 180;
// this.num2 = degree - 180;
// }
// }
// }
}
</script>
<style lang="scss" scoped>
#cycleWrap {
display: flex;
width: 26px;
height: 26px;
position: relative;
border-radius: 51%;
background-color: #F5222D;
.leftWrap,
.rightWrap {
width: 13px;
height: 26px;
position: absolute;
top: 0;
overflow: hidden;
}
.leftWrap {
left: 0;
}
.rightWrap {
right: 0;
}
.left {
width: 13px;
height: 26px;
border-radius: 12px 0 0 12px;
background-color: #ffe1e2;
transform-origin: right center;
}
.right {
width: 13px;
height: 26px;
border-radius: 0 12px 12px 0;
background-color: #fde1e2;
transform-origin: left center;
}
.cover {
position: absolute;
top: 4px;
left: 4px;
width: 18px;
height: 18px;
background-color: #fff;
border-radius: 50%;
}
}
</style>
\ No newline at end of file
<template>
<div id="trash">
<div class="trash" @click="dialogVisible=true">
<i class="iconfont icon-shanchu trashIcon"></i>
<span>一键清除废弃标签值</span>
<div class="trashState">
<component :is="stateComponent" :progress="progress"></component>
<el-popover placement="top-start" trigger="hover" content="一键清除废弃标签值">
<div slot="reference" class="trash" @click="dialogVisible = true">
<el-badge :value="trashList.length > 99 ? '99+' : trashList.length" class="badge">
<i class="iconfont icon-delete trashIcon"></i>
</el-badge>
</div>
</div>
<el-dialog
title="批处理撕标签"
:visible.sync="dialogVisible"
width="600px"
@open="dialogOpen"
@closed="dialogClosed">
<el-alert
title="每次操作一键清除的时间间隔为1小时。"
type="info"
show-icon
:closable="false"
style="width: 535px;margin-bottom:15px">
</el-alert>
<header>已选择删除的标签值</header>
</el-popover>
<el-dialog title="删除标签" :visible.sync="dialogVisible" width="600px" @open="dialogOpen" @closed="dialogClosed">
<el-alert title="标签删除时,同步将标签从会员信息上删除。" type="warning" show-icon :closable="false" style="width: 535px;margin-bottom:20px"> </el-alert>
<header>已选择待删除的标签/标签值</header>
<ul class="tagBox">
<li v-for="item in trashList" :key="item.tagItemId" class="tagItem">
{{ item.tagItemName }}
<i class="el-icon-error delIcon" @click="delCheckTag(item.tagItemId)"></i>
<i class="iconfont icon-guanbi1 delIcon" @click="delCheckTag(item.tagItemId)"></i>
</li>
</ul>
<span slot="footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="doClean" :disabled="delTime > 0 || !trashList.length">{{ delTime > 0 ? getDelTime() : '一键清除' }}</el-button>
<el-button type="primary" @click="doClean" :disabled="delTime > 0 || !trashList.length">{{ delTime > 0 ? getDelTime() : '除' }}</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import CycleWrap from './CycleWrap.vue';
import { getProgress, getTrashList, isCleanTrashList, cleanTrashList, delTrashList } from '@/request/api';
let Success = {
template: '<i class="el-icon-success" style="color:#52C41A;font-size:20px;"></i>'
}
let Pending = {
props: ['progress'],
template: '<div class="pendingClass">{{ progress }}</div>'
}
export default {
name: 'trash',
......@@ -51,87 +32,93 @@ export default {
return {
progress: 0,
trashList: [],
stateComponent: '',
dialogVisible: false,
delTime: 0,
interval: undefined
}
};
},
components: { CycleWrap, Success, Pending },
mounted() {
this.getProgress();
},
methods: {
getProgress() {
getProgress().then(res => {
const { errorCode, message, result } = res;
if(errorCode != 1) return this.$message.error(message);
if(result === null) {
this.getTrashList();
} else {
this.progress = result;
this.stateComponent = 'CycleWrap';
}
})
const { errorCode, message } = res;
if (errorCode != 1) return this.$message.error(message);
this.getTrashList();
});
},
getTrashList() {
getTrashList().then(res => {
const { errorCode, message, result = [] } = res;
if(errorCode != 1) return this.$message.error(message);
if (errorCode != 1) return this.$message.error(message);
this.trashList = result;
this.progress = result.length;
this.stateComponent = !result.length ? 'Success' : 'Pending';
})
});
},
dialogOpen() {
this.getTrashList();
isCleanTrashList().then(res => {
const { errorCode, message, result } = res;
if(errorCode != 1) return this.$message.error(message);
if (errorCode != 1) return this.$message.error(message);
this.delTime = result;
result && (this.interval = setInterval(_ => {
this.delTime -= 1000;
}, 1000))
})
result &&
(this.interval = setInterval(_ => {
this.delTime -= 1000;
}, 1000));
});
},
dialogClosed() {
if(this.interval) clearInterval(this.interval);
if (this.interval) clearInterval(this.interval);
this.getProgress();
},
getDelTime() {
let s = parseInt(this.delTime % (1000 * 60) / 1000);
let s = parseInt((this.delTime % (1000 * 60)) / 1000);
let m = parseInt((this.delTime % (1000 * 60 * 60)) / (1000 * 60));
let h = parseInt(this.delTime % (1000 * 60 * 60 * 24) / (1000 * 60 * 60));
let h = parseInt((this.delTime % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
return `倒计时: ${h}h:${m}min:${s}s`;
},
doClean() {
if(this.delTime) return;
if (this.delTime) return;
cleanTrashList().then(res => {
const { errorCode, message } = res;
if(errorCode != 1) return this.$message.error(message);
if (errorCode != 1) return this.$message.error(message);
this.$message.success('已开始执行');
this.dialogVisible = false;
this.getProgress();
})
this.$emit('beginClean')
});
},
delCheckTag(tagItemId) {
delTrashList({ tagItemId }).then(res => {
const { errorCode, message } = res;
if(errorCode != 1) return this.$message.error(message);
if (errorCode != 1) return this.$message.error(message);
this.getTrashList();
this.$message.success('移除成功');
})
});
}
}
}
};
</script>
<style lang="scss" scoped>
/deep/ .el-dialog__body {
padding-top: 13px;
}
/deep/ .el-dialog__footer {
padding-bottom: 20px;
}
/deep/ .el-alert .el-alert__title {
color: #303133;
}
/deep/ .el-alert__icon {
font-size: 14px;
}
.trash {
position: fixed;
right: 29px;
bottom: 370px;
height: 44px;
z-index: 2;
z-index: 10;
display: flex;
flex-wrap: nowrap;
font-size: 14px;
......@@ -140,15 +127,11 @@ export default {
color: #2F54EB;
box-shadow: 0 0 7px #7795b152;
cursor: pointer;
transition: .4s;
overflow: hidden;
transition: 0.4s;
width: 46px;
&:hover {
width: 220px;
}
.trashIcon {
display: block;
font-size: 28px;
font-size: 24px;
margin: 0 8px 0 10px;
}
span {
......@@ -157,23 +140,6 @@ export default {
margin-top: -2px;
white-space: nowrap;
}
.trashState {
display: flex;
justify-content: center;
align-items: center;
width: 26px;
height: 26px;
margin-left: 8px;
}
.pendingClass {
width: 25px;
height: 25px;
text-align: center;
line-height: 25px;
border-radius: 50%;
background-color: #F5222D;
color: #fff;
}
}
header {
color: #303133;
......@@ -184,24 +150,36 @@ header {
flex-wrap: wrap;
.tagItem {
position: relative;
margin-top: 10px;
margin-right: 13px;
padding: 5px 10px;
border: 1px solid #DCDFE6;
margin-top: 16px;
margin-right: 8px;
padding: 3px 8px;
border: 1px solid #dcdfe6;
border-radius: 2px;
background-color: #FAFAFA;
font-size: 13px;
color: #606266;
&:hover .delIcon {
display: block;
}
color: #2f54eb;
background: #dee3fc;
display: flex;
justify-content: space-between;
align-items: center;
}
.delIcon {
display: none;
position: absolute;
top: -6px;
right: -6px;
font-size: 14px;
width: 16px;
height: 16px;
display: flex;
align-items: center;
margin-left: 3px;
justify-content: center;
cursor: pointer;
position: relative;
top: 1px;
&:hover {
border-radius: 50%;
background: #bcc9fe;
}
}
}
</style>
\ No newline at end of file
/deep/ .badge .el-badge__content.is-fixed {
right: 22px;
}
</style>
.relative-range {
width: 500px;
height: 191px;
......@@ -64,7 +65,9 @@
.bg-f3f6f9 {
background: #F3F6F9;
}
.bg-f2f3f5 {
background: #f2f3f5;
}
.el-button--default.el-button--text {
color: #606266;
padding: 8px 15px;
......
......@@ -1082,6 +1082,84 @@ export default {
}
}
// 会员等级变更
if (this.templateData.length && code === 'com009') {
const findAfter = this.templateData.find(el => el.afterGradeId);
const findBefore = this.templateData.find(el => el.beforeGradeId);
if (findAfter && findBefore) {
const beforeGradeId = findBefore.beforeGradeId;
const afterGradeId = findAfter.afterGradeId;
if (beforeGradeId === afterGradeId) {
this.$message.error('变更前和变更后的会员等级不能相同')
return false;
};
tagValue.val[0].data.compute = '=';
const obj = JSON.parse(JSON.stringify(tagValue.val[0]));
tagValue.val.push(obj);
tagValue.val[0].data.value = beforeGradeId;
tagValue.val[0].data.dealKey = 'beforeGradeId';
tagValue.val[1].data.value = afterGradeId;
tagValue.val[1].data.dealKey = 'afterGradeId';
} else {
returnFlag = false;
}
}
// 开卡纪念日
if (this.templateData.length && code === 'tag030') {
const data = this.templateData.find(el => el.templateCode == 'tag030');
const { recentValue } = data;
if (!data.radioType) {
tagValue.val[0].data.compute = 'between';
tagValue.val[0].data.value = data.fixedTimeRangeValue.toString().replace(/-/g, '');
} else {
let compute = '';
if (!data.checkGroup.length) {
this.$message.error('最近时段的时间精度当前和之后必选其一');
return false;
}
else if (data.checkGroup.length == 1) {
const only = data.checkGroup[0];
compute = only == '当月' ? 'currentMonth' : only == '当天' ? 'today' : data.recentType ? 'aftermonth' : 'afterday';
} else if (data.checkGroup.length == 2){
const both = data.checkGroup;
compute = both.includes('当月') ? 'aftermonthHasCurrentMonth' : 'afterdayHasToday';
}
tagValue.val[0].data.value = '1';
tagValue.val[0].data.compute = compute;
if (data.checkGroup.indexOf('之后') > -1) {
tagValue.val[0].data.value = recentValue;
if (!recentValue) {
this.$message.error(`如果选择了最近时段的之后选项,${data.recentType ? '月' : '天'}为必填项!`);
return false;
};
}
}
let selectVal = '';
switch(tagValue.val[0].data.compute) {
case 'currentMonth':
selectVal = '当月';
break;
case 'today':
selectVal = '当天';
break;
case 'aftermonth':
selectVal = `之后${recentValue}月`;
break;
case 'afterday':
selectVal = `之后${recentValue}天`;
break;
case 'aftermonthHasCurrentMonth':
selectVal = `当月包含之后${recentValue}月`;
break;
case 'afterdayHasToday':
selectVal = `当天包含之后${recentValue}天`;
break;
case 'between':
selectVal = `${data.fixedTimeRangeValue[0]}${data.fixedTimeRangeValue[1]}`;
break;
}
this.postTemplateData.selectedVal.push(selectVal);
}
if (!returnFlag) {
that.$message.error({ message: '请完善标签值' });
return false;
......@@ -1134,7 +1212,6 @@ export default {
}
}
}
that.postTemplateData.template = that.templateData;
tagParams = that.postTemplateData;
if (Array.isArray(tagParams.selectedVal) && tagParams.selectedVal.length) {
......@@ -1188,6 +1265,7 @@ export default {
that.closeTagShortDialog();
// 如果来源是 会员标签编辑的时候
// if (that.fromFlag == 'memberGroup') {
console.log(tagParams, JSON.stringify(tagParams));
let sendObj = {
tagId: that.tagShortId || this.tagId,
tagValue: JSON.stringify(tagValue),
......@@ -1196,6 +1274,7 @@ export default {
isActive: that.tagData.isActive,
templateCode: this.templateCode
};
console.log(sendObj);
this.$emit('returnTagData', sendObj);
}
})
......@@ -1382,9 +1461,24 @@ export default {
that.pindex = pindex;
},
/* eslint-disable */
changeRemoteMethod(e, parent) {
changeRemoteMethod(item) {
// let tagsMap = null;
item.addSelectTags = item.searchOptions.filter(el => item.searchModel.includes(el.clerkId));
// if (!!item.addSelectTags.length) {
// tagsMap = item.addSelectTags.map(item => item.value);
// }
// item.searchOptions.forEach(function(ele, index) {
// if (!!tagsMap && tagsMap.indexOf(ele.value) != -1) {
// return false;
// }
// if (item.searchModel.indexOf(ele.key) != -1) {
// item.addSelectTags.push(ele);
// }
// });
},
removeRemoteMethod(val, item) {
item.addSelectTags = item.addSelectTags.filter(el => el.clerkId != val);
},
/**
* 获取 导购 --- api
*/
......
......@@ -24,3 +24,4 @@ export const aliasNames = [
{ name: '普通会员', title: '会员历史累计消费,消费次数等于1' },
{ name: '未消费会员', title: '会员历史累计消费,消费次数等于0' }
];
......@@ -14,12 +14,15 @@ import '../static/css/index.less';
import '../static/font/iconfont.css';
import vueGicDatepicker from '@gic-test/vue-gic-datepicker';
import buttonCode from '@/config/button-code.js';
import { toTaskCenter } from '@/utils/utils';
import Vue from 'vue';
window.ELEMENT.Dialog.props.closeOnClickModal.default = false; // 全局设置点击蒙层不关闭
Vue.use(vueGicDatepicker);
Vue.config.devtools = true;
Vue.use(VueAxios, axios);
Vue.axios.defaults.withCredentials = true; // 跨域cookie访问
console.log(window.ELEMENT.Dialog)
// 唤起任务中心弹框
Vue.prototype.$toTaskCenter = toTaskCenter;
Vue.axios.interceptors.request.use(
config => {
return config;
......
......@@ -352,3 +352,27 @@ export const updateSyncTag = (params = {}) =>
}
// data: qs.stringify(params)
})
// 变更常用标签状态
export const updateMoreUse = (params = {}) =>
request({
url: '/memberTag/updateMoreUse',
method: 'get',
params: {
requestProject: 'gic-member-tag-web',
...params
}
})
// 标签值排序
export const changeTagSort = (params = {}) =>
request({
url: '/memberTag/updateTagSort',
method: 'get',
params: {
requestProject: 'gic-member-tag-web',
...params
}
})
import Vue from 'vue'
import Clipboard from 'clipboard'
function clipboardSuccess() {
Vue.prototype.$message({
message: 'Copy successfully',
type: 'success',
duration: 1500
})
}
// function clipboardSuccess() {
// Vue.prototype.$message({
// message: 'Copy successfully',
// type: 'success',
// duration: 1500
// })
// }
function clipboardError() {
Vue.prototype.$message({
......@@ -21,7 +21,7 @@ export default function handleClipboard(text, event) {
text: () => text
})
clipboard.on('success', () => {
clipboardSuccess()
// clipboardSuccess()
clipboard.off('error')
clipboard.off('success')
clipboard.destroy()
......
......@@ -10,7 +10,6 @@ export function getParamsByName(attr) {
return ret && decodeURIComponent(ret[1].replace(/\+/g, ' '));
}
/**
* 人群筛选器 返回具体筛选条件的个数
* @param {}
......@@ -23,7 +22,7 @@ export function normalizePeople(jsonStr) {
let ret = 0;
const jsonObj = JSON.parse(jsonStr);
if (jsonObj.list && jsonObj.list.length) {
// 如果是一个对象
// 如果是一个对象
jsonObj.list.forEach(ele => {
// 如果list在ele里面 表示里面包含list数组
if ('list' in ele) {
......@@ -52,11 +51,11 @@ export function formatLongTime(timeStr, type) {
timeStr = '' + timeStr;
let regTest = /^(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})$/g;
if (type == 1) {
return timeStr.replace(regTest, function(match, p, p1, p2, p3, p4, p5){
return timeStr.replace(regTest, function(match, p, p1, p2, p3, p4, p5) {
return [p, p1, p2].join('-') + ' ' + [p3, p4, p5].join(':');
});
} else {
return timeStr.replace(/^(\d{4})(\d{2})(\d{2})$/g, function(match, p, p1, p2){
return timeStr.replace(/^(\d{4})(\d{2})(\d{2})$/g, function(match, p, p1, p2) {
return [p, p1, p2].join('-');
});
}
......@@ -75,7 +74,20 @@ export function paddingBorth(str) {
if (str.length == 3) {
str = 0 + str;
}
return str.replace(/^(\d{2})(\d{2})$/g, function(match, p , p1) {
return str.replace(/^(\d{2})(\d{2})$/g, function(match, p, p1) {
return [p, p1].join('-');
});
}
\ No newline at end of file
}
// 任务中心弹框
export function toTaskCenter(taskId) {
this.$confirm('任务发起成功,请去【企业管理】-【任务中心】查看处理结果和执行进度', '任务发起成功', {
confirmButtonText: '去任务中心',
cancelButtonText: '取消',
closeOnClickModal: false,
customClass: 'import-link-confirm-content',
type: 'warning'
}).then(() => {
window.open(`http://gicdev.demogic.com/gic-web/#/taskDetail/${taskId}`);
}).catch(() => true);
}
......@@ -9,7 +9,7 @@
<transition name="fade" mode="out-in">
<!-- 缓存已经填好内容的页面 -->
<!-- <keep-alive include="editGroupGrade"> -->
<router-view></router-view>
<router-view></router-view>
<!-- </keep-alive > -->
</transition>
</div>
......
<template>
<dm-layout project-name="report">
<router-view :key="$route.fullPath"></router-view>
<keep-alive>
<router-view :key="$route.fullPath"></router-view>
</keep-alive>
</dm-layout>
</template>
......
<template>
<el-dialog :visible.sync="visible" custom-class="delete-dialog" width="416px" :show-close="false">
<div class="content">
<i class="el-alert__icon el-icon-warning is-big icon" />
<h2>确认删除该标签吗?</h2>
<p class="desc">{{ desc }}</p>
<p v-for="item in list" :key="item.memberTagGroupId" class="item">
<a :href="`/member-tag/#/memberGroupEdit?memberTagGroupId=${item.memberTagGroupId}`" target="_blank" @click="isOpenPage = true">{{ item.groupName }}</a>
</p>
<footer class="footer">
<el-button class="ml10" @click="onClose">取消</el-button>
<el-button type="primary" @click="onSubmit">删除</el-button>
</footer>
</div>
</el-dialog>
</template>
<script>
import errMsg from '@/common/js/error';
import { getRequest } from '@/api/api';
export default {
props: {
visible: Boolean,
data: {
type: Object,
default: () => ({})
}
},
data() {
return {
list: [],
isOpenPage: false
};
},
computed: {
desc() {
return this.list.length ? '该标签下的标签值正在被分组使用,删除后会员分组将查询不到对应的会员。' : '标签删除后,若有正在使用该标签的会员分组则会员分组覆盖人群将查询不到该标签下的人群。';
}
},
methods: {
checkGroup() {
const { tagId, tagItemId } = this.data;
const params = {
tagId,
tagItemId
};
getRequest('/member-tag-value/check-member-group-ref', params).then(res => {
const { errorCode } = res.data;
if (errorCode === 1) {
this.list = res.data.result || [];
return;
}
errMsg.errorMsg(res.data);
});
},
onClose() {
this.$emit('update:visible', false);
this.$emit('close');
},
onSubmit() {
this.onClose();
this.$emit('submit', this.data);
},
subWindowChange() {
addEventListener('visibilitychange', this.visibleityWindowFn)
},
visibleityWindowFn() {
if (!document.hidden && this.isOpenPage) this.checkGroup();
}
},
watch: {
visible(newVal) {
newVal && this.checkGroup();
this.subWindowChange();
if (!newVal) {
removeEventListener('visibilitychange', this.visibleityWindowFn);
this.isOpenPage = false;
};
}
}
};
</script>
<style scoped lang="scss">
/deep/ .el-dialog__header {
padding: 0;
}
.delete-dialog {
position: relative;
.content {
padding: 5px 10px 4px 50px;
h2 {
color: #303133;
font-weight: bold;
font-size: 16px;
margin-bottom: 9px;
}
.desc {
font-size: 14px;
font-weight: 400;
color: #303133;
line-height: 20px;
margin-bottom: 16px;
}
.item:not(:last-of-type) {
margin-bottom: 10px;
}
a {
color: #2f54eb;
}
.footer {
margin-top: 24px;
text-align: right;
}
}
}
.ml10 {
margin-left: 10px;
}
.icon {
font-size: 21px;
position: absolute;
color: #fa8c16;
left: 30px;
top: 22px;
}
</style>
<template>
<el-dialog :title="data.title" :visible.sync="data.isShow" custom-class="manual-dialog" @close="onClose">
<div class="import">
<div :class="['excel-icon', filesData ? 'excel-icon--active' : 'excel-icon--add']" @click="handleUpload">
<span v-show="data.excelData.length === 0" class="import-btn">点击上传会员</span>
</div>
<div class="import-cont">
<div class="import-handle">
<input type="file" style="display: none" accept=".xlsx, .xls, .csv" ref="upload" @change="handleFileChange" />
<template v-if="data.excelData.length > 0">
<span>{{ data.excelName }}</span>
<span class="import-num">
已导入会员
<span class="color-303133">{{ data.excelData.length }}</span>
</span>
<el-button type="text" @click="reHandleUpload">重新导入</el-button>
</template>
</div>
<div class="import-tip">
<span class="import-tip-text">只能上传一个excel文件(2003版本以上),且数据不超过50000条</span>
<el-button type="text" @click="downloadExcelTemp">
<span class="font-12">下载Excel模板</span>
</el-button>
</div>
<div class="clear-old">
<el-checkbox v-model="data.optType">清空标签历史标记会员</el-checkbox>
<el-tooltip content="勾选后,此前被该标签标记的会员将移除此标签,此标签标记会员以本次导入为准。">
<i class="iconfont icon-xinxixianshi"></i>
</el-tooltip>
</div>
</div>
</div>
<template slot="footer">
<el-button @click="$emit('update:visiable', false)">取消</el-button>
<el-button type="primary" @click="tagItemImport">确定</el-button>
</template>
</el-dialog>
</template>
<script>
export default {
data() {
return {
filesData: undefined
}
},
props: {
data: {
type: Object,
default: () => ({})
},
visiable: Boolean
},
methods: {
tagItemImport() {
console.log(this.filesData);
if(!this.filesData) return this.$message.warning('请上传文件');
// this.$emit('update:visiable', false);
this.$emit('submit', this.filesData, this.$refs.upload);
},
// 关闭导入会员的弹窗
onClose() {
this.filesData = undefined;
this.$emit('close', false);
},
// 点击上传文件、
handleUpload() {
console.log(this.data);
if (this.data.excelData.length !== 0) return;
this.reHandleUpload();
},
// 重新导入按钮
reHandleUpload() {
this.$refs.upload.click();
},
// 处理上传的表格
handleFileChange(e) {
const files = e.target.files[0];
console.log(files);
// 校验.xlsx, .xls, .csv格式的文件
const reg = /(\.(xlsx|xls|csv))$/;
if (!files) return;
if (!reg.test(files.name)) {
this.$message.warning({
duration: 1000,
message: '仅支持上传xlsx、xls、csv格式的文件'
});
e.target.value = '';
return;
}
this.filesData = files;
},
// 导出 excel 模板
downloadExcelTemp() {
let origin = window.location.origin;
origin = origin.indexOf('localhost') >= 0 ? 'http://gicdev.demogic.com/' : origin;
window.location.href = `${origin}${this.data.downLoadUrl}`;
},
}
};
</script>
<style lang="scss" scoped>
.import {
display: flex;
align-items: start;
.excel-icon {
margin-right: 10px;
width: 40px;
height: 40px;
color: #606266;
background-repeat: no-repeat;
background-size: 100%;
background-position: center;
.import-btn {
display: block;
width: 100px;
transform: translate(50px, 4px);
}
}
.excel-icon--add {
cursor: pointer;
background-image: url('../../../static/img/add.svg');
&:hover {
color: #1890FF;
background-image: url("../../../static/img/add-hover.svg");
}
}
.excel-icon--active {
background-image: url('../../../static/img/excel.svg');
}
.import-cont {
width: 520px;
.import-handle {
display: flex;
align-items: center;
height: 22px;
font-size: 14px;
color: #606266;
.import-num {
margin-left: 24px;
padding-right: 15px;
margin-right: 12px;
color: #909399;
border-right: 1px solid #DCDFE6;
}
}
.import-tip {
font-size: 12px;
color: #909399;
.import-tip-text {
margin-right: 10px;
padding-right: 15px;
border-right: 1px solid #DCDFE6;
}
}
.clear-old {
margin-top: 24px;
font-size: 14px;
color: #606266;
.icon-xinxixianshi {
font-size: 12px;
color: #909399;
}
}
}
}
</style>
......@@ -7,7 +7,7 @@
color: #909399;
}
.manualTagEdit-wrap .el-form-item__label {
color: #606266;
color: #303133;
}
.manualTagEdit-wrap .el-textarea__inner {
height: 96px;
......@@ -20,7 +20,3 @@
.tag-value-wrapper .tag-head {
height: 23px;
}
.tag-value-wrapper .el-table__empty-block {
display: none;
}
<template>
<div class="flex">
<el-input v-model="item.tagItemName" placeholder="请输入标签值" class="w-380" maxlength="15" show-word-limit @change="onChange" />
<template>
<i v-if="currentLength < 50" class="iconfont plus icon margin icon-PlusOutlined" @click="add" />
<i v-else class="icon margin" />
</template>
<i v-if="currentLength > 1" class="iconfont delete icon icon-delete" @click="del" />
</div>
</template>
<script>
export default {
name: 'TagValueItem',
props: {
item: Object,
currentLength: Number
},
data() {
return {
tagValue: ''
};
},
methods: {
add() {
this.$emit('add', this.item.id);
},
del() {
this.$emit('del', this.item.id);
}
}
};
</script>
<style scoped lang="scss">
@mixin flex($justify, $alignItems) {
display: flex;
justify-content: $justify;
align-items: $alignItems;
}
.flex {
@include flex(initial, center);
&:not(:last-of-type) {
margin-bottom: 20px;
}
}
.w-380 {
width: 380px;
}
.icon {
display: inline-block;
width: 24px;
height: 24px;
border-radius: 2px;
text-align: center;
line-height: 24px;
cursor: pointer;
}
.margin {
margin: 0 7px 0 16px;
}
.plus {
color: #2f54eb;
&:hover {
background: rgba(47, 84, 235, .1);
}
}
.delete {
color: #f5222d;
&:hover {
background: rgba(245, 34, 45, .1);
}
}
</style>
<template>
<div class="card-item">
<div class="left">
<p class="title">{{ title }}</p>
<span class="count" @click="$emit('toDetail', data, index)">
{{ formatCount }}
<span></span>
</span>
</div>
<div class="right">
<i class="iconfont icon-jinzitakehu icon"></i>
</div>
</div>
</template>
<script>
export default {
props: {
title: String,
count: Number,
data: Object,
index: Number
},
computed: {
formatCount() {
return Number(this.count).toLocaleString();
}
}
};
</script>
<style scoped lang="scss">
.card-item {
padding: 12px;
width: 250px;
height: 80px;
box-sizing: border-box;
background: rgba(47, 84, 235, 0.04);
border-radius: 4px;
border: 1px solid rgba(47, 84, 235, 0.16);
display: flex;
justify-content: space-between;
align-items: center;
min-width: 0;
.count {
font-weight: bold;
color: #2f54eb;
font-size: 22px;
white-space: nowrap;
cursor: pointer;
span {
font-size: 14px;
color: #303133;
}
}
.title {
color: #303133;
font-size: 14px;
margin-bottom: 10px;
}
.icon {
font-size: 40px;
color: #2f54eb;
opacity: .14;
}
}
</style>
<template>
<div>
<!-- 添加标签、编辑标签 -->
<el-dialog :title="title" :visible.sync="showEditTagPop" top="10vh" width="900px" :before-close="handleClose" custom-class="edit-tag" :close-on-click-modal="false" append-to-body>
<el-dialog :title="title" :visible.sync="showEditTagPop" top="10vh" width="600px" :before-close="handleClose" custom-class="edit-tag" :close-on-click-modal="false" append-to-body>
<div class="dialog-box">
<div class="tag-info">
<p class="tag-name">
{{ tagDataAssgin.tagName }}
<span class="tag-flag">{{ tagDataAssgin.isActive == 1 ? '实时' : '非实时' }}</span>
<span class="tag-flag" :class="['tag-flag', tagDataAssgin.isActive ? 'real-time' : 'unreal-time']">{{ tagDataAssgin.isActive == 1 ? '实时' : '非实时' }}</span>
</p>
<p class="tag-desc">{{ tagDataAssgin.tagDescribe }}</p>
</div>
<p v-if="tagId" class="m-t-20 m-b-20 tag-config">标签值设置<el-tooltip v-if="tagDataAssgin.columnKey==='haobanWechatRelatedTime'||(Object.keys(tagDataAssgin).length&&tagDataAssgin.tagValue&&JSON.parse(tagDataAssgin.tagValue).val[0].data.key==='haobanWechatRelatedTime')" popper-class="edit-tag-tooltip" placement="top" open-delay="100" effect="light"
<p v-if="tagId" class="m-t-20 m-b-20 tag-config">
<dm-sub-title text="标签值设置"/>
<el-tooltip v-if="tagDataAssgin.columnKey==='haobanWechatRelatedTime'||(Object.keys(tagDataAssgin).length&&tagDataAssgin.tagValue&&JSON.parse(tagDataAssgin.tagValue).val[0].data.key==='haobanWechatRelatedTime')" popper-class="edit-tag-tooltip" placement="top" open-delay="100" effect="light"
><div slot="content"><span style="font-weight:600">固定时段:</span>在所选时间段内与关联了好办导购账号的企微员工成为好友的;<br/><span style="font-weight:600">相对时段:</span>在“标签统计时间”(每天凌晨计算统计一次)的前X天/月/年与某员工成为好友的。例:选择相对时段为“最近2天”,那么系统在5号凌晨进行统计时,统计的是在3号、4号与某员工成为企微好友的用户;系统在6号凌晨统计时,统计的是在4号、5号与某员工成为企微好友的客户;</div><i class="iconfont icon-tishi"></i></el-tooltip></p>
<!-- 所有标签的配置项 -->
<div class="tag-config-options">
......@@ -19,7 +21,7 @@
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="handleClose">取 消</el-button>
<el-button type="primary" @click="handleSave">确 定</el-button>
<el-button type="primary" @click="handleSave" style="margin-bottom: 14px">确 定</el-button>
</span>
</el-dialog>
</div>
......@@ -99,13 +101,14 @@ export default {
<style lang="less" scoped>
.dialog-box {
.tag-info {
padding-bottom: 10px;
border-bottom: 1px solid #dcdfe6;
background: #f2f3f5;
padding: 16px;
.tag-name {
display: flex;
align-items: center;
margin-bottom: 5px;
font-weight: 600;
margin-bottom: 8px;
font-weight: 500;
font-size: 16px;
color: #303133;
.tag-flag {
margin-left: 6px;
......@@ -113,8 +116,13 @@ export default {
font-size: 12px;
border-top-right-radius: 5px;
border-bottom-left-radius: 5px;
background-color: #2F54EB;
color: #fff;
&.real-time {
background-color: #2F54EB;
}
&.unreal-time {
background: #FA8C16;
}
}
}
.icon-tag-name {
......@@ -138,7 +146,7 @@ export default {
}
.tag-config-options {
max-height: 50vh;
overflow-y: auto;
// overflow-y: auto;
}
.tag-value {
margin-top: 10px;
......
<template>
<div class="group-list">
<div class="member-group" :class="{'light-group': currentIndex === -1}" @click="handleExpend">
<!-- <div class="member-group" :class="{'light-group': currentIndex === -1}" @click="handleExpend">
<i class="icon-list el-icon-caret-right icon-transform" :class="expendClass"></i>
我的会员分组
<i class="el-icon-plus icon-right icon-list" @click="addGroupDialog = true" :limit-code="$buttonCode.memberTagAddCateGory" v-if="$getButtonLimit($buttonCode.memberTagAddCateGory)"></i>
</div>
</div> -->
<el-collapseTransition>
<ul class="lists" v-show="expendTxt == '展开'">
<!-- <el-collapseTransition> -->
<!--我的会员分组-->
<ul class="lists" v-show="activeType == '1'">
<li v-for="(list, i) in lists" :key="i" :class="['member-list', { 'active-li': i == currentIndex }]" @click="handleChangeIndex(i, list)">
<span class="name-txt" :title="list.classifyName" v-show="!list.edit">{{ list.classifyName }}</span>
<el-input style="width: 100px;" size="mini" v-show="list.edit" v-model="list.classifyName" maxLength="10" @keyup.native.enter="modifyName(list)" />
<div class="oper-area" v-if="list.classifyName !== '未分类'">
<i class="iconfont icon-list-oper" :limit-code="$buttonCode.memberTagEditCateGory" v-if="$getButtonLimit($buttonCode.memberTagEditCateGory)" :class="[list.edit ? 'icon-dagou' : 'icon-bianji1']" @click.stop="editGroupName(list)"></i>
<i class="iconfont icon-list-oper" :limit-code="$buttonCode.memberTagDelCateGory" v-if="$getButtonLimit($buttonCode.memberTagDelCateGory)" :class="[list.edit ? 'icon-guanbi1' : 'icon-guanbi']" @click="deleteGroupName(list)"></i>
<div>
<i class="iconfont icon-kehufenzu icon"></i>
<span span class="name-txt" :title="list.classifyName" v-show="!list.edit">{{ list.classifyName }}</span>
<el-input style="width: 100px;" size="mini" v-show="list.edit" v-model="list.classifyName" maxLength="10" @keyup.native.enter="modifyName(list)" />
</div>
<el-popover placement="bottom" trigger="click">
<p class="more" :limit-code="$buttonCode.memberTagEditCateGory" v-if="$getButtonLimit($buttonCode.memberTagEditCateGory)" @click="editGroupName(list)">编辑分类</p>
<p class="more" :limit-code="$buttonCode.memberTagDelCateGory" v-if="$getButtonLimit($buttonCode.memberTagDelCateGory)" @click="deleteGroupName(list)">删除分类</p>
<i slot="reference" class="iconfont icon-gengduo icon"></i>
</el-popover>
</li>
<li @click="addGroupDialog = true" :limit-code="$buttonCode.memberTagAddCateGory" v-if="$getButtonLimit($buttonCode.memberTagAddCateGory)" style="margin-top:10px">
<el-button type="primary" class="ghost-btn add-group">新增分类</el-button>
</li>
</ul>
</el-collapseTransition>
<!-- </el-collapseTransition> -->
<div :class="['member-group', { 'active-item': currentLevelIndex == -1 }]" v-show="hasLevel" @click="handleExpendTag">
<!-- <div :class="['member-group', { 'active-item': currentLevelIndex == -1 }]" v-show="hasLevel" @click="handleExpendTag">
<i class="icon-list el-icon-caret-right icon-transform" :class="expendTagClass"></i>
金字塔会员分层
</div>
</div> -->
<el-collapseTransition>
<ul class="lists" v-show="expendTxtTag == '展开'">
<!-- <el-collapseTransition> -->
<!--金字塔分层-->
<ul class="lists" v-show="activeType == '3'">
<li v-for="(list, i) in groupLists" :key="i" :class="['member-list', { 'active-li': i == currentLevelIndex }]" @click="handleChangeLevel(i, list)">
<el-tooltip class="item" effect="dark" :content="list.aliasName | aliasTips" placement="top-start" :open-delay="300">
<span>{{ list.aliasName }}</span>
</el-tooltip>
<div>
<i class="iconfont icon-kehufenzu icon"></i>
<el-tooltip class="item" effect="dark" :content="list.aliasName | aliasTips" placement="top-start" :open-delay="300">
<span>{{ list.aliasName }}</span>
</el-tooltip>
</div>
</li>
</ul>
</el-collapseTransition>
<!-- </el-collapseTransition> -->
<div class="member-group" :class="{'light-group': currentFixedIndex === -1}" @click="handleExpendFixed">
<!-- <div class="member-group" :class="{'light-group': currentFixedIndex === -1}" @click="handleExpendFixed">
<i class="icon-list el-icon-caret-right icon-transform" :class="expendFixedClass"></i>
固化人群
</div>
</div> -->
<el-collapseTransition>
<ul class="lists" v-show="expendTxtFixed == '展开'">
<!-- <el-collapseTransition> -->
<!--固化人群-->
<ul class="lists" v-show="activeType == '2'">
<li v-for="(list, i) in fixedLists" :key="i" :class="['member-list', { 'active-li': i == currentFixedIndex }]" @click="handleChangeFixed(i, list)">
<span class="name-txt" :title="list.classifyName" v-show="!list.edit">{{ list.classifyName }}</span>
<div>
<i class="iconfont icon-kehufenzu icon"></i>
<span class="name-txt" :title="list.classifyName" v-show="!list.edit">{{ list.classifyName }}</span>
</div>
</li>
</ul>
</el-collapseTransition>
<!-- </el-collapseTransition> -->
<el-dialog :title="title" :visible.sync="addGroupDialog" width="320px" top="30vh" :close-on-click-modal="false">
<div>
......@@ -70,7 +86,9 @@ Vue.component(CollapseTransition.name, CollapseTransition);
export default {
name: 'group-list',
props: {
activeType: String
},
data() {
return {
lists: [],
......@@ -90,7 +108,7 @@ export default {
hasLevel: false,
currentLevelIndex: -2,
groupLists: [],
fixedLists: []
fixedLists: [],
};
},
......@@ -199,12 +217,7 @@ export default {
// 删除操作
this.excludeName(list);
})
.catch(() => {
this.$message({
type: 'info',
message: '已取消删除'
});
});
.catch(() => {});
},
excludeName(list) {
const param = {
......@@ -341,7 +354,6 @@ export default {
this.expendTxtFixed = this.expendTxtFixed === '展开' ? '收起' : '展开';
this.$emit('second-list', 'showFixedList');
},
//
_hasLevelFeature() {
hasLevelFeature().then(res => {
if (res.errorCode === 1) {
......@@ -364,13 +376,29 @@ export default {
}
return '';
},
},
watch: {
activeType(newVal) {
switch(newVal) {
case '1':
this.handleExpend();
break;
case '2':
this.handleExpendFixed();
break;
case '3':
this.handleExpendTag();
break;
default:
break;
}
}
}
};
</script>
<style lang="scss" scoped>
.group-list {
padding-top: 20px;
.recommend-list {
margin-top: 10px;
padding-left: 37px;
......@@ -420,12 +448,18 @@ export default {
color: #2F54EB;
}
.member-list {
height: 32px;
line-height: 32px;
padding-left: 37px;
height: 40px;
margin: 0 15px;
font-size: 14px;
color: #606266;
cursor: pointer;
border-radius: 4px;
display: flex;
justify-content: space-between;
align-items: center;
.icon {
margin: 0 4px;
}
&:hover {
color: #2F54EB;
.oper-area {
......@@ -438,10 +472,9 @@ export default {
text-overflow: ellipsis;
white-space: nowrap;
width: 100px;
height: 32px;
}
.oper-area {
display: none;
// display: none;
float: right;
margin-right: 10px;
}
......@@ -450,10 +483,10 @@ export default {
color: #606266;
.active-li {
color: #2F54EB;
background-color: #F3F6F9;
background-color: #EBEFFE;
}
li:hover {
background-color: #F3F6F9;
background-color: #EBEFFE;
}
}
......@@ -470,4 +503,15 @@ export default {
transform: rotate(0deg);
}
}
.more {
line-height: 26px;
text-align: center;
cursor: pointer;
&:hover {
color: #2f54eb;
}
}
.add-group {
width: 100%;
}
</style>
......@@ -10,9 +10,9 @@
</span>
<template v-if="$getButtonLimit($buttonCode.memberTagExportPeople)">
<el-button type="primary" class="down-member-list__btn m-l-8" @click="downMemberListPop.show = true" v-if="total < 1000000" :limit-code='$buttonCode.memberTagExportPeople'>人群导出</el-button>
<el-button type="primary" class="down-member-list__btn m-l-8" @click="tableFiledVisible = true" v-if="total < 1000000" :limit-code='$buttonCode.memberTagExportPeople'>人群导出</el-button>
<el-tooltip v-else class="item" effect="dark" content="每张报表导出人数限制为100万,大于100万的人群会自动拆分为多张报表进行导出" placement="top">
<el-button type="primary" class="down-member-list__btn m-l-8" @click="downMemberListPop.show = true" :limit-code='$buttonCode.memberTagExportPeople'>人群导出</el-button>
<el-button type="primary" class="down-member-list__btn m-l-8" @click="tableFiledVisible = true" :limit-code='$buttonCode.memberTagExportPeople'>人群导出</el-button>
</el-tooltip>
</template>
<el-button type="primary" class="down-member-list__btn" @click="$router.push(`/memberGroupLog?groupName=${groupName}`)" :limit-code='$buttonCode.memberTagOperateLog' v-if='$getButtonLimit($buttonCode.memberTagOperateLog)'>操作日志</el-button>
......@@ -309,6 +309,8 @@
type="2"
projectName="member-tag"
></vue-gic-export-excel>
<!--表格字段-->
<dm-table-filed :visible.sync="tableFiledVisible" projectName="member-tag" pageName="memberTag" :max="20" :defaultDisabled="['memberName']" :checkedFields="checkFields" @submit="onSubmiTableFiled" />
</div>
</template>
<script>
......@@ -334,7 +336,8 @@ export default {
excelUrl: '/gic-member-tag-web/member-tag-member/memberExportExcel',
params: {
memberTagGroupId: '',
requestProject: 'member-tag'
requestProject: 'member-tag',
exportFields: ''
}
},
......@@ -371,7 +374,9 @@ export default {
baseUrl: '',
sortFiled: '',
order: '',
tagSearch: ''
tagSearch: '',
tableFiledVisible: false,
checkFields: ['cardNo','gradeName','crateCardDateStringFormat','lastCostTimeFormat','costTimes','avgCost','birthdayMDFormat','pointsCurrent','costAll','mainStoreName','openStoreName']
};
},
computed: {
......@@ -672,7 +677,12 @@ export default {
message: error.message
});
});
}
},
onSubmiTableFiled(data) {
const { downMemberListPop: { params: exportParams } } = this;
this.downMemberListPop.show = true;
exportParams.exportFields = data.toString();
},
},
beforeMount() {
var that = this;
......
<template>
<div>
<div class="flex">
<el-tabs v-model="activeType" class="tabs">
<el-tab-pane label="我的客户分组" name="1"></el-tab-pane>
<el-tab-pane label="固化人群" name="2"></el-tab-pane>
<el-tab-pane label="金字塔客户分组" name="3"></el-tab-pane>
</el-tabs>
</div>
<div class="right-content">
<!-- 左边的会员分组 -->
<div class="left-box">
<group-list @getRecommend="getRecommend" @second-list="getsecondList"></group-list>
<div class="left-box" v-show="activeType != 3 || !isNew">
<group-list :activeType="activeType" @getRecommend="getRecommend" @second-list="getsecondList"></group-list>
</div>
<!-- 右边的表格 -->
<template v-if="showFixedList">
......@@ -343,33 +350,28 @@
</div>
<div class="right-box" v-show="isTagRecommend">
<div class="common-wrap__opt">
<div class="title">
<i class="el-icon-warning dialog-icon"></i>
<span>
覆盖人数于每日上午8点半进行更新
</span>
</div>
<div class="common-wrap__opt flex-between">
<div class="desc">覆盖人数于每日上午8点半进行更新</div>
<div class="batch-option">
<!-- <el-button type="primary" @click="toAddGroup" class="fr">分层配置</el-button> -->
<el-button type="primary" class="fr ghost-btn" @click="isNew = !isNew">{{ `查看${isNew ? '旧' : '新'}版金字塔会员分层` }}</el-button>
</div>
</div>
<div class="common-wrap__table m-t-20">
<pyramid-group-table v-show="isNew" />
<el-table
v-show="!isNew"
v-loading="loading"
ref="multipleTable"
:data="groupTableData"
tooltip-effect="dark"
style="width: 99%"
@selection-change="handleSelectionChange">
<el-table-column label="分层名称" prop="groupName" min-width="200">
<el-table-column label="分层名称" prop="groupName" min-width="130">
<template slot-scope="scope">
<el-tooltip class="item" effect="dark" :content="scope.row.groupName | aliasTips" placement="top-start">
<span>{{ scope.row.groupName }}</span>
</el-tooltip>
<span>{{ scope.row.groupName }}</span>
</template>
</el-table-column>
<el-table-column label="更新时间" prop="latestUpdateTime" min-width="100">
<el-table-column label="最近更新时间" prop="latestUpdateTime" min-width="100">
<template slot-scope="scope">
<p class="h-18">{{ scope.row.latestUpdateTime | formatTimeYMD }}</p>
<p class="h-18">{{ scope.row.latestUpdateTime | formatTimeHMS }}</p>
......@@ -394,7 +396,7 @@
{{ (scope.row.memberCount || 0) | formatNum }}
</template>
</el-table-column>
<el-table-column prop="appStatus" label="好办展示" min-width="100" :limit-code='$buttonCode.memberTagOpenHaoBan' v-if='$getButtonLimit($buttonCode.memberTagOpenHaoBan)'>
<!-- <el-table-column prop="appStatus" label="好办展示" min-width="100" :limit-code='$buttonCode.memberTagOpenHaoBan' v-if='$getButtonLimit($buttonCode.memberTagOpenHaoBan)'>
<template slot="header">
好办展示
<el-tooltip effect="dark" content="开启后,默认次日更新至好办管理后台,如需立即更新,请至好办管理后台操作“同步”" placement="top">
......@@ -404,8 +406,13 @@
<template slot-scope="scope">
<el-switch :active-value="1" :inactive-value="0" v-model="scope.row.appStatus" active-color="#2F54EB" @change="switchAppStatus(scope.row.appStatus, scope.row)"> </el-switch>
</template>
</el-table-column> -->
<el-table-column label="分组描述" min-width="250">
<template slot-scope="{ row }">
{{ row.groupName | aliasTips }}
</template>
</el-table-column>
<el-table-column label="操作" width="100" fixed="right" v-if='$getButtonLimit($buttonCode.memberTagGroupLevelDetail)'>
<!-- <el-table-column label="操作" width="100" fixed="right" v-if='$getButtonLimit($buttonCode.memberTagGroupLevelDetail)'>
<template slot-scope="scope">
<router-link
:to="`/memberLevelDetail?memberTagGroupId=${scope.row.memberTagGroupId}&aliasName=${scope.row.groupName}`"
......@@ -415,10 +422,10 @@
详情
</router-link>
</template>
</el-table-column>
</el-table-column> -->
</el-table>
</div>
<div class="block common-wrap__page text-right" v-if="groupTableData.length != 0">
<div class="block common-wrap__page text-right" v-if="groupTableData.length != 0 && !isNew">
<dm-pagination
background
@size-change="handleSizeChange"
......@@ -535,13 +542,15 @@ import {
import GroupList from './group-list';
import RecommendTable from './recommend-table';
import { aliasNames } from '@/config'
import PyramidGroupTable from './pyramid-group-table.vue';
export default {
name: 'memberGroupList',
components: {
GroupList,
RecommendTable,
BatchList
BatchList,
PyramidGroupTable
},
data() {
return {
......@@ -625,6 +634,8 @@ export default {
custom: [1, 1],
isHaoban: ''
},
activeType: '1', // 切换一级tab
isNew: true // 是否新版金字塔分层
};
},
......@@ -831,7 +842,7 @@ export default {
},
// 会员分组二级
getsecondList(list) {
console.log(list);
console.log(12312, list);
this.showFixedList = false
if(list === 'showFixedList') {
this.params.memberTagGroupClassifyId = '';
......@@ -1439,23 +1450,19 @@ export default {
</script>
<style lang="scss">
.common-wrap__opt {
&.flex-between {
display: flex;
align-items: center;
justify-content: space-between;
}
font-size: 0;
.m-r-8 {
margin-right: 8px;
}
.title {
font-size: 14px;
.desc {
font-size: 12px;
width: 270px;
color: #606266;
padding: 5px 10px;
border-radius: 4px;
background-color: #e6f7ff;
border: 1px solid #91d5ff;
.dialog-icon {
font-size: 12px;
color: #2F54EB;
padding-right: 4px;
}
}
}
.btn-foled-all{
......@@ -1606,4 +1613,19 @@ export default {
height: 0 !important;
overflow: hidden;
}
.tabs .el-tabs__nav-wrap::after {
display: none;
}
.tabs .el-tabs__header {
margin-bottom: 0;
}
</style>
<style lang="scss" scoped>
.flex {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 20px;
border-bottom: 1px solid #e4e7ed;
}
</style>
......@@ -4,16 +4,16 @@
<div class="right-box">
<div class="memberGroupDetail-wrap__info m-b-20">
<span class="group-name">{{ aliasName }}</span>
<span>( {{ tips }} )</span>
<span v-show="$route.query.type">( {{ setDesc($route.query.type, $route.query.time) }} )</span>
<span class="group-total m-l-20 p-l-20">
覆盖人数
<span>{{ separator(total) }}</span>
</span>
<template v-if="$getButtonLimit($buttonCode.memberTagExportPeople)">
<el-button type="primary" class="down-member-list__btn" @click="downMemberListPop.show = true" v-if="total < 1000000" :limit-code='$buttonCode.memberTagExportPeople'>人群导出</el-button>
<el-button type="primary" class="down-member-list__btn" @click="tableFiledVisible = true" v-if="total < 1000000" :limit-code='$buttonCode.memberTagExportPeople'>人群导出</el-button>
<el-tooltip v-else class="item" effect="dark" content="每张报表导出人数限制为100万,大于100万的人群会自动拆分为多张报表进行导出" placement="top">
<el-button type="primary" class="down-member-list__btn" @click="downMemberListPop.show = true" :limit-code='$buttonCode.memberTagExportPeople'>人群导出</el-button>
<el-button type="primary" class="down-member-list__btn" @click="tableFiledVisible = true" :limit-code='$buttonCode.memberTagExportPeople'>人群导出</el-button>
</el-tooltip>
</template>
</div>
......@@ -300,6 +300,8 @@
type="2"
projectName="member-tag"
></vue-gic-export-excel>
<!--表格字段-->
<dm-table-filed :visible.sync="tableFiledVisible" projectName="member-tag" pageName="memberTag" :max="20" :defaultDisabled="['memberName']" :checkedFields="checkFields" @submit="onSubmiTableFiled" />
</div>
</template>
<script>
......@@ -329,7 +331,8 @@ export default {
excelUrl: '/gic-member-tag-web/member-tag-member/memberExportExcel',
params: {
memberTagGroupId: '',
requestProject: 'member-tag'
requestProject: 'member-tag',
exportFields: ''
}
},
......@@ -366,7 +369,9 @@ export default {
baseUrl: '',
sortFiled: '',
order: '',
tagSearch: ''
tagSearch: '',
tableFiledVisible: false,
checkFields: ['cardNo','gradeName','crateCardDateStringFormat','lastCostTimeFormat','costTimes','avgCost','birthdayMDFormat','pointsCurrent','costAll','mainStoreName','openStoreName']
};
},
computed: {
......@@ -426,7 +431,6 @@ export default {
* 排序
*/
sortChange({ column, prop, order }) {
console.log(prop, order);
this.sortFiled = prop;
this.order = order == 'descending' ? 'desc' : 'asc';
this.getGroupDetail();
......@@ -442,7 +446,6 @@ export default {
};
getRequest('/member-tag-group/findOneDetial.json', params)
.then(res => {
console.log(res, 'tagValueDtoList');
that.groupName = res.data.result.tagGroupDto.groupName;
that.groupIsRealTime = res.data.result.tagGroupDto.isRealTime;
let list = res.data.result.tagValueDtoList;
......@@ -475,7 +478,6 @@ export default {
* 确认选择-弹层隐藏
*/
confirmUserDefined(data) {
console.log(data);
if (data.length < 1) {
this.$message.error({
duration: 1000,
......@@ -510,7 +512,6 @@ export default {
* 分页---页码变化
*/
handleSizeChange(val) {
console.log(`每页 ${val} 条`);
this.pageSize = val;
this.getGroupDetail();
},
......@@ -519,7 +520,6 @@ export default {
* 分页---当前页变化
*/
handleCurrentChange(val) {
console.log(`当前页: ${val}`);
this.currentPage = val;
this.getGroupDetail();
},
......@@ -586,7 +586,6 @@ export default {
* 获取头像处显示信息
*/
showSingleInfo(memberId) {
console.log(memberId);
const that = this;
const para = {
memberId: memberId
......@@ -640,7 +639,6 @@ export default {
errMsg.errorMsg(resData);
})
.catch(function(error) {
console.log(error);
that.$message.error({
duration: 1000,
message: error.message
......@@ -651,13 +649,27 @@ export default {
getTagLists({ requestProject: 'gic-member-tag-web' }).then(res => {
if (res.errorCode === 1) {
const ret = res.result;
console.log(ret);
let memberTagGroupId = this.$route.query.memberTagGroupId;
let target = ret.find(el => el.memberTagGroupId === memberTagGroupId);
// this.aliasName = target.aliasName;
this.memberCount = target.memberCount;
}
});
},
onSubmiTableFiled(data) {
const { downMemberListPop: { params: exportParams } } = this;
this.downMemberListPop.show = true;
exportParams.exportFields = data.toString();
},
setDesc(type, time) {
switch(type) {
case '核心':
return `年平均消费次数 ≥ 3 且 年平均消费金额 ≥ 3倍企业去年客单且休眠天数为${time}`;
case '潜力':
return `除核心会员、潜力会员、未消费会员之外的会员且休眠天数为${time}`;
case '普通':
return `消费次数 = 1 次且休眠天数为${time}`;
}
}
},
beforeMount() {
......@@ -678,6 +690,7 @@ export default {
}
this.downMemberListPop.params.gradeId = memberTagGroupId;
this.downMemberListPop.params.memberTagGroupId = memberTagGroupId;
this.downMemberListPop.excelUrl = local + this.downMemberListPop.excelUrl;
// this.canDownMemberList();
this.getTagValueDtoList();
......
<template>
<!--金字塔分组表格-->
<div class="pyramid-group">
<el-table :data="tableList" :header-cell-style="rowClass" v-loading="loading">
<el-table-column label="价值" width="140">
<template #header>
<div class="header">
<span>消费休眠天数</span>
<span>价值</span>
<p class="line"></p>
</div>
</template>
<template #default="{ row }">
{{ row.gradeName || '--' }}
({{ row.gradeName == '核心' ? 1 : row.gradeName == '普通' ? 6 : 3 }})
<el-tooltip placement="top">
<template #content>
<p class="m-b-5">消费周期 = (最近消费日期 - 首次消费日期 + 1) / 365;</p>
<p class="m-b-5">年平均消费次数 = 消费周期 / 有效消费次数;</p>
<p>年平均消费金额 = 累计消费金额 / 消费周期;</p>
</template>
<i v-if="row.gradeName == '核心'" class="iconfont icon-QuestionCircleOutlined" />
</el-tooltip>
</template>
</el-table-column>
<el-table-column v-for="(v, i) in tableHeader" :key="i" :prop="v.prop" :min-width="v.minWidth" :label="v.label" :formatter="v.formatter" :fixed="v.fixed">
<template slot-scope="scope">
<span v-if="v.formatter" v-html="v.formatter(scope.row)" @click="toDetail(scope.row, i)"></span>
<span v-else>{{ scope.row[v.prop] || '--' }}</span>
</template>
</el-table-column>
</el-table>
<div class="unconsume-member">
<span>{{ consumeList.gradeName }}</span>
<card-item style="margin-right: 16px" v-for="(v, i) in consumeList.itemList" :key="i" :title="v.groupName" :count="v.memberCount" :data="consumeList" @toDetail="toDetail" :index="i" />
</div>
<div class="show-haoban">
<h2>展示在好办</h2>
<span class="tips">开启后,默认次日更新好办管理后台,如需立即更新,请至好办管理后台操作“同步”</span>
<p>
<span v-for="item in haobanList" :key="item.memberTagGradeId" class="switch-item">
<span>{{ item.aliasName }}</span>
<el-switch class="switch" v-model="item.hanbanShow" active-color="#2f54eb" @change="onChangeSwitch(item)" />
</span>
</p>
</div>
</div>
</template>
<script>
import { getRequest } from '@/api/api';
import cardItem from './card-item';
export default {
components: {
cardItem
},
data() {
return {
haobanList: [],
tableList: [],
tableHeader: [],
consumeList: [], // 未消费会员
loading: false
};
},
created() {
this.getTableHeader();
this.getHaoBanData();
this.getTableList();
},
methods: {
getTableHeader() {
this.tableHeader = [
{ label: '指标说明', prop: 'gradeDesc', minWidth: 160 },
{ label: '0-30(高活跃)', minWidth: 130, formatter(row) { return `<span style="color:#2f54eb;cursor:pointer">${row.itemList[0].memberCount }人</span>` }},
{ label: '31-90(活跃)', minWidth: 130, formatter(row) { return `<span style="color: #2f54eb;cursor:pointer">${row.itemList[1].memberCount }人</span>` } },
{ label: '91-180(边缘)', minWidth: 130, formatter(row) { return `<span style="color: #2f54eb;cursor:pointer">${row.itemList[2].memberCount }人</span>` } },
{ label: '181-1年(沉睡)', minWidth: 130, formatter(row) { return `<span style="color: #2f54eb;cursor:pointer">${row.itemList[3].memberCount }人</span>` } },
{ label: '1年-2年(流失)', minWidth: 130, formatter(row) { return `<span style="color: #2f54eb;cursor:pointer">${row.itemList[4].memberCount }人</span>` } },
{ label: '2年以上(Lost+)', minWidth: 140, formatter(row) { return `<span style="color: #2f54eb;cursor:pointer">${row.itemList[5].memberCount }人</span>` } },
]
},
async getHaoBanData() {
const res = await getRequest('/memberTagGrade/gradeListNew', {});
const { result } = res.data;
this.haobanList = result;
},
async getTableList() {
this.loading = true;
const res = await getRequest('/memberTagGrade/gradeGroupListNew', {});
const { result } = res.data;
this.tableList = result.result.filter(el => el.gradeName != '未消费');
this.consumeList = result.result.find(el => el.gradeName == '未消费');
this.loading = false;
},
async onChangeSwitch(item) {
const { hanbanShow, memberTagGradeId } = item;
const params = { appStatus: Number(hanbanShow), memberTagGradeId };
const { data } = await getRequest('/memberTagGrade/updateHanbanShow', params);
if (data.errorCode != 1) return this.$message.error(data.message);
},
toDetail(row, index) {
if (!this.$getButtonLimit(this.$buttonCode.memberTagGroupLevelDetail)) return;
if (row.gradeName.includes('未消费')) {
const item = row.itemList[index];
this.$router.push(`/memberLevelDetail?memberTagGroupId=${item.memberTagGroupId}&aliasName=${item.groupName}`)
} else {
const item = row.itemList[--index];
const { gradeName } = row;
let { groupName } = item;
const groupNameArr = groupName.replace(/[(|)]/g, ' ').split(' ');
const time = !groupNameArr[0].includes('年') ? groupNameArr[0] + '天' : groupNameArr[0];
const aliasName = gradeName + groupNameArr[1];
this.$router.push(`/memberLevelDetail?memberTagGroupId=${item.memberTagGroupId}&aliasName=${aliasName}&time=${time}&type=${gradeName}`)
}
}
}
};
</script>
<style lang="scss">
.pyramid-group {
.header {
display: flex;
flex-direction: column;
padding: 0;
font-size: 13px;
position: relative;
span:first-child {
text-align: right;
margin-right: 6px;
}
span:last-of-type {
margin-left: 16px;
}
.line {
position: absolute;
width: 170px;
background: #dcdfe6;
top: 0;
left: -5px;
height: 1px;
transform-origin: left top;
transform: rotate(29deg);
}
}
th.el-table__cell {
padding: 0 !important;
&:nth-of-type(2) {
.cell {
padding: 0 20px !important;
}
}
&:first-child {
.cell {
padding: 0 !important;
}
}
}
.el-table__cell {
&:nth-of-type(2), &:first-child {
border-right: 1px solid #dcdfe6;
}
}
.unconsume-member {
display: flex;
align-items: center;
margin-top: 16px;
& > span {
margin-left: 10px;
margin-right: 56px;
font-size: 14px;
}
}
.show-haoban {
margin-top: 30px;
h2 {
color: #303133;
font-weight: bold;
font-size: 16px;
margin-bottom: 7px;
line-height: 22px;
}
.switch-item {
display: inline-block;
margin-right: 30px;
margin-bottom: 20px;
.switch {
margin-left: 14px;
}
}
}
.tips {
display: inline-block;
font-size: 12px;
color: #909399;
margin-bottom: 20px;
}
}
</style>
<template>
<div class="second">
<span class="name" :class="{ 'manual-name': tagName === '手工标签', 'light-active': tagList.name === tagRealName }" @click="handleSecondtag(tagList)">
<span>{{ tagList.name }}</span>
<div class="second" :class="[isOtherTag && 'manual']">
<span class="name" :class="{ 'manual-name': isOtherTag, 'light-active': tagList.name === tagRealName }" @click="handleSecondtag(tagList)">
<span v-if="isOtherTag">
<!-- tagList.icon -->
<svg class="menu-icon" :class="[ { 'icon-tag-light': tagList.name === tagRealName }]" aria-hidden="true">
<use :xlink:href="`#${tagList.icon}`"></use>
</svg>
<span class="tag-name" :class="{ 'icon-tag-light': tagList.name === tagRealName }">{{ tagList.name }}</span>
</span>
<span class="second-title" v-else>{{ tagList.name }}</span>
<el-tooltip content="请去微盟后台创建标签,且仅同步微盟多选项标签" v-if="tagList.id === '3d11ac15963b4c0790762e6147ea9315'">
<i class="el-icon-info"></i>
<i class="iconfont icon-QuestionCircleOutlined"></i>
</el-tooltip>
</span>
<i class="arrow-line iconfont icon-next-" v-if="tagName !== '手工标签'"></i>
<el-popover placement="bottom" width="30" trigger="click" v-if="getCodeAuth('add') || getCodeAuth('edit')">
<li class="more" @click="addNewType" :limit-code="getCode('add')" v-if="getCodeAuth('add')">新增子分类</li>
<li class="more" @click="handleEditType" :limit-code="getCode('edit')" v-if="getCodeAuth('edit')">编辑子分类</li>
<i slot="reference" class="el-icon-more icon-tag" v-if="tagName === '手工标签' && tagList.id !== '3d11ac15963b4c0790762e6147ea9315'"></i>
</el-popover>
<div class="third-list" :class="{ 'manual-tag': tagName === '手工标签' }">
<!-- <i class="iconfont icon-next-" v-if="tagName === '手工标签'"></i> -->
<i class="arrow-line iconfont icon-next-" v-if="!isOtherTag"></i>
<template v-if="tagName === '手工标签' && tagList.id !== '3d11ac15963b4c0790762e6147ea9315'">
<el-popover placement="bottom" width="30" trigger="click" v-if="getCode('add') || getCode('edit')">
<li class="more" @click="addNewType" :limit-code="getCode('add')" v-if="getCodeAuth('add')">新增子分类</li>
<li class="more" @click="handleEditType" :limit-code="getCode('edit')" v-if="getCodeAuth('edit')">编辑子分类</li>
<i slot="reference" class="iconfont icon-gengduo icon-tag"></i>
</el-popover>
</template>
<div class="third-list" :class="{ 'manual-tag': isOtherTag }">
<span v-for="(item, i) in tagList.children" :key="i" :class="{ 'light-active': item.name === tagRealName }" class="tag-item" @click="handleThirdTag(item)">
{{ item.name }}
</span>
</div>
<!-- 编辑子分类 -->
<el-dialog :title="newName" :visible.sync="editVisiable" :close-on-click-modal="false" width="40%">
<el-dialog :title="newName" :visible.sync="editVisiable" :close-on-click-modal="false" width="600px">
<el-table :data="editData" height="400">
<el-table-column label="子分类名称" prop="levelName">
<template slot-scope="scope">
......@@ -28,10 +36,17 @@
<span v-else>{{ scope.row.levelName }}</span>
</template>
</el-table-column>
<el-table-column label="标签数量" prop="count">
<template slot-scope="scope">
<span>{{ scope.row.count == null ? '--' : scope.row.count }}</span>
</template>
</el-table-column>
<el-table-column label="操作">
<template slot-scope="scope">
<el-button :disabled="scope.row.levelName.indexOf('未分类') > -1" @click="handleEdit(scope.row, scope.$index)" type="text">{{ scope.row.editText }}</el-button>
<el-button :disabled="scope.row.levelName.indexOf('未分类') > -1" type="text" @click="handleDelete(scope.row, scope.$index)"> {{ scope.row.deleteText }} </el-button>
<div class="btn-group">
<el-button :disabled="scope.row.levelName.indexOf('未分类') > -1" @click="handleEdit(scope.row, scope.$index)" type="text">{{ scope.row.editText }}</el-button>
<el-button :disabled="scope.row.levelName.indexOf('未分类') > -1" type="text" @click="handleDelete(scope.row, scope.$index)" style="margin-left: 20px"> {{ scope.row.deleteText }} </el-button>
</div>
</template>
</el-table-column>
</el-table>
......@@ -41,13 +56,13 @@
</el-dialog>
<!-- 新增子分类 -->
<el-dialog :title="newName" :visible.sync="dialogVisible" width="400px" top="20%" :close-on-click-modal="false">
<el-dialog :title="newName" :visible.sync="dialogVisible" width="600px" top="20%" :close-on-click-modal="false" custom-class="add-tag-dialog">
<div class="newtype">
<span class="name">子分类名称 </span>
<el-input style="width: 200px" placeholder="请输入分类名称" maxlength="10" v-model="typeName"> </el-input>
<span class="count">{{ typeName.length }}/10</span>
<p class="name"><span class="required">*</span>子分类 </p>
<el-input style="width: 100%" placeholder="请输入分类名称" maxlength="10" v-model="typeName" show-word-limit> </el-input>
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false">取 消</el-button>
<el-button type="primary" @click="newTag">添 加</el-button>
</span>
</el-dialog>
......@@ -112,6 +127,9 @@ export default {
code = type == 'add' ? 'memberTagAddChildCategory' : 'memberTagEditChildCategory';
return this.$buttonCode[code];
}
},
isOtherTag() {
return ['手工标签', '活动标签'].includes(this.tagName);
}
},
......@@ -156,7 +174,8 @@ export default {
...el,
editName: false,
editText: '编辑',
deleteText: '删除'
deleteText: '删除',
originLevelName: el.levelName
}));
this.editData[i].editName = true;
this.editData[i].editText = '确认';
......@@ -209,6 +228,7 @@ export default {
this.editData[i].editName = false;
this.editData[i].editText = '编辑';
this.editData[i].deleteText = '删除';
this.editData[i].levelName = list.originLevelName;
return;
}
const param = {
......@@ -268,7 +288,6 @@ export default {
})
.catch(err => {
this.addHandTagFlag = false;
console.log(err);
});
}
},
......@@ -301,40 +320,50 @@ export default {
line-height: 26px;
min-height: 26px;
padding-left: 24px;
padding-top: 3px;
padding-bottom: 2px;
overflow: hidden;
.name {
position: relative;
top: 1px;
top: 0;
float: left;
.second-title {
font-weight: bold;
}
span:hover {
color: #2F54EB;
color: #2f54eb;
}
}
.light-active {
color: #2F54EB;
color: #2f54eb;
}
.manual-name {
display: block;
float: none;
text-align: left;
font-size: 14px;
line-height: 22px;
margin-bottom: 16px;
}
.third-list {
margin-left: 90px;
font-size: 0;
.tag-item {
display: inline-block;
vertical-align: middle;
line-height: 26px;
margin-right: 15px;
font-size: 14px;
color: #606266;
line-height: 22px;
height: 22px;
margin-right: 8px;
margin-bottom: 8px;
font-size: 12px;
padding: 0 8px;
background: #F2F3F5;
border-radius: 2px;
color: #303133;
&:hover {
color: #2F54EB;
color: #2f54eb;
}
}
.light-active {
color: #2F54EB;
background: #EBEFFE;
color: #2f54eb;
font-weight: 500;
}
.icon-next- {
font-size: 30px;
......@@ -349,37 +378,86 @@ export default {
.arrow-line {
float: left;
position: relative;
top: 2px;
top: 1px;
font-size: 30px;
}
.icon-tag {
position: absolute;
right: 20px;
top: 10px;
color: #c0c4cc;
right: 16px;
top: 0;
color: #303133;
cursor: pointer;
width: 24px;
height: 24px;
padding: 5px 11px;
box-sizing: border-box;
display: flex;
border-radius: 2px;
align-items: center;
justify-content: center;
&:hover {
color: #606266;
background: #F2F3F7;
}
}
&.manual {
padding: 0;
margin-top: 18px;
&:first-child {
margin-top: 0;
}
}
.icon-tag-light {
color: #2f54eb;
font-weight: bold;
}
}
.more {
line-height: 26px;
text-align: center;
cursor: pointer;
&:hover {
color: #2F54EB;
color: #2f54eb;
}
}
.newtype {
position: relative;
.name {
margin-right: 10px;
.add-tag-dialog {
.newtype {
.name {
margin-bottom: 10px;
}
}
.count {
position: absolute;
top: 4px;
right: 90px;
.required {
color: red;
margin-right: 5px;
}
}
/deep/ .el-dialog__header {
padding-bottom: 0px;
}
/deep/ .el-dialog__title {
font-size: 16px;
font-weight: bold;
}
/deep/ .el-dialog__footer {
padding-bottom: 20px;
}
.tag-name {
display: inline-block;
margin-left: 5px;
font-size: 16px;
font-weight: bold;
color: #303133;
cursor: pointer;
&:hover {
color: #2f54eb;
}
}
.btn-group {
font-size: 0;
}
.menu-icon {
width: 16px; height: 16px;
vertical-align: -0.15em;
fill: currentColor;
overflow: hidden;
}
</style>
<template>
<!-- 具体标签 -->
<div class="tag-some-list">
<el-table :data="tableData" style="width: 100%">
<el-table-column label="标签名称" prop="tagName" min-width="100" fixed="left">
<template slot-scope="scope">
<span class="tag-name">{{ scope.row.tagName }}</span>
<el-tooltip class="item" effect="dark" content="添加标签" placement="bottom">
<i class="iconfont icon-tag-name icon-PlusOutlined" v-if="getCodeAuth" :limit-code="getCode" v-track:common.click="handleTrackParam('addTag', scope.row)" @click="addTag(scope.row)"></i>
</el-tooltip>
</template>
</el-table-column>
<el-table-column label="上级分类名称" min-width="90" prop="tagLevelGroupName">
<template slot-scope="{ row }">
<span>{{ row.tagLevelGroupName || '--' }}</span>
</template>
</el-table-column>
<el-table-column label="覆盖人数" prop="memberCount" min-width="80" show-overflow-tooltip>
<template slot="header">
覆盖人数
<el-popover width="260" trigger="hover" placement="top">
<div style="color: #303133;">
标签下不同标签值可能覆盖相同的会员,因此此处“标签”覆盖人数去重显示(如“喜欢的颜色-白、红、黑、蓝”,某会员身上可能同时具备“白、黑”二种标签值)
</div>
<i slot="reference" class="iconfont icon-QuestionCircleOutlined refresh"></i>
</el-popover>
</template>
<template slot-scope="scope">
{{ scope.row.memberCount ? (scope.row.memberCount | formatNum) + '人' : '--' }}
</template>
</el-table-column>
<el-table-column label="标签描述" prop="tagDescribe" min-width="150">
<template slot-scope="scope">
<div>{{ scope.row.tagDescribe ? scope.row.tagDescribe : '--' }}</div>
</template>
</el-table-column>
<el-table-column label="创建时间" prop="createTime" min-width="90">
<template slot-scope="{ row }">
<template v-if="row.createTime">
<p>{{ dateformat(new Date(row.createTime), 'yyyy-MM-dd') }}</p>
<p>{{ dateformat(new Date(row.createTime), 'hh:mm:ss') }}</p>
</template>
<span v-else>--</span>
</template>
</el-table-column>
<el-table-column label="操作" fixed="right">
<template slot-scope="{ row }">
<el-button type="text" @click="editActiveTag(row)">编辑</el-button>
<el-button type="text" @click="editActiveTagValue(row)">详情</el-button>
<el-button type="text" @click="deleteActiveTag(row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<delete-tag-dialog :visible.sync="deleteTagDialog.visible" :data="deleteTagDialog.deleteData" @submit="doDelete" />
</div>
</template>
<script>
import Emitter from '@/mixins/emitter';
import tagDetails from '@/components/tagDetail/mixin/index';
import { dateformat } from '@/utils/formatTime';
import { delThirdHandTag } from '@/request/api';
import DeleteTagDialog from '../manualTag/delete-tag-dialog.vue';
export default {
name: 'tag-container',
mixins: [tagDetails, Emitter],
components: { DeleteTagDialog },
props: {
data: {
type: Array,
default() {
return [];
}
},
refersh: Object
},
data() {
return {
tableData: [],
tagData: {},
dateformat,
deleteTagDialog: {
visible: false,
deleteData: {}
},
};
},
methods: {
addTag(list) {
this.$emit('addTag', list);
},
handleTrackParam(type, data) {
let fn = {
addTag: () => {
return {
data: { id: data.tagId, name: data.tagName }
};
}
}[type];
return { fn: () => {}, data: fn ? fn() : {} };
},
editActiveTag(list) {
this.$emit('ediActiveTag', list);
},
editActiveTagValue(list) {
this.$emit('setGroupId');
localStorage.setItem('jumpTag', '');
localStorage.setItem('jumpThirdTag', '');
this.$router.push({
path: '/manualTagValueEdit',
query: { tagId: list.tagId, type: 'active' }
});
},
deleteActiveTag(list) {
this.deleteTagDialog.visible = true;
this.deleteTagDialog.deleteData = list;
},
doDelete(list) {
const param = {
tagId: list.tagId,
requestProject: 'gic-member-tag-web'
};
delThirdHandTag(param)
.then(res => {
if (res.errorCode == 1) {
this.$message({
message: '删除成功',
type: 'success',
duration: 1000
});
this.$emit('deleteActiveTag', this.groupId);
}
})
},
},
watch: {
data: {
immediate: true,
handler(newval) {
this.tableData = newval;
}
},
refersh: {
immediate: true,
handler(newval) {
// 刷新
if (newval.changeRefersh) {
let index = this.tableData.findIndex(el => newval.tagId === el.tagId);
this.tableData[index].refersh = true;
}
}
}
},
computed: {
getCodeAuth() {
let code = 'memberTagCreateGroup';
return this.$getButtonLimit(this.$buttonCode[code]);
},
getCode() {
let code = 'memberTagCreateGroup';
return this.$buttonCode[code];
}
}
};
</script>
<style lang="scss" scoped>
.tag-some-list {
margin: 0 20px;
overflow-y: auto;
}
.icon-tag-name {
display: inline-block;
vertical-align: bottom;
font-size: 16px;
cursor: pointer;
color: #303133;
transition: all .3s;
&:hover {
transform: scale(1.25);
}
}
.refresh {
color: #909399;
&:hover {
color: #2f54eb;
}
}
</style>
<template>
<!-- 具体标签 -->
<div class="tag-some-list">
<el-table :data="tableData" style="width: 100%">
<el-table-column label="标签名称" prop="tagName" min-width="130">
<template slot-scope="scope">
<span class="tag-name">{{ scope.row.tagName }}</span>
<el-tooltip class="item" effect="dark" content="添加标签" placement="top">
<i class="iconfont icon-tag-name icon-PlusOutlined" v-if="getCodeAuth" :limit-code="getCode" v-track:common.click="handleTrackParam('addTag', scope.row)" @click="addTag(scope.row)"></i>
</el-tooltip>
</template>
</el-table-column>
<el-table-column label="是否实时" prop="isActive" min-width="60">
<template slot-scope="scope">
<span :class="['base', scope.row.isActive == 1 ? 'keep-active' : 'no-active']"> {{ scope.row.isActive == 1 ? '实时' : '非实时' }} </span>
</template>
</el-table-column>
<el-table-column label="上级分类名称" min-width="90">
<template slot-scope="{ row }">
<span>{{ row.tagLevelGroupName || '--' }}</span>
</template>
</el-table-column>
<el-table-column label="标签描述" prop="tagDescribe" min-width="170">
<template slot-scope="scope">
<div>{{ scope.row.tagDescribe ? scope.row.tagDescribe : '--' }}</div>
</template>
</el-table-column>
<el-table-column label="操作">
<template slot-scope="{ row }">
<el-button type="text" @click="changeMoreUse(row)">{{ row.isMoreUse ? '取消' : '设为常用' }}</el-button>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script>
import Emitter from '@/mixins/emitter';
import tagDetails from '@/components/tagDetail/mixin/index';
import { updateMoreUse } from '@/request/api';
export default {
name: 'tag-container',
mixins: [tagDetails, Emitter],
props: {
data: {
type: Array,
default() {
return [];
}
},
refersh: Object
},
data() {
return {
tableData: [],
tagData: {}
};
},
methods: {
addTag(list) {
this.$emit('addTag', list);
},
handleTrackParam(type, data) {
let fn = {
addTag: () => {
return {
data: { id: data.tagId, name: data.tagName }
};
}
}[type];
return { fn: () => {}, data: fn ? fn() : {} };
},
changeMoreUse(row) {
const params = { tagId: row.tagId, isMoreUse: row.isMoreUse ? 0 : 1 };
updateMoreUse(params).then(() => {
this.$message.success('设置成功');
row.isMoreUse = row.isMoreUse ? 0 : 1;
})
}
},
watch: {
data: {
immediate: true,
handler(newval) {
this.tableData = newval;
}
},
refersh: {
immediate: true,
handler(newval) {
// 刷新
if (newval.changeRefersh) {
let index = this.tableData.findIndex(el => newval.tagId === el.tagId);
this.tableData[index].refersh = true;
}
}
}
},
computed: {
getCodeAuth() {
let code = 'memberTagCreateGroup';
return this.$getButtonLimit(this.$buttonCode[code]);
},
getCode() {
let code = 'memberTagCreateGroup';
return this.$buttonCode[code];
}
}
};
</script>
<style lang="scss" scoped>
.tag-some-list {
margin: 0 20px;
overflow-y: auto;
}
.icon-tag-name {
display: inline-block;
vertical-align: bottom;
font-size: 16px;
cursor: pointer;
color: #303133;
transition: all 0.3s;
&:hover {
transform: scale(1.25);
}
}
.refresh {
color: #909399;
&:hover {
color: #1890ff;
}
}
.base {
height: 22px;
border-radius: 2px;
padding: 0 8px;
display: inline-block;
text-align: center;
line-height: 22px;
font-size: 12px;
&.keep-active {
background: #dee3fc;
color: #2f54eb;
}
&.no-active {
background: #feecda;
color: #fa8c16;
}
}
</style>
<template>
<div class="list">
<!-- v-if="list.name !== '手工标签'" -->
<span class="expends-txt" @click="handleChangeExpends">{{ expends }} </span>
<div class="first-tag">
<div>
<i :class="[list.icon, { 'icon-tag-light': list.name === tagRealName }]" class="iconfont menu-icon"></i>
<span class="tag-name" :class="{ 'icon-tag-light': list.name === tagRealName }" @click="handleFirstTag">{{ list.name }}</span>
<div v-if="isOtherTag" class="mb16">
<svg class="menu-icon" :class="[ { 'icon-tag-light': list.name === tagRealName }]" aria-hidden="true">
<use :xlink:href="`#${list.icon}`"></use>
</svg>
<span class="tag-name" :class="{ 'icon-tag-light': list.name === tagRealName }" @click="handleFirstTag">{{ list.name }}</span>
</div>
<el-collapseTransition>
<div class="second-tag" v-show="expends === '收起'">
<second-tag :list="item" :tag-name="list.name" v-for="(item, i) in list.children" :key="i"></second-tag>
<div class="second-tag">
<second-tag :type="activeTag" :list="item" :tag-name="tagName" v-for="(item, i) in list.children" :key="i"></second-tag>
</div>
</el-collapseTransition>
</div>
......@@ -33,26 +33,30 @@ export default {
props: {
// 会员标签的数据
tagList: Object
tagList: Object,
activeTag: String
},
data() {
return {
list: {},
typeName: '',
editData: [],
expends: '收起'
editData: []
};
},
computed: {
...mapState(['tagRealName'])
...mapState(['tagRealName']),
tagName() {
const { activeTag } = this;
return activeTag == 'system' ? '系统标签' : activeTag == 'manual' ? '手工标签' : '活动标签';
},
isOtherTag() {
return !['手工标签', '活动标签'].includes(this.list.name);
}
},
methods: {
handleChangeExpends() {
this.expends = this.expends === '收起' ? '展开' : '收起';
},
// 处理一级标签
handleFirstTag() {
localStorage.setItem('jumpTag', '');
......@@ -75,43 +79,54 @@ export default {
<style lang="scss" scoped>
.list {
position: relative;
padding-top: 10px;
margin-top: 10px;
margin-top: 22px;
overflow: hidden;
&:last-child {
border-bottom: none;
}
&:first-child {
margin-top: 24px;
}
.expends-txt {
position: absolute;
right: 20px;
font-size: 14px;
color: #2F54EB;
color: #2f54eb;
cursor: pointer;
}
.tag-name {
display: inline-block;
margin-left: 5px;
font-size: 14px;
font-size: 16px;
font-weight: bold;
color: #303133;
cursor: pointer;
line-height: 22px;
&:hover {
color: #2F54EB;
color: #2f54eb;
}
}
.second-tag {
margin: 0 1px;
font-size: 14px;
color: #303133;
border-bottom: 1px solid #ebeef5;
cursor: pointer;
}
.icon-tag-light {
color: #2F54EB;
font-size: 14px;
color: #2f54eb;
font-weight: bold;
}
}
.list:last-child .second-tag {
border-bottom: none;
}
.mb16 {
margin-bottom: 16px;
}
.menu-icon {
width: 16px; height: 16px;
vertical-align: -0.15em;
fill: currentColor;
overflow: hidden;
}
</style>
......@@ -100,7 +100,6 @@
position: relative;
width: 100%;
height: 100%;
background: #f7f8fa;
}
.right-content {
padding-top: 12px;
......@@ -110,4 +109,18 @@
padding: 20px;
min-height: calc(100vh - 296px);
background: #fff;
}
\ No newline at end of file
}
// 幽灵按钮放在全局方便全局改样式
.ghost-btn {
background: #fff !important;
color: #2f54eb !important;
&:hover {
border-color: #597EF7;
color: #597EF7 !important;
}
&:active {
border-color: #1D39C4;
color: #1D39C4 !important;
}
}
......@@ -352,6 +352,9 @@ input:focus {
.m-r-20 {
margin-right: 20px;
}
.m-b-5 {
margin-bottom: 5px;
}
.m-b-20 {
margin-bottom: 20px;
}
......
......@@ -11263,7 +11263,7 @@
.el-button:focus {
color: #2F54EB;
border-color: #2F54EB;
background-color: #e8f4ff;
background-color: #EBEFFE;
}
.el-button:active {
......@@ -11385,8 +11385,8 @@
.el-button--primary.is-plain {
color: #2F54EB;
background: #e8f4ff;
border-color: #a3d3ff;
background: #EBEFFE;
border-color: #2f54eb;
}
.el-button--primary.is-plain:hover,
......@@ -11408,7 +11408,7 @@
.el-button--primary.is-plain.is-disabled:focus,
.el-button--primary.is-plain.is-disabled:active {
color: #74bcff;
background-color: #e8f4ff;
background-color: #EBEFFE;
border-color: #d1e9ff;
}
......@@ -12526,7 +12526,7 @@
.el-dropdown-menu__item:not(.is-disabled):hover,
.el-dropdown-menu__item:focus {
background-color: #e8f4ff;
background-color: #EBEFFE;
color: #597EF7;
}
......@@ -13663,7 +13663,7 @@
.el-menu-item:hover,
.el-menu-item:focus {
outline: none;
background-color: #e8f4ff;
background-color: #EBEFFE;
}
.el-menu-item.is-disabled {
......@@ -13721,7 +13721,7 @@
.el-submenu__title:hover,
.el-submenu__title:focus {
outline: none;
background-color: #e8f4ff;
background-color: #EBEFFE;
}
.el-submenu__title.is-disabled {
......@@ -13731,7 +13731,7 @@
}
.el-submenu__title:hover {
background-color: #e8f4ff;
background-color: #EBEFFE;
}
.el-submenu .el-menu {
......@@ -25700,7 +25700,7 @@
.el-button:focus {
color: #2F54EB;
border-color: #2F54EB;
background-color: #e8f4ff;
background-color: #EBEFFE;
}
.el-button:active {
......@@ -25822,8 +25822,8 @@
.el-button--primary.is-plain {
color: #2F54EB;
background: #e8f4ff;
border-color: #a3d3ff;
background: #EBEFFE;
border-color: #2f54eb;
}
.el-button--primary.is-plain:hover,
......@@ -25845,7 +25845,7 @@
.el-button--primary.is-plain.is-disabled:focus,
.el-button--primary.is-plain.is-disabled:active {
color: #74bcff;
background-color: #e8f4ff;
background-color: #EBEFFE;
border-color: #d1e9ff;
}
......@@ -29645,18 +29645,18 @@
}
.el-table--striped .el-table__body tr.el-table__row--striped.current-row td {
background-color: #e8f4ff;
background-color: #EBEFFE;
}
.el-table__body tr.hover-row>td,
.el-table__body tr.hover-row.current-row>td,
.el-table__body tr.hover-row.el-table__row--striped>td,
.el-table__body tr.hover-row.el-table__row--striped.current-row>td {
background-color: #e8f4ff;
background-color: #EBEFFE;
}
.el-table__body tr.current-row>td {
background-color: #e8f4ff;
background-color: #EBEFFE;
}
.el-table__column-resize-proxy {
......@@ -31929,7 +31929,7 @@
}
.el-table-filter__list-item:hover {
background-color: #e8f4ff;
background-color: #EBEFFE;
color: #597EF7;
}
......@@ -49297,7 +49297,7 @@
.el-button:focus {
color: #2F54EB;
border-color: #2F54EB;
background-color: #e8f4ff;
background-color: #EBEFFE;
}
.el-button:active {
......@@ -49419,8 +49419,8 @@
.el-button--primary.is-plain {
color: #2F54EB;
background: #e8f4ff;
border-color: #a3d3ff;
background: #EBEFFE;
border-color: #2f54eb;
}
.el-button--primary.is-plain:hover,
......@@ -49442,7 +49442,7 @@
.el-button--primary.is-plain.is-disabled:focus,
.el-button--primary.is-plain.is-disabled:active {
color: #74bcff;
background-color: #e8f4ff;
background-color: #EBEFFE;
border-color: #d1e9ff;
}
......@@ -77876,8 +77876,8 @@
.el-button--primary.is-plain {
color: #2F54EB;
background: #e8f4ff;
border-color: #a3d3ff;
background: #EBEFFE;
border-color: #2f54eb;
}
.el-button--primary.is-plain:hover,
......@@ -77897,7 +77897,7 @@
/* .el-button--primary.is-plain.is-disabled, .el-button--primary.is-plain.is-disabled:hover, .el-button--primary.is-plain.is-disabled:focus, .el-button--primary.is-plain.is-disabled:active {
color: #74bcff;
background-color: #e8f4ff;
background-color: #EBEFFE;
border-color: #d1e9ff; } */
.el-button--success {
......@@ -81804,4 +81804,4 @@
.damo-popover {
max-height: 400px;
overflow: auto;
}
\ No newline at end of file
}
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