实现思路:参考微信支付和支付宝支付

用户出示二维码商家进行扫码扣款,可以是用户余额钱包也可以是绑定的会员卡

前端用的uniapp,后端thinkphp6.0,同时兼容微信小程序和app

<template><view class="page"><view class="cu-card"><view class="cu-item padding shadow" style="padding-bottom: 100upx;"><view class="cu-bar bg-white solid-bottom"><view class="action"><text class="cuIcon-check text-green"></text>商家进行扫码扣点 {{ str2 }}</view><view class="action"><text class="cuIcon-moreandroid"></text></view></view><view class="image qrbar margin-top"><canvas canvas-id="canvasbar" id="canvasbar" style="width:590rpx; height:180rpx;"></canvas><view class="gui-margin-top gui-text-center"><text class="text-lg">{{ str1 }}</text></view></view><view class="image qrcode"><canvas canvas-id="canvasqrcode" id="canvasqrcode" style="width:360rpx; height:360rpx;"></canvas></view></view><view class="cu-list menu sm-border card-menu "><view class="cu-item shadow arrow" @click="showModal"><view class="content flex-sub padding"><view class="text-bold">{{ currCard.type_name }}({{ currCard.type_text }})</view><view>{{ currCard.card_number }}</view><view class="text-gray text-sm flex justify-between"><view>优先使用此卡券进行扣点</view></view></view></view></view></view><view class="cu-modal bottom-modal block" :class="modalShow ? 'show' : ''"><view class="cu-dialog"><view class="cu-bar bg-white justify-end"><view class="content">选择扣点的卡券</view><view class="action" @tap="hideModal"><text class="cuIcon-close text-red"></text></view></view><view class="padding"><radio-group class="block" @change="RadioChange"><view class="cu-list menu sm-border text-left"><view class="cu-item" v-for="(item, index) in cardpaylist" :key="index"><label class="flex justify-between align-center flex-sub"><view class="flex-sub">{{ item.type_name }}({{ item.type_text }}){{ item.card_number }}</view><radio class="" :checked="item.is_dev == 1 ? true : false" :value="item"></radio></label></view></view></radio-group></view><view class="cu-bar bg-white justify-center"><view class="action"><button class="cu-btn bg-green margin-left lg" @tap="qudingselectcard">确定选择</button></view></view></view></view></view>
</template><script>
var QRCode = require('../../utils/qrcode.js');
var barcode = require('../../utils/barcode.js');
const util = require('../../utils/otp/util.js');
const otpapi = require('../../utils/otp/otpapi.js');
const otp = require('../../utils/otp/otp.js');
export default {data() {return {// 二维码绘制对象qrcode: null,// 二维码尺寸,单位 rpxqrcodeSize: 360,// 二维码数据qrcodeContent: '',// 二维码背景颜色qrcodeBgColor: '#FFFFFF',// 二维码颜色qrcodeColor: '#000000',// 画布 idqrcodeId: 'canvasqrcode',// 条形码绘制对象barcode: null,// 条形码尺寸,单位 rpx [ 宽度, 高度 ]barcodeSize: [590, 180],// 二维码数据barcodeContent: '',// 画布 idcanvasId: 'canvasbar',selected_secret_name: null, // 选中的口令名selected_secret: null, // 选中的口令selected_secret_result: null, // 选中的口令的计算结果totp_secret_list: [], // 口令列表intervalId: null, // 动态绘制更新口令结果的定时器timestamp_adj: null, // 用来矫正时间,使得从12点方向开始绘制进度str2: '',str1: '',windowWidth: null,windowHeight: null,secret_list_height: '400rpx',modalShow: false,cardpaylist: [],currCard: '',daicurrCard: ''};},onLoad() {this.initpage();},onHide() {this.stopUpdateSelectedSecret();},onUnload() {this.stopUpdateSelectedSecret();},onReady() {//this.makeqrcode();var that = this;setTimeout(function() {that.totp_gen_token();}, 200);},methods: {initpage() {var that = this;this.$api.post('user/userpaylist', {}, function(res) {var data = res.data;data.forEach((item, index) => {if (item.is_dev == 1) {that.currCard = item;}});that.cardpaylist = data;});},makeqrcode(qrcodeContent) {barcode.code128(uni.createCanvasContext(this.canvasId), qrcodeContent, uni.upx2px(this.barcodeSize[0]), uni.upx2px(this.barcodeSize[1]));this.qrcode = new QRCode(this.qrcodeId, {text: qrcodeContent,width: uni.upx2px(this.qrcodeSize),height: uni.upx2px(this.qrcodeSize),colorDark: this.qrcodeColor,colorLight: this.qrcodeBgColor,correctLevel: QRCode.CorrectLevel.H});},totp_gen_token() {//获取默认的卡券var secret = this.currCard.secret;this.selected_secret = secret;this.selected_secret_result = null;this.startUpdateSelectedSecret();},// 停止显示口令stopUpdateSelectedSecret() {if (this.intervalId != null) {clearInterval(this.intervalId);this.intervalId = null;this.selected_secret_result = null;}this.updateTotpToken(null);},// 启动显示口令restartUpdateSelectedSecret() {this.stopUpdateSelectedSecret();this.startUpdateSelectedSecret();},startUpdateSelectedSecret() {// 已启动if (this.intervalId) return;// 验证if (!this.selected_secret) {this.updateTotpToken(null);return;}// 启动定时计算和绘制口令结果//console.log('setInterval...');this.computeTimestampAdj();var intervalId = setInterval(this.updateSelectedSecret, 100);this.intervalId = intervalId;},// 计算adj,作为补偿,使得从12点钟方向开始显示口令computeTimestampAdj: function() {var timestamp = new Date().getTime() / 1000;var timestamp_adj = timestamp % 30;if (timestamp_adj > 15) {timestamp_adj = 30 - timestamp_adj; // 大于15,补到30,用下一轮的} else {timestamp_adj = -timestamp_adj; // 不够15,退回到0,用之前的}timestamp_adj = timestamp_adj * 1000;//console.log(timestamp_adj);this.timestamp_adj=timestamp_adj;},// 定时刷新口令并显示updateSelectedSecret() {var that = this;// 验证需要绘制if (!that.selected_secret) {that.stopUpdateSelectedSecret();return;}// 使用旧结果绘制,如果旧结果有效的话。var result = that.selected_secret_result;if (result) {// 通过对比当前时间和刷新时间和刷新周期来判断var timestamp = new Date().getTime() + this.timestamp_adj;if (timestamp - result.refresh_time <= result.refresh_interval) {that.updateTotpToken(result.token, timestamp, result.refresh_time, result.refresh_interval);return;}} else {// 旧结果没效,那应该是重选了另一个口令,或口令删除,需要重计算adjthis.computeTimestampAdj();}// 使用新结果绘制var timestamp = new Date().getTime() + this.timestamp_adj;otpapi.totp_gen2(that.selected_secret, timestamp).then(function(res) {//console.log("获取到令牌,设置令牌", res);var result = res.data;that.selected_secret_result = result;that.updateTotpToken(result.token, timestamp, result.refresh_time, result.refresh_interval);});},// ==============================================// 口令绘制updateTotpToken: function(token, timestamp, refresh_time, refresh_interval) {var str1 = '0000000000000000';//if (token) str1 =String(token);//String(parseInt(this.currCard.card_number)*3+);//String();if (token) str1 = String(parseInt(this.currCard.id) + parseInt(token) * 10000002527); //String();//付款码=TOTP * 质数 +  用户ID//质数取值需要大于最大用户ID,如:当前系统设计最大承受用户有9900人,则质数可以设定必须大于9900的数值(999999991).var str2 = '- - - - - -';if (timestamp && refresh_time && refresh_interval) {var sec = parseInt((refresh_interval + refresh_time - timestamp) / 1000) + 1;str2 = sec + '秒后刷新';}this.str1 = str1;this.str2 = str2;//二维码应该能确定用户的身份,能确认卡号,用完一次就失效this.makeqrcode(str1);},qudingselectcard() {this.hideModal();if (this.daicurrCard != '') {this.currCard = this.daicurrCard;//this.selected_secret_name = this.daicurrCard.card_number;this.selected_secret = this.daicurrCard.secret;this.totp_gen_token();}},showModal() {this.modalShow = true;},RadioChange(e) {this.daicurrCard = e.target.value;},hideModal() {this.modalShow = false;}}
};
</script><style>
.page {background-color: #f23030;height: 100vh;
}
.section {
}
.qrcode {display: flex;align-items: center;flex-direction: column;padding: 30upx;
}
.qrbar {display: flex;align-items: center;flex-direction: column;padding: 30upx;
}
</style>

离线二维码项目已完成tp6+uniapp相关推荐

  1. qrcode生成二维码-项目记录

    vue项目最开始使用的是qrcode1.5de 版本, 在Kylin+firefox43(浏览器版本比较低)的环境中报错, vue-router: failed to resolve async co ...

  2. 麦克表单可以做二维码吗_令令开门二维码门禁设备、手机均断网,可以开门吗?...

    一网友发微博,诉说了自己尴尬的遭遇:网友着急去上班,还有5分钟就要迟到,冲进写字楼,急忙掏出手机,准备扫码进门禁时.尴尬的一幕发生了,由于网络问题,手机上始终加载不出二维码,搞了半天也不行,只能求助工 ...

  3. 实现支付功能并生成二维码

    最近做了一个需求,需要根据返回的url生成二维码,实现支付功能.对于第一次接触这个需求的我还是比较期待的,因为又能学到新的知识啦!话不多说,进入正题. 第一步 正常情况下支付订单的话都会有规定的时间, ...

  4. 导览讲解 | 二维码语音讲解有什么优势?

    中国进入特色社会主义新时代之后,国家更是对旅游业的发展加大了支持力度.在政府的大力支持下,人人都想将绿水青山通过旅游发展转变为金山银山. 而旅游景区作为吸引游客的主要途径和生产力,景区之间的竞争也是如 ...

  5. 【Android】多功能二维码实现思路,自动连接WI-FI

    现在项目的需求是: 1. 带AP功能的机顶盒端能生成二维码,供手机客户端扫描 1.1 如果用非特定应用(手机助手)扫描,则跳转下载手机助手界面 1.2 如果用手机助手扫描,自动连接到该机顶盒的WI-F ...

  6. 手机移动端-纯js浏览器h5调用摄像头扫描识别解析 条形码+二维码

    一.场景 手机移动端-原生js 浏览器h5 解决 识别二维码 条形码功能: 不借助Hbuilder.需要自己打包成APP,比如用Hbuilder打包,浏览器端项目h5 无打包成app部署 X 不采用 ...

  7. 开源中国 OsChina Android 客户端源码分析(7)二维码生成对话框

    为什么80%的码农都做不了架构师?>>>    功能描述:主界面中点击"我"进入个人中心, 点击右侧二维码图标,弹出附有个人信息的二维码对话框. 1源码中的布局文 ...

  8. vue生成app二维码,并扫码下载app

    文章目录 项目需求 开发 web官网下载页的开发 web官网地址生成下载二维码 项目需求 公司要做一个web官网的下载页面,功能是微信扫码可以直接下载Ios手机端app.Android手机端app.及 ...

  9. 手机二维码软件及资源大汇总

    手机二维码大家已不陌生了,把所有关于二维码的软件.生成. 资源搜集整理出,供大家参考,更多http://www.qrwap.com/index.php ●●●二维码五种基本应用的生成 ●生成中国移动标 ...

最新文章

  1. 运维数据库平台~inception审核规则详解
  2. 第十六届智能车竞赛参赛队员提问与回答 |2021年7月12
  3. leetcode 101 Symmetric Tree
  4. 【C++】 C++标准模板库(三) Map
  5. PAT1004 成绩排名【vector sort排序、string的使用】
  6. java多态的简单例子_要JAVA的简单例子,继承\多态的,详细讲解运行的每一步
  7. 20140213-面向对象技术概论
  8. 用php循环星期一到星期日,php – 获取最后一个星期一 – 星期日的日期:有更好的方法吗?...
  9. data.getData()返回的Uri
  10. Java学生成绩管理系统主界面和登录界面参考
  11. 在线广告系统的架构变迁
  12. matlab各种文件读写,Matlab的各种数据读取、文件读写等操作汇总
  13. 微信人脸识别-采集个人信息
  14. MATLAB清除内存中变量
  15. 利用动态加载实现手机淘宝的节日特效
  16. Build: 0 succeeded, 0 failed, 1 up-to-date, 0 skipped
  17. 关于内存地址和内存空间的理解
  18. 参数的点估计问题与矩估计法
  19. 华为KubeEdge在边缘计算的实践
  20. Log4j2配置SMTP邮件实现邮件发送

热门文章

  1. 公告栏轮播效果html
  2. 【虚幻引擎UE】UE5 材质动态修改的2种方法(含工程源码)
  3. UIday1102:UITabelView 3 cell的混合使用代码举例
  4. [SCOI2007]组队
  5. 工业 4.0 时代,你准备好了吗?
  6. Python正则表达式知识点串联
  7. 2022年裂解(裂化)工艺考试内容及裂解(裂化)工艺证考试
  8. Python学习笔记——判断输入内容是否为数字
  9. 计算机专业自学美术,成人大专计算机应用专业考自学本科美术教育哪些科..._自学考试_帮考网...
  10. 大数据可视化大屏电子沙盘合集