添加:邀请码管理(增加、作废、导出、批量下载)
修复:兑换码、邀请码 - 点击导出但实际却执行下载操作的问题 优化:兑换码、邀请码 - 二维码扫码内容优化,添加类型区分 优化:兑换码、邀请码 - 导出表格内容添加二维码具体内容信息 修复:增加兑换码、邀请码 - 类型为随机生成时,会进入顺序生成的步骤,然后直接报错,导致生成失败的问题
This commit is contained in:
parent
3540ec75c9
commit
98155cd4dd
|
|
@ -468,9 +468,26 @@ export function exchangeCodeCancelForm() {
|
|||
export function exchangeCodeUpdate(data) {
|
||||
return request.post('user/exchangeCode/updateCode',data)
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 邀请码 - 列表获取
|
||||
export function inviteCodeList(data) {
|
||||
return request.get('user/inviteCode/getList', data)
|
||||
}
|
||||
// 邀请码 - 批次列表获取
|
||||
export function inviteCodeBatchList() {
|
||||
return request.get('user/inviteCode/getBatchList')
|
||||
}
|
||||
// 邀请码 - 添加表单
|
||||
export function inviteCodeEditForm() {
|
||||
return request.get('user/inviteCode/editForm')
|
||||
}
|
||||
// 邀请码 - 作废
|
||||
export function inviteCodeCancelForm() {
|
||||
return request.get('user/inviteCode/cancelForm')
|
||||
}
|
||||
// 邀请码 - 修改兑换码
|
||||
export function inviteCodeUpdate(data) {
|
||||
return request.post('user/inviteCode/updateCode',data)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -132,6 +132,15 @@ const userRouter =
|
|||
},
|
||||
component: () => import('@/views/user/member/exchangeCode')
|
||||
},
|
||||
{
|
||||
path: 'inviteCode',
|
||||
name: 'inviteCode',
|
||||
meta: {
|
||||
title: '邀请码',
|
||||
noCache: true
|
||||
},
|
||||
component: () => import('@/views/user/member/inviteCode')
|
||||
},
|
||||
]
|
||||
},
|
||||
]
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@
|
|||
<el-button size="small" type="success" @click="addExchangeCode">添加兑换码</el-button>
|
||||
<el-button size="small" type="warning" @click="activateExchangeCode">分配给商户</el-button>
|
||||
<el-button size="small" type="danger" @click="cancelExchangeCode">作废兑换码</el-button>
|
||||
<el-button size="small" type="info" @click="exports">导出兑换码</el-button>
|
||||
<el-button size="small" type="info" @click="exports('excel')">导出兑换码</el-button>
|
||||
<el-button size="small" type="info" @click="exports('down')">下载二维码</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -167,7 +167,7 @@ export default {
|
|||
Object.values(res.data.list).forEach(item => {
|
||||
let refName = 'qrCodeImg'+item.id;
|
||||
new QRCodeOld(_this.$refs[refName], {
|
||||
text: item.exchange_code, // 需要转换为二维码的内容
|
||||
text: item.qr_code_text, // 需要转换为二维码的内容
|
||||
width: 80,
|
||||
height: 80,
|
||||
colorDark: '#000000',
|
||||
|
|
@ -262,14 +262,14 @@ export default {
|
|||
// 生成下载数据
|
||||
const data = [];
|
||||
for (const item of list) {
|
||||
const base64 = await this.textQrcodeToBase64(item[2]);
|
||||
const base64 = await this.textQrcodeToBase64(item[3]);
|
||||
data.push({
|
||||
name: item[2],
|
||||
value: base64,
|
||||
});
|
||||
}
|
||||
// 下载
|
||||
this.dataUrlZip(data);
|
||||
this.dataUrlZip(data, exportData.filename || 'qrcodes');
|
||||
},
|
||||
/**
|
||||
* 将字符串生成二维码并且转成base64
|
||||
|
|
@ -300,8 +300,9 @@ export default {
|
|||
/**
|
||||
* 将base64字符串以png格式装进jszip, 然后下载保存到本地
|
||||
* @param {Array} data {value: base64字符串, name: 二维码的名字}
|
||||
* @param fileName
|
||||
*/
|
||||
dataUrlZip(data) {
|
||||
dataUrlZip(data, fileName) {
|
||||
const zip = new JSZip();
|
||||
|
||||
for (const item of data) {
|
||||
|
|
@ -313,7 +314,7 @@ export default {
|
|||
|
||||
// 以二进制形式保存、并且通过file-saver下载到本地
|
||||
zip.generateAsync({ type: "blob" }).then( (content) =>{
|
||||
FileSaver.saveAs(content, "qrcodes.zip");
|
||||
FileSaver.saveAs(content, fileName + ".zip");
|
||||
});
|
||||
},
|
||||
// 点击修改兑换码
|
||||
|
|
|
|||
|
|
@ -0,0 +1,438 @@
|
|||
<template>
|
||||
<div class="divBox">
|
||||
<!--主要内容-->
|
||||
<el-card class="box-card">
|
||||
<!--顶部搜索栏-->
|
||||
<div slot="header" class="clearfix">
|
||||
<div class="container">
|
||||
<el-form inline size="small" label-width="80px">
|
||||
<el-form-item label="">
|
||||
<el-select v-model="tableFrom.status" class="selWidth" clearable>
|
||||
<el-option label="未激活" :value="0"></el-option>
|
||||
<el-option label="已激活" :value="1"></el-option>
|
||||
<el-option label="已使用" :value="2"></el-option>
|
||||
<el-option label="已作废" :value="3"></el-option>
|
||||
</el-select>
|
||||
<el-select v-if="Object.values(batch_list).length > 0" v-model="tableFrom.batch_unique" class="selWidth" clearable>
|
||||
<el-option v-for="(item,index) in batch_list" :label="index" :value="item"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-button size="small" type="primary" @click="getList(1)">搜索</el-button>
|
||||
<el-button size="small" type="success" @click="addExchangeCode">添加兑换码</el-button>
|
||||
<el-button size="small" type="danger" @click="cancelExchangeCode">作废兑换码</el-button>
|
||||
<el-button size="small" type="info" @click="exports('excel')">导出兑换码</el-button>
|
||||
<el-button size="small" type="info" @click="exports('down')">下载二维码</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<!--表格信息-->
|
||||
<el-table v-loading="listLoading" :data="tableData.data" style="width: 100%" size="mini">
|
||||
<el-table-column label="ID" prop="id" min-width="80" align="center"/>
|
||||
<el-table-column label="归属批次" min-width="130" align="center">
|
||||
<template slot-scope="scope">
|
||||
{{ scope.row.batch_title }}<br />
|
||||
{{ scope.row.batch_unique }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="兑换码" min-width="150" align="center">
|
||||
<template slot-scope="scope">
|
||||
<el-tooltip v-if="scope.row.status == 0" class="item" effect="dark" content="点击修改兑换码" placement="top-start">
|
||||
<el-button type="info" size="small" icon="el-icon-edit" @click="updateExchangeCode(scope.row)">
|
||||
{{ scope.row.exchange_code }}
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
<el-tag v-else-if="scope.row.status == 1" type="primary" effect="dark">{{ scope.row.exchange_code }}</el-tag>
|
||||
<el-tag v-else-if="scope.row.status == 2" type="success" effect="dark">{{ scope.row.exchange_code }}</el-tag>
|
||||
<el-tag v-else-if="scope.row.status == 3" type="danger" effect="dark">{{ scope.row.exchange_code }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" min-width="150" align="center">
|
||||
<template slot="header" slot-scope="scope">
|
||||
状态<br />
|
||||
激活时间 / 使用时间
|
||||
</template>
|
||||
<template slot-scope="scope">
|
||||
<el-tag v-if="scope.row.status == 0" type="info">{{ scope.row.mer_id > 0 ? '待激活' : '待分配' }}</el-tag>
|
||||
<template v-else-if="scope.row.status == 1">
|
||||
<el-tag type="primary">
|
||||
已激活<br />
|
||||
{{scope.row.activate}}
|
||||
</el-tag>
|
||||
</template>
|
||||
<template v-else-if="scope.row.status == 2">
|
||||
<el-tag type="success">
|
||||
已使用<br />
|
||||
{{scope.row.use_time}}
|
||||
</el-tag>
|
||||
</template>
|
||||
<template v-else-if="scope.row.status == 3">
|
||||
<el-tag type="danger">已作废</el-tag>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="激活用户" min-width="230" align="center">
|
||||
<template slot-scope="scope">
|
||||
<div class="user-content" v-if="scope.row.activateUser">
|
||||
<div class="user-avatar">
|
||||
<img :src="scope.row.activateUser.avatar || moren" />
|
||||
</div>
|
||||
<div class="user-info">
|
||||
<div class="nickname">{{ scope.row.activateUser.nickname }}</div>
|
||||
<div class="agent-type-text">
|
||||
<el-tag type="info" effect="dark" size="small">{{ scope.row.activateUser.uid }}</el-tag>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="添加时间" prop="create_time" min-width="130" align="center"/>
|
||||
<el-table-column label="绑定会员卡" prop="svip_name" min-width="100" align="center"/>
|
||||
<el-table-column label="使用人员" min-width="230" align="center">
|
||||
<template slot-scope="scope">
|
||||
<div class="user-content" v-if="scope.row.useUser">
|
||||
<div class="user-avatar">
|
||||
<img :src="scope.row.useUser.avatar || moren" />
|
||||
</div>
|
||||
<div class="user-info">
|
||||
<div class="nickname">{{ scope.row.useUser.nickname }}</div>
|
||||
<div class="agent-type-text">
|
||||
<el-tag type="info" effect="dark" size="small">{{ scope.row.useUser.uid }}</el-tag>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="二维码" min-width="100" align="center">
|
||||
<template slot-scope="scope">
|
||||
<div :ref="'qrCodeImg'+scope.row.id" class="qr-code-img"></div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!--分页-->
|
||||
<div class="block">
|
||||
<el-pagination
|
||||
:page-sizes="[20, 40, 60, 80]"
|
||||
:page-size="tableFrom.limit"
|
||||
:current-page="tableFrom.page"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="tableData.total"
|
||||
@size-change="handleUserSizeChange"
|
||||
@current-change="pageUserChange"
|
||||
/>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {inviteCodeBatchList, inviteCodeCancelForm, inviteCodeEditForm, inviteCodeList, inviteCodeUpdate} from "@/api/user";
|
||||
import createWorkBook from "@/utils/newToExcel";
|
||||
import QRCodeOld from "qrcodejs2";
|
||||
import QRCode from "qrcode";
|
||||
import JSZip from "jszip";
|
||||
import FileSaver from "file-saver";
|
||||
|
||||
export default {
|
||||
name: "preSaleProductList",
|
||||
components: {},
|
||||
data() {
|
||||
return {
|
||||
moren: require("@/assets/images/f.png"),
|
||||
// 列表
|
||||
listLoading: false,
|
||||
tableFrom: {
|
||||
page: 1,
|
||||
limit: 20,
|
||||
status: '',
|
||||
batch_unique: '',
|
||||
},
|
||||
tableData: {
|
||||
data: [],
|
||||
total: 0,
|
||||
},
|
||||
batch_list: {},
|
||||
};
|
||||
},
|
||||
watch: {},
|
||||
mounted() {
|
||||
this.getList();
|
||||
this.getBatchList();
|
||||
},
|
||||
methods: {
|
||||
// 列表
|
||||
getList(num = ''){
|
||||
let _this = this;
|
||||
_this.listLoading = true;
|
||||
_this.tableFrom.page = num ? num : _this.tableFrom.page;
|
||||
inviteCodeList(_this.tableFrom).then((res) => {
|
||||
_this.tableData.data = res.data.list;
|
||||
_this.tableData.total = res.data.count;
|
||||
_this.listLoading = false;
|
||||
// 循环显示二维码
|
||||
_this.$nextTick(function () {
|
||||
Object.values(res.data.list).forEach(item => {
|
||||
let refName = 'qrCodeImg'+item.id;
|
||||
new QRCodeOld(_this.$refs[refName], {
|
||||
text: item.qr_code_text, // 需要转换为二维码的内容
|
||||
width: 80,
|
||||
height: 80,
|
||||
colorDark: '#000000',
|
||||
colorLight: '#ffffff',
|
||||
correctLevel: QRCodeOld.CorrectLevel.H,
|
||||
});
|
||||
})
|
||||
});
|
||||
}).catch((res) => {
|
||||
_this.listLoading = false;
|
||||
_this.$message.error(res.message);
|
||||
});
|
||||
},
|
||||
pageUserChange(page) {
|
||||
this.tableFrom.page = page;
|
||||
this.getList('');
|
||||
},
|
||||
handleUserSizeChange(val) {
|
||||
this.tableFrom.limit = val;
|
||||
this.getList('');
|
||||
},
|
||||
// 批次列表
|
||||
getBatchList(){
|
||||
let _this = this;
|
||||
inviteCodeBatchList().then((res) => {
|
||||
_this.batch_list = res.data || {};
|
||||
}).catch((res) => {
|
||||
_this.$message.error(res.message);
|
||||
});
|
||||
},
|
||||
// 添加
|
||||
addExchangeCode(){
|
||||
this.$modalForm(inviteCodeEditForm()).then(() => this.getList(''));
|
||||
},
|
||||
// 作废
|
||||
cancelExchangeCode(){
|
||||
this.$modalForm(inviteCodeCancelForm()).then(() => this.getList(''));
|
||||
},
|
||||
// 导出 - 导出信息
|
||||
async exports(type = 'excel'){
|
||||
let _this = this;
|
||||
// 获取全部列表
|
||||
let params = Object.assign({}, _this.tableFrom);
|
||||
params.page = 1;
|
||||
params.limit = 20;
|
||||
params.is_export = 1;
|
||||
let exportData = await this.exportsAllList(params);
|
||||
|
||||
if(type == 'excel') createWorkBook(exportData.header || {}, exportData.title || {}, exportData.list || {}, exportData.foot || '',exportData.filename || '');
|
||||
else _this.downloadQrCode(exportData);
|
||||
},
|
||||
// 导出 - 获取全部信息列表
|
||||
exportsAllList(params, exportData = {}){
|
||||
let _this = this;
|
||||
return new Promise((resolve, reject) => {
|
||||
inviteCodeList(params).then((res) => {
|
||||
let data = res.data || {};
|
||||
if(params.page == 1){
|
||||
exportData.title = data.title || {};
|
||||
exportData.header = data.header || {};
|
||||
exportData.filename = data.filename || '';
|
||||
}
|
||||
// 计算是否存在下一页 并且合并数组
|
||||
let totalPage = Math.ceil(data.count / params.limit);
|
||||
let exportList = exportData.list || {};
|
||||
exportData.list = Object.values(exportList).concat(data.list);
|
||||
if(params.page < totalPage){
|
||||
// 存在下一页
|
||||
params.page++;
|
||||
_this.exportsAllList(params, exportData).then(res => {
|
||||
return resolve(res)
|
||||
});
|
||||
}else{
|
||||
// 不存在下一页
|
||||
return resolve(exportData)
|
||||
}
|
||||
}).catch((res) => {
|
||||
console.log('错误',res)
|
||||
return resolve(list)
|
||||
});
|
||||
})
|
||||
},
|
||||
// 二维码下载
|
||||
async downloadQrCode(exportData){
|
||||
let _this = this;
|
||||
let list = exportData.list || {};
|
||||
// 生成下载数据
|
||||
const data = [];
|
||||
for (const item of list) {
|
||||
const base64 = await this.textQrcodeToBase64(item[3]);
|
||||
data.push({
|
||||
name: item[2],
|
||||
value: base64,
|
||||
});
|
||||
}
|
||||
// 下载
|
||||
this.dataUrlZip(data, exportData.filename || 'qrcodes');
|
||||
},
|
||||
/**
|
||||
* 将字符串生成二维码并且转成base64
|
||||
* @param {要生成二维码的字符串} text
|
||||
* @returns
|
||||
*/
|
||||
textQrcodeToBase64(text) {
|
||||
return new Promise((res, rej) => {
|
||||
QRCode.toDataURL(
|
||||
text, // 二维码字符串
|
||||
{
|
||||
type: "image/png", // 生成dataurl图片格式
|
||||
width: 200, // 二维码宽度
|
||||
quality: 0.8, // 质量
|
||||
margin: 1, // 白边大小
|
||||
color: {
|
||||
dark: "#000", // 暗色颜色
|
||||
light: "#fff", // 亮色颜色
|
||||
},
|
||||
},
|
||||
(err, dataUrl)=> {
|
||||
if (err) rej(err);
|
||||
res(dataUrl.substring(22)); // substring(22)是去掉图片base64头
|
||||
}
|
||||
);
|
||||
});
|
||||
},
|
||||
/**
|
||||
* 将base64字符串以png格式装进jszip, 然后下载保存到本地
|
||||
* @param {Array} data {value: base64字符串, name: 二维码的名字}
|
||||
* @param fileName
|
||||
*/
|
||||
dataUrlZip(data, fileName) {
|
||||
const zip = new JSZip();
|
||||
|
||||
for (const item of data) {
|
||||
const { value, name } = item;
|
||||
zip.file(name + ".png", value, {
|
||||
base64: true,
|
||||
});
|
||||
}
|
||||
|
||||
// 以二进制形式保存、并且通过file-saver下载到本地
|
||||
zip.generateAsync({ type: "blob" }).then( (content) =>{
|
||||
FileSaver.saveAs(content, fileName + ".zip");
|
||||
});
|
||||
},
|
||||
// 点击修改兑换码
|
||||
updateExchangeCode(info){
|
||||
let _this = this;
|
||||
_this.$prompt(`当前兑换码:${info.exchange_code}`, {
|
||||
confirmButtonText: "提交修改",
|
||||
cancelButtonText: "取消修改",
|
||||
inputErrorMessage: "请输入新的兑换码",
|
||||
inputType: "text",
|
||||
inputPlaceholder: "请输入新的兑换码",
|
||||
inputValidator: value => {
|
||||
if (!value) return "输入不能为空";
|
||||
if(value.length > 10) return "兑换码长度不能超过10个字符";
|
||||
|
||||
const regex = /^[A-Za-z0-9]+$/;
|
||||
if (!regex.test(value)) return "请输入英文字母或者数字";
|
||||
}
|
||||
}).then(({value}) => {
|
||||
let params = {
|
||||
id: info.id,
|
||||
new_exchange_code: value
|
||||
};
|
||||
inviteCodeUpdate(params).then(res => {
|
||||
_this.$message.success(res.message)
|
||||
|
||||
_this.getList()
|
||||
}).catch((err) => {
|
||||
_this.$message.error(err.message)
|
||||
});
|
||||
}).catch(() => {});
|
||||
}
|
||||
|
||||
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.qr-code-img{
|
||||
width: 90px!important;
|
||||
height: 90px!important;
|
||||
padding-top: 5px;
|
||||
padding-left: 5px;
|
||||
}
|
||||
/deep/ .el-table .cell{
|
||||
padding: 0!important;
|
||||
}
|
||||
.selWidth{
|
||||
margin-bottom: 10px!important;
|
||||
}
|
||||
.user-content{
|
||||
--user-content-height-: 80px;
|
||||
|
||||
height: var(--user-content-height-);
|
||||
width: 100%;
|
||||
display: inline-flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: nowrap;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
.user-avatar{
|
||||
height: var(--user-content-height-);
|
||||
width: var(--user-content-height-);
|
||||
display: inline-flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: nowrap;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
img{
|
||||
height: 80%!important;
|
||||
width: 80%!important;
|
||||
border-radius: 50% !important;
|
||||
}
|
||||
}
|
||||
.user-info{
|
||||
max-width: calc(100% - var(--user-content-height-));
|
||||
height: var(--user-content-height-);
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: nowrap;
|
||||
justify-content: center;
|
||||
align-items: flex-start;
|
||||
.nickname{
|
||||
width: 100%;
|
||||
height: 25px;
|
||||
line-height: 25px;
|
||||
text-align: left;
|
||||
font-size: 15px;
|
||||
font-weight: bold;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: inline-flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: nowrap;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
.user-id{
|
||||
color: #fff;
|
||||
background-color: #409eff;
|
||||
border-color: #409eff;
|
||||
height: 18px;
|
||||
line-height: 20px;
|
||||
font-size: 13px;
|
||||
padding: 0 5px;
|
||||
border-radius: 5px;
|
||||
margin-left: 10px;
|
||||
width: max-content!important;
|
||||
}
|
||||
}
|
||||
.user-id{
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
font-size: 13px;
|
||||
line-height: calc(var(--user-content-height- * 35%));
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Loading…
Reference in New Issue