diff --git a/components/qrcode-modal/qrcode-modal.js b/components/qrcode-modal/qrcode-modal.js new file mode 100644 index 0000000..46324fc --- /dev/null +++ b/components/qrcode-modal/qrcode-modal.js @@ -0,0 +1,48 @@ +const drawQrcode = require('../../utils/weapp.qrcode.esm.js').default + +Component({ + properties: { + visible: { + type: Boolean, + value: false + }, + qrcodeId: { + type: String, + value: '' + } + }, + + data: { + loading: true + }, + + observers: { + 'visible'(val) { + if (val && this.data.qrcodeId) { + this.setData({ loading: true }) + this.draw() + } + } + }, + + methods: { + draw() { + wx.nextTick(() => { + drawQrcode({ + width: 200, + height: 200, + canvasId: 'qrcodeCanvas', + _this: this, + text: this.data.qrcodeId, + callback: () => { + this.setData({ loading: false }) + } + }) + }) + }, + + onClose() { + this.triggerEvent('close') + } + } +}) diff --git a/components/qrcode-modal/qrcode-modal.json b/components/qrcode-modal/qrcode-modal.json new file mode 100644 index 0000000..a89ef4d --- /dev/null +++ b/components/qrcode-modal/qrcode-modal.json @@ -0,0 +1,4 @@ +{ + "component": true, + "usingComponents": {} +} diff --git a/components/qrcode-modal/qrcode-modal.wxml b/components/qrcode-modal/qrcode-modal.wxml new file mode 100644 index 0000000..e6a9fea --- /dev/null +++ b/components/qrcode-modal/qrcode-modal.wxml @@ -0,0 +1,13 @@ + + + 预约凭证 + + + + + + + {{qrcodeId}} + 请向工作人员出示此二维码 + + diff --git a/components/qrcode-modal/qrcode-modal.wxss b/components/qrcode-modal/qrcode-modal.wxss new file mode 100644 index 0000000..c032e64 --- /dev/null +++ b/components/qrcode-modal/qrcode-modal.wxss @@ -0,0 +1,79 @@ +.qrcode-modal { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(0, 0, 0, 0.5); + display: flex; + align-items: center; + justify-content: center; + z-index: 100; +} + +.qrcode-container { + background: #fff; + border-radius: 24rpx; + padding: 48rpx 64rpx; + display: flex; + flex-direction: column; + align-items: center; +} + +.qrcode-title { + font-size: 34rpx; + font-weight: 600; + color: #1a1a1a; + margin-bottom: 32rpx; +} + +.qrcode-canvas-wrap { + position: relative; + width: 400rpx; + height: 400rpx; +} + +.qrcode-canvas { + width: 400rpx; + height: 400rpx; +} + +.qrcode-loading { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + display: flex; + align-items: center; + justify-content: center; + background: #fff; +} + +.qrcode-spinner { + width: 48rpx; + height: 48rpx; + border: 4rpx solid #e0e0e0; + border-top: 4rpx solid #1890ff; + border-radius: 50%; + animation: qrcode-spin 0.8s linear infinite; +} + +@keyframes qrcode-spin { + from { transform: rotate(0deg); } + to { transform: rotate(360deg); } +} + +.qrcode-id { + font-size: 24rpx; + color: #999; + margin-top: 24rpx; + word-break: break-all; + text-align: center; +} + +.qrcode-tip { + font-size: 24rpx; + color: #bbb; + margin-top: 12rpx; +} diff --git a/pages/index/index.js b/pages/index/index.js index 6a68aa2..53bfd37 100644 --- a/pages/index/index.js +++ b/pages/index/index.js @@ -6,7 +6,9 @@ Page({ data: { isLoggedIn: false, loginFailed: false, - latestRecord: null + latestRecord: null, + qrcodeVisible: false, + qrcodeId: '' }, onLoad() { @@ -77,5 +79,14 @@ Page({ wx.navigateTo({ url: '/pages/records/records' }) + }, + + showQrcode(e) { + const id = e.currentTarget.dataset.id + this.setData({ qrcodeVisible: true, qrcodeId: id }) + }, + + hideQrcode() { + this.setData({ qrcodeVisible: false, qrcodeId: '' }) } }) diff --git a/pages/index/index.json b/pages/index/index.json index e02c929..fa87f54 100644 --- a/pages/index/index.json +++ b/pages/index/index.json @@ -1,4 +1,6 @@ { - "usingComponents": {}, + "usingComponents": { + "qrcode-modal": "/components/qrcode-modal/qrcode-modal" + }, "navigationBarTitleText": "访客预约系统" } diff --git a/pages/index/index.wxml b/pages/index/index.wxml index cbdb92e..d969a16 100644 --- a/pages/index/index.wxml +++ b/pages/index/index.wxml @@ -45,8 +45,14 @@ - 最新预约 - {{latestRecord.statusText}} + + 最新预约 + 出示凭证 + + + + {{latestRecord.statusText}} + @@ -75,4 +81,7 @@ 协能工厂 · 访客管理 - + + + + \ No newline at end of file diff --git a/pages/index/index.wxss b/pages/index/index.wxss index ae325c5..9cebe70 100644 --- a/pages/index/index.wxss +++ b/pages/index/index.wxss @@ -177,6 +177,25 @@ page { border-bottom: 1rpx solid #f0f0f0; } +.latest-header-right { + display: flex; + align-items: center; + gap: 12rpx; +} + +.qrcode-btn { + font-size: 22rpx; + color: #52c41a; + background: rgba(82, 196, 26, 0.1); + padding: 6rpx 20rpx; + border-radius: 20rpx; + border: 1rpx solid rgba(82, 196, 26, 0.3); +} + +.qrcode-btn:active { + background: rgba(82, 196, 26, 0.2); +} + .latest-title { font-size: 28rpx; font-weight: 600; @@ -188,6 +207,7 @@ page { padding: 4rpx 16rpx; border-radius: 16rpx; font-weight: 500; + margin-left: auto; } .status-pending { @@ -251,3 +271,5 @@ page { font-size: 24rpx; color: #ccc; } + + diff --git a/pages/records/records.js b/pages/records/records.js index a72e451..601c8f1 100644 --- a/pages/records/records.js +++ b/pages/records/records.js @@ -7,7 +7,9 @@ Page({ records: [], filteredRecords: [], currentTab: 'all', - loading: true + loading: true, + qrcodeVisible: false, + qrcodeId: '' }, onLoad() { @@ -81,5 +83,14 @@ Page({ wx.navigateTo({ url: '/pages/appointment/appointment' }) + }, + + showQrcode(e) { + const id = e.currentTarget.dataset.id + this.setData({ qrcodeVisible: true, qrcodeId: id }) + }, + + hideQrcode() { + this.setData({ qrcodeVisible: false, qrcodeId: '' }) } }) diff --git a/pages/records/records.json b/pages/records/records.json index 7bc86a0..d8828ef 100644 --- a/pages/records/records.json +++ b/pages/records/records.json @@ -1,4 +1,6 @@ { - "usingComponents": {}, + "usingComponents": { + "qrcode-modal": "/components/qrcode-modal/qrcode-modal" + }, "navigationBarTitleText": "预约记录" } diff --git a/pages/records/records.wxml b/pages/records/records.wxml index aa4f52f..2252350 100644 --- a/pages/records/records.wxml +++ b/pages/records/records.wxml @@ -23,7 +23,9 @@ - {{item._id}} + + 出示凭证 + {{item.statusText}} @@ -74,4 +76,7 @@ 暂无预约记录 去预约 + + + diff --git a/pages/records/records.wxss b/pages/records/records.wxss index 3e6afc7..dfb246c 100644 --- a/pages/records/records.wxss +++ b/pages/records/records.wxss @@ -72,11 +72,25 @@ page { color: #999; } +.qrcode-btn { + font-size: 24rpx; + color: #52c41a; + background: rgba(82, 196, 26, 0.1); + padding: 8rpx 24rpx; + border-radius: 24rpx; + border: 1rpx solid rgba(82, 196, 26, 0.3); +} + +.qrcode-btn:active { + background: rgba(82, 196, 26, 0.2); +} + .status-tag { font-size: 24rpx; padding: 6rpx 20rpx; border-radius: 20rpx; font-weight: 500; + margin-left: auto; } .status-pending { @@ -172,3 +186,5 @@ page { .empty-btn:active { background: #096dd9; } + + diff --git a/utils/config.js b/utils/config.js index 169fcd7..16954f3 100644 --- a/utils/config.js +++ b/utils/config.js @@ -6,7 +6,7 @@ const ENV_CONFIG = { // release: 'https://xcx.yun.588580.xyz', trial: 'https://qywx.yun.588580.xyz', // 开发版 & 体验版 - develop: 'https://qywx.yun.588580.xyz' + develop: 'http://172.16.60.235:8080' } // 自动判断当前运行环境 diff --git a/utils/weapp.qrcode.esm.js b/utils/weapp.qrcode.esm.js new file mode 100644 index 0000000..5613f25 --- /dev/null +++ b/utils/weapp.qrcode.esm.js @@ -0,0 +1,5 @@ +/** + * weapp.qrcode.js v1.0.0 (https://github.com/yingye/weapp-qrcode#readme) + */ + +var hasOwn=Object.prototype.hasOwnProperty,toStr=Object.prototype.toString,defineProperty=Object.defineProperty,gOPD=Object.getOwnPropertyDescriptor,isArray=function(t){return"function"==typeof Array.isArray?Array.isArray(t):"[object Array]"===toStr.call(t)},isPlainObject=function(t){if(!t||"[object Object]"!==toStr.call(t))return!1;var e,r=hasOwn.call(t,"constructor"),o=t.constructor&&t.constructor.prototype&&hasOwn.call(t.constructor.prototype,"isPrototypeOf");if(t.constructor&&!r&&!o)return!1;for(e in t);return void 0===e||hasOwn.call(t,e)},setProperty=function(t,e){defineProperty&&"__proto__"===e.name?defineProperty(t,e.name,{enumerable:!0,configurable:!0,value:e.newValue,writable:!0}):t[e.name]=e.newValue},getProperty=function(t,e){if("__proto__"===e){if(!hasOwn.call(t,e))return;if(gOPD)return gOPD(t,e).value}return t[e]},extend=function t(){var e,r,o,n,i,a,s=arguments[0],u=1,l=arguments.length,h=!1;for("boolean"==typeof s&&(h=s,s=arguments[1]||{},u=2),(null==s||"object"!=typeof s&&"function"!=typeof s)&&(s={});u=7&&this.setupTypeNumber(t),null==this.dataCache&&(this.dataCache=QRCode.createData(this.typeNumber,this.errorCorrectLevel,this.dataList)),this.mapData(this.dataCache,e)},setupPositionProbePattern:function(t,e){for(var r=-1;r<=7;r++)if(!(t+r<=-1||this.moduleCount<=t+r))for(var o=-1;o<=7;o++)e+o<=-1||this.moduleCount<=e+o||(this.modules[t+r][e+o]=0<=r&&r<=6&&(0==o||6==o)||0<=o&&o<=6&&(0==r||6==r)||2<=r&&r<=4&&2<=o&&o<=4)},getBestMaskPattern:function(){for(var t=0,e=0,r=0;r<8;r++){this.makeImpl(!0,r);var o=QRUtil.getLostPoint(this);(0==r||t>o)&&(t=o,e=r)}return e},createMovieClip:function(t,e,r){var o=t.createEmptyMovieClip(e,r);this.make();for(var n=0;n>r&1);this.modules[Math.floor(r/3)][r%3+this.moduleCount-8-3]=o}for(r=0;r<18;r++){o=!t&&1==(e>>r&1);this.modules[r%3+this.moduleCount-8-3][Math.floor(r/3)]=o}},setupTypeInfo:function(t,e){for(var r=this.errorCorrectLevel<<3|e,o=QRUtil.getBCHTypeInfo(r),n=0;n<15;n++){var i=!t&&1==(o>>n&1);n<6?this.modules[n][8]=i:n<8?this.modules[n+1][8]=i:this.modules[this.moduleCount-15+n][8]=i}for(n=0;n<15;n++){i=!t&&1==(o>>n&1);n<8?this.modules[8][this.moduleCount-n-1]=i:n<9?this.modules[8][15-n-1+1]=i:this.modules[8][15-n-1]=i}this.modules[this.moduleCount-8][8]=!t},mapData:function(t,e){for(var r=-1,o=this.moduleCount-1,n=7,i=0,a=this.moduleCount-1;a>0;a-=2)for(6==a&&a--;;){for(var s=0;s<2;s++)if(null==this.modules[o][a-s]){var u=!1;i>>n&1)),QRUtil.getMask(e,o,a-s)&&(u=!u),this.modules[o][a-s]=u,-1==--n&&(i++,n=7)}if((o+=r)<0||this.moduleCount<=o){o-=r,r=-r;break}}}},QRCode.PAD0=236,QRCode.PAD1=17,QRCode.createData=function(t,e,r){for(var o=QRRSBlock.getRSBlocks(t,e),n=new QRBitBuffer,i=0;i8*s)throw new Error("code length overflow. ("+n.getLengthInBits()+">"+8*s+")");for(n.getLengthInBits()+4<=8*s&&n.put(0,4);n.getLengthInBits()%8!=0;)n.putBit(!1);for(;!(n.getLengthInBits()>=8*s||(n.put(QRCode.PAD0,8),n.getLengthInBits()>=8*s));)n.put(QRCode.PAD1,8);return QRCode.createBytes(n,o)},QRCode.createBytes=function(t,e){for(var r=0,o=0,n=0,i=new Array(e.length),a=new Array(e.length),s=0;s=0?g.get(c):0}}var d=0;for(h=0;h=0;)e^=QRUtil.G15<=0;)e^=QRUtil.G18<>>=1;return e},getPatternPosition:function(t){return QRUtil.PATTERN_POSITION_TABLE[t-1]},getMask:function(t,e,r){switch(t){case QRMaskPattern.PATTERN000:return(e+r)%2==0;case QRMaskPattern.PATTERN001:return e%2==0;case QRMaskPattern.PATTERN010:return r%3==0;case QRMaskPattern.PATTERN011:return(e+r)%3==0;case QRMaskPattern.PATTERN100:return(Math.floor(e/2)+Math.floor(r/3))%2==0;case QRMaskPattern.PATTERN101:return e*r%2+e*r%3==0;case QRMaskPattern.PATTERN110:return(e*r%2+e*r%3)%2==0;case QRMaskPattern.PATTERN111:return(e*r%3+(e+r)%2)%2==0;default:throw new Error("bad maskPattern:"+t)}},getErrorCorrectPolynomial:function(t){for(var e=new QRPolynomial([1],0),r=0;r5&&(r+=3+i-5)}for(o=0;o=256;)t-=255;return QRMath.EXP_TABLE[t]},EXP_TABLE:new Array(256),LOG_TABLE:new Array(256)},i=0;i<8;i++)QRMath.EXP_TABLE[i]=1<=1&&n<=127?e+=t.charAt(r):n>2047?(e+=String.fromCharCode(224|n>>12&15),e+=String.fromCharCode(128|n>>6&63),e+=String.fromCharCode(128|n>>0&63)):(e+=String.fromCharCode(192|n>>6&31),e+=String.fromCharCode(128|n>>0&63));return e}function drawQrcode(t){t=t||{},(t=extend(!0,{width:256,height:256,x:0,y:0,typeNumber:-1,correctLevel:QRErrorCorrectLevel.H,background:"#ffffff",foreground:"#000000",image:{imageResource:"",dx:0,dy:0,dWidth:100,dHeight:100}},t)).canvasId||t.ctx?function(){var e,r=new QRCode(t.typeNumber,t.correctLevel);r.addData(utf16to8(t.text)),r.make(),e=t.ctx?t.ctx:t._this?wx.createCanvasContext&&wx.createCanvasContext(t.canvasId,t._this):wx.createCanvasContext&&wx.createCanvasContext(t.canvasId);for(var o=t.width/r.getModuleCount(),n=t.height/r.getModuleCount(),i=0;i>>7-t%8&1)},put:function(t,e){for(var r=0;r>>e-r-1&1))},getLengthInBits:function(){return this.length},putBit:function(t){var e=Math.floor(this.length/8);this.buffer.length<=e&&this.buffer.push(0),t&&(this.buffer[e]|=128>>>this.length%8),this.length++}};export default drawQrcode;