Commit 07353533 by liuchenxi

update: 会员标签

parent e9b89103
......@@ -3,13 +3,9 @@
<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>GIC-会员标签</title>
<link rel="stylesheet" href="//at.alicdn.com/t/font_688955_99jmfacmlpp.css">
<link rel="stylesheet" href="//at.alicdn.com/t/font_3276801_vxllf19dief.css">
</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" 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,81 +32,87 @@ 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;
......@@ -140,12 +127,8 @@ 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;
......@@ -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,7 +1461,19 @@ export default {
that.pindex = pindex;
},
/* eslint-disable */
changeRemoteMethod(e, parent) {
changeRemoteMethod(item) {
let tagsMap = null;
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);
}
});
},
/**
......
......@@ -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,26 @@ 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
}
})
......@@ -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);
}
<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.data.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() {
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() {
if (this.data.excelData.length !== 0) return;
this.reHandleUpload();
},
// 重新导入按钮
reHandleUpload() {
this.$refs.upload.click();
},
// 处理上传的表格
handleFileChange(e) {
const files = e.target.files[0];
// 校验.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>
<template>
<div class="manualTagDetail-wrap common-wrap">
<!-- <nav-crumb :navpath="navpath"></nav-crumb> -->
<div class="right-content">
<div class="right-box">
<div class="manualTagDetail-wrap__info">
<p class="group-name">{{ tagItemName }}</p>
<template v-if="getCodeAuth">
<el-button type="primary" class="down-member-list__btn m-l-8" @click="downTagDetailListPop.show = true" v-if="total < 1000000" :limit-code="getCode">人群导出</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="downTagDetailListPop.show = true" :limit-code="getCode">人群导出</el-button>
</el-tooltip>
</template>
<dm-sub-title :text="tagItemName" />
</div>
<div class="manualTagDetail-wrap__table">
<el-input
class="w-220 m-r-8"
placeholder="请输入会员卡号、手机号"
prefix-icon="el-icon-search"
v-model="pageParam.search"
clearable
style="margin: 20px 0"
@clear="clearSearch"
@keyup.enter.native="enterSearch"
/>
<div class="operation-line">
<el-input
class="m-r-8"
placeholder="请输入姓名/昵称/手机号/会员卡号"
prefix-icon="el-icon-search"
v-model="pageParam.search"
clearable
style="margin: 20px 0;width: 270px"
@clear="clearSearch"
@keyup.enter.native="enterSearch"
/>
<template v-if="getCodeAuth">
<el-button type="primary" class="down-member-list__btn m-l-8" @click="showExport" v-if="total < 1000000" :limit-code="getCode">
<i class="iconfont icon-xiazai" />
导出人群
</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="showExport" :limit-code="getCode">
<i class="iconfont icon-xiazai" />
导出人群
</el-button>
</el-tooltip>
</template>
</div>
<el-table v-loading="loading" @sort-change="sortChange" :data="tagDetailList" style="width: 100%">
<!-- <div v-for="item in selectedFields" :key="item.code"> -->
<el-table-column
......@@ -192,16 +199,17 @@
<div :index="$index">{{ row.memberTagRelationTime ? dateformat(new Date(row.memberTagRelationTime), 'yyyy-MM-dd hh:mm:ss') : '--' }}</div>
</template>
</el-table-column>
<el-table-column label-class-name="table-header__handle" fixed="right" min-width="150">
<el-table-column v-if="$getButtonLimit($buttonCode.memberTagRecordObserve)" label-class-name="table-header__handle" fixed="right" min-width="150">
<template slot="header">
<span>操作</span>
<i class="el-icon-setting" @click="showDefined"></i>
<i class="el-icon-setting setting" @click="showDefined"></i>
</template>
<template slot-scope="scope">
<a
rel="nofollow noopener noreferrer"
target="_blank"
v-if="scope.row.isWeixinMember"
:limit-code="$buttonCode.memberTagRecordObserve"
:href="'/member/#/wechatmemberDetail?memberId=' + scope.row.memberId + '&channel=wxMember&fromPage=memberGroup'"
class="el-button el-button--text"
>查看</a
......@@ -210,6 +218,7 @@
rel="nofollow noopener noreferrer"
target="_blank"
v-else
:limit-code="$buttonCode.memberTagRecordObserve"
:href="'/member/#/posmemberDetail?memberId=' + scope.row.memberId + '&channel=posMember&fromPage=memberGroup'"
class="el-button el-button--text"
>查看</a
......@@ -244,12 +253,13 @@
type="2"
projectName="member-tag"
></vue-gic-export-excel>
<!--表格字段导出-->
<dm-table-filed :visible.sync="tableFiledVisible" projectName="member-tag" pageName="memberTag" :max="8" :defaultDisabled="['memberName']" @submit="onSubmiTableFiled" />
</div>
</template>
<script>
import './manualTagDetail.less';
import { dateformat } from '@/utils/formatTime';
// import navCrumb from '@/components/nav/nav.vue';
import userDefined from '@/components/userDefined.vue';
import errMsg from '@/common/js/error';
import { getRequest } from '@/api/api';
......@@ -307,36 +317,12 @@ export default {
authStatus: 0
},
baseUrl: '',
tagSearch: ''
tagSearch: '',
tableFiledVisible: false,
checkedFields: []
};
},
computed: {
// 面包屑参数
navpath() {
return [
{
name: '首页',
path: `${window.location.origin}/report/#/memberSummary`,
relocation: true
},
{
name: '会员管理',
path: ''
},
{
name: '会员标签',
path: '/member-tag'
},
{
name: '标签值设置',
path: `/manualTagValueEdit?tagId=${this.$route.query.tagId}`
},
{
name: '覆盖人群明细',
path: ''
}
];
},
getCodeAuth() {
let code = "memberTagExportMember";
return this.$getButtonLimit(this.$buttonCode[code]);
......@@ -488,8 +474,6 @@ export default {
that.selectedFields.push(ele);
}
});
console.log(that.selectedFields)
console.log(that.tagDetailList)
}
})
.catch(e => {
......@@ -522,6 +506,7 @@ export default {
* 点击信息跳转分组详情
*/
linkDetail(memberId, isWeixinMember) {
if (!this.$getButtonLimit(this.$buttonCode.memberTagRecordObserve)) return;
window.open(
!!isWeixinMember
? `${window.location.origin}/member/#/wechatmemberDetail?memberId=${memberId}&channel=wxMember&fromPage=memberGroup`
......@@ -581,8 +566,8 @@ export default {
console.log(res, '自定义列表字段');
const resData = res.data;
if (resData.errorCode == 0) {
// showMsg.showmsg('保存成功','success')
that.memberFields = resData.result; // 保存所有自定义列表字段
console.log(resData.result);
that.getTagDetailList(resData.result);
return;
}
......@@ -595,6 +580,15 @@ export default {
message: error.message
});
});
},
onSubmiTableFiled(data) {
const { downTagDetailListPop: { params: exportParams } } = this;
this.downTagDetailListPop.show = true;
exportParams.exportFields = data.toString();
},
showExport() {
if (!this.tagDetailList.length) return this.$message.error('没有要导出的数据');
this.tableFiledVisible = true;
}
},
beforeMount() {
......@@ -615,14 +609,12 @@ export default {
this.pageParam.tagItemId=tagItemId;
this.downTagDetailListPop.params.tagItemId = tagItemId;
this.downTagDetailListPop.excelUrl = local + this.downTagDetailListPop.excelUrl;
// this.canDownMemberList();
this.getTagItemInfo(tagItemId)
// 获取自定义字段
this.getFieldsList();
document.getElementById('app').style.zIndex = 'auto';
},
components: {
// navCrumb,
userDefined,
}
};
......@@ -659,13 +651,9 @@ export default {
}
.manualTagDetail-wrap__info {
display: flex;
justify-content: space-between;
align-items: center;
height: 32px;
padding-bottom: 20px;
box-sizing: content-box;
border-bottom: 1px solid #ebeef5;
padding-bottom: 20px;
box-sizing: content-box;
.group-name {
font-size: 18px;
line-height: 32px;
......@@ -683,6 +671,13 @@ box-sizing: content-box;
}
}
}
.operation-line {
height: 32px;
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}
.down-member-list-wrapper {
padding: 0 20px 30px;
text-align: center;
......@@ -804,4 +799,7 @@ box-sizing: content-box;
color: #dfe6f0;
}
}
/deep/ .table-header__handle {
padding-right: 0 !important;
}
</style>
......@@ -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>
......@@ -6,11 +6,13 @@
<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,12 +101,12 @@ 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;
margin-bottom: 8px;
font-weight: 600;
color: #303133;
.tag-flag {
......@@ -113,8 +115,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 +145,7 @@ export default {
}
.tag-config-options {
max-height: 50vh;
overflow-y: auto;
// overflow-y: auto;
}
.tag-value {
margin-top: 10px;
......
<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">
<i :class="[tagList.icon, { 'icon-tag-light': tagList.name === tagRealName }]" class="iconfont menu-icon"></i>
<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 +33,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 +53,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 +124,9 @@ export default {
code = type == 'add' ? 'memberTagAddChildCategory' : 'memberTagEditChildCategory';
return this.$buttonCode[code];
}
},
isOtherTag() {
return ['手工标签', '活动标签'].includes(this.tagName);
}
},
......@@ -268,7 +283,6 @@ export default {
})
.catch(err => {
this.addHandTagFlag = false;
console.log(err);
});
}
},
......@@ -301,40 +315,48 @@ export default {
line-height: 26px;
min-height: 26px;
padding-left: 24px;
padding-top: 3px;
padding-bottom: 2px;
padding-top: 4px;
overflow: hidden;
.name {
position: relative;
top: 1px;
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;
.tag-item {
display: inline-block;
vertical-align: middle;
line-height: 26px;
margin-right: 15px;
font-size: 14px;
color: #606266;
line-height: 22px;
margin-right: 8px;
margin-bottom: 12px;
font-size: 12px;
padding: 3px 8px;
background: #F2F3F5;
border-radius: 2px;
color: #303133;
&:hover {
color: #2F54EB;
background: #EBEFFE;
color: #2f54eb;
}
}
.light-active {
color: #2F54EB;
color: #2f54eb;
}
.icon-next- {
font-size: 30px;
......@@ -354,32 +376,74 @@ export default {
}
.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;
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;
}
</style>
<template>
<!-- 具体标签 -->
<div class="tag-some-list">
<el-table :data="tableData" style="width: 100%">
<el-table-column label="标签名称" prop="tagName" min-width="100">
<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(row.createTime, 'yyyy-MM-dd') }}</p>
<p>{{ dateformat(row.createTime, 'hh:mm:ss') }}</p>
</template>
<span v-else>--</span>
</template>
</el-table-column>
<el-table-column label="操作">
<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 }
});
},
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="100">
<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="80">
<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>
<div v-if="isOtherTag" class="mb16">
<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>
<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 +31,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 +77,48 @@ export default {
<style lang="scss" scoped>
.list {
position: relative;
padding-top: 10px;
margin-top: 10px;
margin-top: 18px;
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;
}
</style>
......@@ -110,4 +110,18 @@
padding: 20px;
min-height: calc(100vh - 296px);
background: #fff;
}
\ No newline at end of file
}
// 幽灵按钮放在全局方便全局改样式
.ghost-btn {
background: #fff !important;
color: #1890ff !important;
&:hover {
border-color: #40a9ff;
color: #40a9ff !important;
}
&:active {
border-color: #096dd9;
color: #096dd9 !important;
}
}
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