Commit 197c0ae2 by caoyanzhi

实现在会员标签页添加手工标签的功能

parent 68f5972e
...@@ -75,11 +75,11 @@ export const constantRouterMap = [ ...@@ -75,11 +75,11 @@ export const constantRouterMap = [
} }
}, },
{ {
path: '/manualTagEdit', path: '/manualTagValueEdit',
component: _import('manualTag', 'manualTagEdit'), component: _import('manualTag', 'manual-tag-value-edit'),
name: '编辑手工标签', name: '标签值设置',
meta: { meta: {
title: '会员标签-编辑手工标签' title: '会员标签-标签值设置'
} }
}, },
{ {
......
<template>
<div class="manualTagEdit-wrap common-wrap">
<nav-crumb :navpath="navpath"></nav-crumb>
<div class="right-content">
<div class="right-box">
<div class="manualTagEdit-wrap__title">{{ tagInfo.tagName }}</div>
<div class="tag-value-wrapper">
<div class="tag-value-table" v-if="tagValTableData.length > 0">
<el-table :data="tagValTableData">
<el-table-column width="50" class-name="tag-cell" label-class-name="tag-head"><!-- 占位用 --></el-table-column>
<el-table-column label="标签值" prop="tagItemName" min-width="200" class-name="tag-cell" label-class-name="tag-head"></el-table-column>
<el-table-column label="操作" min-width="100" class-name="tag-cell" label-class-name="tag-head">
<template slot-scope="scope">
<!-- 正在上传中 -->
<div v-if="scope.row.status === 4 || scope.row.status === 6" class="uploading">
<span>正在上传</span>
<span class="uploading-progress">
<el-progress
:percentage="scope.row.percent">
</el-progress>
</span>
</div>
<!-- 初始状态和导入完成状态 -->
<template v-else>
<el-button type="text" size="small" class="m-r-20" :disabled="scope.row.status === 5" @click="showImportPop(scope.$index, scope.row)">
导入会员
</el-button>
<span class="upload-state" v-if="uploadedTag.includes(scope.row.tagItemId) || scope.row.errorCount > 0">
<!-- 导入完成 -->
<span v-show="uploadedTag.includes(scope.row.tagItemId)" class="uploading-succ">
上传完成
</span>
<span v-show="scope.row.errorCount > 0" class="download-failed">
<span :class="['download-failed-btn', {disabled: scope.row.status === 5}]" @click="downloadErrorData(scope.row)">点击下载</span>
失败会员清单
</span>
</span>
<!-- 删除中的状态 -->
<template v-if="scope.row.status === 5">
<span class="color-c0c4cc">删除中...</span>
</template>
<!-- 删除的初始状态 -->
<template v-else>
<el-popover placement="top" width="300" trigger="click" v-model="scope.row.showDelPopOver">
<p>删除标签后,符合该标签值的会员对应标签值将同步删除。一旦删除将无法恢复,确认要删除吗?</p>
<div style="text-align: right; margin: 5px 0 0 0;">
<el-button type="text" size="mini" @click.native="scope.row.showDelPopOver = false">取消</el-button>
<el-button type="primary" size="mini" @click.native="delTagApi(scope.$index, scope.row)">确定
</el-button>
</div>
<el-button type="text" size="small" slot="reference">删除</el-button>
</el-popover>
</template>
</template>
</template>
</el-table-column>
</el-table>
</div>
<div class="add-tag">
<div class="add-tag-btn" @click="addTagValPop.isShow = true">
<i class="iconfont icon-icon02"></i>
添加标签值
</div>
</div>
</div>
<div class="back">
<el-button @click="back">返回手工标签列表</el-button>
</div>
<!-- 添加标签值 -->
<el-dialog title="添加标签值" :visible.sync="addTagValPop.isShow" width="490px" custom-class="manual-dialog">
<div class="add-tag-val">
<span>标签值</span>
<el-input placeholder="请输入" :maxlength="10" v-model.trim="addTagValPop.tagVal"></el-input>
<label class="input-label">{{addTagValPop.tagVal.length}}/10</label>
</div>
<template slot="footer">
<el-button @click="closeAddPop">取消</el-button>
<el-button type="primary" @click="addTagVal">确定</el-button>
</template>
</el-dialog>
<!-- excel导入 -->
<el-dialog :title="importPop.title" :visible.sync="importPop.isShow" width="600px" custom-class="manual-dialog">
<div class="import">
<div :class="['excel-icon', importPop.excelData.length > 0 ? 'excel-icon--active' : 'excel-icon--add']" @click="handleUpload">
<span v-show="importPop.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="importPop.excelData.length > 0">
<span>{{importPop.excelName}}</span>
<span class="import-num">
已导入会员
<span class="color-303133">{{importPop.excelData.length}}</span>
</span>
<el-button type="text" @click="reHandleUpload">重新导入</el-button>
</template>
</div>
<div class="import-tip">
<span class="import-tip-text">只能上传一个excle文件(2003版本以上),且数据不超过5000条</span>
<el-button type="text" class="font-12" @click="downloadExcelTemp">下载Excel模板</el-button>
</div>
<div class="clear-old">
<el-checkbox v-model="importPop.optType">清空标签历史标记会员</el-checkbox>
<el-tooltip content="勾选后,此前被该标签标记的会员将移除此标签,此标签标记会员以本次导入为准。">
<i class="iconfont icon-xinxixianshi"></i>
</el-tooltip>
</div>
</div>
</div>
<template slot="footer">
<el-button @click="closeImportPop">取消</el-button>
<el-button type="primary" @click="tagItemImport">确定</el-button>
</template>
</el-dialog>
</div>
</div>
<vue-gic-footer></vue-gic-footer>
</div>
</template>
<script>
import './manualTagEdit.css';
import XLSX from 'xlsx';
import navCrumb from '@/components/nav/nav.vue';
import { export_json_to_excel } from '@/vendor/Export2Excel';
import showMsg from '@/common/js/showmsg';
import errMsg from '@/common/js/error';
import { getRequest, postRequest } from '@/api/api';
/**
* 通过excel导入会员的业务逻辑 2019-5-27
* 轮询接口的实现方式
* refreshTag用来保存需要轮询的标签值tagItemIndex索引和tagItemId ID
* 页面打开后,会调用getValueData根据取到的标签值的状态,将需要轮询的标签值存入refreshTag中,然后开始轮询
* 添加和删除标签值后,会重新调用getValueData,执行上一步操作
* 当有标签值状态更新后,会将refreshTag中对应的标签值移除
* 当refreshTag中无数据时,终止轮询。
* */
export default {
name: 'manual-tag-value-edit',
data() {
return {
// 编辑标签的时候,获取标签的 id
tagId: '',
// 标签的基本信息
tagInfo: {
tagName: '',
tagDescribe: '',
tagLevelGroupId: '',
tagLevelGroupName: ''
},
// 添加标签值的弹窗的相关数据
addTagValPop: {
isShow: false,
tagVal: '',
},
// excel导入的弹窗的相关数据
importPop: {
isShow: false,
// 标签值的索引
tagItemIndex: '',
// 标签值的id
tagItemId: '',
// false=0: 不删除, true=1: 删除
optType: false,
title: '',
// 当前上传 excel 的表格名字
excelName: '',
// 当前上传 excel 内容的数据
excelData: [],
// 当前上传 excel 表头的数据
excelHeader: []
},
// 标签值列表的数据
tagValTableData: [],
// 需要查询进度的标签值索引和id
// 每次获取标签值列表时更新、标签值有新的状态时更新
refreshTag: [],
// 需要显示上传完成的标签值id
uploadedTag: [],
timer: null
};
},
computed: {
// 面包屑参数
navpath() {
return [
{
name: '首页',
path: `${window.location.origin}/report/#/memberSummary`,
relocation: true
},
{
name: '会员管理',
path: ''
},
{
name: '会员标签',
path: `/member-tag`
},
// {
// name: '手工标签列表',
// path: '/manualTagList'
// },
{
name: '标签值设置',
path: ''
}
];
}
},
methods: {
// 返回手工标签列表
back() {
const levelGroupInfo = {
id: this.tagInfo.tagLevelGroupId,
name: this.tagInfo.tagLevelGroupName
};
localStorage.setItem('groupId', JSON.stringify(levelGroupInfo));
this.$router.push('/member-tag');
},
// 取消添加标签值
closeAddPop() {
this.addTagValPop.isShow = false;
this.addTagValPop.tagVal = '';
},
// 添加标签值
addTagVal() {
if (this.addTagValPop.tagVal.length === 0) {
this.$message.error({
duration: 1000,
message: '请输入标签值'
});
return false;
}
if (this.tagValTableData.some(item => item.name === this.addTagValPop.tagVal)) {
this.$message.error({
duration: 1000,
message: '标签值已存在'
});
return false;
}
this.addTagItem('', this.addTagValPop.tagVal);
this.closeAddPop();
},
// 添加和编辑标签值
addTagItem(tagItemId, tagItemName) {
const para = {
tagItemId: tagItemId,
tagItemName: tagItemName,
tagId: this.tagId
};
getRequest('/memberTag/saveHandTagItem', para).then(res => {
const { errorCode } = res.data;
if (errorCode === 1) {
showMsg.showmsg('添加成功', 'success');
this.getValueData();
return;
}
errMsg.errorMsg(res.data);
}).catch(error => {
this.$message.error({
duration: 1000,
message: error.message
});
});
},
// 删除标签值
delTagApi(index, item) {
const para = {
tagItemId: item.tagItemId
};
this.refreshTag.push({
tagItemIndex: index,
tagItemId: item.tagItemId
});
getRequest('/memberTag/delHandTagItem', para).then(res => {
const { errorCode } = res.data;
if (errorCode === 1) {
item.delStatus = 0;
this.handleRefreshTag();
return;
}
errMsg.errorMsg(res.data);
}).catch(error => {
this.$message.error({
duration: 1000,
message: error.message
});
});
},
// 获取标签值列表
getValueData() {
const para = {
tagId: this.tagId
};
getRequest('/memberTag/queryHandTagItem', para).then((res) => {
const { errorCode, result } = res.data;
if (errorCode === 1) {
/**
* 前端自定义的扩展字段
* 为了实现一个标签值的数据上传中另一个标签值仍可以上传的功能
* 上传完毕后,扩展字段需要重置
* */
this.refreshTag = [];
result.forEach((ele, index) => {
ele.showDelPopOver = false;
// 上传进度百分比值
ele.percent = 0;
// 4 删除中 5删除项 6 处理中
if (ele.status === 4 || ele.status === 5 || ele.status === 6) {
this.refreshTag.push({tagItemIndex: index, tagItemId: ele.tagItemId});
}
});
this.tagValTableData = result;
this.handleRefreshTag();
return;
}
errMsg.errorMsg(res.data);
}).catch(error => {
this.$message.error({
duration: 1000,
message: error.message
});
});
},
// 显示导入会员的弹窗
showImportPop(index, row) {
// 状态为删除中,不可以导入会员
this.importPop.isShow = true;
this.importPop.tagItemIndex = index;
this.importPop.tagItemId = row.tagItemId;
this.importPop.title = `${row.tagItemName}-导入会员`
},
// 关闭导入会员的弹窗
closeImportPop() {
this.importPop.isShow = false;
this.resetImportData();
},
// 重置导入的表格数据
resetImportData() {
this.importPop.excelName = '';
this.importPop.excelData = [];
this.importPop.excelHeader = [];
this.importPop.optType = false;
},
// 点击上传文件、
handleUpload() {
if (this.importPop.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.importPop.excelName = files.name;
const reader = new FileReader();
reader.onload = e => {
const data = e.target.result;
const fixedData = this.fixData(data);
const workbook = XLSX.read(btoa(fixedData), { type: 'base64' });
const firstSheetName = workbook.SheetNames[0];
const worksheet = workbook.Sheets[firstSheetName];
if (Object.keys(worksheet).indexOf('!ref') === -1) {
this.$message.error({
duration: 1000,
message: '文档内容为空'
});
return false;
}
this.importPop.excelHeader = this.get_header_row(worksheet);
this.importPop.excelData = XLSX.utils.sheet_to_json(worksheet);
if (this.importPop.excelData.length > 5000) {
this.$message.error({
duration: 1000,
message: '单次上传数据不能超过 5000 条,请重新上传文件'
});
}
};
reader.readAsArrayBuffer(files);
},
fixData(data) {
let o = '';
let l = 0;
const w = 10240;
for (; l < data.byteLength / w; ++l) o += String.fromCharCode.apply(null, new Uint8Array(data.slice(l * w, l * w + w)));
o += String.fromCharCode.apply(null, new Uint8Array(data.slice(l * w)));
return o;
},
get_header_row(sheet) {
const headers = [];
const range = XLSX.utils.decode_range(sheet['!ref']);
let C;
const R = range.s.r; /* start in the first row */
for (C = range.s.c; C <= range.e.c; ++C) {
/* walk every column in the range */
let cell = sheet[XLSX.utils.encode_cell({ c: C, r: R })]; /* find the cell in the first row */
let hdr = 'UNKNOWN ' + C; // <-- replace with your desired default
if (cell && cell.t) hdr = XLSX.utils.format_cell(cell);
headers.push(hdr);
}
return headers;
},
uploadExcel() {
// 上传之前,不需要根据是否勾选“清空标签历史标记会员”进行拦截 2019-05-22
return;
if (this.importPop.optType) {
this.$confirm('勾选此选项则清空之前有此标签会员身上的标签,以本次导入会员为准;否则本次导入和之前已有数据去重添加。请慎重选择!', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(this.tagItemImport);
return;
}
this.tagItemImport()
},
// 导入数据到服务端
tagItemImport() {
if (this.importPop.excelData.length === 0) {
this.$message.error({
duration: 1000,
message: '导入数据有为空或者数据异常'
});
return;
}
this.$refs.upload.value = '';
this.refreshTag.push({
tagItemIndex: this.importPop.tagItemIndex,
tagItemId: this.importPop.tagItemId
});
const para = {
tagItemId: this.importPop.tagItemId,
data: JSON.stringify(this.importPop.excelData)
};
postRequest('/memberTag/uploadHandTagItemImport', para).then((res) => {
const { errorCode } = res.data;
errorCode === 1 ? this.handTagItemImport() : errMsg.errorMsg(res.data);
}).catch(error => {
this.$message.error({
duration: 1000,
message: error.message
});
});
},
// 服务端处理导入数据
handTagItemImport() {
let {tagItemId, optType } = this.importPop;
optType = optType ? 1 : 0;
getRequest('/memberTag/dealHandTagItemImport', { tagItemId, optType }).then((res) => {
const { errorCode } = res.data;
if (errorCode === 1) {
// 关闭上传的弹窗
this.closeImportPop();
// 查询上传进度
this.handleRefreshTag();
} else {
errMsg.errorMsg(res.data);
}
}).catch(error => {
this.$message.error({
duration: 1000,
message: error.message
});
});
},
handleRefreshTag() {
// 根据refreshTag的tagItemIndex比对tagValueTableData的tagItemId是否相同,如果相同,就操作tagValueTableData的数据,不同就不操作
// 新增和删除标签值完成后,重新执行getValueData方法,刷新标签值列表数据,重启轮询
// 当refreshTag的length为0时,终止轮询
if (this.refreshTag.length === 0) return;
let allPro = [];
this.refreshTag.forEach(item => {
allPro.push(this.getImportReport(item.tagItemIndex, item.tagItemId));
})
Promise.all(allPro).then(() => {
clearTimeout(this.timer);
this.timer = setTimeout(this.handleRefreshTag, 1000);
})
},
// 查询上传、删除的进度
getImportReport(tagItemIndex, tagItemId) {
return getRequest('/memberTag/getImportReport', { tagItemId }).then((res) => {
const { errorCode, result } = res.data;
if (errorCode === 1) {
// 0 删除 1正常 2导入中 3 导入完成 4 删除中 5删除项 6 处理中 7 异常 8 处理成功
switch (result.status) {
case 0:
// 已删除
if (this.tagValTableData[tagItemIndex].tagItemId === tagItemId) {
this.refreshTag = this.refreshTag.filter(item => item.tagItemId !== tagItemId)
this.getValueData();
}
break;
case 5:
// 删除进行中
if (this.tagValTableData[tagItemIndex].tagItemId === tagItemId) {
this.tagValTableData[tagItemIndex].status = 5;
}
break;
case 4:
case 6:
// 导入进行中
if (this.tagValTableData[tagItemIndex].tagItemId === tagItemId) {
this.tagValTableData[tagItemIndex].status = result.status;
const num = parseInt((result.totalNum - result.needExec) / result.totalNum * 100);
this.tagValTableData[tagItemIndex].percent = num === 100 ? 99 : num;
}
break;
case 8:
// 导入完成
if (this.tagValTableData[tagItemIndex].tagItemId === tagItemId) {
this.tagValTableData[tagItemIndex].status = result.status;
// 已经上传完成的标签值不在轮询
this.refreshTag = this.refreshTag.filter(item => item.tagItemId !== tagItemId);
this.uploadedTag.push(tagItemId);
// 上传的错误数量
this.tagValTableData[tagItemIndex].errorCount = result.needError;
// 重置百分比为0
this.tagValTableData[tagItemIndex].percent = 0;
}
break;
default:
if (this.tagValTableData[tagItemIndex].tagItemId === tagItemId) {
this.tagValTableData[tagItemIndex].status = result.status;
// 已经上传完成的标签值不在轮询
this.refreshTag = this.refreshTag.filter(item => item.tagItemId !== tagItemId);
// 重置错误数量、百分比为0
this.tagValTableData[tagItemIndex].errorCount = 0;
this.tagValTableData[tagItemIndex].percent = 0;
}
break;
}
} else {
errMsg.errorMsg(res.data);
}
}).catch(error => {
this.$message.error({
duration: 1000,
message: error.message
});
});
},
// 下载上传失败的会员清单
downloadErrorData(row) {
const {status, tagItemId} = row;
if (status === 5) return;
getRequest('/memberTag/queryImportErrorData', { tagItemId }).then(res => {
const { errorCode, result } = res.data;
if (errorCode === 1) {
if (result && result.length) {
const header = Object.keys(result[0]);
//获取数据后执行 excel 导出
const data = result.map(item => header.map(key => item[key]));
export_json_to_excel(header, data, '导出列表');
} else {
this.$message.error({
duration: 1000,
message: '暂无失败数据'
});
}
return;
}
errMsg.errorMsg(res.data);
}).catch(error => {
this.$message.error({
duration: 1000,
message: error.message
});
});
},
// 导出 excel 模板
downloadExcelTemp() {
const tHeader = ['手机号', '卡号'];
const data = [
['17098078224', 'jhdm2018071315'],
['13100000055', 'jhdm20180608000000003']
];
export_json_to_excel(tHeader, data, '导入 excel 模板');
},
// 获取三级分类列表
getOptionsThree(tagLevelGroupId) {
getRequest('/tagLevel/handThirdLevel', { tagLevelGroupId }).then(res => {
const { errorCode, result } = res.data;
if (errorCode === 1) {
let tagGroup = result.filter(item => item.tagLevelGroupId === this.tagInfo.tagLevelGroupId);
if (tagGroup.length > 0) {
this.tagInfo.tagLevelGroupName = tagGroup[0].levelName;
}
}
}).catch(error => {
this.$message.error({
duration: 1000,
message: error.message
});
});
},
// 编辑时获取当前标签数据
getTagData(tagId) {
getRequest('/memberTag/getTagById', { tagId }).then(res => {
const { errorCode, result } = res.data;
if (errorCode === 1) {
this.tagInfo = {
tagName: result.tagName,
tagLevelGroupId: result.tagLevelGroupId,
tagDescribe: result.tagDescribe
}
// 获取标签值列表
this.getValueData();
this.getOptionsThree(result.tagTwoLevelGroupId);
}
}).catch(err => {
console.log(err);
});
}
},
mounted() {
const tagId = this.$route.query.tagId;
localStorage.removeItem('groupId');
if (tagId) {
this.tagId = tagId;
this.getValueData();
this.getTagData(tagId);
}
},
beforeDestroy() {
clearTimeout(this.timer);
},
components: {
navCrumb
}
}
</script>
<style lang="less" scoped>
.manualTagEdit-wrap {
padding-bottom: 56px;
}
.right-box {
padding: 0 !important;
min-height: 60vh;
.manualTagEdit-wrap__title {
margin-bottom: 0;
padding: 22px 24px 18px;
width: 100%;
font-size: 16px;
color: #303133;
border-bottom: 2px solid #EDEFF2;
}
.tag-value-wrapper {
padding: 0 24px;
.tag-value-table {
padding-top: 24px;
}
}
.back {
position: fixed;
right: 0;
bottom: 0;
left: 0;
z-index: 1;
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 56px;
background: #fff;
border-top: 1px solid #DCDFE6;
}
.add-tag {
border-bottom: 1px solid #E4E7ED;
.add-tag-btn {
margin: 0 auto;
width: 100px;
height: 70px;
text-align: center;
line-height: 70px;
font-size: 14px;
color: #909399;
cursor: pointer;
&:hover {
color: #1890ff;
}
}
}
.add-tag-val {
position: relative;
display: flex;
align-items: center;
margin: 0 auto;
width: 375px;
span {
margin-right: 10px;
flex: 1 1 55px;
font-size: 14px;
}
.input-label{
position: absolute;
top: 0;
right: 10px;
z-index: 1;
display: flex;
align-items: center;
font-size: 12px;
color: #C0C4CC;
height: 100%;
}
}
.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: 500px;
.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;
}
}
}
}
.uploading {
color: #909399;
font-size: 14px;
.uploading-progress {
padding: 0 0 0 10px;
display: inline-block;
width: 200px;
}
}
.upload-state {
padding: 0 20px 0 0;
.uploading-succ {
color: #909399;
}
.download-failed {
color: #909399;
.download-failed-btn {
padding: 0 10px 0 5px;
color: #f5222d;
cursor: pointer;
&:hover {
color: #dc535b;
}
}
.disabled {
color: #fba6aa;
cursor: not-allowed;
&:hover {
color: #fba6aa
}
}
}
}
}
</style>
...@@ -9,3 +9,9 @@ ...@@ -9,3 +9,9 @@
.manualTagEdit-wrap .manualTagEdit-wrap__form .el-form-item__label { .manualTagEdit-wrap .manualTagEdit-wrap__form .el-form-item__label {
color: #606266; color: #606266;
} }
.tag-value-table .tag-cell {
height: 70px;
}
.tag-value-table .tag-head {
height: 23px;
}
<template> <template>
<div class="manualTagEdit-wrap common-wrap"> <el-dialog :visible.sync="showPop" :title="options.popTitle" width="566px" @close="closePop">
<nav-crumb :navpath="navpath"></nav-crumb> <div class="manualTagEdit-wrap manualTagEdit-wrap__form">
<div class="right-content"> <el-form :model="ruleForm" :rules="rules" ref="ruleForm" label-width="78px">
<div class="right-box"> <el-form-item label="标签名称" prop="tagName" class="w-329">
<div class="manualTagEdit-wrap__title">标签基本信息</div> <el-input class="w-220" placeholder="请输入内容" v-model="ruleForm.tagName" :maxlength="10"></el-input>
<label class="input-label">{{ ruleForm.tagName.length }}/10</label>
<div class="manualTagEdit-wrap__form"> </el-form-item>
<el-form :model="ruleForm" :rules="rules" ref="ruleForm" label-width="78px"> <el-form-item label="所属分类" prop="tagLevel">
<el-form-item label="标签名称" prop="tagName" class="w-329"> <el-form-item prop="tagTwoLevelGroupId" class="fl">
<el-input class="w-220" placeholder="请输入内容" v-model="ruleForm.tagName" :maxlength="10"></el-input> <el-select class="w-220" placeholder="请选择" v-model="ruleForm.tagTwoLevelGroupId" @change="changeTwo">
<label class="input-label">{{ ruleForm.tagName.length }}/10</label> <el-option
</el-form-item> v-for="item in optionsTwo"
<el-form-item label="所属分类" prop="tagLevel"> :key="item.tagLevelGroupId"
<el-form-item prop="tagTwoLevelGroupId" class="fl"> :label="item.levelName"
<el-select class="w-220" placeholder="请选择" v-model="ruleForm.tagTwoLevelGroupId" @change="changeTwo"> :value="item.tagLevelGroupId">
<el-option </el-option>
v-for="item in optionsTwo" </el-select>
:key="item.tagLevelGroupId" </el-form-item>
:label="item.levelName" <el-form-item prop="tagLevelGroupId" class="fl">
:value="item.tagLevelGroupId"> <el-select class="w-220 m-l-8" placeholder="请选择" v-model="ruleForm.tagLevelGroupId">
</el-option> <el-option
</el-select> v-for="item in optionsThree"
</el-form-item> :key="item.tagLevelGroupId"
<el-form-item prop="tagLevelGroupId" class="fl"> :label="item.levelName"
<el-select class="w-220 m-l-8" placeholder="请选择" v-model="ruleForm.tagLevelGroupId"> :value="item.tagLevelGroupId">
<el-option </el-option>
v-for="item in optionsThree" </el-select>
:key="item.tagLevelGroupId" </el-form-item>
:label="item.levelName" </el-form-item>
:value="item.tagLevelGroupId"> <el-form-item label="标签描述" prop="tagDescribe" class="w-560">
</el-option> <el-input class="w-447" type="textarea" row="4" v-model="ruleForm.tagDescribe" :maxlength="200">
</el-select> </el-input>
</el-form-item> <label class="textarea-label">{{ ruleForm.tagDescribe.length }}/200</label>
</el-form-item> </el-form-item>
<el-form-item label="标签描述" prop="tagDescribe" class="w-560"> </el-form>
<el-input class="w-447" type="textarea" row="4" v-model="ruleForm.tagDescribe" :maxlength="200"> <div class="manualTagEdit-btns">
</el-input> <el-button @click="closePop">取消</el-button>
<label class="textarea-label">{{ ruleForm.tagDescribe.length }}/200</label> <el-button type="primary" @click="confirmSave">保存</el-button>
</el-form-item>
<el-form-item>
<el-button type="primary" :disabled="canSave" @click="confirmSave">保存</el-button>
</el-form-item>
</el-form>
</div>
<div class="manualTagEdit-wrap__title">标签值设置</div>
<!-- 标签值列表 -->
<div class="manualTagEdit-wrap__form" v-if="tagValTableData.length > 0">
<el-table :data="tagValTableData">
<el-table-column width="50"><!-- 占位用 --></el-table-column>
<el-table-column label="标签值" prop="tagItemName" min-width="200"></el-table-column>
<el-table-column label="操作" min-width="100">
<template slot-scope="scope">
<!-- 正在上传中 -->
<div v-if="scope.row.status === 4 || scope.row.status === 6" class="uploading">
<span>正在上传</span>
<span class="uploading-progress">
<el-progress
:percentage="scope.row.percent">
</el-progress>
</span>
</div>
<!-- 初始状态和导入完成状态 -->
<template v-else>
<el-button type="text" size="small" class="m-r-20" @click="showImportPop(scope.$index, scope.row)">
导入会员
</el-button>
<span class="upload-state" v-if="uploadedTag.includes(scope.row.tagItemId) || scope.row.errorCount > 0">
<!-- 导入完成 -->
<span v-show="uploadedTag.includes(scope.row.tagItemId)" class="uploading-succ">
上传完成
</span>
<span v-show="scope.row.errorCount > 0" class="download-failed">
<span class="download-failed-btn" @click="downloadErrorData(scope.row.tagItemId)">点击下载</span>
失败会员清单
</span>
</span>
<!-- 删除中的状态 -->
<template v-if="scope.row.status === 5">
<span class="color-c0c4cc">删除中...</span>
</template>
<!-- 删除的初始状态 -->
<template v-else>
<el-popover placement="top" width="300" trigger="click" v-model="scope.row.showDelPopOver">
<p>删除标签后,符合该标签值的会员对应标签值将同步删除。一旦删除将无法恢复,确认要删除吗?</p>
<div style="text-align: right; margin: 5px 0 0 0;">
<el-button type="text" size="mini" @click.native="scope.row.showDelPopOver = false">取消</el-button>
<el-button type="primary" size="mini" @click.native="delTagApi(scope.$index, scope.row)">确定</el-button>
</div>
<el-button type="text" size="small" slot="reference">删除</el-button>
</el-popover>
</template>
</template>
</template>
</el-table-column>
</el-table>
<div class="add-tag">
<div class="add-tag-btn" @click="addTagValPop.isShow = true">
<i class="iconfont icon-icon02"></i>
添加标签值
</div>
</div>
</div>
<!-- 无标签值 -->
<div class="no-tag-value" v-else>
<p class="font-14 color-909399">你还没有创建标签,</p>
<p class="m-t-10 font-14 color-909399">请先完善标签基本信息再添加标签值</p>
<el-button class="m-t-18" :disabled="!canAddTagVal" type="primary" @click="addTagValPop.isShow = true">添加标签值</el-button>
</div>
<!-- 添加标签值 -->
<el-dialog title="添加标签值" :visible.sync="addTagValPop.isShow" width="490px" custom-class="manual-dialog">
<div class="add-tag-val">
<span>标签值</span>
<el-input placeholder="请输入" :maxlength="10" v-model.trim="addTagValPop.tagVal"></el-input>
<label class="input-label">{{addTagValPop.tagVal.length}}/10</label>
</div>
<template slot="footer">
<el-button @click="closeAddPop">取消</el-button>
<el-button type="primary" @click="addTagVal">确定</el-button>
</template>
</el-dialog>
<!-- excel导入 -->
<el-dialog :title="importPop.title" :visible.sync="importPop.isShow" width="600px" custom-class="manual-dialog">
<div class="import">
<div :class="['excel-icon', importPop.excelData.length > 0 ? 'excel-icon--active' : 'excel-icon--add']" @click="handleUpload">
<span v-show="importPop.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="importPop.excelData.length > 0">
<span>{{importPop.excelName}}</span>
<span class="import-num">
已导入会员
<span class="color-303133">{{importPop.excelData.length}}</span>
</span>
<el-button type="text" @click="reHandleUpload">重新导入</el-button>
</template>
</div>
<div class="import-tip">
<span class="import-tip-text">只能上传一个excle文件(2003版本以上),且数据不超过5000条</span>
<el-button type="text" class="font-12" @click="downloadExcelTemp">下载Excel模板</el-button>
</div>
<div class="clear-old">
<el-checkbox v-model="importPop.optType">清空标签历史标记会员</el-checkbox>
<el-tooltip content="勾选后,此前被该标签标记的会员将移除此标签,此标签标记会员以本次导入为准。">
<i class="iconfont icon-xinxixianshi"></i>
</el-tooltip>
</div>
</div>
</div>
<template slot="footer">
<el-button @click="closeImportPop">取消</el-button>
<el-button type="primary" @click="tagItemImport">确定</el-button>
</template>
</el-dialog>
</div> </div>
</div> </div>
<vue-gic-footer></vue-gic-footer> </el-dialog>
</div>
</template> </template>
<script> <script>
import './manualTagEdit.css'; import './manualTagEdit.css';
import '@/../static/font/iconfont';
import XLSX from 'xlsx';
import navCrumb from '@/components/nav/nav.vue';
import { export_json_to_excel } from '@/vendor/Export2Excel';
import showMsg from '@/common/js/showmsg'; import showMsg from '@/common/js/showmsg';
import errMsg from '@/common/js/error'; import { getRequest} from '@/api/api';
import { getRequest, postRequest } from '@/api/api';
/** /**
* 通过excel导入会员的业务逻辑 2019-5-27 * 通过excel导入会员的业务逻辑 2019-5-27
* 新增分组 * 新增分组
...@@ -193,23 +66,22 @@ import { getRequest, postRequest } from '@/api/api'; ...@@ -193,23 +66,22 @@ import { getRequest, postRequest } from '@/api/api';
* */ * */
export default { export default {
name: 'manualTagEdit', name: 'manualTagEdit',
props: {
showPop: Boolean,
options: Object
},
data() { data() {
return { return {
// 编辑标签的时候,获取标签的 id // 编辑标签的时候,获取标签的 id
tagId: '', // tagId: '',
// 标签的基本信息
tagInfo: {
tagName: '',
tagDescribe: '',
tagLevelGroupId: ''
},
// 标签基本信息模块的表单 // 标签基本信息模块的表单
ruleForm: { ruleForm: {
tagName: '', tagName: '',
tagLevel: 'test', tagLevel: 'test',
tagTwoLevelGroupId: '', tagTwoLevelGroupId: '',
tagLevelGroupId: '', tagLevelGroupId: '',
tagDescribe: '' tagDescribe: '',
pending: false
}, },
// 标签基本信息模块的表单验证 // 标签基本信息模块的表单验证
rules: { rules: {
...@@ -222,90 +94,33 @@ export default { ...@@ -222,90 +94,33 @@ export default {
optionsTwo: [], optionsTwo: [],
optionsThree: [], optionsThree: [],
// 添加标签值的弹窗的相关数据
addTagValPop: {
isShow: false,
tagVal: '',
},
// excel导入的弹窗的相关数据
importPop: {
isShow: false,
// 标签值的索引
tagItemIndex: '',
// 标签值的id
tagItemId: '',
// false=0: 不删除, true=1: 删除
optType: false,
title: '',
// 当前上传 excel 的表格名字
excelName: '',
// 当前上传 excel 内容的数据
excelData: [],
// 当前上传 excel 表头的数据
excelHeader: []
},
// 标签值列表的数据 // 标签值列表的数据
tagValTableData: [], tagValTableData: []
// 需要查询进度的标签值索引和id
// 每次获取标签值列表时更新、标签值有新的状态时更新
refreshTag: [],
// 需要显示上传完成的标签值id
uploadedTag: [],
timer: null
}; };
}, },
computed: { watch: {
// 面包屑参数 options: {
navpath() { deep: true,
let that = this; handler(newVal) {
return [ this.ruleForm.tagTwoLevelGroupId = newVal.tagTwoLevelGroupId;
{ this.ruleForm.tagLevelGroupId = newVal.tagLevelGroupId;
name: '首页', if (newVal.tagId) {
path: `${window.location.origin}/report/#/memberSummary`, this.getTagData(newVal.tagId);
relocation: true } else {
}, this.ruleForm.tagName = '';
{ this.getOptionsThree(newVal.tagTwoLevelGroupId);
name: '会员管理',
path: ''
},
{
name: '会员标签',
path: `/member-tag`
},
// {
// name: '手工标签列表',
// path: '/manualTagList'
// },
{
name: that.$route.query.tagId ? '手工标签编辑' : '新增手工标签',
path: ''
} }
]; }
},
// 新增标签,保存按钮长亮
// 编辑标签,当标签基本信息有改动时,保存按钮亮起
canSave() {
// 新增标签
if (!this.tagId) return false;
// 编辑标签
return this.tagInfo.tagName === this.ruleForm.tagName
&& this.tagInfo.tagDescribe === this.ruleForm.tagDescribe
&& this.tagInfo.tagLevelGroupId === this.ruleForm.tagLevelGroupId;
},
// 新增标签值按钮是否可用
canAddTagVal() {
/**
* 新增分组,必须先保存标签基本信息
* 编辑分组,保持常亮
* */
return !!this.tagId;
} }
}, },
methods: { methods: {
closePop() {
this.$emit('update:showPop', false);
},
// 保存标签基本信息 // 保存标签基本信息
confirmSave() { confirmSave() {
if (this.ruleForm.pending) return;
this.ruleForm.pending = true;
this.$refs.ruleForm.validate((valid) => { this.$refs.ruleForm.validate((valid) => {
if (valid) this.saveApi(); if (valid) this.saveApi();
}); });
...@@ -314,14 +129,15 @@ export default { ...@@ -314,14 +129,15 @@ export default {
// 保存标签基本信息 // 保存标签基本信息
saveApi() { saveApi() {
const para = { const para = {
tagId: this.tagId, tagId: this.options.tagId,
tagName: this.ruleForm.tagName, tagName: this.ruleForm.tagName,
tagDescribe: this.ruleForm.tagDescribe, tagDescribe: this.ruleForm.tagDescribe,
tagLevelGroupId: this.ruleForm.tagLevelGroupId tagLevelGroupId: this.ruleForm.tagLevelGroupId
}; };
getRequest('/memberTag/saveHandMemberTag', para).then(res => { getRequest('/memberTag/saveHandMemberTag', para).then(res => {
const { errorCode, result, message } = res.data; const { errorCode, message } = res.data;
this.ruleForm.pending = false;
if (errorCode !== 1) { if (errorCode !== 1) {
this.$message.error({ this.$message.error({
duration: 1000, duration: 1000,
...@@ -330,278 +146,10 @@ export default { ...@@ -330,278 +146,10 @@ export default {
return; return;
} }
showMsg.showmsg('保存成功', 'success'); showMsg.showmsg('保存成功', 'success');
// 如果新增需要获取 tagId this.$emit('save');
this.tagId = result; this.closePop();
this.tagInfo = {
tagName: this.ruleForm.tagName,
tagDescribe: this.ruleForm.tagDescribe,
tagLevelGroupId: this.ruleForm.tagLevelGroupId
}
// 获取标签值列表
this.getValueData();
}).catch(error => {
this.$message.error({
duration: 1000,
message: error.message
});
});
},
// 取消添加标签值
closeAddPop() {
this.addTagValPop.isShow = false;
this.addTagValPop.tagVal = '';
},
// 添加标签值
addTagVal() {
if (this.addTagValPop.tagVal.length === 0) {
this.$message.error({
duration: 1000,
message: '请输入标签值'
});
return false;
}
if (this.tagValTableData.some(item => item.name === this.addTagValPop.tagVal)) {
this.$message.error({
duration: 1000,
message: '标签值已存在'
});
return false;
}
this.addTagItem('', this.addTagValPop.tagVal);
this.closeAddPop();
},
// 添加和编辑标签值
addTagItem(tagItemId, tagItemName) {
const para = {
tagItemId: tagItemId,
tagItemName: tagItemName,
tagId: this.tagId
};
getRequest('/memberTag/saveHandTagItem', para).then(res => {
const { errorCode } = res.data;
if (errorCode === 1) {
showMsg.showmsg('添加成功', 'success');
this.getValueData();
return;
}
errMsg.errorMsg(res.data);
}).catch(error => {
this.$message.error({
duration: 1000,
message: error.message
});
});
},
confirmDel(index, item) {
// 业务逻辑变更,不需要此拦截弹窗 2019-05-22
return;
this.$confirm('删除标签后,符合该标签值的会员对应标签值将同步删除。一旦删除将无法恢复,确认要删除吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.delTagApi(index, item);
});
},
// 删除标签值
delTagApi(index, item) {
const para = {
tagItemId: item.tagItemId
};
this.refreshTag.push({
tagItemIndex: index,
tagItemId: item.tagItemId
});
getRequest('/memberTag/delHandTagItem', para).then(res => {
const { errorCode } = res.data;
if (errorCode === 1) {
item.delStatus = 0;
this.handleRefreshTag();
return;
}
errMsg.errorMsg(res.data);
}).catch(error => {
this.$message.error({
duration: 1000,
message: error.message
});
});
},
// 获取标签值列表
getValueData() {
const para = {
tagId: this.tagId
};
getRequest('/memberTag/queryHandTagItem', para).then((res) => {
const { errorCode, result } = res.data;
if (errorCode === 1) {
/**
* 前端自定义的扩展字段
* 为了实现一个标签值的数据上传中另一个标签值仍可以上传的功能
* 上传完毕后,扩展字段需要重置
* */
result.forEach((ele, index) => {
ele.showDelPopOver = false;
// 上传进度百分比值
ele.percent = 0;
// 4 删除中 5删除项 6 处理中
if (ele.status === 4 || ele.status === 5 || ele.status === 6) {
this.refreshTag.push({tagItemIndex: index, tagItemId: ele.tagItemId});
}
});
this.tagValTableData = result;
this.handleRefreshTag();
return;
}
errMsg.errorMsg(res.data);
}).catch(error => {
this.$message.error({
duration: 1000,
message: error.message
});
});
},
// 显示导入会员的弹窗
showImportPop(index, row) {
this.importPop.isShow = true;
this.importPop.tagItemIndex = index;
this.importPop.tagItemId = row.tagItemId;
this.importPop.title = `${row.tagItemName}-导入会员`
},
// 关闭导入会员的弹窗
closeImportPop() {
this.importPop.isShow = false;
this.resetImportData();
},
// 重置导入的表格数据
resetImportData() {
this.importPop.excelName = '';
this.importPop.excelData = [];
this.importPop.excelHeader = [];
this.importPop.optType = false;
},
// 点击上传文件、
handleUpload() {
if (this.importPop.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.importPop.excelName = files.name;
const reader = new FileReader();
reader.onload = e => {
const data = e.target.result;
const fixedData = this.fixData(data);
const workbook = XLSX.read(btoa(fixedData), { type: 'base64' });
const firstSheetName = workbook.SheetNames[0];
const worksheet = workbook.Sheets[firstSheetName];
if (Object.keys(worksheet).indexOf('!ref') === -1) {
this.$message.error({
duration: 1000,
message: '文档内容为空'
});
return false;
}
this.importPop.excelHeader = this.get_header_row(worksheet);
this.importPop.excelData = XLSX.utils.sheet_to_json(worksheet);
if (this.importPop.excelData.length > 5000) {
this.$message.error({
duration: 1000,
message: '单次上传数据不能超过 5000 条,请重新上传文件'
});
}
};
reader.readAsArrayBuffer(files);
},
fixData(data) {
let o = '';
let l = 0;
const w = 10240;
for (; l < data.byteLength / w; ++l) o += String.fromCharCode.apply(null, new Uint8Array(data.slice(l * w, l * w + w)));
o += String.fromCharCode.apply(null, new Uint8Array(data.slice(l * w)));
return o;
},
get_header_row(sheet) {
const headers = [];
const range = XLSX.utils.decode_range(sheet['!ref']);
let C;
const R = range.s.r; /* start in the first row */
for (C = range.s.c; C <= range.e.c; ++C) {
/* walk every column in the range */
let cell = sheet[XLSX.utils.encode_cell({ c: C, r: R })]; /* find the cell in the first row */
let hdr = 'UNKNOWN ' + C; // <-- replace with your desired default
if (cell && cell.t) hdr = XLSX.utils.format_cell(cell);
headers.push(hdr);
}
return headers;
},
uploadExcel() {
// 上传之前,不需要根据是否勾选“清空标签历史标记会员”进行拦截 2019-05-22
return;
if (this.importPop.optType) {
this.$confirm('勾选此选项则清空之前有此标签会员身上的标签,以本次导入会员为准;否则本次导入和之前已有数据去重添加。请慎重选择!', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(this.tagItemImport);
return;
}
this.tagItemImport()
},
// 导入数据到服务端
tagItemImport() {
if (this.importPop.excelData.length === 0) {
this.$message.error({
duration: 1000,
message: '导入数据有为空或者数据异常'
});
return;
}
this.$refs.upload.value = '';
this.refreshTag.push({
tagItemIndex: this.importPop.tagItemIndex,
tagItemId: this.importPop.tagItemId
});
const para = {
tagItemId: this.importPop.tagItemId,
data: JSON.stringify(this.importPop.excelData)
};
postRequest('/memberTag/uploadHandTagItemImport', para).then((res) => {
const { errorCode } = res.data;
errorCode === 1 ? this.handTagItemImport() : errMsg.errorMsg(res.data);
}).catch(error => { }).catch(error => {
this.ruleForm.pending = false;
this.$message.error({ this.$message.error({
duration: 1000, duration: 1000,
message: error.message message: error.message
...@@ -609,141 +157,9 @@ export default { ...@@ -609,141 +157,9 @@ export default {
}); });
}, },
// 服务端处理导入数据
handTagItemImport() {
let {tagItemId, optType } = this.importPop;
optType = optType ? 1 : 0;
getRequest('/memberTag/dealHandTagItemImport', { tagItemId, optType }).then((res) => {
const { errorCode } = res.data;
if (errorCode === 1) {
// 关闭上传的弹窗
this.closeImportPop();
// 查询上传进度
this.handleRefreshTag();
} else {
errMsg.errorMsg(res.data);
}
}).catch(error => {
this.$message.error({
duration: 1000,
message: error.message
});
});
},
handleRefreshTag() {
// 根据refreshTag的tagItemIndex比对tagValueTableData的tagItemId是否相同,如果相同,就操作tagValueTableData的数据,不同就不操作
// 新增和删除标签值完成后,重新执行getValueData方法,刷新标签值列表数据,重启轮询
// 当refreshTag的length为0时,终止轮询
if (this.refreshTag.length === 0) return;
let allPro = [];
this.refreshTag.forEach(item => {
allPro.push(this.getImportReport(item.tagItemIndex, item.tagItemId));
})
Promise.all(allPro).then(() => {
clearTimeout(this.timer);
this.timer = setTimeout(this.handleRefreshTag, 1000);
})
},
// 查询上传、删除的进度
getImportReport(tagItemIndex, tagItemId) {
return getRequest('/memberTag/getImportReport', { tagItemId }).then((res) => {
const { errorCode, result } = res.data;
if (errorCode === 1) {
// 0 删除 1正常 2导入中 3 导入完成 4 删除中 5删除项 6 处理中 7 异常 8 处理成功
switch (result.status) {
case 0:
// 已删除
this.getValueData();
break;
case 5:
if (this.tagValTableData[tagItemIndex].tagItemId === tagItemId) {
this.tagValTableData[tagItemIndex].status = 5;
}
break;
case 4:
case 6:
if (this.tagValTableData[tagItemIndex].tagItemId === tagItemId) {
this.tagValTableData[tagItemIndex].status = result.status;
const num = parseInt((result.totalNum - result.needExec) / result.totalNum * 100);
this.tagValTableData[tagItemIndex].percent = num === 100 ? 99 : num;
}
break;
case 8:
if (this.tagValTableData[tagItemIndex].tagItemId === tagItemId) {
this.tagValTableData[tagItemIndex].status = result.status;
// 已经上传完成的标签值不在轮询
this.refreshTag = this.refreshTag.filter(item => item.tagItemId !== tagItemId);
this.uploadedTag.push(tagItemId);
// 上传的错误数量
this.tagValTableData[tagItemIndex].errorCount = result.needError;
// 重置百分比为0
this.tagValTableData[tagItemIndex].percent = 0;
}
break;
default:
if (this.tagValTableData[tagItemIndex].tagItemId === tagItemId) {
this.tagValTableData[tagItemIndex].status = result.status;
// 已经上传完成的标签值不在轮询
this.refreshTag = this.refreshTag.filter(item => item.tagItemId !== tagItemId);
// 重置错误数量、百分比为0
this.tagValTableData[tagItemIndex].errorCount = 0;
this.tagValTableData[tagItemIndex].percent = 0;
}
break;
}
} else {
errMsg.errorMsg(res.data);
}
}).catch(error => {
this.$message.error({
duration: 1000,
message: error.message
});
});
},
// 下载上传失败的会员清单
downloadErrorData(tagItemId) {
getRequest('/memberTag/queryImportErrorData', { tagItemId }).then(res => {
const { errorCode, result } = res.data;
if (errorCode === 1) {
if (result && result.length) {
const header = Object.keys(result[0]);
//获取数据后执行 excel 导出
const data = result.map(item => header.map(key => item[key]));
export_json_to_excel(header, data, '导出列表');
} else {
this.$message.error({
duration: 1000,
message: '暂无失败数据'
});
}
return;
}
errMsg.errorMsg(res.data);
}).catch(error => {
this.$message.error({
duration: 1000,
message: error.message
});
});
},
// 导出 excel 模板
downloadExcelTemp() {
const tHeader = ['手机号', '卡号'];
const data = [
['17098078224', 'jhdm2018071315'],
['13100000055', 'jhdm20180608000000003']
];
export_json_to_excel(tHeader, data, '导入 excel 模板');
},
// 获取二级分类列表 // 获取二级分类列表
getOptionsTwo() { getOptionsTwo() {
getRequest('/tagLevel/handSecondLevel', {}).then(res => { return getRequest('/tagLevel/handSecondLevel', {}).then(res => {
const { errorCode, result } = res.data; const { errorCode, result } = res.data;
if (errorCode === 1) { if (errorCode === 1) {
this.optionsTwo = result; this.optionsTwo = result;
...@@ -786,15 +202,8 @@ export default { ...@@ -786,15 +202,8 @@ export default {
this.ruleForm.tagLevelGroupId = result.tagLevelGroupId; this.ruleForm.tagLevelGroupId = result.tagLevelGroupId;
this.ruleForm.tagTwoLevelGroupId = result.tagTwoLevelGroupId; this.ruleForm.tagTwoLevelGroupId = result.tagTwoLevelGroupId;
this.ruleForm.tagDescribe = result.tagDescribe; this.ruleForm.tagDescribe = result.tagDescribe;
this.tagInfo = {
tagName: result.tagName,
tagLevelGroupId: result.tagLevelGroupId,
tagDescribe: result.tagDescribe
}
// 根据已选二级 id 获取三级列表 // 根据已选二级 id 获取三级列表
this.getOptionsThree(result.tagTwoLevelGroupId); this.getOptionsThree(result.tagTwoLevelGroupId);
// 获取标签值列表
this.getValueData();
} }
}).catch(err => { }).catch(err => {
console.log(err); console.log(err);
...@@ -802,206 +211,29 @@ export default { ...@@ -802,206 +211,29 @@ export default {
} }
}, },
mounted() { mounted() {
const tagId = this.$route.query.tagId;
// 获取二级列表
this.getOptionsTwo(); this.getOptionsTwo();
if (tagId) {
// 编辑
this.tagId = tagId;
this.getTagData(tagId);
} else {
// 新增
let tagList = localStorage.getItem('jumpTag');
let tagThirdList = localStorage.getItem('jumpThirdTag');
if (tagList) {
tagList = JSON.parse(tagList);
this.ruleForm.tagTwoLevelGroupId = tagList.id;
this.getOptionsThree(tagList.id);
}
if (tagList && tagThirdList) {
tagThirdList = JSON.parse(tagThirdList);
this.ruleForm.tagLevelGroupId = tagThirdList.id;
}
}
},
beforeDestroy() {
clearTimeout(this.timer);
},
components: {
navCrumb
} }
} }
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
.right-box { .input-label {
padding: 0 !important; position: absolute;
.manualTagEdit-wrap__title { top: 2px;
margin-bottom: 0; right: 45px;
padding: 18px 42px 16px; z-index: 1;
width: 100%; font-size: 12px;
font-size: 16px; color: #C0C4CC;
color: #303133; }
border-bottom: 2px solid #EDEFF2;
}
.manualTagEdit-wrap__form {
padding: 30px 42px;
width: 100%;
}
.input-label {
position: absolute;
top: 2px;
right: 45px;
z-index: 1;
font-size: 12px;
color: #C0C4CC;
}
.textarea-label {
.input-label;
top: 92px;
right: 45px;
}
.no-tag-value {
padding: 60px 0 65px;
text-align: center;
p {
font-weight: 300;
}
}
.add-tag-val {
position: relative;
display: flex;
align-items: center;
margin: 0 auto;
width: 375px;
span {
margin-right: 10px;
flex: 1 1 55px;
font-size: 14px;
}
.input-label{
display: flex;
align-items: center;
right: 10px;
top: 0;
height: 100%;
}
}
.add-tag {
border-bottom: 1px solid #E4E7ED;
.add-tag-btn {
margin: 0 auto;
width: 100px;
height: 48px;
text-align: center;
line-height: 48px;
font-size: 14px;
color: #909399;
cursor: pointer;
&:hover {
color: #1890ff;
}
}
}
.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: 500px;
.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 { .textarea-label {
margin-top: 24px; .input-label;
font-size: 14px; top: 92px;
color: #606266; right: 45px;
}
.icon-xinxixianshi { .manualTagEdit-btns {
font-size: 12px; padding: 10px 0;
color: #909399; text-align: right;
}
}
}
}
.uploading {
color: #909399;
font-size: 14px;
.uploading-progress {
padding: 0 0 0 10px;
display: inline-block;
width: 200px;
}
}
.upload-state {
padding: 0 20px 0 0;
.uploading-succ {
color: #909399;
}
.download-failed {
color: #909399;
.download-failed-btn {
padding: 0 10px 0 5px;
color: #f5222d;
cursor: pointer;
&:hover {
color: #dc535b;
}
}
}
}
} }
.w-447 { .w-447 {
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
<div class="member-box"> <div class="member-box">
<div class="tag-input"> <div class="tag-input">
<el-input placeholder="请输入关键词回车搜索标签" prefix-icon="el-icon-search" style="width: 348px" v-model="memberTag" @keyup.native.enter="searchMemberList" clearable></el-input> <el-input placeholder="请输入关键词回车搜索标签" prefix-icon="el-icon-search" style="width: 348px" v-model="memberTag" @keyup.native.enter="searchMemberList" @clear="allTagList" clearable></el-input>
</div> </div>
<div class="main-tag"> <div class="main-tag">
<div class="tag-list"> <div class="tag-list">
...@@ -21,10 +21,10 @@ ...@@ -21,10 +21,10 @@
<p class="tag-name"> <p class="tag-name">
<!--{{ tagName }}--> <!--{{ tagName }}-->
{{showSearchResult ? `【${tagName}】搜索结果` : tagName}} {{showSearchResult ? `【${tagName}】搜索结果` : tagName}}
<el-button type="primary" class="add-newtag" @click="addNewTag" v-show="handTag == 1">新增标签</el-button> <el-button type="primary" class="add-newtag" @click="editHandTag()" v-show="handTag == 1">新增标签</el-button>
</p> </p>
<tag-container @deleteHandTag="deleteHandTag" :data="memberTagList" :handTag="handTag" :groupId="groupId" :refersh="refershList" @addTag="selectedTag" ref="tagContainer" /> <tag-container @deleteHandTag="deleteHandTag" :data="memberTagList" :handTag="handTag" :groupId="groupId" :refersh="refershList" @addTag="selectedTag" @editHandTag="editHandTag" ref="tagContainer" />
<div class="page-box" v-if="total > 0"> <div class="page-box" v-if="total > 0">
<el-pagination <el-pagination
...@@ -109,6 +109,7 @@ ...@@ -109,6 +109,7 @@
</div> </div>
</div> </div>
<edit-tag :showEditTagPop.sync="showEditTagPop" :tagData="tagData" :title="editPopType === 'add' ? '添加标签' : '编辑标签'" @returnTagData="returnTagData" @refersh="refersh"></edit-tag> <edit-tag :showEditTagPop.sync="showEditTagPop" :tagData="tagData" :title="editPopType === 'add' ? '添加标签' : '编辑标签'" @returnTagData="returnTagData" @refersh="refersh"></edit-tag>
<manual-tag-edit :options="manualTagPop" :showPop.sync="manualTagPop.show" @save="addNewTag"></manual-tag-edit>
</div> </div>
</template> </template>
...@@ -119,6 +120,7 @@ import navCrumb from '@/components/nav/nav.vue'; ...@@ -119,6 +120,7 @@ import navCrumb from '@/components/nav/nav.vue';
import TagsGroupList from '../memberGroup/tags-group-list'; import TagsGroupList from '../memberGroup/tags-group-list';
import TagType from './tag-type'; import TagType from './tag-type';
import TagContainer from './tag-container'; import TagContainer from './tag-container';
import ManualTagEdit from '../manualTag/manualTagEdit';
import { getMemberTag, getMemberTagList, addNewGroup } from '@/request/api'; import { getMemberTag, getMemberTagList, addNewGroup } from '@/request/api';
import EditTag from '../memberGroup/edit-tag'; import EditTag from '../memberGroup/edit-tag';
import { mapState } from 'vuex'; import { mapState } from 'vuex';
...@@ -135,7 +137,8 @@ export default { ...@@ -135,7 +137,8 @@ export default {
TagType, TagType,
TagContainer, TagContainer,
TagsGroupList, TagsGroupList,
EditTag EditTag,
ManualTagEdit
}, },
data() { data() {
...@@ -237,7 +240,16 @@ export default { ...@@ -237,7 +240,16 @@ export default {
showEditTagPop: false, showEditTagPop: false,
tagData: {}, tagData: {},
editPopType: 'add' editPopType: 'add',
manualTagPop: {
show: false,
popTitle: '',
// popTitle: '编辑手工标签',
// tagId: '6285cee7e2e14dddae3e2322c6ef6089'
tagId: '',
tagLevelGroupId: '',
tagTwoLevelGroupId: ''
}
}; };
}, },
...@@ -385,6 +397,22 @@ export default { ...@@ -385,6 +397,22 @@ export default {
this.tagData.editCondition = false; this.tagData.editCondition = false;
this.showEditTagPop = true; this.showEditTagPop = true;
}, },
// 新增第三级手工标签
editHandTag(list) {
/**
* 第一级标签切换时,重置manualTagPop.tagTwoLevelGroupId和manualTagPop.tagLevelGroupId为空
* 第二级标签切换时,修改manualTagPop.tagTwoLevelGroupId为当前第二级标签的tagLevelGroupId,重置manualTagPop.tagLevelGroupId为空
* 第三级标签切换时,修改manualTagPop。tagLevelGroupId为当前第三级标签的tagLevelGroupId,修改manualTagPop.tagTwoLevelGroupId为parentLevelGroupId
*
* 编辑三级手工标签,修改manualTagPop.tagId为list.tagId
* 新增三级手工标签,重置manualTagPop.tagId为空
*
* 然后将manualTagPop传递给manualTagEdit组件
* */
this.manualTagPop.tagId = list ? list.tagId : '';
this.manualTagPop.popTitle = list ? '编辑手工标签' : '新增手工标签';
this.manualTagPop.show = true;
},
async getTagList() { async getTagList() {
const Data = await getMemberTag(); const Data = await getMemberTag();
if (Data.result && Data.result.length) { if (Data.result && Data.result.length) {
...@@ -478,6 +506,8 @@ export default { ...@@ -478,6 +506,8 @@ export default {
this.loadMemberTagList(this.params); this.loadMemberTagList(this.params);
this.groupId = list.id; this.groupId = list.id;
this.handTag = list.handTag; this.handTag = list.handTag;
this.manualTagPop.tagTwoLevelGroupId = '';
this.manualTagPop.tagLevelGroupId = '';
this.changeTagTitle(list.name); this.changeTagTitle(list.name);
}, },
changeTagTitle(name) { changeTagTitle(name) {
...@@ -500,11 +530,9 @@ export default { ...@@ -500,11 +530,9 @@ export default {
localStorage.setItem('groupId', ''); localStorage.setItem('groupId', '');
} }
}, },
// 添加手工标签 // 添加手工标签后刷新标签列表
addNewTag() { addNewTag() {
this.$router.push({ this.loadMemberTagList(this.params);
path: '/manualTagEdit'
});
}, },
// 删除手工 // 删除手工
deleteHandTag(id) { deleteHandTag(id) {
...@@ -589,6 +617,8 @@ export default { ...@@ -589,6 +617,8 @@ export default {
this.loadMemberTagList(this.params); this.loadMemberTagList(this.params);
this.groupId = list.id; this.groupId = list.id;
this.handTag = list.handTag; this.handTag = list.handTag;
this.manualTagPop.tagTwoLevelGroupId = list.tagLevelGroupId;
this.manualTagPop.tagLevelGroupId = '';
this.changeTagTitle(list.name); this.changeTagTitle(list.name);
}); });
// 处理三级标签 // 处理三级标签
...@@ -613,6 +643,8 @@ export default { ...@@ -613,6 +643,8 @@ export default {
this.loadMemberTagList(this.params); this.loadMemberTagList(this.params);
this.groupId = list.id; this.groupId = list.id;
this.handTag = list.handTag; this.handTag = list.handTag;
this.manualTagPop.tagTwoLevelGroupId = list.parentLevelGroupId;
this.manualTagPop.tagLevelGroupId = list.tagLevelGroupId;
this.changeTagTitle(list.name); this.changeTagTitle(list.name);
}); });
this.defaultDate(); this.defaultDate();
...@@ -692,6 +724,7 @@ export default { ...@@ -692,6 +724,7 @@ export default {
.member-box { .member-box {
padding-bottom: 20px; padding-bottom: 20px;
margin: 20px 32px 0; margin: 20px 32px 0;
min-width: 1500px;
min-height: 70vh; min-height: 70vh;
background-color: #fff; background-color: #fff;
.tag-input { .tag-input {
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
<span class="tag-name">{{ scope.row.tagName }}</span> <span class="tag-name">{{ scope.row.tagName }}</span>
<el-tooltip class="item" effect="dark" :content="scope.row.refersh ? '更新标签' : '添加标签'" placement="bottom"> <el-tooltip class="item" effect="dark" :content="scope.row.refersh ? '更新标签' : '添加标签'" placement="bottom">
<!-- :class="{ 'icon-shoudonggengxin': scope.row.refersh }" --> <!-- :class="{ 'icon-shoudonggengxin': scope.row.refersh }" -->
<i class="iconfont icon-jia icon-tag-name" @click="addTag(scope.row)"></i> <i class="iconfont icon-tag-name" :class="scope.row.refersh ? 'icon-shoudonggengxin' : 'icon-jia'" @click="addTag(scope.row)"></i>
</el-tooltip> </el-tooltip>
</template> </template>
</el-table-column> </el-table-column>
...@@ -21,10 +21,11 @@ ...@@ -21,10 +21,11 @@
<span> {{ scope.row.isActive == 1 ? '实时' : '非实时' }} </span> <span> {{ scope.row.isActive == 1 ? '实时' : '非实时' }} </span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="操作" v-if="handTag" min-width="150"> <el-table-column label="操作" v-if="handTag" min-width="200">
<template slot-scope="scope"> <template slot-scope="scope">
<!-- <span v-if="scope.row.tagType == 1"> --> <!-- <span v-if="scope.row.tagType == 1"> -->
<el-button type="text" @click="editHandTag(scope.row)">编辑</el-button> <el-button type="text" @click="editHandTag(scope.row)">编辑</el-button>
<el-button type="text" @click="editHandTagValue(scope.row)">标签值设置</el-button>
<el-button type="text" @click="deleteHandTag(scope.row)">删除</el-button> <el-button type="text" @click="deleteHandTag(scope.row)">删除</el-button>
<!-- </span> --> <!-- </span> -->
</template> </template>
...@@ -67,16 +68,19 @@ export default { ...@@ -67,16 +68,19 @@ export default {
}, },
methods: { methods: {
// 添加标签 弹框里面操作 // 将标签添加到已选标签 弹框里面操作
addTag(list) { addTag(list) {
this.$emit('addTag', list); this.$emit('addTag', list);
}, },
editHandTag(list) { editHandTag(list) {
this.$emit('editHandTag', list);
},
editHandTagValue(list) {
localStorage.setItem('jumpTag', ''); localStorage.setItem('jumpTag', '');
localStorage.setItem('jumpThirdTag', ''); localStorage.setItem('jumpThirdTag', '');
this.dispatch('member-tag', 'edit-third-tag'); // this.dispatch('member-tag', 'edit-third-tag');
this.$router.push({ this.$router.push({
path: '/manualTagEdit', path: '/manualTagValueEdit',
query: { tagId: list.tagId } query: { tagId: list.tagId }
}); });
}, },
......
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