吕海超 il y a 10 mois
commit
76ec6c1ef1
100 fichiers modifiés avec 8248 ajouts et 0 suppressions
  1. 17 0
      App.vue
  2. 309 0
      components/mosowe-canvas-image/mosowe-canvas-image.vue
  3. 174 0
      components/mosowe-canvas-image/readme.md
  4. 987 0
      components/mosowe-canvas-image/wxqrcode.js
  5. 111 0
      components/navigationBarView.vue
  6. 173 0
      components/payCodePopup.vue
  7. 22 0
      components/uni-popup/message.js
  8. 25 0
      components/uni-popup/popup.js
  9. 243 0
      components/uni-popup/uni-popup-dialog.vue
  10. 116 0
      components/uni-popup/uni-popup-message.vue
  11. 165 0
      components/uni-popup/uni-popup-share.vue
  12. 294 0
      components/uni-popup/uni-popup.vue
  13. 279 0
      components/uni-transition/uni-transition.vue
  14. 1382 0
      js_sdk/Sansnn-uQRCode/uqrcode.js
  15. 21 0
      main.js
  16. 80 0
      manifest.json
  17. 72 0
      pages.json
  18. 375 0
      pages/admin/index.vue
  19. 91 0
      pages/admin/login.vue
  20. 308 0
      pages/admin/port.vue
  21. 204 0
      pages/admin/setting.vue
  22. 255 0
      pages/bagStorage/login.vue
  23. 667 0
      pages/bagStorage/orders.vue
  24. 125 0
      pages/bagStorage/success.vue
  25. 244 0
      pages/fetchPacket/index.vue
  26. 210 0
      pages/fetchPacket/success.vue
  27. 662 0
      pages/index/index.vue
  28. 376 0
      pages/order/details.vue
  29. 261 0
      pages/order/list.vue
  30. BIN
      static/TakeStore/store_862607052911665.png
  31. BIN
      static/TakeStore/store_862607052969937.png
  32. BIN
      static/TakeStore/store_862607052976122.png
  33. BIN
      static/TakeStore/store_862607052978334.png
  34. BIN
      static/TakeStore/store_862607052995395.png
  35. BIN
      static/TakeStore/store_862607052998829.png
  36. BIN
      static/TakeStore/store_862607053003694.png
  37. BIN
      static/TakeStore/store_862607053020359.png
  38. BIN
      static/TakeStore/store_862607053060660.png
  39. BIN
      static/TakeStore/store_862607053062807.png
  40. BIN
      static/TakeStore/store_862607053062971.png
  41. BIN
      static/TakeStore/store_862607053063177.png
  42. BIN
      static/TakeStore/store_862607053077425.png
  43. BIN
      static/TakeStore/store_862607053077938.png
  44. BIN
      static/TakeStore/store_862607053088349.png
  45. BIN
      static/TakeStore/store_862607053102132.png
  46. BIN
      static/TakeStore/store_867032053822800.png
  47. BIN
      static/TakeStore/store_867032053835778.png
  48. BIN
      static/TakeStore/store_867032053852286.png
  49. BIN
      static/TakeStore/store_867032053868381.png
  50. BIN
      static/TakeStore/store_867032053869892.png
  51. BIN
      static/TakeStore/store_867032053869900.png
  52. BIN
      static/TakeStore/take_862607052911665.png
  53. BIN
      static/TakeStore/take_862607052969937.png
  54. BIN
      static/TakeStore/take_862607052976122.png
  55. BIN
      static/TakeStore/take_862607052978334.png
  56. BIN
      static/TakeStore/take_862607052995395.png
  57. BIN
      static/TakeStore/take_862607052998829.png
  58. BIN
      static/TakeStore/take_862607053003694.png
  59. BIN
      static/TakeStore/take_862607053020359.png
  60. BIN
      static/TakeStore/take_862607053060660.png
  61. BIN
      static/TakeStore/take_862607053062807.png
  62. BIN
      static/TakeStore/take_862607053062971.png
  63. BIN
      static/TakeStore/take_862607053063177.png
  64. BIN
      static/TakeStore/take_862607053077425.png
  65. BIN
      static/TakeStore/take_862607053077938.png
  66. BIN
      static/TakeStore/take_862607053088349.png
  67. BIN
      static/TakeStore/take_862607053102132.png
  68. BIN
      static/TakeStore/take_867032053822800.png
  69. BIN
      static/TakeStore/take_867032053835778.png
  70. BIN
      static/TakeStore/take_867032053852286.png
  71. BIN
      static/TakeStore/take_867032053868381.png
  72. BIN
      static/TakeStore/take_867032053869892.png
  73. BIN
      static/TakeStore/take_867032053869900.png
  74. BIN
      static/images/icon-address.png
  75. BIN
      static/images/icon-arrow-left-block.png
  76. BIN
      static/images/icon-arrow-right-grey.png
  77. BIN
      static/images/icon-back-bg.png
  78. BIN
      static/images/icon-big-box-popup.png
  79. BIN
      static/images/icon-big-box-selected.png
  80. BIN
      static/images/icon-big-box.png
  81. BIN
      static/images/icon-delete-info.png
  82. BIN
      static/images/icon-delete.png
  83. BIN
      static/images/icon-fail.png
  84. BIN
      static/images/icon-fetch-bg.png
  85. BIN
      static/images/icon-fetch.png
  86. BIN
      static/images/icon-middle-box-popup.png
  87. BIN
      static/images/icon-middle-box-selected.png
  88. BIN
      static/images/icon-middle-box.png
  89. BIN
      static/images/icon-scan-code-bg.png
  90. BIN
      static/images/icon-selected.png
  91. BIN
      static/images/icon-sn.png
  92. BIN
      static/images/icon-storage-bg.png
  93. BIN
      static/images/icon-storage-process.png
  94. BIN
      static/images/icon-storage.png
  95. BIN
      static/images/icon-sub-box-popup.png
  96. BIN
      static/images/icon-sub-box-selected.png
  97. BIN
      static/images/icon-sub-box.png
  98. BIN
      static/images/icon-success-fetch.png
  99. BIN
      static/images/icon-success.png
  100. BIN
      static/images/icon-take-out.png

+ 17 - 0
App.vue

@@ -0,0 +1,17 @@
+<script>
+	export default {
+		onLaunch: function() {
+			console.log('App Launch')
+		},
+		onShow: function() {
+			console.log('App Show')
+		},
+		onHide: function() {
+			console.log('App Hide')
+		}
+	}
+</script>
+
+<style>
+	/*每个页面公共css */
+</style>

+ 309 - 0
components/mosowe-canvas-image/mosowe-canvas-image.vue

@@ -0,0 +1,309 @@
+<!-- mosowe-canvas-image -->
+<template>
+  <view class='mosowe-canvas-image'>
+		<view class="slot-view" @click="createCanvas">
+			<slot></slot>
+		</view>
+		<view class="canvas-wrap">
+			<canvas class="canvas-wrap" canvas-id="canvas" :style="'width: '+ width +'; height: '+ height +';'"></canvas>
+		</view>
+	</view>
+</template>
+
+<script>
+import QR from './wxqrcode.js';
+export default {
+  name: 'mosowe-canvas-image',
+  components: {},
+  props: {
+		showPreview: { // 生成图像后是否预览
+			type: Boolean,
+			default: false
+		},
+	  height: { // canvas高度
+			type: [String, Number],
+			default: 200
+		},
+	  width: { // canvas宽度
+			type: [String, Number],
+			default: 200
+		},
+		lists: {
+			type: Array,
+			default: () => {
+				return [// 图片,图片有先后,叠加画图
+						{
+							type: 'image',
+							content: 'https://www.zhonglixunqing.cn/images/uniapp/1.jpg', // 图片url
+							width: 200, // 图片绘制宽度
+							height: 200, // 图片绘制高度
+							x: 0, // 图片绘制X轴位置
+							y: 0, // 图片绘制Y轴位置
+							arc: false, // 圆形
+							arcX: 0, // 圆的x坐标
+							arcY: 0, // 圆的y坐标
+							arcR: 0 // 圆的半径
+						},
+						{
+							type: 'image',
+							content: 'https://www.zhonglixunqing.cn/images/uniapp/2.jpg', // 图片url
+							width: 100, // 图片绘制宽度
+							height: 100, // 图片绘制高度
+							x: 0, // 图片绘制X轴位置
+							y: 0, // 图片绘制Y轴位置
+							arc: false, // 圆形,如果需要圆形图片绘制,请放在列表最后,否则后续绘制将在此圆形内
+							arcX: 0, // 圆的x坐标
+							arcY: 0, // 圆的y坐标
+							arcR: 0 // 圆的半径
+						},
+						{
+							type: 'text',
+							content: '你好', // 文字
+							x: 10, // X轴
+							y: 50, // Y轴
+							color: '#ff0000', // 颜色
+							size: 20, // 字号
+							maxWidth: 100, // 最大宽度
+							align: 'left', // 对齐方式
+						},
+						{
+							type: 'image',
+							content: 'https://www.zhonglixunqing.cn/images/uniapp/3.jpg', // 图片url
+							width: 100, // 图片绘制宽度
+							height: 100, // 图片绘制高度
+							x: 150, // 图片绘制X轴位置
+							y: 150, // 图片绘制Y轴位置
+							arc: true, // 圆形,如果需要圆形图片绘制,请放在列表最后,否则后续绘制将在此圆形内
+							arcX: 200, // 圆的x坐标
+							arcY: 200, // 圆的y坐标
+							arcR: 50 // 圆的半径
+						},
+					];
+			}
+		}
+	},
+  data () {
+    return {
+			canvas: null,
+			listsIndex: 0,
+			listsLength: 0
+    };
+  },
+	watch: {},
+  // 组件实例化之前 
+  beforeCreate () {},
+  // 组件创建完成
+  created () {
+		this.canvas = uni.createCanvasContext('canvas', this);
+	},
+  // 组件挂载之前
+  beforeMount () {},
+  // 组件挂载之后
+  mounted () {},
+  // 组件数据更新时
+  beforeUpdate () {},
+  // 组价更新
+  updated () {},
+  // 组件销毁前
+  beforeDestroy () {},
+  // 组件销毁后
+  destroyed () {},
+  // 页面方法
+  methods: {
+		// 开始绘制
+		createCanvas () {
+			this.listsIndex = 0;
+			this.listsLength = this.lists.length - 1;
+			// #ifndef H5
+				uni.showLoading();
+			// #endif
+			// #ifdef H5
+				uni.showLoading({
+					mask: true
+				});			
+			// #endif
+
+			this.dataDrawCanvas();
+		},
+		// 数据绘制
+		dataDrawCanvas () {
+			let item = this.lists[this.listsIndex];
+			if (item.type === 'image') { // 图片
+				// #ifndef H5
+				// 非H5
+				this.downloadImageNotH5(item);
+				// #endif
+				// #ifdef H5
+				// H5
+				this.downloadImageH5(item);
+				// #endif
+			} else if (item.type === 'text') { // 文本
+				this.drawText(item);
+			} else if (item.type === 'rect') { // 矩形(线条)
+				this.drawRect(item);
+			} else if (item.type === 'arc') { // 圆形
+				this.drawArc(item);
+			} else if (item.type === 'qr') { // 二维码
+				this.drawQR(item);
+			}
+		},
+		// #ifndef H5
+		// 图片下载本地并绘制,非H5
+		downloadImageNotH5 (item) {
+			uni.downloadFile({
+				url: item.content,
+				header: {
+					'Access-Control-Allow-Origin': '*',
+				},
+				success: (res) => {
+					if (item.hasOwnProperty('arc') && item.arc) { // 绘制圆形
+						this.canvas.arc(item.arcX, item.arcY, item.arcR, 0, 2 * Math.PI);
+						this.canvas.clip();
+						this.canvas.closePath();
+					}
+					this.canvas.drawImage(
+						res.tempFilePath, 
+						item.x, 
+						item.y, 
+						item.hasOwnProperty('width') ? item.width : this.width, 
+						item.hasOwnProperty('height') ? item.height : this.height
+					);
+					this.checkDrawOver();
+				},
+				fail: (res) => {
+					console.log(res);
+					uni.hideLoading();
+				}
+			});			
+			
+		},
+		// #endif
+		// #ifdef H5
+		// 图片下载本地并绘制,H5
+		downloadImageH5 (item) {
+			let image = new Image();
+			image.setAttribute('crossOrigin', 'anonymous');
+			image.src = item.content;
+			image.onload = () => {
+				if (item.arc) { // 绘制圆形
+					this.canvas.arc(item.arcX, item.arcY, item.arcR, 0, 2 * Math.PI);
+					this.canvas.clip();
+					this.canvas.closePath();
+				}
+				this.canvas.drawImage(
+					item.content, 
+					item.x, 
+					item.y, 
+					item.hasOwnProperty('width') ? item.width : this.width, 
+					item.hasOwnProperty('height') ? item.height : this.height
+				);
+				this.checkDrawOver();
+			};
+		},
+		// #endif
+		// 文本绘制
+		drawText (item) {
+				this.canvas.setFillStyle(item.hasOwnProperty('color') ? item.color : '#000000');
+				this.canvas.setFontSize(item.hasOwnProperty('size')? item.size : 20);
+				this.canvas.setTextAlign(item.hasOwnProperty('align') ? item.align: 'left');
+				if (item.maxWidth) {
+					this.canvas.fillText(item.content, item.x, item.y, item.maxWidth);
+				} else {
+					this.canvas.fillText(item.content, item.x, item.y);
+				}
+				this.checkDrawOver();
+		},
+		
+		// 矩形(线条)绘制
+		drawRect (item) {
+			this.canvas.setFillStyle(item.hasOwnProperty('color') ? item.color : '#000000');
+			this.canvas.fillRect(item.x, item.y, item.width, item.height);
+			this.checkDrawOver();
+		},
+		
+		// 圆形绘制
+		drawArc (item) {
+			this.canvas.arc(item.arcX, item.arcY, item.arcR, 0, 2 * Math.PI);
+			this.canvas.setFillStyle(item.hasOwnProperty('color') ? item.color : '#000000');
+			this.canvas.fill();
+			this.canvas.closePath();
+			this.checkDrawOver();
+		},
+		
+		// 二维码绘制
+		drawQR (item) {
+				item['qr'] = QR.createQrCodeImg(item.content, {  
+					size: parseInt(300)  
+				});
+				this.canvas.drawImage(
+					item.qr, 
+					item.x, 
+					item.y, 
+					item.hasOwnProperty('width') ? item.width : this.width, 
+					item.hasOwnProperty('height') ? item.height : this.height
+				);
+				this.checkDrawOver();
+		},
+		
+		// 判断是否绘制完
+		 checkDrawOver () {
+			 if (this.listsIndex < this.listsLength) { // lists未画完
+			 	this.listsIndex++;
+			 	this.dataDrawCanvas();
+			 } else {
+			 	this.canvasImage();
+			 }
+		 },
+		
+		// 绘制到画布并生成图片
+		canvasImage () {
+			this.canvas.draw(false, setTimeout(() => {
+				setTimeout(() => {
+					// #ifndef MP-ALIPAY
+					uni.canvasToTempFilePath({
+						x: 0,
+						y: 0,
+						width: Number(this.width),
+						height: Number(this.height),
+						fileType: 'jpg',
+						canvasId: 'canvas',
+						success: (res) => {
+							this.$emit('canvasImage', res.tempFilePath);
+							if (this.showPreview) {
+								this.showPreviewFn(res.tempFilePath);
+							}
+						},
+						fail: (res) => {
+							console.log(res);
+						},
+						complete: () => {
+							uni.hideLoading();
+						}
+					}, this);
+					// #endif
+					// #ifdef MP-ALIPAY
+					// 支付宝的
+					// #endif
+				}, 500);
+			}));
+		},
+		// 预览图
+		showPreviewFn (img) {
+			uni.previewImage({
+				current: 0,
+				urls: [img]
+			});
+		},
+	}
+};
+</script>
+<style lang='scss' scoped>
+.mosowe-canvas-image{
+	overflow: hidden;
+	.canvas-wrap {
+		overflow: hidden;
+		height: 0;
+		width: 0;
+	}
+}
+</style>

+ 174 - 0
components/mosowe-canvas-image/readme.md

@@ -0,0 +1,174 @@
+## mosowe-canvas-image:一个可以制作多用途图片的插件(海报,二维码,分享图)
+
+#### 平台支持:
+
+| APP  |  H5  | 微信小程序 | 支付宝小程序 | 百度小程序 | 字节跳动小程序 | QQ小程序 |
+| :--: | :--: | :--------: | :----------: | :--------: | :------------: | :------: |
+|  √   |  √   |     √      |      ×       |    未测    |      未测      |   未测   |
+
+#### 插件功能
+
+1. 支持多图片绘制,多文本绘制,圆形图片绘制;
+2. 支持矩形(线条)绘制;
+3. 支持圆形绘制;
+4. 支持二维码生成,项目用不上可以去插件内去除,毕竟这个插件携带的比较大,单纯用来生成二维码图片也是阔以的;
+5. 支持绘图后预览。
+
+多用于海报图,分享图;
+
+注意H5跨域问题及小程序白名单配置;
+
+图片是网络图片:https://....(require及import引入不了3Kb以上的绝对路径图片,若有大神知道处理方法,望不吝赐教,谢谢!)
+
+#### 属性
+
+| 名称        | 类型             | 默认值 | 说明                                                     |
+| :---------- | :--------------- | :----- | :------------------------------------------------------- |
+| width       | Number \| String | 200    | canvas画布宽度,也是导出图片宽度,单位px,值中不要带单位 |
+| height      | Number \| String | 200    | canvas画布高度,也是导出图片高度,单位px,值中不要带单位 |
+| showPreview | Boolean          | false  | 绘制完成后是否打开预览                                   |
+| lists       | Array            | []     | 绘制的元素列表:图片,文字,矩形(线条),圆形,二维码   |
+
+#### lists\<item>属性
+
+注意:图文先后顺序,底层的图片靠前,最上层的在最后,圆形图片放在最后,因为一旦绘制圆形,后续的元素都只在该圆形内显示,而超过圆形范围的将看不见。
+
+| 名称     | 类型   | 必填 | 说明                                                         |
+| :------- | :----- | :--- | :----------------------------------------------------------- |
+| type     | String | 是   | 元素类型:`image`图片,`text`文本,`rect`矩形(线条),`arc`圆形,`qr`二维码 |
+| content  | String | 否   | image:图片路径(必填),text:文字(必填),qr:转二维码的数据(必填),rect及arc:非必填 |
+| x        | Number | 是   | X轴坐标,绘制圆形图片时:x = arcX - arcR                     |
+| y        | Number | 是   | Y轴坐标,绘制圆形图片时:y = arcY - arcR                     |
+| width    | Number | 否   | 图片、矩形(线条)、二维码宽度                               |
+| height   | Number | 否   | 图片、矩形(线条)、二维码高度                               |
+| arc      | Boolen | 否   | type=image时:是否绘制圆形图片                               |
+| arcX     | Number | 否   | type=image、arc时:绘制圆形时中心点X轴坐标                   |
+| arcY     | Number | 否   | type=image、arc时:绘制圆形时中心点Y轴坐标                   |
+| arcR     | Number | 否   | type=image、arc时:绘制圆形的半径                            |
+| color    | String | 否   | 绘制文本、矩形(线条)的颜色,默认:#000000                  |
+| size     | Number | 否   | 绘制文本的字号大小,默认:20                                 |
+| align    | String | 否   | 绘制文本的对齐方式,默认:left                               |
+| maxWidth | Number | 否   | 绘制文本的最大宽度,文字长度超过该值会被压缩                 |
+
+#### slots
+
+| 名称    | 说明                               |
+| :------ | :--------------------------------- |
+| default | 自定义插槽,点击此区会触发绘图事件 |
+
+#### 事件
+
+| 名称        | 回调参数 | 说明                                 |
+| ----------- | -------- | ------------------------------------ |
+| canvasImage | url      | 绘制成功后返回的本地地址,H5为base64 |
+
+
+
+#### 使用方式
+
+若`page.json`中配置了`"easycom": true`,则无需`script`引入就可以使用,没有则需要引入。
+
+1. 无slot:组件标签添加`ref`属性,采用父级调用子组件`createCanvas()`方法使用,见后文示例;
+2. 有slot:slot区点击就会执行
+
+#### 示例
+
+```javascript
+// js
+data () {
+    return {
+			canvasUrl: '',
+			lists: [
+						{
+							type: 'image',
+							content: 'https://www.zhonglixunqing.cn/images/uniapp/1.jpg', 
+							width: 200, 
+							height: 100, 
+							x: 50, 
+							y: 20, 
+						},
+						{
+							type: 'image',
+							content: 'https://www.zhonglixunqing.cn/images/uniapp/2.jpg', 
+							width: 80, 
+							height: 80, 
+							x: 20, 
+							y: 200, 
+							arc: false, 
+							arcX: 0, 
+							arcY: 0, 
+							arcR: 0 
+						},
+						{
+							type: 'text',
+							content: '扫一扫,获取更多信息', 
+							x: 120, 
+							y: 250, 
+							color: '#ff0000', 
+							size: 10, 
+							// maxWidth: 100, 
+							// align: 'left', 
+						},
+						{
+							type: 'rect',
+							width: 1,
+							height: 100,
+							x: 0,
+							y: 10,
+							color: '#ff0000',
+						},
+						{
+							type: 'image',
+							content: 'https://www.zhonglixunqing.cn/images/uniapp/3.jpg', 
+							width: 100, 
+							height: 100, 
+							x: 200, 
+							y: 200, 
+							arc: true, 
+							arcX: 250, 
+							arcY: 250, 
+							arcR: 50 
+						},
+					]
+    };
+  },
+  methods: {
+		beginCanvas () {
+			this.$refs.mosoweCanvasComponents.createCanvas();
+		},
+		_canvasImage (e) {
+			this.canvasUrl = e;
+		}
+	}
+```
+
+插件外独立按钮触发:
+
+```html
+		<button type="default" @click="beginCanvas">开始绘图</button>
+		<image :src="canvasUrl" mode="widthFix"></image>
+		<mosowe-canvas-image 
+			ref="mosoweCanvasComponents" 
+			@canvasImage="_canvasImage" 
+			:lists="lists" 
+			height="300" 
+			width="300"
+			showPreview />
+```
+
+slot插槽触发:
+
+```html
+		<mosowe-canvas-image 
+			:lists="lists" 
+			height="300" 
+			width="300"
+			showPreview >
+			<view class="in_btn">
+				slot按钮的
+			</view>
+			</mosowe-canvas-image>
+```
+
+#### 预览地址
+

Fichier diff supprimé car celui-ci est trop grand
+ 987 - 0
components/mosowe-canvas-image/wxqrcode.js


+ 111 - 0
components/navigationBarView.vue

@@ -0,0 +1,111 @@
+<template>
+	<view class="navigationBarView">
+		<view class="back-btn" @click="back">
+			<image class="arrow-bg" :src="require('../static/images/icon-back-bg.png')"></image>
+			<!-- <text>返回</text> -->
+		</view>
+		<view class="countdown" v-if="maxTimer">{{timer}}s</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		props: {
+			maxTimer: {
+				type: Number
+			}
+		},
+		data() {
+			return {
+				timer: 60,
+				navTimer: ''
+			};
+		},
+
+		created() {
+			console.log(1)
+			if (this.maxTimer) {
+				this.timer = this.maxTimer;
+				this.countdown()
+			}
+		},
+
+		beforeDestroy() {
+			clearInterval(this.navTimer)
+		},
+
+		methods: {
+			countdown() {
+				const $this = this;
+				clearInterval(this.navTimer);
+				this.navTimer = setInterval(function() {
+					// console.log($this.timer)
+					$this.timer = $this.timer - 1;
+					if ($this.timer == 0) {
+						clearInterval($this.navTimer);
+						uni.navigateBack();
+						return;
+					}
+				}, 1000)
+			},
+			back() {
+				uni.navigateBack();
+			},
+
+			clearTimer() {
+				clearInterval(this.navTimer);
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	.navigationBarView {
+		position: relative;
+		display: flex;
+		align-items: center;
+		justify-content: space-between;
+		width: 100vw;
+		padding-top: 5.4vw;
+		z-index: 1;
+
+		.back-btn {
+			position: relative;
+			display: flex;
+			align-items: center;
+			// justify-content: center;
+			width: 39.8vw;
+			height: 12.5vw;
+			border-radius: 0 12.5vw 12.5vw 0;
+			
+			
+			.arrow-bg {
+				position: absolute;
+				top: 0;
+				left: 0;
+				width: 39.8vw;
+				height: 12.5vw;
+			}
+
+			.arrow {
+				width: 2.5vw;
+				height: 4.2vw;
+				margin-right: 1.7vw;
+			}
+			
+			text {
+				position: relative;
+				margin-left: 10.4vw;
+				color: #FFFFFF;
+				font-size: 5vw;
+			}
+		}
+
+		.countdown {
+			color: #1994D7;
+			margin-right: 3.3vw;
+			font-size: 5vw;
+			font-weight: 600;
+		}
+	}
+</style>

+ 173 - 0
components/payCodePopup.vue

@@ -0,0 +1,173 @@
+<template>
+	<view>
+		<uni-popup ref="payPopup" type="center">
+			<view class="pay-popup">
+				<image class="delete-icon" src="../static/images/icon-delete.png" @click="closePayDetail"></image>
+				<view class="item">
+					<view class="label">支付宝</view>
+					<view class="qrcode">
+						<image :src="aliCodeImg"></image>
+						<!-- <mosowe-canvas-image ref="aliCanvas" @canvasImage="aliCanvasImage" :lists="aliLists" height="40vw" width="40vw" /> -->
+					</view>
+				</view>
+				<view class="item">
+					<view class="label">微信</view>
+					<view class="qrcode">
+						<image :src="wxCodeImg"></image>
+						<!-- <mosowe-canvas-image ref="wxCanvas" @canvasImage="wxCanvasImage" :lists="wxLists" height="40vw" width="40vw" /> -->
+					</view>
+				</view>
+			</view>
+		</uni-popup>
+	</view>
+</template>
+
+<script>
+	import uniPopup from '@/components/uni-popup/uni-popup.vue'
+	import uniPopupMessage from '@/components/uni-popup/uni-popup-message.vue'
+	import uniPopupDialog from '@/components/uni-popup/uni-popup-dialog.vue'
+
+
+	export default {
+		props: {
+			orderSn: {
+				type: String
+			},
+
+			type: {
+				type: String
+			}
+		},
+		data() {
+			return {
+				timer: '',
+				aliLists: [{
+					type: 'qr',
+					content: '',
+					x: 0,
+					y: 0,
+				}],
+				aliCodeImg: '',
+				wxLists: [{
+					type: 'qr',
+					content: '',
+					x: 0,
+					y: 0,
+				}],
+				wxCodeImg: ''
+			};
+		},
+
+		created() {
+
+		},
+
+		methods: {
+			init(res) {
+				const $this = this;
+				let info = uni.getSystemInfoSync()
+				this.aliCodeImg = res.aliCode;
+				this.wxCodeImg = res.wxCode;
+				// this.aliLists[0].content = res.aliCode;
+				// this.aliLists[0].width = info.screenWidth * 0.4
+				// this.aliLists[0].height = info.screenWidth * 0.4
+				// this.wxLists[0].content = res.wxCode;
+				// this.wxLists[0].width = info.screenWidth * 0.4
+				// this.wxLists[0].height = info.screenWidth * 0.4
+				this.$nextTick(function() {
+					console.log("SSS2-1");
+					$this.$refs.payPopup.open();
+					console.log("SSS2");
+					$this.$refs.payPopup.open();
+					// setTimeout(function() {
+					// 	console.log("SSS3");
+					// 	$this.$refs.aliCanvas.createCanvas();
+					// 	console.log("SSS4");
+					// 	$this.$refs.wxCanvas.createCanvas();
+					// }, 500)
+					clearInterval($this.timer)
+					$this.timer = setInterval(function() {
+						$this.getPayStatus();
+					}, 3000)
+				})
+
+			},
+
+			aliCanvasImage(e) {
+				this.aliCodeImg = e;
+			},
+
+			wxCanvasImage(e) {
+				this.wxCodeImg = e;
+			},
+
+			getPayStatus() {
+				this.$api.offorderGetStatus({
+					orderSn: this.orderSn
+				}).then(res => {
+					if (res.status == 1) {
+						clearInterval(this.timer);
+						console.log("SSS5");
+						this.$refs.payPopup.close();
+						this.$emit('success', this.type)
+					}
+				})
+			},
+
+			clearTimer() {
+				clearInterval(this.timer);
+			},
+
+			closePayDetail() {
+				clearInterval(this.timer)
+				this.$nextTick(function() {
+					this.$refs.payPopup.close();
+				})
+			},
+		}
+	}
+</script>
+
+<style lang="scss">
+	.pay-popup {
+		position: relative;
+		display: flex;
+		align-items: center;
+		justify-content: space-around;
+		width: 90vw;
+		min-height: 70vw;
+		margin: 0 5.8vw 1.9vw;
+		border-radius: .8vw;
+		background-color: #F8F8F8;
+
+		.delete-icon {
+			position: absolute;
+			top: 4vw;
+			right: 4vw;
+			width: 3.3vw;
+			height: 3.3vw;
+		}
+
+		.item {
+			display: flex;
+			align-items: center;
+			flex-direction: column;
+
+			.qrcode {
+				width: 40vw;
+				height: 40vw;
+
+				image {
+					width: 40vw;
+					height: 40vw;
+				}
+			}
+
+			.label {
+				margin-bottom: 2.9vw;
+				font-size: 2.9vw;
+				font-weight: 500;
+			}
+		}
+	}
+</style>

+ 22 - 0
components/uni-popup/message.js

@@ -0,0 +1,22 @@
+export default {
+	created() {
+		if (this.type === 'message') {
+			// 不显示遮罩
+			this.maskShow = false 
+			// 获取子组件对象
+			this.childrenMsg = null
+		}
+	},
+	methods: {
+		customOpen() {
+			if (this.childrenMsg) {
+				this.childrenMsg.open()
+			}
+		},
+		customClose() {
+			if (this.childrenMsg) {
+				this.childrenMsg.close()
+			}
+		}
+	}
+}

+ 25 - 0
components/uni-popup/popup.js

@@ -0,0 +1,25 @@
+import message from './message.js';
+// 定义 type 类型:弹出类型:top/bottom/center
+const config = {
+	// 顶部弹出
+	top:'top',
+	// 底部弹出
+	bottom:'bottom',
+	// 居中弹出
+	center:'center',
+	// 消息提示
+	message:'top',
+	// 对话框
+	dialog:'center',
+	// 分享
+	share:'bottom',
+}
+
+export default {
+	data(){
+		return {
+			config:config
+		}
+	},
+	mixins: [message],
+}

+ 243 - 0
components/uni-popup/uni-popup-dialog.vue

@@ -0,0 +1,243 @@
+<template>
+	<view class="uni-popup-dialog">
+		<view class="uni-dialog-title">
+			<text class="uni-dialog-title-text" :class="['uni-popup__'+dialogType]">{{title}}</text>
+		</view>
+		<view class="uni-dialog-content">
+			<text class="uni-dialog-content-text" v-if="mode === 'base'">{{content}}</text>
+			<input v-else class="uni-dialog-input" v-model="val" type="text" :placeholder="placeholder" :focus="focus" >
+		</view>
+		<view class="uni-dialog-button-group">
+			<view class="uni-dialog-button" @click="close">
+				<text class="uni-dialog-button-text">取消</text>
+			</view>
+			<view class="uni-dialog-button uni-border-left" @click="onOk">
+				<text class="uni-dialog-button-text uni-button-color">确定</text>
+			</view>
+		</view>
+
+	</view>
+</template>
+
+<script>
+	/**
+	 * PopUp 弹出层-对话框样式
+	 * @description 弹出层-对话框样式
+	 * @tutorial https://ext.dcloud.net.cn/plugin?id=329
+	 * @property {String} value input 模式下的默认值
+	 * @property {String} placeholder input 模式下输入提示
+	 * @property {String} type = [success|warning|info|error] 主题样式
+	 *  @value success 成功
+	 * 	@value warning 提示
+	 * 	@value info 消息
+	 * 	@value error 错误
+	 * @property {String} mode = [base|input] 模式、
+	 * 	@value base 基础对话框
+	 * 	@value input 可输入对话框
+	 * @property {String} content 对话框内容
+	 * @property {Boolean} beforeClose 是否拦截取消事件
+	 * @event {Function} confirm 点击确认按钮触发
+	 * @event {Function} close 点击取消按钮触发
+	 */
+
+	export default {
+		name: "uniPopupDialog",
+		props: {
+			value: {
+				type: [String, Number],
+				default: ''
+			},
+			placeholder: {
+				type: [String, Number],
+				default: '请输入内容'
+			},
+			/**
+			 * 对话框主题 success/warning/info/error	  默认 success
+			 */
+			type: {
+				type: String,
+				default: 'error'
+			},
+			/**
+			 * 对话框模式 base/input
+			 */
+			mode: {
+				type: String,
+				default: 'base'
+			},
+			/**
+			 * 对话框标题
+			 */
+			title: {
+				type: String,
+				default: '提示'
+			},
+			/**
+			 * 对话框内容
+			 */
+			content: {
+				type: String,
+				default: ''
+			},
+			/**
+			 * 拦截取消事件 ,如果拦截取消事件,必须监听close事件,执行 done()
+			 */
+			beforeClose: {
+				type: Boolean,
+				default: false
+			}
+		},
+		data() {
+			return {
+				dialogType: 'error',
+				focus: false,
+				val: ""
+			}
+		},
+		inject: ['popup'],
+		watch: {
+			type(val) {
+				this.dialogType = val
+			},
+			mode(val) {
+				if (val === 'input') {
+					this.dialogType = 'info'
+				}
+			},
+			value(val) {
+				this.val = val
+			}
+		},
+		created() {
+			// 对话框遮罩不可点击
+			this.popup.mkclick = false
+			if (this.mode === 'input') {
+				this.dialogType = 'info'
+				this.val = this.value
+			} else {
+				this.dialogType = this.type
+			}
+		},
+		mounted() {
+			this.focus = true
+		},
+		methods: {
+			/**
+			 * 点击确认按钮
+			 */
+			onOk() {
+				this.$emit('confirm', () => {
+					this.popup.close()
+					if (this.mode === 'input') this.val = this.value
+				}, this.mode === 'input' ? this.val : '')
+			},
+			/**
+			 * 点击取消按钮
+			 */
+			close() {
+				if (this.beforeClose) {
+					this.$emit('close', () => {
+						this.popup.close()
+					})
+					return
+				}
+				this.popup.close()
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.uni-popup-dialog {
+		width: 300px;
+		border-radius: 15px;
+		background-color: #fff;
+	}
+
+	.uni-dialog-title {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+		justify-content: center;
+		padding-top: 15px;
+		padding-bottom: 5px;
+	}
+
+	.uni-dialog-title-text {
+		font-size: 16px;
+		font-weight: 500;
+	}
+
+	.uni-dialog-content {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+		justify-content: center;
+		align-items: center;
+		padding: 5px 15px 15px 15px;
+	}
+
+	.uni-dialog-content-text {
+		font-size: 14px;
+		color: #6e6e6e;
+	}
+
+	.uni-dialog-button-group {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+		border-top-color: #f5f5f5;
+		border-top-style: solid;
+		border-top-width: 1px;
+	}
+
+	.uni-dialog-button {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+
+		flex: 1;
+		flex-direction: row;
+		justify-content: center;
+		align-items: center;
+		height: 45px;
+	}
+
+	.uni-border-left {
+		border-left-color: #f0f0f0;
+		border-left-style: solid;
+		border-left-width: 1px;
+	}
+
+	.uni-dialog-button-text {
+		font-size: 14px;
+	}
+
+	.uni-button-color {
+		color: $uni-color-primary;
+	}
+
+	.uni-dialog-input {
+		flex: 1;
+		font-size: 14px;
+	}
+
+	.uni-popup__success {
+		color: $uni-color-success;
+	}
+
+	.uni-popup__warn {
+		color: $uni-color-warning;
+	}
+
+	.uni-popup__error {
+		color: $uni-color-error;
+	}
+
+	.uni-popup__info {
+		color: #909399;
+	}
+</style>

+ 116 - 0
components/uni-popup/uni-popup-message.vue

@@ -0,0 +1,116 @@
+<template>
+	<view class="uni-popup-message" :class="'uni-popup__'+[type]">
+		<text class="uni-popup-message-text" :class="'uni-popup__'+[type]+'-text'">{{message}}</text>
+	</view>
+</template>
+
+<script>
+	
+	/**
+	 * PopUp 弹出层-消息提示
+	 * @description 弹出层-消息提示
+	 * @tutorial https://ext.dcloud.net.cn/plugin?id=329
+	 * @property {String} type = [success|warning|info|error] 主题样式
+	 *  @value success 成功
+	 * 	@value warning 提示
+	 * 	@value info 消息
+	 * 	@value error 错误
+	 * @property {String} message 消息提示文字
+	 * @property {String} duration 显示时间,设置为 0 则不会自动关闭
+	 */
+	
+	export default {
+		name: 'UniPopupMessage',
+		props: {
+			/**
+			 * 主题 success/warning/info/error	  默认 success
+			 */
+			type: {
+				type: String,
+				default: 'success'
+			},
+			/**
+			 * 消息文字
+			 */
+			message: {
+				type: String,
+				default: ''
+			},
+			/**
+			 * 显示时间,设置为 0 则不会自动关闭
+			 */
+			duration: {
+				type: Number,
+				default: 3000
+			}
+		},
+		inject: ['popup'],
+		data() {
+			return {}
+		},
+		created() {
+			this.popup.childrenMsg = this
+		},
+		methods: {
+			open() {
+				if (this.duration === 0) return
+				clearTimeout(this.popuptimer)
+				this.popuptimer = setTimeout(() => {
+					this.popup.close()
+				}, this.duration)
+			},
+			close() {
+				clearTimeout(this.popuptimer)
+			}
+		}
+	}
+</script>
+<style lang="scss" scoped>
+	.uni-popup-message {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+		background-color: #e1f3d8;
+		padding: 10px 15px;
+		border-color: #eee;
+		border-style: solid;
+		border-width: 1px;
+	}
+	.uni-popup-message-text {
+		font-size: 14px;
+		padding: 0;
+	}
+
+	.uni-popup__success {
+		background-color: #e1f3d8;
+	}
+
+	.uni-popup__success-text {
+		color: #67C23A;
+	}
+
+	.uni-popup__warn {
+		background-color: #faecd8;
+	}
+
+	.uni-popup__warn-text {
+		color: #E6A23C;
+	}
+
+	.uni-popup__error {
+		background-color: #fde2e2;
+	}
+
+	.uni-popup__error-text {
+		color: #F56C6C;
+	}
+
+	.uni-popup__info {
+		background-color: #F2F6FC;
+	}
+
+	.uni-popup__info-text {
+		color: #909399;
+	}
+</style>

+ 165 - 0
components/uni-popup/uni-popup-share.vue

@@ -0,0 +1,165 @@
+<template>
+	<view class="uni-popup-share">
+		<view class="uni-share-title"><text class="uni-share-title-text">{{title}}</text></view>
+		<view class="uni-share-content">
+			<view class="uni-share-content-box">
+				<view class="uni-share-content-item" v-for="(item,index) in bottomData" :key="index" @click.stop="select(item,index)">
+					<image class="uni-share-image" :src="item.icon" mode="aspectFill"></image>
+					<text class="uni-share-text">{{item.text}}</text>
+				</view>
+
+			</view>
+		</view>
+		<view class="uni-share-button-box">
+			<button class="uni-share-button" @click="close">取消</button>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		name: 'UniPopupShare',
+		props: {
+			title: {
+				type: String,
+				default: '分享到'
+			}
+		},
+		inject: ['popup'],
+		data() {
+			return {
+				bottomData: [{
+						text: '微信',
+						icon: 'https://img-cdn-qiniu.dcloud.net.cn/uni-ui/grid-2.png',
+						name: 'wx'
+					},
+					{
+						text: '支付宝',
+						icon: 'https://img-cdn-qiniu.dcloud.net.cn/uni-ui/grid-8.png',
+						name: 'wx'
+					},
+					{
+						text: 'QQ',
+						icon: 'https://img-cdn-qiniu.dcloud.net.cn/uni-ui/gird-3.png',
+						name: 'qq'
+					},
+					{
+						text: '新浪',
+						icon: 'https://img-cdn-qiniu.dcloud.net.cn/uni-ui/grid-1.png',
+						name: 'sina'
+					},
+					{
+						text: '百度',
+						icon: 'https://img-cdn-qiniu.dcloud.net.cn/uni-ui/grid-7.png',
+						name: 'copy'
+					},
+					{
+						text: '其他',
+						icon: 'https://img-cdn-qiniu.dcloud.net.cn/uni-ui/grid-5.png',
+						name: 'more'
+					}
+				]
+			}
+		},
+		created() {},
+		methods: {
+			/**
+			 * 选择内容
+			 */
+			select(item, index) {
+				this.$emit('select', {
+					item,
+					index
+				}, () => {
+					this.popup.close()
+				})
+			},
+			/**
+			 * 关闭窗口
+			 */
+			close() {
+				this.popup.close()
+			}
+		}
+	}
+</script>
+<style lang="scss" scoped>
+	.uni-popup-share {
+		background-color: #fff;
+	}
+	.uni-share-title {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+		align-items: center;
+		justify-content: center;
+		height: 40px;
+	}
+	.uni-share-title-text {
+		font-size: 14px;
+		color: #666;
+	}
+	.uni-share-content {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+		justify-content: center;
+		padding-top: 10px;
+	}
+	
+	.uni-share-content-box {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+		flex-wrap: wrap;
+		width: 360px;
+	}
+	
+	.uni-share-content-item {
+		width: 90px;
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: column;
+		justify-content: center;
+		padding: 10px 0;
+		align-items: center;
+	}
+	
+	.uni-share-content-item:active {
+		background-color: #f5f5f5;
+	}
+	
+	.uni-share-image {
+		width: 30px;
+		height: 30px;
+	}
+	
+	.uni-share-text {
+		margin-top: 10px;
+		font-size: 14px;
+		color: #3B4144;
+	}
+	
+	.uni-share-button-box {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+		padding: 10px 15px;
+	}
+	
+	.uni-share-button {
+		flex: 1;
+		border-radius: 50px;
+		color: #666;
+		font-size: 16px;
+	}
+	
+	.uni-share-button::after {
+		border-radius: 50px;
+	}
+</style>

+ 294 - 0
components/uni-popup/uni-popup.vue

@@ -0,0 +1,294 @@
+<template>
+	<view v-if="showPopup" class="uni-popup" :class="[popupstyle]" @touchmove.stop.prevent="clear">
+		<uni-transition v-if="maskShow" :mode-class="['fade']" :styles="maskClass" :duration="duration" :show="showTrans"
+		 @click="onTap" />
+		<uni-transition :mode-class="ani" :styles="transClass" :duration="duration" :show="showTrans" @click="onTap">
+			<view class="uni-popup__wrapper-box" @click.stop="clear">
+				<slot />
+			</view>
+		</uni-transition>
+	</view>
+</template>
+
+<script>
+	import uniTransition from '../uni-transition/uni-transition.vue'
+	import popup from './popup.js'
+	/**
+	 * PopUp 弹出层
+	 * @description 弹出层组件,为了解决遮罩弹层的问题
+	 * @tutorial https://ext.dcloud.net.cn/plugin?id=329
+	 * @property {String} type = [top|center|bottom] 弹出方式
+	 * 	@value top 顶部弹出
+	 * 	@value center 中间弹出
+	 * 	@value bottom 底部弹出
+	 * 	@value message 消息提示
+	 * 	@value dialog 对话框
+	 * 	@value share 底部分享示例
+	 * @property {Boolean} animation = [ture|false] 是否开启动画
+	 * @property {Boolean} maskClick = [ture|false] 蒙版点击是否关闭弹窗
+	 * @event {Function} change 打开关闭弹窗触发,e={show: false}
+	 */
+
+	export default {
+		name: 'UniPopup',
+		components: {
+			uniTransition
+		},
+		props: {
+			// 开启动画
+			animation: {
+				type: Boolean,
+				default: true
+			},
+			// 弹出层类型,可选值,top: 顶部弹出层;bottom:底部弹出层;center:全屏弹出层
+			// message: 消息提示 ; dialog : 对话框
+			type: {
+				type: String,
+				default: 'center'
+			},
+			// maskClick
+			maskClick: {
+				type: Boolean,
+				default: true
+			}
+		},
+		provide() {
+			return {
+				popup: this
+			}
+		},
+		mixins: [popup],
+		watch: {
+			/**
+			 * 监听type类型
+			 */
+			type: {
+				handler: function(newVal) {
+					this[this.config[newVal]]()
+				},
+				immediate: true
+			},
+			/**
+			 * 监听遮罩是否可点击
+			 * @param {Object} val
+			 */
+			maskClick(val) {
+				this.mkclick = val
+			}
+		},
+		data() {
+			return {
+				duration: 300,
+				ani: [],
+				showPopup: false,
+				showTrans: false,
+				maskClass: {
+					'position': 'fixed',
+					'bottom': 0,
+					'top': 0,
+					'left': 0,
+					'right': 0,
+					'backgroundColor': 'rgba(0, 0, 0, 0.4)'
+				},
+				transClass: {
+					'position': 'fixed',
+					'left': 0,
+					'right': 0,
+				},
+				maskShow: true,
+				mkclick: true,
+				popupstyle: 'top'
+			}
+		},
+		created() {
+			this.mkclick = this.maskClick
+			if (this.animation) {
+				this.duration = 300
+			} else {
+				this.duration = 0
+			}
+		},
+		methods: {
+			clear(e) {
+				// TODO nvue 取消冒泡
+				e.stopPropagation()
+			},
+			open() {
+				this.showPopup = true
+				this.$nextTick(() => {
+					new Promise(resolve => {
+						clearTimeout(this.timer)
+						this.timer = setTimeout(() => {
+							this.showTrans = true
+							// fixed by mehaotian 兼容 app 端
+							this.$nextTick(() => {
+								resolve();
+							})
+						}, 50);
+					}).then(res => {
+						// 自定义打开事件
+						clearTimeout(this.msgtimer)
+						this.msgtimer = setTimeout(() => {
+							this.customOpen && this.customOpen()
+						}, 100)
+						this.$emit('change', {
+							show: true,
+							type: this.type
+						})
+					})
+				})
+			},
+			close(type) {
+				this.showTrans = false
+				this.$nextTick(() => {
+					this.$emit('change', {
+						show: false,
+						type: this.type
+					})
+					clearTimeout(this.timer)
+					// 自定义关闭事件
+					this.customOpen && this.customClose()
+					this.timer = setTimeout(() => {
+						this.showPopup = false
+					}, 300)
+				})
+			},
+			onTap() {
+				if (!this.mkclick) return
+				this.close()
+			},
+			/**
+			 * 顶部弹出样式处理
+			 */
+			top() {
+				this.popupstyle = 'top'
+				this.ani = ['slide-top']
+				this.transClass = {
+					'position': 'fixed',
+					'left': 0,
+					'right': 0,
+				}
+			},
+			/**
+			 * 底部弹出样式处理
+			 */
+			bottom() {
+				this.popupstyle = 'bottom'
+				this.ani = ['slide-bottom']
+				this.transClass = {
+					'position': 'fixed',
+					'left': 0,
+					'right': 0,
+					'bottom': 0
+				}
+			},
+			/**
+			 * 中间弹出样式处理
+			 */
+			center() {
+				this.popupstyle = 'center'
+				this.ani = ['zoom-out', 'fade']
+				this.transClass = {
+					'position': 'fixed',
+					/* #ifndef APP-NVUE */
+					'display': 'flex',
+					'flexDirection': 'column',
+					/* #endif */
+					'bottom': 0,
+					'left': 0,
+					'right': 0,
+					'top': 0,
+					'justifyContent': 'center',
+					'alignItems': 'center'
+				}
+			}
+		}
+	}
+</script>
+<style lang="scss" scoped>
+	.uni-popup {
+		position: fixed;
+		/* #ifndef APP-NVUE */
+		z-index: 99;
+		/* #endif */
+	}
+
+	.uni-popup__mask {
+		position: absolute;
+		top: 0;
+		bottom: 0;
+		left: 0;
+		right: 0;
+		background-color: $uni-bg-color-mask;
+		opacity: 0;
+	}
+
+	.mask-ani {
+		transition-property: opacity;
+		transition-duration: 0.2s;
+	}
+
+	.uni-top-mask {
+		opacity: 1;
+	}
+
+	.uni-bottom-mask {
+		opacity: 1;
+	}
+
+	.uni-center-mask {
+		opacity: 1;
+	}
+
+	.uni-popup__wrapper {
+		/* #ifndef APP-NVUE */
+		display: block;
+		/* #endif */
+		position: absolute;
+	}
+
+	.top {
+		/* #ifdef H5 */
+		top: var(--window-top);
+		/* #endif */
+		/* #ifndef H5 */
+		top: 0;
+		/* #endif */
+	}
+
+	.bottom {
+		bottom: 0;
+	}
+
+	.uni-popup__wrapper-box {
+		/* #ifndef APP-NVUE */
+		display: block;
+		/* #endif */
+		position: relative;
+		/* iphonex 等安全区设置,底部安全区适配 */
+		/* #ifndef APP-NVUE */
+		padding-bottom: constant(safe-area-inset-bottom);
+		padding-bottom: env(safe-area-inset-bottom);
+		/* #endif */
+	}
+
+	.content-ani {
+		// transition: transform 0.3s;
+		transition-property: transform, opacity;
+		transition-duration: 0.2s;
+	}
+
+
+	.uni-top-content {
+		transform: translateY(0);
+	}
+
+	.uni-bottom-content {
+		transform: translateY(0);
+	}
+
+	.uni-center-content {
+		transform: scale(1);
+		opacity: 1;
+	}
+</style>

+ 279 - 0
components/uni-transition/uni-transition.vue

@@ -0,0 +1,279 @@
+<template>
+	<view v-if="isShow" ref="ani" class="uni-transition" :class="[ani.in]" :style="'transform:' +transform+';'+stylesObject"
+	 @click="change">
+		 <slot></slot>
+	</view>
+</template>
+
+<script>
+	// #ifdef APP-NVUE
+	const animation = uni.requireNativePlugin('animation');
+	// #endif
+	/**
+	 * Transition 过渡动画
+	 * @description 简单过渡动画组件
+	 * @tutorial https://ext.dcloud.net.cn/plugin?id=985
+	 * @property {Boolean} show = [false|true] 控制组件显示或隐藏
+     * @property {Array} modeClass = [fade|slide-top|slide-right|slide-bottom|slide-left|zoom-in|zoom-out] 过渡动画类型
+     *  @value fade 渐隐渐出过渡
+     *  @value slide-top 由上至下过渡
+     *  @value slide-right 由右至左过渡
+     *  @value slide-bottom 由下至上过渡
+     *  @value slide-left 由左至右过渡
+     *  @value zoom-in 由小到大过渡
+     *  @value zoom-out 由大到小过渡
+	 * @property {Number} duration 过渡动画持续时间
+	 * @property {Object} styles 组件样式,同 css 样式,注意带’-‘连接符的属性需要使用小驼峰写法如:`backgroundColor:red`
+	 */
+	export default {
+		name: 'uniTransition',
+		props: {
+			show: {
+				type: Boolean,
+				default: false
+			},
+			modeClass: {
+				type: Array,
+				default () {
+					return []
+				}
+			},
+			duration: {
+				type: Number,
+				default: 300
+			},
+			styles: {
+				type: Object,
+				default () {
+					return {}
+				}
+			}
+		},
+		data() {
+			return {
+				isShow: false,
+				transform: '',
+				ani: { in: '',
+					active: ''
+				}
+			};
+		},
+		watch: {
+			show: {
+				handler(newVal) {
+					if (newVal) {
+						this.open()
+					} else {
+						this.close()
+					}
+				},
+				immediate: true
+			}
+		},
+		computed: {
+			stylesObject() {
+				let styles = {
+					...this.styles,
+					'transition-duration': this.duration / 1000 + 's'
+				}
+				let transfrom = ''
+				for (let i in styles) {
+					let line = this.toLine(i)
+					transfrom += line + ':' + styles[i] + ';'
+				}
+				return transfrom
+			}
+		},
+		created() {
+			// this.timer = null
+			// this.nextTick = (time = 50) => new Promise(resolve => {
+			// 	clearTimeout(this.timer)
+			// 	this.timer = setTimeout(resolve, time)
+			// 	return this.timer
+			// });
+		},
+		methods: {
+			change() {
+				this.$emit('click', {
+					detail: this.isShow
+				})
+			},
+			open() {
+				clearTimeout(this.timer)
+				this.isShow = true
+				this.transform = ''
+				this.ani.in = ''
+				for (let i in this.getTranfrom(false)) {
+					if (i === 'opacity') {
+						this.ani.in = 'fade-in'
+					} else {
+						this.transform += `${this.getTranfrom(false)[i]} `
+					}
+				}
+				this.$nextTick(() => {
+					setTimeout(() => {
+						this._animation(true)
+					}, 50)
+				})
+
+			},
+			close(type) {
+				clearTimeout(this.timer)
+				this._animation(false)
+			},
+			_animation(type) {
+				let styles = this.getTranfrom(type)
+				// #ifdef APP-NVUE
+				if(!this.$refs['ani']) return
+				animation.transition(this.$refs['ani'].ref, {
+					styles,
+					duration: this.duration, //ms
+					timingFunction: 'ease',
+					needLayout: false,
+					delay: 0 //ms
+				}, () => {
+					if (!type) {
+						this.isShow = false
+					}
+					this.$emit('change', {
+						detail: this.isShow
+					})
+				})
+				// #endif
+				// #ifndef APP-NVUE
+				this.transform = ''
+				for (let i in styles) {
+					if (i === 'opacity') {
+						this.ani.in = `fade-${type?'out':'in'}`
+					} else {
+						this.transform += `${styles[i]} `
+					}
+				}
+				this.timer = setTimeout(() => {
+					if (!type) {
+						this.isShow = false
+					}
+					this.$emit('change', {
+						detail: this.isShow
+					})
+
+				}, this.duration)
+				// #endif
+
+			},
+			getTranfrom(type) {
+				let styles = {
+					transform: ''
+				}
+				this.modeClass.forEach((mode) => {
+					switch (mode) {
+						case 'fade':
+							styles.opacity = type ? 1 : 0
+							break;
+						case 'slide-top':
+							styles.transform += `translateY(${type?'0':'-100%'}) `
+							break;
+						case 'slide-right':
+							styles.transform += `translateX(${type?'0':'100%'}) `
+							break;
+						case 'slide-bottom':
+							styles.transform += `translateY(${type?'0':'100%'}) `
+							break;
+						case 'slide-left':
+							styles.transform += `translateX(${type?'0':'-100%'}) `
+							break;
+						case 'zoom-in':
+							styles.transform += `scale(${type?1:0.8}) `
+							break;
+						case 'zoom-out':
+							styles.transform += `scale(${type?1:1.2}) `
+							break;
+					}
+				})
+				return styles
+			},
+			_modeClassArr(type) {
+				let mode = this.modeClass
+				if (typeof(mode) !== "string") {
+					let modestr = ''
+					mode.forEach((item) => {
+						modestr += (item + '-' + type + ',')
+					})
+					return modestr.substr(0, modestr.length - 1)
+				} else {
+					return mode + '-' + type
+				}
+			},
+			// getEl(el) {
+			// 	console.log(el || el.ref || null);
+			// 	return el || el.ref || null
+			// },
+			toLine(name) {
+				return name.replace(/([A-Z])/g, "-$1").toLowerCase();
+			}
+		}
+	}
+</script>
+
+<style>
+	.uni-transition {
+		transition-timing-function: ease;
+		transition-duration: 0.3s;
+		transition-property: transform, opacity;
+	}
+
+	.fade-in {
+		opacity: 0;
+	}
+
+	.fade-active {
+		opacity: 1;
+	}
+
+	.slide-top-in {
+		/* transition-property: transform, opacity; */
+		transform: translateY(-100%);
+	}
+
+	.slide-top-active {
+		transform: translateY(0);
+		/* opacity: 1; */
+	}
+
+	.slide-right-in {
+		transform: translateX(100%);
+	}
+
+	.slide-right-active {
+		transform: translateX(0);
+	}
+
+	.slide-bottom-in {
+		transform: translateY(100%);
+	}
+
+	.slide-bottom-active {
+		transform: translateY(0);
+	}
+
+	.slide-left-in {
+		transform: translateX(-100%);
+	}
+
+	.slide-left-active {
+		transform: translateX(0);
+		opacity: 1;
+	}
+
+	.zoom-in-in {
+		transform: scale(0.8);
+	}
+
+	.zoom-out-active {
+		transform: scale(1);
+	}
+
+	.zoom-out-in {
+		transform: scale(1.2);
+	}
+</style>

+ 1382 - 0
js_sdk/Sansnn-uQRCode/uqrcode.js

@@ -0,0 +1,1382 @@
+//---------------------------------------------------------------------
+// github https://github.com/Sansnn/uQRCode
+//---------------------------------------------------------------------
+
+let uQRCode = {};
+
+(function() {
+	//---------------------------------------------------------------------
+	// QRCode for JavaScript
+	//
+	// Copyright (c) 2009 Kazuhiko Arase
+	//
+	// URL: http://www.d-project.com/
+	//
+	// Licensed under the MIT license:
+	//   http://www.opensource.org/licenses/mit-license.php
+	//
+	// The word "QR Code" is registered trademark of 
+	// DENSO WAVE INCORPORATED
+	//   http://www.denso-wave.com/qrcode/faqpatent-e.html
+	//
+	//---------------------------------------------------------------------
+
+	//---------------------------------------------------------------------
+	// QR8bitByte
+	//---------------------------------------------------------------------
+
+	function QR8bitByte(data) {
+		this.mode = QRMode.MODE_8BIT_BYTE;
+		this.data = data;
+	}
+
+	QR8bitByte.prototype = {
+
+		getLength: function(buffer) {
+			return this.data.length;
+		},
+
+		write: function(buffer) {
+			for (var i = 0; i < this.data.length; i++) {
+				// not JIS ...
+				buffer.put(this.data.charCodeAt(i), 8);
+			}
+		}
+	};
+
+	//---------------------------------------------------------------------
+	// QRCode
+	//---------------------------------------------------------------------
+
+	function QRCode(typeNumber, errorCorrectLevel) {
+		this.typeNumber = typeNumber;
+		this.errorCorrectLevel = errorCorrectLevel;
+		this.modules = null;
+		this.moduleCount = 0;
+		this.dataCache = null;
+		this.dataList = new Array();
+	}
+
+	QRCode.prototype = {
+
+		addData: function(data) {
+			var newData = new QR8bitByte(data);
+			this.dataList.push(newData);
+			this.dataCache = null;
+		},
+
+		isDark: function(row, col) {
+			if (row < 0 || this.moduleCount <= row || col < 0 || this.moduleCount <= col) {
+				throw new Error(row + "," + col);
+			}
+			return this.modules[row][col];
+		},
+
+		getModuleCount: function() {
+			return this.moduleCount;
+		},
+
+		make: function() {
+			// Calculate automatically typeNumber if provided is < 1
+			if (this.typeNumber < 1) {
+				var typeNumber = 1;
+				for (typeNumber = 1; typeNumber < 40; typeNumber++) {
+					var rsBlocks = QRRSBlock.getRSBlocks(typeNumber, this.errorCorrectLevel);
+
+					var buffer = new QRBitBuffer();
+					var totalDataCount = 0;
+					for (var i = 0; i < rsBlocks.length; i++) {
+						totalDataCount += rsBlocks[i].dataCount;
+					}
+
+					for (var i = 0; i < this.dataList.length; i++) {
+						var data = this.dataList[i];
+						buffer.put(data.mode, 4);
+						buffer.put(data.getLength(), QRUtil.getLengthInBits(data.mode, typeNumber));
+						data.write(buffer);
+					}
+					if (buffer.getLengthInBits() <= totalDataCount * 8)
+						break;
+				}
+				this.typeNumber = typeNumber;
+			}
+			this.makeImpl(false, this.getBestMaskPattern());
+		},
+
+		makeImpl: function(test, maskPattern) {
+
+			this.moduleCount = this.typeNumber * 4 + 17;
+			this.modules = new Array(this.moduleCount);
+
+			for (var row = 0; row < this.moduleCount; row++) {
+
+				this.modules[row] = new Array(this.moduleCount);
+
+				for (var col = 0; col < this.moduleCount; col++) {
+					this.modules[row][col] = null; //(col + row) % 3;
+				}
+			}
+
+			this.setupPositionProbePattern(0, 0);
+			this.setupPositionProbePattern(this.moduleCount - 7, 0);
+			this.setupPositionProbePattern(0, this.moduleCount - 7);
+			this.setupPositionAdjustPattern();
+			this.setupTimingPattern();
+			this.setupTypeInfo(test, maskPattern);
+
+			if (this.typeNumber >= 7) {
+				this.setupTypeNumber(test);
+			}
+
+			if (this.dataCache == null) {
+				this.dataCache = QRCode.createData(this.typeNumber, this.errorCorrectLevel, this.dataList);
+			}
+
+			this.mapData(this.dataCache, maskPattern);
+		},
+
+		setupPositionProbePattern: function(row, col) {
+
+			for (var r = -1; r <= 7; r++) {
+
+				if (row + r <= -1 || this.moduleCount <= row + r) continue;
+
+				for (var c = -1; c <= 7; c++) {
+
+					if (col + c <= -1 || this.moduleCount <= col + c) continue;
+
+					if ((0 <= r && r <= 6 && (c == 0 || c == 6)) ||
+						(0 <= c && c <= 6 && (r == 0 || r == 6)) ||
+						(2 <= r && r <= 4 && 2 <= c && c <= 4)) {
+						this.modules[row + r][col + c] = true;
+					} else {
+						this.modules[row + r][col + c] = false;
+					}
+				}
+			}
+		},
+
+		getBestMaskPattern: function() {
+
+			var minLostPoint = 0;
+			var pattern = 0;
+
+			for (var i = 0; i < 8; i++) {
+
+				this.makeImpl(true, i);
+
+				var lostPoint = QRUtil.getLostPoint(this);
+
+				if (i == 0 || minLostPoint > lostPoint) {
+					minLostPoint = lostPoint;
+					pattern = i;
+				}
+			}
+
+			return pattern;
+		},
+
+		createMovieClip: function(target_mc, instance_name, depth) {
+
+			var qr_mc = target_mc.createEmptyMovieClip(instance_name, depth);
+			var cs = 1;
+
+			this.make();
+
+			for (var row = 0; row < this.modules.length; row++) {
+
+				var y = row * cs;
+
+				for (var col = 0; col < this.modules[row].length; col++) {
+
+					var x = col * cs;
+					var dark = this.modules[row][col];
+
+					if (dark) {
+						qr_mc.beginFill(0, 100);
+						qr_mc.moveTo(x, y);
+						qr_mc.lineTo(x + cs, y);
+						qr_mc.lineTo(x + cs, y + cs);
+						qr_mc.lineTo(x, y + cs);
+						qr_mc.endFill();
+					}
+				}
+			}
+
+			return qr_mc;
+		},
+
+		setupTimingPattern: function() {
+
+			for (var r = 8; r < this.moduleCount - 8; r++) {
+				if (this.modules[r][6] != null) {
+					continue;
+				}
+				this.modules[r][6] = (r % 2 == 0);
+			}
+
+			for (var c = 8; c < this.moduleCount - 8; c++) {
+				if (this.modules[6][c] != null) {
+					continue;
+				}
+				this.modules[6][c] = (c % 2 == 0);
+			}
+		},
+
+		setupPositionAdjustPattern: function() {
+
+			var pos = QRUtil.getPatternPosition(this.typeNumber);
+
+			for (var i = 0; i < pos.length; i++) {
+
+				for (var j = 0; j < pos.length; j++) {
+
+					var row = pos[i];
+					var col = pos[j];
+
+					if (this.modules[row][col] != null) {
+						continue;
+					}
+
+					for (var r = -2; r <= 2; r++) {
+
+						for (var c = -2; c <= 2; c++) {
+
+							if (r == -2 || r == 2 || c == -2 || c == 2 ||
+								(r == 0 && c == 0)) {
+								this.modules[row + r][col + c] = true;
+							} else {
+								this.modules[row + r][col + c] = false;
+							}
+						}
+					}
+				}
+			}
+		},
+
+		setupTypeNumber: function(test) {
+
+			var bits = QRUtil.getBCHTypeNumber(this.typeNumber);
+
+			for (var i = 0; i < 18; i++) {
+				var mod = (!test && ((bits >> i) & 1) == 1);
+				this.modules[Math.floor(i / 3)][i % 3 + this.moduleCount - 8 - 3] = mod;
+			}
+
+			for (var i = 0; i < 18; i++) {
+				var mod = (!test && ((bits >> i) & 1) == 1);
+				this.modules[i % 3 + this.moduleCount - 8 - 3][Math.floor(i / 3)] = mod;
+			}
+		},
+
+		setupTypeInfo: function(test, maskPattern) {
+
+			var data = (this.errorCorrectLevel << 3) | maskPattern;
+			var bits = QRUtil.getBCHTypeInfo(data);
+
+			// vertical		
+			for (var i = 0; i < 15; i++) {
+
+				var mod = (!test && ((bits >> i) & 1) == 1);
+
+				if (i < 6) {
+					this.modules[i][8] = mod;
+				} else if (i < 8) {
+					this.modules[i + 1][8] = mod;
+				} else {
+					this.modules[this.moduleCount - 15 + i][8] = mod;
+				}
+			}
+
+			// horizontal
+			for (var i = 0; i < 15; i++) {
+
+				var mod = (!test && ((bits >> i) & 1) == 1);
+
+				if (i < 8) {
+					this.modules[8][this.moduleCount - i - 1] = mod;
+				} else if (i < 9) {
+					this.modules[8][15 - i - 1 + 1] = mod;
+				} else {
+					this.modules[8][15 - i - 1] = mod;
+				}
+			}
+
+			// fixed module
+			this.modules[this.moduleCount - 8][8] = (!test);
+
+		},
+
+		mapData: function(data, maskPattern) {
+
+			var inc = -1;
+			var row = this.moduleCount - 1;
+			var bitIndex = 7;
+			var byteIndex = 0;
+
+			for (var col = this.moduleCount - 1; col > 0; col -= 2) {
+
+				if (col == 6) col--;
+
+				while (true) {
+
+					for (var c = 0; c < 2; c++) {
+
+						if (this.modules[row][col - c] == null) {
+
+							var dark = false;
+
+							if (byteIndex < data.length) {
+								dark = (((data[byteIndex] >>> bitIndex) & 1) == 1);
+							}
+
+							var mask = QRUtil.getMask(maskPattern, row, col - c);
+
+							if (mask) {
+								dark = !dark;
+							}
+
+							this.modules[row][col - c] = dark;
+							bitIndex--;
+
+							if (bitIndex == -1) {
+								byteIndex++;
+								bitIndex = 7;
+							}
+						}
+					}
+
+					row += inc;
+
+					if (row < 0 || this.moduleCount <= row) {
+						row -= inc;
+						inc = -inc;
+						break;
+					}
+				}
+			}
+
+		}
+
+	};
+
+	QRCode.PAD0 = 0xEC;
+	QRCode.PAD1 = 0x11;
+
+	QRCode.createData = function(typeNumber, errorCorrectLevel, dataList) {
+
+		var rsBlocks = QRRSBlock.getRSBlocks(typeNumber, errorCorrectLevel);
+
+		var buffer = new QRBitBuffer();
+
+		for (var i = 0; i < dataList.length; i++) {
+			var data = dataList[i];
+			buffer.put(data.mode, 4);
+			buffer.put(data.getLength(), QRUtil.getLengthInBits(data.mode, typeNumber));
+			data.write(buffer);
+		}
+
+		// calc num max data.
+		var totalDataCount = 0;
+		for (var i = 0; i < rsBlocks.length; i++) {
+			totalDataCount += rsBlocks[i].dataCount;
+		}
+
+		if (buffer.getLengthInBits() > totalDataCount * 8) {
+			throw new Error("code length overflow. (" +
+				buffer.getLengthInBits() +
+				">" +
+				totalDataCount * 8 +
+				")");
+		}
+
+		// end code
+		if (buffer.getLengthInBits() + 4 <= totalDataCount * 8) {
+			buffer.put(0, 4);
+		}
+
+		// padding
+		while (buffer.getLengthInBits() % 8 != 0) {
+			buffer.putBit(false);
+		}
+
+		// padding
+		while (true) {
+
+			if (buffer.getLengthInBits() >= totalDataCount * 8) {
+				break;
+			}
+			buffer.put(QRCode.PAD0, 8);
+
+			if (buffer.getLengthInBits() >= totalDataCount * 8) {
+				break;
+			}
+			buffer.put(QRCode.PAD1, 8);
+		}
+
+		return QRCode.createBytes(buffer, rsBlocks);
+	}
+
+	QRCode.createBytes = function(buffer, rsBlocks) {
+
+		var offset = 0;
+
+		var maxDcCount = 0;
+		var maxEcCount = 0;
+
+		var dcdata = new Array(rsBlocks.length);
+		var ecdata = new Array(rsBlocks.length);
+
+		for (var r = 0; r < rsBlocks.length; r++) {
+
+			var dcCount = rsBlocks[r].dataCount;
+			var ecCount = rsBlocks[r].totalCount - dcCount;
+
+			maxDcCount = Math.max(maxDcCount, dcCount);
+			maxEcCount = Math.max(maxEcCount, ecCount);
+
+			dcdata[r] = new Array(dcCount);
+
+			for (var i = 0; i < dcdata[r].length; i++) {
+				dcdata[r][i] = 0xff & buffer.buffer[i + offset];
+			}
+			offset += dcCount;
+
+			var rsPoly = QRUtil.getErrorCorrectPolynomial(ecCount);
+			var rawPoly = new QRPolynomial(dcdata[r], rsPoly.getLength() - 1);
+
+			var modPoly = rawPoly.mod(rsPoly);
+			ecdata[r] = new Array(rsPoly.getLength() - 1);
+			for (var i = 0; i < ecdata[r].length; i++) {
+				var modIndex = i + modPoly.getLength() - ecdata[r].length;
+				ecdata[r][i] = (modIndex >= 0) ? modPoly.get(modIndex) : 0;
+			}
+
+		}
+
+		var totalCodeCount = 0;
+		for (var i = 0; i < rsBlocks.length; i++) {
+			totalCodeCount += rsBlocks[i].totalCount;
+		}
+
+		var data = new Array(totalCodeCount);
+		var index = 0;
+
+		for (var i = 0; i < maxDcCount; i++) {
+			for (var r = 0; r < rsBlocks.length; r++) {
+				if (i < dcdata[r].length) {
+					data[index++] = dcdata[r][i];
+				}
+			}
+		}
+
+		for (var i = 0; i < maxEcCount; i++) {
+			for (var r = 0; r < rsBlocks.length; r++) {
+				if (i < ecdata[r].length) {
+					data[index++] = ecdata[r][i];
+				}
+			}
+		}
+
+		return data;
+
+	}
+
+	//---------------------------------------------------------------------
+	// QRMode
+	//---------------------------------------------------------------------
+
+	var QRMode = {
+		MODE_NUMBER: 1 << 0,
+		MODE_ALPHA_NUM: 1 << 1,
+		MODE_8BIT_BYTE: 1 << 2,
+		MODE_KANJI: 1 << 3
+	};
+
+	//---------------------------------------------------------------------
+	// QRErrorCorrectLevel
+	//---------------------------------------------------------------------
+
+	var QRErrorCorrectLevel = {
+		L: 1,
+		M: 0,
+		Q: 3,
+		H: 2
+	};
+
+	//---------------------------------------------------------------------
+	// QRMaskPattern
+	//---------------------------------------------------------------------
+
+	var QRMaskPattern = {
+		PATTERN000: 0,
+		PATTERN001: 1,
+		PATTERN010: 2,
+		PATTERN011: 3,
+		PATTERN100: 4,
+		PATTERN101: 5,
+		PATTERN110: 6,
+		PATTERN111: 7
+	};
+
+	//---------------------------------------------------------------------
+	// QRUtil
+	//---------------------------------------------------------------------
+
+	var QRUtil = {
+
+		PATTERN_POSITION_TABLE: [
+			[],
+			[6, 18],
+			[6, 22],
+			[6, 26],
+			[6, 30],
+			[6, 34],
+			[6, 22, 38],
+			[6, 24, 42],
+			[6, 26, 46],
+			[6, 28, 50],
+			[6, 30, 54],
+			[6, 32, 58],
+			[6, 34, 62],
+			[6, 26, 46, 66],
+			[6, 26, 48, 70],
+			[6, 26, 50, 74],
+			[6, 30, 54, 78],
+			[6, 30, 56, 82],
+			[6, 30, 58, 86],
+			[6, 34, 62, 90],
+			[6, 28, 50, 72, 94],
+			[6, 26, 50, 74, 98],
+			[6, 30, 54, 78, 102],
+			[6, 28, 54, 80, 106],
+			[6, 32, 58, 84, 110],
+			[6, 30, 58, 86, 114],
+			[6, 34, 62, 90, 118],
+			[6, 26, 50, 74, 98, 122],
+			[6, 30, 54, 78, 102, 126],
+			[6, 26, 52, 78, 104, 130],
+			[6, 30, 56, 82, 108, 134],
+			[6, 34, 60, 86, 112, 138],
+			[6, 30, 58, 86, 114, 142],
+			[6, 34, 62, 90, 118, 146],
+			[6, 30, 54, 78, 102, 126, 150],
+			[6, 24, 50, 76, 102, 128, 154],
+			[6, 28, 54, 80, 106, 132, 158],
+			[6, 32, 58, 84, 110, 136, 162],
+			[6, 26, 54, 82, 110, 138, 166],
+			[6, 30, 58, 86, 114, 142, 170]
+		],
+
+		G15: (1 << 10) | (1 << 8) | (1 << 5) | (1 << 4) | (1 << 2) | (1 << 1) | (1 << 0),
+		G18: (1 << 12) | (1 << 11) | (1 << 10) | (1 << 9) | (1 << 8) | (1 << 5) | (1 << 2) | (1 << 0),
+		G15_MASK: (1 << 14) | (1 << 12) | (1 << 10) | (1 << 4) | (1 << 1),
+
+		getBCHTypeInfo: function(data) {
+			var d = data << 10;
+			while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15) >= 0) {
+				d ^= (QRUtil.G15 << (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15)));
+			}
+			return ((data << 10) | d) ^ QRUtil.G15_MASK;
+		},
+
+		getBCHTypeNumber: function(data) {
+			var d = data << 12;
+			while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18) >= 0) {
+				d ^= (QRUtil.G18 << (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18)));
+			}
+			return (data << 12) | d;
+		},
+
+		getBCHDigit: function(data) {
+
+			var digit = 0;
+
+			while (data != 0) {
+				digit++;
+				data >>>= 1;
+			}
+
+			return digit;
+		},
+
+		getPatternPosition: function(typeNumber) {
+			return QRUtil.PATTERN_POSITION_TABLE[typeNumber - 1];
+		},
+
+		getMask: function(maskPattern, i, j) {
+
+			switch (maskPattern) {
+
+				case QRMaskPattern.PATTERN000:
+					return (i + j) % 2 == 0;
+				case QRMaskPattern.PATTERN001:
+					return i % 2 == 0;
+				case QRMaskPattern.PATTERN010:
+					return j % 3 == 0;
+				case QRMaskPattern.PATTERN011:
+					return (i + j) % 3 == 0;
+				case QRMaskPattern.PATTERN100:
+					return (Math.floor(i / 2) + Math.floor(j / 3)) % 2 == 0;
+				case QRMaskPattern.PATTERN101:
+					return (i * j) % 2 + (i * j) % 3 == 0;
+				case QRMaskPattern.PATTERN110:
+					return ((i * j) % 2 + (i * j) % 3) % 2 == 0;
+				case QRMaskPattern.PATTERN111:
+					return ((i * j) % 3 + (i + j) % 2) % 2 == 0;
+
+				default:
+					throw new Error("bad maskPattern:" + maskPattern);
+			}
+		},
+
+		getErrorCorrectPolynomial: function(errorCorrectLength) {
+
+			var a = new QRPolynomial([1], 0);
+
+			for (var i = 0; i < errorCorrectLength; i++) {
+				a = a.multiply(new QRPolynomial([1, QRMath.gexp(i)], 0));
+			}
+
+			return a;
+		},
+
+		getLengthInBits: function(mode, type) {
+
+			if (1 <= type && type < 10) {
+
+				// 1 - 9
+
+				switch (mode) {
+					case QRMode.MODE_NUMBER:
+						return 10;
+					case QRMode.MODE_ALPHA_NUM:
+						return 9;
+					case QRMode.MODE_8BIT_BYTE:
+						return 8;
+					case QRMode.MODE_KANJI:
+						return 8;
+					default:
+						throw new Error("mode:" + mode);
+				}
+
+			} else if (type < 27) {
+
+				// 10 - 26
+
+				switch (mode) {
+					case QRMode.MODE_NUMBER:
+						return 12;
+					case QRMode.MODE_ALPHA_NUM:
+						return 11;
+					case QRMode.MODE_8BIT_BYTE:
+						return 16;
+					case QRMode.MODE_KANJI:
+						return 10;
+					default:
+						throw new Error("mode:" + mode);
+				}
+
+			} else if (type < 41) {
+
+				// 27 - 40
+
+				switch (mode) {
+					case QRMode.MODE_NUMBER:
+						return 14;
+					case QRMode.MODE_ALPHA_NUM:
+						return 13;
+					case QRMode.MODE_8BIT_BYTE:
+						return 16;
+					case QRMode.MODE_KANJI:
+						return 12;
+					default:
+						throw new Error("mode:" + mode);
+				}
+
+			} else {
+				throw new Error("type:" + type);
+			}
+		},
+
+		getLostPoint: function(qrCode) {
+
+			var moduleCount = qrCode.getModuleCount();
+
+			var lostPoint = 0;
+
+			// LEVEL1
+
+			for (var row = 0; row < moduleCount; row++) {
+
+				for (var col = 0; col < moduleCount; col++) {
+
+					var sameCount = 0;
+					var dark = qrCode.isDark(row, col);
+
+					for (var r = -1; r <= 1; r++) {
+
+						if (row + r < 0 || moduleCount <= row + r) {
+							continue;
+						}
+
+						for (var c = -1; c <= 1; c++) {
+
+							if (col + c < 0 || moduleCount <= col + c) {
+								continue;
+							}
+
+							if (r == 0 && c == 0) {
+								continue;
+							}
+
+							if (dark == qrCode.isDark(row + r, col + c)) {
+								sameCount++;
+							}
+						}
+					}
+
+					if (sameCount > 5) {
+						lostPoint += (3 + sameCount - 5);
+					}
+				}
+			}
+
+			// LEVEL2
+
+			for (var row = 0; row < moduleCount - 1; row++) {
+				for (var col = 0; col < moduleCount - 1; col++) {
+					var count = 0;
+					if (qrCode.isDark(row, col)) count++;
+					if (qrCode.isDark(row + 1, col)) count++;
+					if (qrCode.isDark(row, col + 1)) count++;
+					if (qrCode.isDark(row + 1, col + 1)) count++;
+					if (count == 0 || count == 4) {
+						lostPoint += 3;
+					}
+				}
+			}
+
+			// LEVEL3
+
+			for (var row = 0; row < moduleCount; row++) {
+				for (var col = 0; col < moduleCount - 6; col++) {
+					if (qrCode.isDark(row, col) &&
+						!qrCode.isDark(row, col + 1) &&
+						qrCode.isDark(row, col + 2) &&
+						qrCode.isDark(row, col + 3) &&
+						qrCode.isDark(row, col + 4) &&
+						!qrCode.isDark(row, col + 5) &&
+						qrCode.isDark(row, col + 6)) {
+						lostPoint += 40;
+					}
+				}
+			}
+
+			for (var col = 0; col < moduleCount; col++) {
+				for (var row = 0; row < moduleCount - 6; row++) {
+					if (qrCode.isDark(row, col) &&
+						!qrCode.isDark(row + 1, col) &&
+						qrCode.isDark(row + 2, col) &&
+						qrCode.isDark(row + 3, col) &&
+						qrCode.isDark(row + 4, col) &&
+						!qrCode.isDark(row + 5, col) &&
+						qrCode.isDark(row + 6, col)) {
+						lostPoint += 40;
+					}
+				}
+			}
+
+			// LEVEL4
+
+			var darkCount = 0;
+
+			for (var col = 0; col < moduleCount; col++) {
+				for (var row = 0; row < moduleCount; row++) {
+					if (qrCode.isDark(row, col)) {
+						darkCount++;
+					}
+				}
+			}
+
+			var ratio = Math.abs(100 * darkCount / moduleCount / moduleCount - 50) / 5;
+			lostPoint += ratio * 10;
+
+			return lostPoint;
+		}
+
+	};
+
+
+	//---------------------------------------------------------------------
+	// QRMath
+	//---------------------------------------------------------------------
+
+	var QRMath = {
+
+		glog: function(n) {
+
+			if (n < 1) {
+				throw new Error("glog(" + n + ")");
+			}
+
+			return QRMath.LOG_TABLE[n];
+		},
+
+		gexp: function(n) {
+
+			while (n < 0) {
+				n += 255;
+			}
+
+			while (n >= 256) {
+				n -= 255;
+			}
+
+			return QRMath.EXP_TABLE[n];
+		},
+
+		EXP_TABLE: new Array(256),
+
+		LOG_TABLE: new Array(256)
+
+	};
+
+	for (var i = 0; i < 8; i++) {
+		QRMath.EXP_TABLE[i] = 1 << i;
+	}
+	for (var i = 8; i < 256; i++) {
+		QRMath.EXP_TABLE[i] = QRMath.EXP_TABLE[i - 4] ^
+			QRMath.EXP_TABLE[i - 5] ^
+			QRMath.EXP_TABLE[i - 6] ^
+			QRMath.EXP_TABLE[i - 8];
+	}
+	for (var i = 0; i < 255; i++) {
+		QRMath.LOG_TABLE[QRMath.EXP_TABLE[i]] = i;
+	}
+
+	//---------------------------------------------------------------------
+	// QRPolynomial
+	//---------------------------------------------------------------------
+
+	function QRPolynomial(num, shift) {
+
+		if (num.length == undefined) {
+			throw new Error(num.length + "/" + shift);
+		}
+
+		var offset = 0;
+
+		while (offset < num.length && num[offset] == 0) {
+			offset++;
+		}
+
+		this.num = new Array(num.length - offset + shift);
+		for (var i = 0; i < num.length - offset; i++) {
+			this.num[i] = num[i + offset];
+		}
+	}
+
+	QRPolynomial.prototype = {
+
+		get: function(index) {
+			return this.num[index];
+		},
+
+		getLength: function() {
+			return this.num.length;
+		},
+
+		multiply: function(e) {
+
+			var num = new Array(this.getLength() + e.getLength() - 1);
+
+			for (var i = 0; i < this.getLength(); i++) {
+				for (var j = 0; j < e.getLength(); j++) {
+					num[i + j] ^= QRMath.gexp(QRMath.glog(this.get(i)) + QRMath.glog(e.get(j)));
+				}
+			}
+
+			return new QRPolynomial(num, 0);
+		},
+
+		mod: function(e) {
+
+			if (this.getLength() - e.getLength() < 0) {
+				return this;
+			}
+
+			var ratio = QRMath.glog(this.get(0)) - QRMath.glog(e.get(0));
+
+			var num = new Array(this.getLength());
+
+			for (var i = 0; i < this.getLength(); i++) {
+				num[i] = this.get(i);
+			}
+
+			for (var i = 0; i < e.getLength(); i++) {
+				num[i] ^= QRMath.gexp(QRMath.glog(e.get(i)) + ratio);
+			}
+
+			// recursive call
+			return new QRPolynomial(num, 0).mod(e);
+		}
+	};
+
+	//---------------------------------------------------------------------
+	// QRRSBlock
+	//---------------------------------------------------------------------
+
+	function QRRSBlock(totalCount, dataCount) {
+		this.totalCount = totalCount;
+		this.dataCount = dataCount;
+	}
+
+	QRRSBlock.RS_BLOCK_TABLE = [
+
+		// L
+		// M
+		// Q
+		// H
+
+		// 1
+		[1, 26, 19],
+		[1, 26, 16],
+		[1, 26, 13],
+		[1, 26, 9],
+
+		// 2
+		[1, 44, 34],
+		[1, 44, 28],
+		[1, 44, 22],
+		[1, 44, 16],
+
+		// 3
+		[1, 70, 55],
+		[1, 70, 44],
+		[2, 35, 17],
+		[2, 35, 13],
+
+		// 4		
+		[1, 100, 80],
+		[2, 50, 32],
+		[2, 50, 24],
+		[4, 25, 9],
+
+		// 5
+		[1, 134, 108],
+		[2, 67, 43],
+		[2, 33, 15, 2, 34, 16],
+		[2, 33, 11, 2, 34, 12],
+
+		// 6
+		[2, 86, 68],
+		[4, 43, 27],
+		[4, 43, 19],
+		[4, 43, 15],
+
+		// 7		
+		[2, 98, 78],
+		[4, 49, 31],
+		[2, 32, 14, 4, 33, 15],
+		[4, 39, 13, 1, 40, 14],
+
+		// 8
+		[2, 121, 97],
+		[2, 60, 38, 2, 61, 39],
+		[4, 40, 18, 2, 41, 19],
+		[4, 40, 14, 2, 41, 15],
+
+		// 9
+		[2, 146, 116],
+		[3, 58, 36, 2, 59, 37],
+		[4, 36, 16, 4, 37, 17],
+		[4, 36, 12, 4, 37, 13],
+
+		// 10		
+		[2, 86, 68, 2, 87, 69],
+		[4, 69, 43, 1, 70, 44],
+		[6, 43, 19, 2, 44, 20],
+		[6, 43, 15, 2, 44, 16],
+
+		// 11
+		[4, 101, 81],
+		[1, 80, 50, 4, 81, 51],
+		[4, 50, 22, 4, 51, 23],
+		[3, 36, 12, 8, 37, 13],
+
+		// 12
+		[2, 116, 92, 2, 117, 93],
+		[6, 58, 36, 2, 59, 37],
+		[4, 46, 20, 6, 47, 21],
+		[7, 42, 14, 4, 43, 15],
+
+		// 13
+		[4, 133, 107],
+		[8, 59, 37, 1, 60, 38],
+		[8, 44, 20, 4, 45, 21],
+		[12, 33, 11, 4, 34, 12],
+
+		// 14
+		[3, 145, 115, 1, 146, 116],
+		[4, 64, 40, 5, 65, 41],
+		[11, 36, 16, 5, 37, 17],
+		[11, 36, 12, 5, 37, 13],
+
+		// 15
+		[5, 109, 87, 1, 110, 88],
+		[5, 65, 41, 5, 66, 42],
+		[5, 54, 24, 7, 55, 25],
+		[11, 36, 12],
+
+		// 16
+		[5, 122, 98, 1, 123, 99],
+		[7, 73, 45, 3, 74, 46],
+		[15, 43, 19, 2, 44, 20],
+		[3, 45, 15, 13, 46, 16],
+
+		// 17
+		[1, 135, 107, 5, 136, 108],
+		[10, 74, 46, 1, 75, 47],
+		[1, 50, 22, 15, 51, 23],
+		[2, 42, 14, 17, 43, 15],
+
+		// 18
+		[5, 150, 120, 1, 151, 121],
+		[9, 69, 43, 4, 70, 44],
+		[17, 50, 22, 1, 51, 23],
+		[2, 42, 14, 19, 43, 15],
+
+		// 19
+		[3, 141, 113, 4, 142, 114],
+		[3, 70, 44, 11, 71, 45],
+		[17, 47, 21, 4, 48, 22],
+		[9, 39, 13, 16, 40, 14],
+
+		// 20
+		[3, 135, 107, 5, 136, 108],
+		[3, 67, 41, 13, 68, 42],
+		[15, 54, 24, 5, 55, 25],
+		[15, 43, 15, 10, 44, 16],
+
+		// 21
+		[4, 144, 116, 4, 145, 117],
+		[17, 68, 42],
+		[17, 50, 22, 6, 51, 23],
+		[19, 46, 16, 6, 47, 17],
+
+		// 22
+		[2, 139, 111, 7, 140, 112],
+		[17, 74, 46],
+		[7, 54, 24, 16, 55, 25],
+		[34, 37, 13],
+
+		// 23
+		[4, 151, 121, 5, 152, 122],
+		[4, 75, 47, 14, 76, 48],
+		[11, 54, 24, 14, 55, 25],
+		[16, 45, 15, 14, 46, 16],
+
+		// 24
+		[6, 147, 117, 4, 148, 118],
+		[6, 73, 45, 14, 74, 46],
+		[11, 54, 24, 16, 55, 25],
+		[30, 46, 16, 2, 47, 17],
+
+		// 25
+		[8, 132, 106, 4, 133, 107],
+		[8, 75, 47, 13, 76, 48],
+		[7, 54, 24, 22, 55, 25],
+		[22, 45, 15, 13, 46, 16],
+
+		// 26
+		[10, 142, 114, 2, 143, 115],
+		[19, 74, 46, 4, 75, 47],
+		[28, 50, 22, 6, 51, 23],
+		[33, 46, 16, 4, 47, 17],
+
+		// 27
+		[8, 152, 122, 4, 153, 123],
+		[22, 73, 45, 3, 74, 46],
+		[8, 53, 23, 26, 54, 24],
+		[12, 45, 15, 28, 46, 16],
+
+		// 28
+		[3, 147, 117, 10, 148, 118],
+		[3, 73, 45, 23, 74, 46],
+		[4, 54, 24, 31, 55, 25],
+		[11, 45, 15, 31, 46, 16],
+
+		// 29
+		[7, 146, 116, 7, 147, 117],
+		[21, 73, 45, 7, 74, 46],
+		[1, 53, 23, 37, 54, 24],
+		[19, 45, 15, 26, 46, 16],
+
+		// 30
+		[5, 145, 115, 10, 146, 116],
+		[19, 75, 47, 10, 76, 48],
+		[15, 54, 24, 25, 55, 25],
+		[23, 45, 15, 25, 46, 16],
+
+		// 31
+		[13, 145, 115, 3, 146, 116],
+		[2, 74, 46, 29, 75, 47],
+		[42, 54, 24, 1, 55, 25],
+		[23, 45, 15, 28, 46, 16],
+
+		// 32
+		[17, 145, 115],
+		[10, 74, 46, 23, 75, 47],
+		[10, 54, 24, 35, 55, 25],
+		[19, 45, 15, 35, 46, 16],
+
+		// 33
+		[17, 145, 115, 1, 146, 116],
+		[14, 74, 46, 21, 75, 47],
+		[29, 54, 24, 19, 55, 25],
+		[11, 45, 15, 46, 46, 16],
+
+		// 34
+		[13, 145, 115, 6, 146, 116],
+		[14, 74, 46, 23, 75, 47],
+		[44, 54, 24, 7, 55, 25],
+		[59, 46, 16, 1, 47, 17],
+
+		// 35
+		[12, 151, 121, 7, 152, 122],
+		[12, 75, 47, 26, 76, 48],
+		[39, 54, 24, 14, 55, 25],
+		[22, 45, 15, 41, 46, 16],
+
+		// 36
+		[6, 151, 121, 14, 152, 122],
+		[6, 75, 47, 34, 76, 48],
+		[46, 54, 24, 10, 55, 25],
+		[2, 45, 15, 64, 46, 16],
+
+		// 37
+		[17, 152, 122, 4, 153, 123],
+		[29, 74, 46, 14, 75, 47],
+		[49, 54, 24, 10, 55, 25],
+		[24, 45, 15, 46, 46, 16],
+
+		// 38
+		[4, 152, 122, 18, 153, 123],
+		[13, 74, 46, 32, 75, 47],
+		[48, 54, 24, 14, 55, 25],
+		[42, 45, 15, 32, 46, 16],
+
+		// 39
+		[20, 147, 117, 4, 148, 118],
+		[40, 75, 47, 7, 76, 48],
+		[43, 54, 24, 22, 55, 25],
+		[10, 45, 15, 67, 46, 16],
+
+		// 40
+		[19, 148, 118, 6, 149, 119],
+		[18, 75, 47, 31, 76, 48],
+		[34, 54, 24, 34, 55, 25],
+		[20, 45, 15, 61, 46, 16]
+	];
+
+	QRRSBlock.getRSBlocks = function(typeNumber, errorCorrectLevel) {
+
+		var rsBlock = QRRSBlock.getRsBlockTable(typeNumber, errorCorrectLevel);
+
+		if (rsBlock == undefined) {
+			throw new Error("bad rs block @ typeNumber:" + typeNumber + "/errorCorrectLevel:" + errorCorrectLevel);
+		}
+
+		var length = rsBlock.length / 3;
+
+		var list = new Array();
+
+		for (var i = 0; i < length; i++) {
+
+			var count = rsBlock[i * 3 + 0];
+			var totalCount = rsBlock[i * 3 + 1];
+			var dataCount = rsBlock[i * 3 + 2];
+
+			for (var j = 0; j < count; j++) {
+				list.push(new QRRSBlock(totalCount, dataCount));
+			}
+		}
+
+		return list;
+	}
+
+	QRRSBlock.getRsBlockTable = function(typeNumber, errorCorrectLevel) {
+
+		switch (errorCorrectLevel) {
+			case QRErrorCorrectLevel.L:
+				return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 0];
+			case QRErrorCorrectLevel.M:
+				return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 1];
+			case QRErrorCorrectLevel.Q:
+				return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 2];
+			case QRErrorCorrectLevel.H:
+				return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 3];
+			default:
+				return undefined;
+		}
+	}
+
+	//---------------------------------------------------------------------
+	// QRBitBuffer
+	//---------------------------------------------------------------------
+
+	function QRBitBuffer() {
+		this.buffer = new Array();
+		this.length = 0;
+	}
+
+	QRBitBuffer.prototype = {
+
+		get: function(index) {
+			var bufIndex = Math.floor(index / 8);
+			return ((this.buffer[bufIndex] >>> (7 - index % 8)) & 1) == 1;
+		},
+
+		put: function(num, length) {
+			for (var i = 0; i < length; i++) {
+				this.putBit(((num >>> (length - i - 1)) & 1) == 1);
+			}
+		},
+
+		getLengthInBits: function() {
+			return this.length;
+		},
+
+		putBit: function(bit) {
+
+			var bufIndex = Math.floor(this.length / 8);
+			if (this.buffer.length <= bufIndex) {
+				this.buffer.push(0);
+			}
+
+			if (bit) {
+				this.buffer[bufIndex] |= (0x80 >>> (this.length % 8));
+			}
+
+			this.length++;
+		}
+	};
+
+	//---------------------------------------------------------------------
+	// Support Chinese
+	//---------------------------------------------------------------------
+	function utf16To8(text) {
+		var result = '';
+		var c;
+		for (var i = 0; i < text.length; i++) {
+			c = text.charCodeAt(i);
+			if (c >= 0x0001 && c <= 0x007F) {
+				result += text.charAt(i);
+			} else if (c > 0x07FF) {
+				result += String.fromCharCode(0xE0 | c >> 12 & 0x0F);
+				result += String.fromCharCode(0x80 | c >> 6 & 0x3F);
+				result += String.fromCharCode(0x80 | c >> 0 & 0x3F);
+			} else {
+				result += String.fromCharCode(0xC0 | c >> 6 & 0x1F);
+				result += String.fromCharCode(0x80 | c >> 0 & 0x3F);
+			}
+		}
+		return result;
+	}
+
+	uQRCode = {
+		
+		errorCorrectLevel: QRErrorCorrectLevel,
+		
+		defaults: {
+			size: 354,
+			margin: 0,
+			backgroundColor: '#ffffff',
+			foregroundColor: '#000000',
+			fileType: 'png', // 'jpg', 'png'
+			errorCorrectLevel: QRErrorCorrectLevel.H,
+			typeNumber: -1
+		},
+
+		make: function(options) {
+			var defaultOptions = {
+				canvasId: options.canvasId,
+				componentInstance: options.componentInstance,
+				text: options.text,
+				size: this.defaults.size,
+				margin: this.defaults.margin,
+				backgroundColor: this.defaults.backgroundColor,
+				foregroundColor: this.defaults.foregroundColor,
+				fileType: this.defaults.fileType,
+				errorCorrectLevel: this.defaults.errorCorrectLevel,
+				typeNumber: this.defaults.typeNumber
+			};
+			if (options) {
+				for (var i in options) {
+					defaultOptions[i] = options[i];
+				}
+			}
+			options = defaultOptions;
+			if (!options.canvasId) {
+				console.error('uQRCode: Please set canvasId!');
+				return;
+			}
+
+			function createCanvas() {
+				var qrcode = new QRCode(options.typeNumber, options.errorCorrectLevel);
+				qrcode.addData(utf16To8(options.text));
+				qrcode.make();
+
+				var ctx = uni.createCanvasContext(options.canvasId, options.componentInstance);
+				ctx.setFillStyle(options.backgroundColor);
+				ctx.fillRect(0, 0, options.size, options.size);
+
+				var tileW = (options.size - options.margin * 2) / qrcode.getModuleCount();
+				var tileH = tileW;
+
+				for (var row = 0; row < qrcode.getModuleCount(); row++) {
+					for (var col = 0; col < qrcode.getModuleCount(); col++) {
+						var style = qrcode.isDark(row, col) ? options.foregroundColor : options.backgroundColor;
+						ctx.setFillStyle(style);
+						var x = Math.round(col * tileW) + options.margin;
+						var y = Math.round(row * tileH) + options.margin;
+						var w = Math.ceil((col + 1) * tileW) - Math.floor(col * tileW);
+						var h = Math.ceil((row + 1) * tileW) - Math.floor(row * tileW);
+						ctx.fillRect(x, y, w, h);
+					}
+				}
+
+				setTimeout(function() {
+					ctx.draw(false, (function() {
+						setTimeout(function() {
+							uni.canvasToTempFilePath({
+								canvasId: options.canvasId,
+								fileType: options.fileType,
+								width: options.size,
+								height: options.size,
+								destWidth: options.size,
+								destHeight: options.size,
+								success: function(res) {
+									options.success && options.success(res.tempFilePath);
+								},
+								fail: function(error) {
+									options.fail && options.fail(error);
+								},
+								complete: function(res) {
+									options.complete && options.complete(res);
+								}
+							}, options.componentInstance);
+						}, options.text.length + 100);
+					})());
+				}, 150);
+			}
+			
+			createCanvas();
+		}
+
+	}
+
+})()
+
+export default uQRCode

+ 21 - 0
main.js

@@ -0,0 +1,21 @@
+import Vue from 'vue'
+import App from './App'
+
+Vue.config.productionTip = false
+
+App.mpType = 'app'
+
+import api from './unit/api.js'
+Vue.prototype.$api = api
+
+import tools from './unit/tools.js'
+Vue.prototype.$tools = tools
+
+import config from './unit/config.js'
+Vue.prototype.$config = config
+
+
+const app = new Vue({
+    ...App
+})
+app.$mount()

+ 80 - 0
manifest.json

@@ -0,0 +1,80 @@
+{
+    "name" : "app",
+    "appid" : "__UNI__AAFAC79",
+    "description" : "",
+    "versionName" : "1.0.0",
+    "versionCode" : "100",
+    "transformPx" : false,
+    /* 5+App特有相关 */
+    "app-plus" : {
+        "usingComponents" : true,
+        "nvueCompiler" : "uni-app",
+        "compilerVersion" : 3,
+        "splashscreen" : {
+            "alwaysShowBeforeRender" : true,
+            "waiting" : true,
+            "autoclose" : true,
+            "delay" : 0
+        },
+        /* 模块配置 */
+        "modules" : {},
+        /* 应用发布信息 */
+        "distribute" : {
+            /* android打包配置 */
+            "android" : {
+                "permissions" : [
+                    "<uses-feature android:name=\"android.hardware.camera\"/>",
+                    "<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
+                    "<uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\"/>",
+                    "<uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\"/>",
+                    "<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
+                    "<uses-permission android:name=\"android.permission.ACCESS_SURFACE_FLINGER\"/>",
+                    "<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
+                    "<uses-permission android:name=\"android.permission.CALL_PHONE\"/>",
+                    "<uses-permission android:name=\"android.permission.CAMERA\"/>",
+                    "<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
+                    "<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
+                    "<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
+                    "<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
+                    "<uses-permission android:name=\"android.permission.MODIFY_AUDIO_SETTINGS\"/>",
+                    "<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
+                    "<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
+                    "<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
+                    "<uses-permission android:name=\"android.permission.RECORD_AUDIO\"/>",
+                    "<uses-permission android:name=\"android.permission.VIBRATE\"/>",
+                    "<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
+                    "<uses-permission android:name=\"android.permission.WRITE_CONTACTS\"/>",
+                    "<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
+                ]
+            },
+            /* ios打包配置 */
+            "ios" : {},
+            /* SDK配置 */
+            "sdkConfigs" : {
+                "ad" : {}
+            }
+        }
+    },
+    /* 快应用特有相关 */
+    "quickapp" : {},
+    /* 小程序特有相关 */
+    "mp-weixin" : {
+        "appid" : "",
+        "setting" : {
+            "urlCheck" : false
+        },
+        "usingComponents" : true
+    },
+    "mp-alipay" : {
+        "usingComponents" : true
+    },
+    "mp-baidu" : {
+        "usingComponents" : true
+    },
+    "mp-toutiao" : {
+        "usingComponents" : true
+    },
+    "uniStatistics" : {
+        "enable" : false
+    }
+}

+ 72 - 0
pages.json

@@ -0,0 +1,72 @@
+{
+	"pages": [ //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
+		{
+			"path": "pages/index/index",
+			"style": {
+				"navigationStyle": "custom"
+			}
+		}, {
+			"path": "pages/bagStorage/login",
+			"style": {
+				"navigationStyle": "custom"
+			}
+		}, {
+			"path": "pages/bagStorage/orders",
+			"style": {
+				"navigationStyle": "custom"
+			}
+		}, {
+			"path": "pages/bagStorage/success",
+			"style": {
+				"navigationStyle": "custom"
+			}
+		}, {
+			"path": "pages/fetchPacket/index",
+			"style": {
+				"navigationStyle": "custom"
+			}
+		}, {
+			"path": "pages/fetchPacket/success",
+			"style": {
+				"navigationStyle": "custom"
+			}
+		}, {
+			"path": "pages/order/details",
+			"style": {
+				"navigationStyle": "custom"
+			}
+		}, {
+			"path": "pages/order/list",
+			"style": {
+				"enablePullDownRefresh": true,
+				"navigationStyle": "custom"
+			}
+		}, {
+			"path": "pages/admin/login",
+			"style": {
+				"navigationStyle": "custom"
+			}
+		}, {
+			"path": "pages/admin/index",
+			"style": {
+				"navigationStyle": "custom"
+			}
+		}, {
+			"path": "pages/admin/port",
+			"style": {
+				"navigationStyle": "custom"
+			}
+		}, {
+			"path": "pages/admin/setting",
+			"style": {
+				"navigationStyle": "custom"
+			}
+		}
+	],
+	"globalStyle": {
+		"navigationBarTextStyle": "black",
+		"navigationBarTitleText": "uni-app",
+		"navigationBarBackgroundColor": "#F8F8F8",
+		"backgroundColor": "#F8F8F8"
+	}
+}

+ 375 - 0
pages/admin/index.vue

@@ -0,0 +1,375 @@
+<template>
+	<view class="adminIndex">
+		<navigation-bar-view ref="nav"></navigation-bar-view>
+
+		<view class="group">
+			<view class="label" @click="toSetting">
+				<view class="line"></view>
+				<text>当前设备</text>
+				<view class="more">
+					<text>设置</text>
+					<image class="arrow" src="../../static/images/icon-arrow-right-grey.png"></image>
+				</view>
+		<!-- 		<view class="more" style="color: #007AFF;" @click="uploadVersion" v-if="!version">
+					<text>有新版本</text>
+				</view> -->
+			</view>
+			<view class="value">
+				<text>{{body.stationName}}(</text>
+				<text v-if="body.status == 1">在线</text>
+				<text v-if="body.status == 2">下线</text>
+				<text>)</text>
+			</view>
+		</view>
+		<view class="group">
+			<view class="label" @click="toOrderList">
+				<view class="line"></view>
+				<text>订单统计</text>
+				<view class="more">
+					<text>查看</text>
+					<image class="arrow" src="../../static/images/icon-arrow-right-grey.png"></image>
+				</view>
+			</view>
+			<view class="value order">
+				<view class="item">
+					<view class="title">今日订单数</view>
+					<view class="amount">{{data.todayNum}}</view>
+				</view>
+				<view class="item">
+					<view class="title">今日订单金额</view>
+					<view class="amount">¥{{data.todayAmount}}</view>
+				</view>
+				<view class="item">
+					<view class="title">今日使用人数</view>
+					<view class="amount">{{data.personNum}}</view>
+				</view>
+			</view>
+		</view>
+		<view class="group">
+			<view class="label" @click="toPortList">
+				<view class="line"></view>
+				<text>设备统计</text>
+				<view class="more">
+					<text>查看</text>
+					<image class="arrow" src="../../static/images/icon-arrow-right-grey.png"></image>
+				</view>
+			</view>
+			<view class="value order">
+				<view class="item">
+					<view class="title">使用中</view>
+					<view class="amount">{{data.useCount}}</view>
+				</view>
+				<view class="item">
+					<view class="title">空闲中</view>
+					<view class="amount">{{data.freeCount}}</view>
+				</view>
+				<view class="item">
+					<view class="title">冻结中</view>
+					<view class="amount">{{data.frozenCount}}</view>
+				</view>
+				<view class="item">
+					<view class="title">禁用中</view>
+					<view class="amount">{{data.disableCount}}</view>
+				</view>
+			</view>
+		</view>
+		<view class="btns">
+			<view class="btn full" @click="knockOut">一键清箱</view>
+		</view>
+		<view class="btns">
+			<view class="btn" @click="openDoor">一键开门</view>
+			<view style="width: 4vw;"></view>
+			<view class="btn" @click="closeDoor">一键关门</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	import navigationBarView from '../../components/navigationBarView.vue';
+	export default {
+		components: {
+			navigationBarView
+		},
+		data() {
+			return {
+				body: {},
+				data: {},
+				version: '',
+			}
+		},
+		onLoad() {
+			this.getData();
+		},
+		
+		onShow() {
+			this.getVersion();
+		},
+
+		methods: {
+			getVersion() {
+				let sn = uni.getStorageSync('sn');
+				this.$api.getCurrentVersion({
+					deviceSn: sn
+				}).then(res => {
+					if (this.$config.version != res.version) {
+						this.version = res.url;
+					} else {
+						this.version = ''
+					}
+				})
+			},
+
+			uploadVersion() {
+				uni.showLoading({
+					title: '更新中……'
+				})
+				console.log('ssaaa', this.version);
+				const downloadTask = uni.downloadFile({ //执行下载
+					url: this.version, //下载地址
+					success: downloadResult => { //下载成功
+						uni.hideLoading();
+						if (downloadResult.statusCode == 200) {
+							uni.showModal({
+								title: '',
+								content: '更新成功,确定现在重启吗?',
+								confirmText: '重启',
+								confirmColor: '#EE8F57',
+								success: function(res) {
+									if (res.confirm == true) {
+										plus.runtime.install( //安装
+											downloadResult.tempFilePath, {
+												force: true
+											},
+											function(res) {
+												utils.showToast('更新成功,重启中');
+												plus.runtime.restart();
+											}
+										);
+									}
+								}
+							});
+						}
+					},
+					fail: err => {
+						console.log('下载错误', err);
+					}
+				});
+
+				downloadTask.onProgressUpdate((res) => {
+					console.log('下载进度' + res.progress);
+					console.log('已经下载的数据长度' + res.totalBytesWritten);
+					console.log('预期需要下载的数据总长度' + res.totalBytesExpectedToWrite);
+
+					// 测试条件,取消下载任务。
+					// if (res.progress == 100) {
+					// 	downloadTask.abort();
+					// }
+				});
+			},
+
+			getData() {
+				let sn = uni.getStorageSync('sn');
+				this.$api.managerStatistics({
+					deviceSn: sn
+				}).then(res => {
+					this.body = res.device;
+					res.todayAmount = res.todayAmount.toFixed(2)
+					this.data = res;
+				})
+			},
+
+			// 一键清箱
+			knockOut() {
+				const _ = this;
+				uni.showModal({
+					title: '提示',
+					content: '请确认是否一键清箱?',
+					success: r => {
+						if (r.confirm) {
+							let sn = uni.getStorageSync('sn');
+							_.$api.managerTranslateSys({
+								deviceSn: sn,
+								port: 0
+							}).then(res => {
+								uni.showToast({
+									title: '一键清箱成功'
+								})
+								_.getData()
+							})
+						}
+					}
+				})
+			},
+
+			// 一键开箱
+			openDoor() {
+				const _ = this;
+				uni.showModal({
+					title: '提示',
+					content: '请确认是否一键开箱?',
+					success: r => {
+						if (r.confirm) {
+							let sn = uni.getStorageSync('sn');
+							_.$api.managerOperationSys({
+								deviceSn: sn,
+								witch: 1,
+								port: 0
+							}).then(res => {
+								uni.showToast({
+									title: '一键开箱成功'
+								})
+								_.getData()
+							})
+						}
+					}
+				})
+			},
+
+			// 一键开箱
+			closeDoor() {
+				const _ = this;
+				uni.showModal({
+					title: '提示',
+					content: '请确认是否一键关箱?',
+					success: r => {
+						if (r.confirm) {
+							let sn = uni.getStorageSync('sn');
+							_.$api.managerOperationSys({
+								deviceSn: sn,
+								witch: 0,
+								port: 0
+							}).then(res => {
+								uni.showToast({
+									title: '一键关箱成功'
+								})
+								_.getData()
+							})
+						}
+					}
+				})
+			},
+
+			toOrderList() {
+				uni.navigateTo({
+					url: '/pages/order/list'
+				})
+			},
+
+			toPortList() {
+				uni.navigateTo({
+					url: '/pages/admin/port'
+				})
+			},
+			
+			toSetting() {
+				uni.navigateTo({
+					url: '/pages/admin/setting'
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	.adminIndex {
+		min-height: 100vh;
+		background-color: #f8f8f8;
+
+		.group {
+			border-radius: 2.7vw;
+			margin: 2.7vw 4vw 0;
+			background: #FFFFFF;
+			padding: 0 4.1vw 4.9vw;
+
+			.label {
+				display: flex;
+				align-items: center;
+				height: 13.2vw;
+				font-size: 4vw;
+				font-weight: bold;
+				border-bottom: 2rpx solid #F8F8F8;
+
+				.line {
+					width: 1.1vw;
+					height: 4vw;
+					border-radius: 1.1vw;
+					background-color: #FDD302;
+					margin-right: 2.1vw;
+				}
+
+				text {
+					flex: 1;
+				}
+
+				.more {
+					display: flex;
+					align-items: center;
+					font-weight: 300;
+					font-size: 3.7vw;
+					color: #333333;
+
+					.arrow {
+						width: 2vw;
+						height: 3.6vw;
+						margin-left: 2vw;
+					}
+				}
+			}
+
+			.value {
+				color: #222222;
+				font-size: 4.5vw;
+				margin-top: 4.9vw;
+				font-weight: 600;
+
+				&.order {
+					display: flex;
+					align-items: center;
+
+					.item {
+						flex: 1;
+						text-align: center;
+
+						.title {
+							margin-bottom: 3.2vw;
+							font-weight: 300;
+							color: #999999;
+							font-size: 3.2vw;
+							line-height: 3.2vw;
+						}
+
+						.amount {
+							font-family: DIN Alternate;
+							font-weight: bold;
+							color: #444444;
+							font-size: 4.8vw;
+							line-height: 4.8vw;
+						}
+					}
+				}
+			}
+		}
+
+		.btns {
+			display: flex;
+			margin: 5.3vw 4vw 0;
+
+			.btn {
+				flex: 1;
+				display: flex;
+				align-items: center;
+				justify-content: center;
+				font-weight: 500;
+				font-size: 4vw;
+				height: 11.5vw;
+				border-radius: 11.5vw;
+				background: linear-gradient(to right, #FEE704, #FDD001);
+
+				&.full {
+					background: linear-gradient(to right, #44F62C, #00CB75);
+					// color: #FFFFFF;
+				}
+			}
+		}
+	}
+</style>

+ 91 - 0
pages/admin/login.vue

@@ -0,0 +1,91 @@
+<template>
+	<view class="adminLogin">
+		<navigation-bar-view ref="nav"></navigation-bar-view>
+		<view class="body">
+			<view class="input-box">
+				<input :value="body.account" placeholder="请输入账号" placeholder-style="color: #B7B7B7" @input="changeAccount" />
+			</view>
+			<view class="input-box" style="margin-top: 1.7vw;">
+				<input placeholder="请输入密码" password placeholder-style="color: #B7B7B7" @input="changePassword" />
+			</view>
+			<view class="btn" @click="login">登录</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	import navigationBarView from '../../components/navigationBarView.vue';
+	export default {
+		components: {
+			navigationBarView
+		},
+
+		data() {
+			return {
+				body: {
+					account: '',
+					password: ''
+				}
+			}
+		},
+		
+		onLoad() {
+			this.body.account = uni.getStorageSync('account');
+		},
+
+		methods: {
+			changeAccount(e) {
+				console.log(e);
+				this.body.account = e.detail.value;
+			},
+
+			changePassword(e) {
+				this.body.password = e.detail.value;
+			},
+
+			login() {
+				this.body.deviceSn = uni.getStorageSync('sn');
+				this.$api.managerLogin(this.body).then(res => {
+					uni.setStorageSync('access_token', res.data.token);
+					uni.setStorageSync('account', this.body.account);
+					uni.redirectTo({
+						url: '/pages/admin/index'
+					})
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	.adminLogin {
+		width: 100vw;
+		height: 100vw;
+		background-color: #FFFFFF;
+
+		.body {
+			padding: 30.3vw 7.3vw 0;
+
+			.input-box {
+				padding: 4.3vw 0;
+				border-bottom: 2rpx solid #999999;
+
+				input {
+					font-size: 4.3vw;
+				}
+			}
+
+			.btn {
+				display: flex;
+				align-items: center;
+				justify-content: center;
+				height: 11.5vw;
+				border-radius: 11.5vw;
+				margin-top: 8.1vw;
+				font-weight: 500;
+				font-size: 4.3vw;
+				background: linear-gradient(to right, #FEE704, #FDD001);
+			}
+		}
+	}
+</style>

+ 308 - 0
pages/admin/port.vue

@@ -0,0 +1,308 @@
+<template>
+	<view class="portList">
+		<view class="nav">
+			<navigation-bar-view ref="nav"></navigation-bar-view>
+		</view>
+		<view class="header">
+			<picker mode="selector" :range="cabinetTypeList" range-key="label" :value="cabinetTypeIndex" @change="changeCabinetType">
+				<view class="title">
+					<text>{{cabinetTypeIndex ? cabinetTypeList[cabinetTypeIndex].label: '端口类型'}}</text>
+				</view>
+			</picker>
+			<picker mode="selector" :range="statusList" range-key="label" :value="statusIndex" @change="changeStatus">
+				<view class="title">
+					<text>{{statusIndex ? statusList[statusIndex].label: '端口状态'}}</text>
+				</view>
+			</picker>
+			<picker mode="selector" :range="useStatusList" range-key="label" :value="useStatusIndex" @change="changeUseStatus">
+				<view class="title">
+					<text>{{useStatusIndex ? useStatusList[useStatusIndex].label: '使用状态'}}</text>
+				</view>
+			</picker>
+		</view>
+		<view style="height: 21.8vw"></view>
+		<block v-for="(item, i) in list" :key="i">
+			<view class="cell">
+				<view class="top">
+					<view class="order-sn">端口号:{{item.portSn}}</view>
+					<view class="status">
+						<text v-if="item.useStatus == 0">空闲中</text>
+						<text v-if="item.useStatus == 1">使用中</text>
+					</view>
+				</view>
+				<view class="center">
+					<view class="message">柜子号:{{item.caseSn}}</view>
+					<view class="message">
+						<text>格口类型:</text>
+						<text v-if="item.cabinetType == 1">小格子</text>
+						<text v-if="item.cabinetType == 2">中格子</text>
+						<text v-if="item.cabinetType == 3">大格子</text>
+					</view>
+					<view class="message">
+						<text>柜子状态:{{item.payTime}}</text>
+						<text v-if="item.status == 0">禁用</text>
+						<text v-if="item.status == 1">启用</text>
+						<text v-if="item.status == 2">冻结</text>
+					</view>
+				</view>
+				<view class="bottom">
+					<view class="btn" @click="knockOut(item)">清箱</view>
+					<view class="btn" @click="handelDoor(item, 1)">开门</view>
+					<view class="btn" @click="handelDoor(item, 0)">关门</view>
+				</view>
+			</view>
+		</block>
+		<view style="height: 3.3vw;"></view>
+	</view>
+</template>
+
+<script>
+	import navigationBarView from '../../components/navigationBarView.vue';
+	export default {
+		components: {
+			navigationBarView
+		},
+		data() {
+			return {
+				list: [],
+				params: {
+					deviceSn: '',
+					cabinetType: '',
+					status: '',
+					useStatus: ''
+				},
+				cabinetTypeList: [{
+					label: '全部',
+					value: ''
+				}, {
+					label: '小格子',
+					value: 1
+				}, {
+					label: '中格子',
+					value: 2
+				}, {
+					label: '大格子',
+					value: 3
+				}],
+				cabinetTypeIndex: 0,
+				statusList: [{
+					label: '全部',
+					value: ''
+				}, {
+					label: '禁用',
+					value: 0
+				}, {
+					label: '启用',
+					value: 1
+				}, {
+					label: '冻结',
+					value: 2
+				}],
+				statusIndex: 0,
+				useStatusList: [{
+					label: '全部',
+					value: ''
+				}, {
+					label: '空闲中',
+					value: 0
+				}, {
+					label: '使用中',
+					value: 1
+				}],
+				useStatusIndex: 0
+			}
+		},
+		onLoad() {
+			this.params.deviceSn = uni.getStorageSync('sn');
+			this.getData()
+		},
+
+		methods: {
+			getData() {
+				uni.showLoading({
+					title: "加载中..."
+				})
+				this.$api.managerPortList(this.params).then(res => {
+					this.list = res.data;
+				})
+			},
+
+			changeCabinetType(e) {
+				this.cabinetTypeIndex = e.detail.value;
+				this.params.cabinetType = this.cabinetTypeList[e.detail.value].value;
+				this.getData();
+			},
+
+			changeStatus(e) {
+				this.statusIndex = e.detail.value;
+				this.params.status = this.statusList[e.detail.value].value;
+				this.getData();
+			},
+			changeUseStatus(e) {
+				this.useStatusIndex = e.detail.value;
+				this.params.useStatus = this.useStatusList[e.detail.value].value;
+				this.getData();
+			},
+
+			knockOut(e) {
+				const _ = this;
+				uni.showModal({
+					title: '提示',
+					content: '请确认是否对这个端口清箱?',
+					success: r => {
+						if (r.confirm) {
+							let sn = uni.getStorageSync('sn');
+							_.$api.managerTranslateSys({
+								deviceSn: sn,
+								port: e.portSn
+							}).then(res => {
+								uni.showToast({
+									title: '操作成功'
+								})
+								setTimeout(function() {
+									_.getData()
+								}, 3000)
+							})
+						}
+					}
+				})
+			},
+
+			handelDoor(e, witch) {
+				const _ = this;
+				uni.showModal({
+					title: '提示',
+					content: `请确认是否这个${witch ? '开启' : '关闭'}端口?`,
+					success: r => {
+						if (r.confirm) {
+							let sn = uni.getStorageSync('sn');
+							_.$api.managerOperationSys({
+								deviceSn: sn,
+								witch: witch,
+								port: e.portSn
+							}).then(res => {
+								uni.showToast({
+									title: '操作成功'
+								})
+								setTimeout(function() {
+									_.getData()
+								}, 3000)
+							})
+						}
+					}
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	.portList {
+		min-height: 100vh;
+		background-color: #eee;
+
+		.nav {
+			position: fixed;
+			top: 0;
+			left: 0;
+			background: #FFF;
+		}
+
+		.header {
+			position: fixed;
+			top: 11.3vw;
+			display: flex;
+			align-items: center;
+			justify-content: space-around;
+			width: 100vw;
+			height: 10.5vw;
+			background-color: #FFFFFF;
+
+			.title {
+				display: flex;
+				align-items: center;
+				font-size: 3.5vw;
+				color: #161920;
+			}
+		}
+
+		.cell {
+			padding: 0 3.3vw;
+			border-radius: 1.6vw;
+			background-color: #FFFFFF;
+			margin: 3.3vw 4vw 0;
+
+			.top {
+				display: flex;
+				align-items: center;
+				justify-content: space-between;
+				height: 10.7vw;
+				border-bottom: .3vw solid #eee;
+
+				.order-sn {
+					color: #999999;
+					font-size: 3.5vw;
+				}
+
+				.status {
+					display: flex;
+					align-items: center;
+					justify-content: center;
+					width: 16vw;
+					height: 5.6vw;
+					border-radius: 5.6vw;
+					background: linear-gradient(to right, #FEE704, #FDD001);
+					font-size: 3.2vw;
+				}
+			}
+
+			.center {
+				padding-top: 4.5vw;
+				padding-bottom: 4.5vw;
+
+				.take-code {
+					display: flex;
+					align-items: center;
+					margin-bottom: 4.4vw;
+					font-weight: bold;
+					line-height: 4vw;
+
+					.label {
+						font-size: 4vw;
+					}
+
+					.code {
+						color: #FFB706;
+						font-size: 4.8vw;
+					}
+				}
+
+				.message {
+					margin-bottom: 3.1vw;
+					color: #666666;
+					font-size: 3.5vw;
+					line-height: 3.5vw;
+				}
+			}
+
+			.bottom {
+				display: flex;
+				justify-content: flex-end;
+				padding-bottom: 3.2vw;
+
+				.btn {
+					display: flex;
+					align-items: center;
+					justify-content: center;
+					width: 22.7vw;
+					height: 8.3vw;
+					border-radius: 8.3vw;
+					border: .3vw solid #CCCCCC;
+					color: #222222;
+					font-size: 3.5vw;
+					margin-left: 2vw;
+				}
+			}
+		}
+	}
+</style>

+ 204 - 0
pages/admin/setting.vue

@@ -0,0 +1,204 @@
+<template>
+	<view class="adminSetting">
+		<navigation-bar-view ref="nav"></navigation-bar-view>
+		<view class="group">
+			<view class="label">
+				<text>当前版本</text>
+				<view class="more" style="color: #007AFF;" @click="uploadVersion" v-if="version">
+					<text>有新版本</text>
+				</view>
+				<view class="more" v-else>
+					<text>v{{$config.version}}</text>
+				</view>
+			</view>
+			<view class="label" @click="clearCache">
+				<text>清除缓存</text>
+				<view class="more">
+					<text>{{fileSizeString}}</text>
+					<image class="arrow" src="../../static/images/icon-arrow-right-grey.png"></image>
+
+				</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	import navigationBarView from '../../components/navigationBarView.vue';
+	export default {
+		components: {
+			navigationBarView
+		},
+		data() {
+			return {
+				body: {},
+				data: {},
+				version: '',
+				fileSizeString: '',
+			}
+		},
+		onShow() {
+			this.getVersion();
+		},
+
+		methods: {
+			getVersion() {
+				let sn = uni.getStorageSync('sn');
+				this.$api.getCurrentVersion({
+					deviceSn: sn
+				}).then(res => {
+					if (this.$config.version != res.version) {
+						this.version = res.url;
+					} else {
+						this.version = ''
+					}
+				})
+			},
+
+			formatSize() {
+				let that = this;
+				plus.cache.calculate(function(size) {
+					let sizeCache = parseInt(size);
+					if (sizeCache == 0) {
+						that.fileSizeString = "0B";
+					} else if (sizeCache < 1024) {
+						that.fileSizeString = sizeCache + "B";
+					} else if (sizeCache < 1048576) {
+						that.fileSizeString = (sizeCache / 1024).toFixed(2) + "KB";
+					} else if (sizeCache < 1073741824) {
+						that.fileSizeString = (sizeCache / 1048576).toFixed(2) + "MB";
+					} else {
+						that.fileSizeString = (sizeCache / 1073741824).toFixed(2) + "GB";
+					}
+				});
+			},
+
+			clearCache() {
+				let that = this;
+				let os = plus.os.name;
+				if (os == 'Android') {
+					let main = plus.android.runtimeMainActivity();
+					let sdRoot = main.getCacheDir();
+					let files = plus.android.invoke(sdRoot, "listFiles");
+					let len = files.length;
+					for (let i = 0; i < len; i++) {
+						let filePath = '' + files[i]; // 没有找到合适的方法获取路径,这样写可以转成文件路径  
+						plus.io.resolveLocalFileSystemURL(filePath, function(entry) {
+							if (entry.isDirectory) {
+								entry.removeRecursively(function(entry) { //递归删除其下的所有文件及子目录  
+									uni.showToast({
+										title: '缓存清理完成',
+										duration: 2000
+									});
+									that.formatSize(); // 重新计算缓存  
+								}, function(e) {
+									console.log(e.message)
+								});
+							} else {
+								entry.remove();
+							}
+						}, function(e) {
+							console.log('文件路径读取失败')
+						});
+					}
+				}
+			},
+
+			uploadVersion() {
+				uni.showLoading({
+					title: '更新中……'
+				})
+				console.log('ssaaa', this.version);
+				const downloadTask = uni.downloadFile({ //执行下载
+					url: this.version, //下载地址
+					success: downloadResult => { //下载成功
+						uni.hideLoading();
+						if (downloadResult.statusCode == 200) {
+							uni.showModal({
+								title: '',
+								content: '更新成功,确定现在重启吗?',
+								confirmText: '重启',
+								confirmColor: '#EE8F57',
+								success: function(res) {
+									if (res.confirm == true) {
+										plus.runtime.install( //安装
+											downloadResult.tempFilePath, {
+												force: true
+											},
+											function(res) {
+												utils.showToast('更新成功,重启中');
+												plus.runtime.restart();
+											}
+										);
+									}
+								}
+							});
+						}
+					},
+					fail: err => {
+						console.log('下载错误', err);
+					}
+				});
+
+				downloadTask.onProgressUpdate((res) => {
+					console.log('下载进度' + res.progress);
+					console.log('已经下载的数据长度' + res.totalBytesWritten);
+					console.log('预期需要下载的数据总长度' + res.totalBytesExpectedToWrite);
+
+					// 测试条件,取消下载任务。
+					// if (res.progress == 100) {
+					// 	downloadTask.abort();
+					// }
+				});
+			},
+		}
+	}
+</script>
+
+<style lang="scss">
+	.adminSetting {
+		min-height: 100vh;
+		background-color: #f8f8f8;
+
+		.group {
+			border-radius: 2.7vw;
+			margin: 2.7vw 0 0;
+			background: #FFFFFF;
+			padding: 0 4.1vw;
+
+			.label {
+				display: flex;
+				align-items: center;
+				height: 13.2vw;
+				font-size: 4vw;
+				border-bottom: 2rpx solid #F8F8F8;
+
+				.line {
+					width: 1.1vw;
+					height: 4vw;
+					border-radius: 1.1vw;
+					background-color: #FDD302;
+					margin-right: 2.1vw;
+				}
+
+				text {
+					flex: 1;
+				}
+
+				.more {
+					display: flex;
+					align-items: center;
+					font-weight: 300;
+					font-size: 3.7vw;
+					color: #333333;
+
+					.arrow {
+						width: 2vw;
+						height: 3.6vw;
+						margin-left: 2vw;
+					}
+				}
+			}
+		}
+	}
+</style>

+ 255 - 0
pages/bagStorage/login.vue

@@ -0,0 +1,255 @@
+<template>
+	<view class="bagStorageLogin">
+		<navigation-bar-view ref="nav" :maxTimer="60"></navigation-bar-view>
+		<!-- <view class="label-box">请选择您的存放方式</view> -->
+		<view class="content">
+			<view class="scan-code-box">
+				<image class="scan-code-bg" :src="require('../../static/images/icon-scan-code-bg.png')" mode="aspectFit"></image>
+				<image class="scan-code" :src="codeUrl" mode="aspectFit"></image>
+			</view>
+			<view class="message">点开微信”扫一扫“</view>
+			<view class="message">Scan QR Code via WeChat</view>
+			<!-- <view class="item">
+				<view class="label" style="margin-bottom: 2vw;">微信扫码</view>
+			
+				<view class="message">微信/支付宝扫码</view>
+			</view>
+			<view class="item">
+				<view class="label">手机号验证</view>
+				<view class="cell">
+					<input class="input-box" placeholder="请输入存放手机号码" type="number" @input="changePhone" />
+				</view>
+				<view class="cell">
+					<input class="input-box" placeholder="请输入验证码" maxlength="4" type="number" @input="changeCode" />
+					<view class="code-btn" @click="getCode">{{countDownStr}}</view>
+				</view>
+			</view> -->
+		</view>
+
+		<view class="take-out-the-process">
+			<image class="icon" :src="require('../../static/images/icon-storage-process.png')" mode="aspectFit"></image>
+		</view>
+	</view>
+</template>
+
+<script>
+	import navigationBarView from '../../components/navigationBarView.vue';
+	import uQRCode from '../../js_sdk/Sansnn-uQRCode/uqrcode.js';
+
+	export default {
+		components: {
+			navigationBarView
+		},
+		data() {
+			return {
+				countDownStr: '获取验证码',
+				body: {
+					phone: ''
+				},
+				codeUrl: ''
+			}
+		},
+
+		onLoad() {
+			this.getData()
+		},
+
+		onHide() {
+			const $this = this;
+			$this.$nextTick(function() {
+				$this.$refs.nav.clearTimer();
+			})
+		},
+
+		methods: {
+
+			getData() {
+				let sn = uni.getStorageSync('sn');
+				this.codeUrl = `../../static/TakeStore/store_${sn}.png`
+				this.$api.deviceInfo({
+					deviceSn: sn
+				}).then(res => {
+					this.codeUrl = res.data.url
+				})
+			},
+
+			changePhone(e) {
+				this.body.phone = e.detail.value;
+			},
+			changeCode(e) {
+				if (e.detail.value.length == 4) {
+					this.$api.commonSmsValidate({
+						phone: this.body.phone,
+						code: e.detail.value
+					}).then(res => {
+						uni.redirectTo({
+							url: '/pages/bagStorage/orders?phone=' + this.body.phone
+						})
+					})
+				}
+			},
+
+			getCode() {
+				if (!this.body.phone) {
+					uni.showToast({
+						title: '请输入手机号',
+						icon: 'none'
+					})
+					return
+				}
+				if (this.countDownStr != '获取验证码') {
+					return;
+				}
+				this.$api.commonSmsSend({
+					phone: this.body.phone
+				}).then(res => {
+					uni.showToast({
+						title: '验证码已发送'
+					})
+				})
+				this.countDown()
+			},
+
+			countDown() {
+				const $this = this;
+				this.$tools.countDownForSecond(60, (timer, elemnet) => {
+					if (timer == 0) {
+						$this.countDownStr = '获取验证码'
+					}
+					$this.countDownStr = timer + 's'
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	.bagStorageLogin {
+		min-height: 100vh;
+		background-color: #FFFFFF;
+
+		.label-box {
+			padding: 15.2vw 5vw 5.2vw;
+			color: #222222;
+			font-size: 4.2vw;
+		}
+
+		.content {
+			display: flex;
+			align-items: center;
+			justify-content: space-between;
+			flex-direction: column;
+			// background-color: red;
+			margin-top: 29.2vw;
+			// padding: 0 5vw;
+
+			.scan-code-box {
+				position: relative;
+				display: flex;
+				align-items: center;
+				justify-content: center;
+				width: 39.7vw;
+				height: 39.6vw;
+				margin-bottom: 8.3vw;
+
+				.scan-code-bg {
+					position: absolute;
+					top: 0;
+					left: 0;
+					width: 39.7vw;
+					height: 39.6vw;
+				}
+				
+				.scan-code {
+					position: relative;
+					width: 29.2vw;
+					height: 29.2vw;
+				}
+			}
+			
+			.message {
+				// margin-top: 8.3vw;
+				text-align: center;
+				font-size: 4.2vw;
+				line-height: 5.8vw;
+				color: #253B56;
+			}
+
+			// 	.item {
+			// 		display: flex;
+			// 		align-items: center;
+			// 		flex-direction: column;
+			// 		width: 42.5vw;
+			// 		height: 60.4vw;
+			// 		border-radius: 1.7vw;
+			// 		background-color: #FFFFFF;
+
+			// 		.label {
+			// 			margin: 11.3vw 0 5vw;
+			// 			color: #222222;
+			// 			font-size: 4.2vw;
+			// 			line-height: 4.2vw;
+			// 		}
+
+			// 		.message {
+			// 			color: #666;
+			// 			font-size: 3.2vw;
+			// 			line-height: 3.2vw;
+			// 		}
+
+			// 		.img {
+			// 			width: 30vw;
+			// 			height: 30vw;
+
+			// 			image {
+			// 				width: 100%;
+			// 				height: 100%;
+			// 			}
+			// 		}
+
+			// 		.cell {
+			// 			display: flex;
+			// 			align-items: center;
+			// 			width: 35.2vw;
+			// 			margin-bottom: 11rpx;
+
+			// 			.input-box {
+			// 				flex: 1;
+			// 				height: 7.5vw;
+			// 				line-height: 7.5vw;
+			// 				border: 0.2vw solid #DCDCDC;
+			// 				border-radius: .8vw;
+			// 				padding: 0 1vw;
+			// 				background-color: #F4F4F4;
+			// 				font-size: 2.5vw;
+			// 			}
+
+			// 			.code-btn {
+			// 				display: flex;
+			// 				align-items: center;
+			// 				justify-content: center;
+			// 				width: 15vw;
+			// 				height: 7.5vw;
+			// 				border-radius: .8vw;
+			// 				background-color: #FDD002;
+			// 				margin-left: 1.9vw;
+			// 				font-size: 2.5vw;
+			// 			}
+			// 		}
+			// 	}
+		}
+
+		.take-out-the-process {
+			position: fixed;
+			bottom: 0;
+			left: 0;
+			right: 0;
+			
+			.icon {
+				width: 100vw;
+				height: 43.75vw;
+				vertical-align: top;
+			}
+		}
+	}
+</style>

+ 667 - 0
pages/bagStorage/orders.vue

@@ -0,0 +1,667 @@
+<template>
+	<view class="bagStorageOrders">
+		<navigation-bar-view ref="nav" :maxTimer="60"></navigation-bar-view>
+		<view class="label-box">第一步:选择箱门</view>
+		<view class="selected-box">
+			<block v-for="(item, i) in rentCabinetList" :key="i">
+				<view class="item" :class="selectedIndex == i ? 'active' : ''" @click="changeSpec(i)">
+					<image class="selected-icon" :src="require('../../static/images/icon-selected.png')" v-if="selectedIndex == i"></image>
+					<block v-if="item.cabinetType == 1">
+						<image class="small-icon" :src="require('../../static/images/icon-sub-box-selected.png')" v-if="selectedIndex == i"></image>
+						<image class="small-icon" :src="require('../../static/images/icon-sub-box.png')" v-else></image>
+						<view class="label">小格子</view>
+					</block>
+					<block v-if="item.cabinetType == 2">
+						<image class="middle-icon" :src="require('../../static/images/icon-middle-box-selected.png')" v-if="selectedIndex == i"></image>
+						<image class="middle-icon" :src="require('../../static/images/icon-middle-box.png')" v-else></image>
+						<view class="label">中格子</view>
+					</block>
+					<block v-if="item.cabinetType == 3">
+						<image class="big-icon" :src="require('../../static/images/icon-big-box-selected.png')" v-if="selectedIndex == i"></image>
+						<image class="big-icon" :src="require('../../static/images/icon-big-box.png')" v-else></image>
+						<view class="label">大格子</view>
+					</block>
+					<view class="message">{{item.cabinetDesc}}</view>
+				</view>
+			</block>
+		</view>
+		<view class="label-box">第二步:存物人手机号</view>
+		<view class="input-box">{{options.phone}}</view>
+		<view class="label-box">第三步:选择存放时长</view>
+		<picker mode="selector" :range="rentOptionDtoList" range-key="name" :value="timersIndex" @change="changeTimers">
+			<view class="input-box selected">
+				<text v-if="rentOptionDtoList.length">{{rentOptionDtoList[timersIndex].name}}</text>
+				<image class="arrow" :src="require('../../static/images/icon-arrow-right-grey.png')"></image>
+			</view>
+		</picker>
+		<view class="agreement-box">
+			<text>下单即同意</text>
+			<text class="agreement" @click="openAgreementPopup">《木桩租柜服务用户协议》</text>
+		</view>
+		<view class="footer-btn">
+			<view class="left">
+				<view class="price" v-if="rentCabinetList.length">¥{{rentCabinetList[selectedIndex].price}}</view>
+				<!--  -->
+				<!-- <view class="message" @click="showPriceDetail">
+					<text>查看价格详情</text>
+					<image class="arrow" :src="require('../../static/images/icon-arrow-right-grey.png')"></image>
+				</view> -->
+			</view>
+			<view class="right" @click="orders">下单</view>
+		</view>
+
+		<uni-popup ref="agreementPopup" type="center">
+			<view class="agreement-popup">
+				<image class="delete-icon" :src="require('../../static/images/icon-delete.png')" @click="closeAgreementPopup"></image>
+				<scroll-view class="text-box" scroll-y>
+					<rich-text :nodes="agreement.data"></rich-text>
+				</scroll-view>
+			</view>
+		</uni-popup>
+
+		<uni-popup ref="priceDetailPopup" type="center">
+			<view class="price-popup">
+				<image class="delete-icon" src="../../static/images/icon-delete.png" @click="closePriceDetail"></image>
+				<view class="title">
+					<text>存包费用:</text>
+					<text class="num">3</text>
+					<text>元</text>
+				</view>
+				<view class="label">详细价格详情</view>
+				<block v-for="(item, i) in rentPopup" :key="i">
+					<view class="cell">
+						<image class="icon" :src="require('../../static/images/icon-sub-box-popup.png')" mode="aspectFit" v-if="item.cabinetType == 1"></image>
+						<image class="icon" :src="require('../../static/images/icon-middle-box-popup.png')" mode="aspectFit" v-if="item.cabinetType == 2"></image>
+						<image class="icon" :src="require" mode="aspectFit" v-if="item.cabinetType == 3"></image>
+						<view class="info">
+							<view class="message" v-for="(sub, j) in item.list" :key="j">
+								<text>{{sub.description}},</text>
+								<text class="num">{{sub.price}}</text>
+								<text>元</text>
+							</view>
+						</view>
+					</view>
+				</block>
+				<view class="btn" @click="closePriceDetail">知道了</view>
+			</view>
+		</uni-popup>
+		<uni-popup ref="payPopup" type="center">
+			<view class="pay-popup">
+				<image class="delete-icon" :src="require('../../static/images/icon-delete.png')" @click="closePayDetail"></image>
+				<view class="title">
+					<text>请扫码支付,你的存物箱号为:{{order.caseSn}}</text>
+				</view>
+				<view class="code-box">
+					<view class="item">
+
+						<view class="qrcode">
+							<!-- <canvas canvas-id="aliCode" /> -->
+							<image :src="aliCodeImg"></image>
+							<!-- <mosowe-canvas-image ref="aliCanvas" @canvasImage="aliCanvasImage" :lists="aliLists" height="40vw" width="40vw" /> -->
+						</view>
+						<view class="label">支付宝</view>
+					</view>
+					<view class="item">
+
+						<view class="qrcode">
+							<!-- <canvas canvas-id="weChatCode" /> -->
+							<image :src="wxCodeImg"></image>
+							<!-- <mosowe-canvas-image ref="wxCanvas" @canvasImage="wxCanvasImage" :lists="wxLists" height="40vw" width="40vw" /> -->
+						</view>
+						<view class="label">微信</view>
+					</view>
+				</view>
+
+			</view>
+		</uni-popup>
+	</view>
+</template>
+
+<script>
+	import navigationBarView from '../../components/navigationBarView.vue';
+	import uniPopup from '@/components/uni-popup/uni-popup.vue'
+	import uniPopupMessage from '@/components/uni-popup/uni-popup-message.vue'
+	import uniPopupDialog from '@/components/uni-popup/uni-popup-dialog.vue'
+	import uQRCode from '@/js_sdk/Sansnn-uQRCode/uqrcode.js';
+	import mosoweCanvasImage from '@/components/mosowe-canvas-image/mosowe-canvas-image.vue'
+	export default {
+		components: {
+			navigationBarView,
+			uniPopup,
+			uniPopupMessage,
+			uniPopupDialog,
+			mosoweCanvasImage
+		},
+		data() {
+			return {
+				selectedIndex: 0,
+				rentOptionDtoList: [],
+				timersIndex: 0,
+				agreement: {},
+				info: {},
+				rentCabinetList: [],
+				rentPopup: [],
+				options: {},
+				order: {},
+				codeBody: {},
+				timer: '',
+				aliLists: [{
+					type: 'qr',
+					content: '',
+					x: 0,
+					y: 0,
+				}],
+				aliCodeImg: '',
+				wxLists: [{
+					type: 'qr',
+					content: '',
+					x: 0,
+					y: 0,
+				}],
+				wxCodeImg: ''
+			}
+		},
+
+		onLoad(options) {
+			this.options = options
+			this.getAgreement();
+			this.getData();
+		},
+
+		onHide() {
+			clearInterval(this.timer);
+			const $this = this;
+			$this.$nextTick(function() {
+				$this.$refs.nav.clearTimer();
+			})
+		},
+
+		beforeDestroy() {
+			clearInterval(this.timer);
+		},
+
+		methods: {
+			getData() {
+				let sn = uni.getStorageSync('sn');
+				this.$api.deviceInfo({
+					deviceSn: sn
+				}).then(res => {
+					this.info = res.data;
+					this.rentOptionDtoList = res.data.rentOptionDtoList;
+					this.rentCabinetList = res.data.rentOptionDtoList.length ? res.data.rentOptionDtoList[this.timersIndex].rentCabinetList :
+						[];
+					let cabinetTypes = res.data.cabinetTypes.split(',')
+					this.selectedIndex = Number(cabinetTypes[0]) - 1
+
+					let lists = []
+					// for (let i = 0; i < res.data.rentOptionDtoList.length; i++) {
+					// 	let item = res.data.rentOptionDtoList[i];
+					// 	for (let j = 0; j < item.rentCabinetList.length; j++) {
+					// 		let rentCabinet = item.rentCabinetList[j];
+					// 		rentCabinet.list = rentCabinet.list || [] 
+					// 		let n = 0;
+					// 		for (let k = 0; k < lists.length; k++) {
+					// 			if (lists[k].cabinetType == rentCabinet.cabinetType) {
+					// 				n++;
+					// 				if (!lists[k].list) lists[k].list = []
+					// 				lists[k].list.push({
+					// 					...item,
+					// 					...rentCabinet
+					// 				})
+					// 			}
+					// 		}
+					// 		if (n == 0) {
+					// 			let list = [{ 
+					// 				description: item.description,
+					// 				price: rentCabinet.price
+					// 			}]
+					// 			rentCabinet.list = list
+					// 			lists.push(rentCabinet)
+					// 		}
+					// 	}
+					// }
+					this.rentPopup = lists;
+				})
+			},
+
+
+			changeSpec(e) {
+				if (this.info.cabinetTypes.indexOf(String(e + 1)) == -1) {
+					uni.showToast({
+						icon: 'none',
+						title: '该箱门不可用'
+					})
+					return;
+				}
+				this.selectedIndex = e
+			},
+
+			getAgreement() {
+				this.$api.commonAboutus({
+					type: 2
+				}).then(res => {
+					this.agreement = res;
+				})
+			},
+
+			changeTimers(e) {
+				this.timersIndex = e.detail.value
+			},
+
+			openAgreementPopup() {
+				this.$nextTick(function() {
+					this.$refs.agreementPopup.open();
+				})
+			},
+
+			closeAgreementPopup() {
+				this.$nextTick(function() {
+					this.$refs.agreementPopup.close();
+				})
+			},
+
+			aliCanvasImage(e) {
+				this.aliCodeImg = e;
+			},
+
+			wxCanvasImage(e) {
+				this.wxCodeImg = e;
+			},
+
+			orders() {
+				const params = {
+					cabinetType: this.rentCabinetList[this.selectedIndex].cabinetType,
+					mobile: this.options.phone,
+					optionId: this.rentOptionDtoList[this.timersIndex].id,
+					deviceSn: uni.getStorageSync('sn')
+				}
+				this.$api.offorderCreateOffline(params).then(res => {
+					console.log(res);
+					this.order = res.order;
+					this.codeBody.aliCode = res.aliCode;
+					this.codeBody.wxCode = res.wxCode;
+					this.aliCodeImg = res.aliCode;
+					this.wxCodeImg = res.wxCode;
+					const $this = this;
+					let info = uni.getSystemInfoSync()
+					// this.aliLists[0].content = res.aliCode;
+					// this.aliLists[0].width = info.screenWidth * 0.4
+					// this.aliLists[0].height = info.screenWidth * 0.4
+					// this.wxLists[0].content = res.wxCode;
+					// this.wxLists[0].width = info.screenWidth * 0.4
+					// this.wxLists[0].height = info.screenWidth * 0.4
+					this.$nextTick(function() {
+						$this.$refs.nav.timer = 60;
+						$this.$refs.nav.countdown()
+						$this.$refs.payPopup.open();
+						// setTimeout(function() {
+						// $this.$refs.aliCanvas.createCanvas();
+						// $this.$refs.wxCanvas.createCanvas();
+						// }, 500)
+
+						$this.timer = setInterval(function() {
+							$this.getPayStatus();
+						}, 3000)
+					})
+				})
+			},
+
+			getPayStatus() {
+				this.$api.offorderGetStatus({
+					orderSn: this.order.orderSn
+				}).then(res => {
+					if (res.status == 1) {
+						clearInterval(this.timer);
+						uni.redirectTo({
+							url: '/pages/bagStorage/success?remind=' + this.order.remind
+						})
+					}
+				})
+			},
+
+			showPriceDetail() {
+				this.$nextTick(function() {
+					this.$refs.priceDetailPopup.open();
+				})
+			},
+
+			closePriceDetail() {
+				this.$nextTick(function() {
+					this.$refs.priceDetailPopup.close();
+				})
+			},
+
+			closePayDetail() {
+				clearInterval(this.timer)
+				this.$nextTick(function() {
+					this.$refs.payPopup.close();
+				})
+			},
+		}
+	}
+</script>
+
+<style lang="scss">
+	.bagStorageOrders {
+		min-height: 100vh;
+		background-color: #F8F8F8;
+
+		.label-box {
+			padding: 7.7vw 5vw 2.9vw;
+			color: #222222;
+			font-size: 4.2vw;
+			line-height: 4.2vw;
+		}
+
+		.selected-box {
+			display: flex;
+			align-items: center;
+			flex-wrap: wrap;
+			margin: 0 4.8vw;
+
+			.item {
+				position: relative;
+				display: flex;
+				align-items: center;
+				flex-direction: column;
+				width: 26.5vw;
+				padding-bottom: 9vw;
+				margin-right: 4.2vw;
+				border: .4vw solid #EBEBEB;
+				border-radius: .8vw;
+				background-color: #FFFFFF;
+
+				&:last-child {
+					margin-right: 0;
+				}
+
+				&.active {
+					border-color: #FFDB82;
+				}
+
+				.selected-icon {
+					position: absolute;
+					top: 0;
+					right: 0;
+					width: 5.4vw;
+					height: 5.4vw;
+				}
+
+				.small-icon {
+					margin-top: 11vw;
+					width: 16.3vw;
+					height: 6.9vw;
+				}
+
+				.label {
+					margin-top: 6vw;
+					font-weight: 500;
+					color: #FFB706;
+					font-size: 4.2vw;
+					line-height: 4.2vw;
+				}
+
+				.message {
+					margin-top: 2.7vw;
+					color: #AAAAAA;
+					font-size: 2.9vw;
+					line-height: 2.9vw;
+				}
+
+				.middle-icon {
+					margin-top: 11vw;
+					width: 16.7vw;
+					height: 6.7vw;
+				}
+
+				.big-icon {
+					margin-top: 9.6vw;
+					width: 16.7vw;
+					height: 8.1vw;
+				}
+			}
+		}
+
+		.input-box {
+			display: flex;
+			align-items: center;
+			justify-content: space-between;
+			height: 13.3vw;
+			border: .4vw solid #DEDEDE;
+			background-color: #F4F4F4;
+			padding: 0 3.5vw;
+			margin: .3vw 4.8vw 0;
+			color: #444444;
+			font-size: 5vw;
+			border-radius: .8vw;
+
+			&.selected {
+				border-color: #FBD87F;
+				font-weight: 500;
+				color: #FFB706;
+				background-color: #FFFFFF;
+			}
+
+			.arrow {
+				width: 2.3vw;
+				height: 3.8vw;
+			}
+		}
+
+		.agreement-box {
+			margin: 8vw 5vw 0;
+			font-size: 2.9vw;
+			line-height: 2.9vw;
+
+			.agreement {
+				color: #008CFF;
+			}
+		}
+
+		.footer-btn {
+			display: flex;
+			height: 16.7vw;
+			margin: 4vw 5vw 3.8vw;
+
+			.left {
+				flex: 1;
+				display: flex;
+				justify-content: center;
+				flex-direction: column;
+				padding: 0 8.1vw;
+				border-radius: 16.7vw 0 0 16.7vw;
+				background-color: #0C0B09;
+
+				.price {
+					color: #FFFFFF;
+					font-size: 6.3vw;
+					line-height: 6.3vw;
+				}
+
+				.message {
+					display: flex;
+					align-items: center;
+					margin-top: 2.3vw;
+					color: #9E9D9D;
+					font-size: 2.9vw;
+					line-height: 2.9vw;
+
+					.arrow {
+						width: 1.3vw;
+						height: 1.7vw;
+						margin-left: .6vw;
+					}
+				}
+			}
+
+			.right {
+				display: flex;
+				align-items: center;
+				justify-content: center;
+				width: 35.4vw;
+				border-radius: 0 16.7vw 16.7vw 0;
+				background: linear-gradient(to right, #FEE704, #FDD001);
+				font-size: 5vw;
+			}
+		}
+
+		.agreement-popup {
+			position: relative;
+			width: 90.8vw;
+			height: 70vh;
+			background-color: #FFFFFF;
+			border-radius: 1.7vw;
+			overflow-y: scroll;
+
+			.delete-icon {
+				position: absolute;
+				top: 4vw;
+				right: 4vw;
+				width: 3.3vw;
+				height: 3.3vw;
+			}
+
+			.text-box {
+				width: calc(100% - 11.6vw);
+				height: 56.5vh;
+				margin: 11.3vw 0 0;
+				padding: 0 5.8vw;
+				color: #888888;
+				font-size: 3.2vw;
+			}
+		}
+
+		.price-popup {
+			position: relative;
+			width: 90.8vw;
+			height: 70vh;
+			background-color: #FFFFFF;
+			border-radius: 1.7vw;
+			overflow-y: scroll;
+
+			.delete-icon {
+				position: absolute;
+				top: 4vw;
+				right: 4vw;
+				width: 3.3vw;
+				height: 3.3vw;
+			}
+
+			.title {
+				margin-top: 14vw;
+				text-align: center;
+				font-weight: 500;
+				font-size: 4.2vw;
+				line-height: 4.2vw;
+
+				.num {
+					color: #FFB706;
+				}
+			}
+
+			.label {
+				margin: 7.3vw 5.8vw 5.6vw;
+				font-size: 2.9vw;
+				font-weight: 500;
+			}
+
+			.cell {
+				display: flex;
+				align-items: center;
+				min-height: 18.5vw;
+				margin: 0 5.8vw 1.9vw;
+				border-radius: .8vw;
+				background-color: #F8F8F8;
+
+				.icon {
+					width: 16.7vw;
+					height: 6.7vw;
+					margin: 0 11.5vw 0 6.5vw;
+				}
+
+				.info {
+					flex: 1;
+
+					.message {
+						font-size: 2.1vw;
+						line-height: 2.1vw;
+						margin-bottom: 1.9vw;
+
+						&:last-child {
+							margin-bottom: 0;
+						}
+
+						.num {
+							color: #FFB706;
+						}
+					}
+				}
+			}
+
+			.btn {
+				display: flex;
+				align-items: center;
+				justify-content: center;
+				font-size: 5vw;
+				line-height: 5vw;
+				margin: 12.1vw 0 0;
+			}
+		}
+
+		.pay-popup {
+			position: relative;
+			width: 90vw;
+			min-height: 70vw;
+			margin: 0 5.8vw 1.9vw;
+			border-radius: .8vw;
+			background-color: #F8F8F8;
+			padding-top: 1rpx;
+
+			.title {
+				margin: 7vw 0;
+				text-align: center;
+				font-weight: 500;
+				font-size: 4.2vw;
+				line-height: 4.2vw;
+			}
+
+			.delete-icon {
+				position: absolute;
+				top: 4vw;
+				right: 4vw;
+				width: 3.3vw;
+				height: 3.3vw;
+			}
+
+			.code-box {
+				display: flex;
+				align-items: center;
+				justify-content: space-around;
+
+				.item {
+					display: flex;
+					align-items: center;
+					flex-direction: column;
+
+					.qrcode {
+						width: 40vw;
+						height: 40vw;
+
+						image {
+							width: 40vw;
+							height: 40vw;
+						}
+					}
+
+					.label {
+						margin-top: 2.9vw;
+						font-size: 2.9vw;
+						font-weight: 500;
+					}
+				}
+			}
+
+
+		}
+	}
+</style>

+ 125 - 0
pages/bagStorage/success.vue

@@ -0,0 +1,125 @@
+<template>
+	<view class="bagStorageSuccess">
+		<view class="top">
+			<navigation-bar-view ref="nav" :maxTimer="60"></navigation-bar-view>
+			<view class="icon-box">
+				<image class="icon" :src="require('../../static/images/icon-success.png')"></image>
+				<view class="label">下单成功</view>
+			</view>
+			<view class="hint">{{options.remind}}</view>
+		</view>
+		<!-- <view class="bottom">
+			<view class="label-box">常见问题:</view>
+			<scroll-view scroll-y style="height: 39.9vh;">
+				<block v-for="(item, i) in faq" :key="i">
+					<view class="item">
+						<view class="label">{{i + 1}}、{{item.title}}</view>
+						<view class="message">{{item.content}}</view>
+					</view>
+				</block>
+				<view style="height: 5vw;"></view>
+			</scroll-view>
+		</view> -->
+	</view>
+</template>
+
+<script>
+	import navigationBarView from '../../components/navigationBarView.vue';
+	export default {
+		components: {
+			navigationBarView,
+		},
+
+		data() {
+			return {
+				faq: [],
+				options: {}
+			}
+		},
+
+		onLoad(options) {
+			this.options = options
+			this.getFaq();
+		},
+		
+		onHide() {
+			const $this = this;
+			$this.$nextTick(function(){
+				$this.$refs.nav.clearTimer();
+			})
+		},
+
+		methods: {
+			getFaq() {
+				this.$api.commonHelpList({
+					// type: 1
+				}).then(res => {
+					this.faq = res.data;
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	.bagStorageSuccess {
+		min-height: 100vh;
+		background-color: #F8F8F8;
+
+		.top {
+			padding-bottom: 10.4vw;
+			background-color: #FFFFFF;
+
+			.icon-box {
+				display: flex;
+				align-items: center;
+				flex-direction: column;
+				margin-top: 12.1vw;
+
+				.icon {
+					width: 18.8vw;
+					height: 18.8vw;
+				}
+
+				.label {
+					margin-top: 4.6vw;
+					font-size: 4.5vw;
+					line-height: 4.5vw;
+				}
+			}
+
+			.hint {
+				display: flex;
+				align-items: center;
+				justify-content: center;
+				height: 12.1vw;
+				border-radius: 12.1vw;
+				background: linear-gradient(to right, #FEE704, #FDD001);
+				margin: 9vw 7.3vw 0;
+				font-size: 4.2vw;
+			}
+		}
+
+		.bottom {
+			.label-box {
+				margin: 8.3vw 7.5vw 3vw;
+				font-weight: bold;
+				font-size: 4.3vw;
+				line-height: 4.3vw;
+			}
+			
+			.item {
+				padding: 0 7.3vw 7.3vw;
+				.label {
+					font-size: 3.5vw;
+				}
+				
+				.message {
+					margin: 3vw 7.3vw 0;
+					color: #888888;
+					font-size: 3.2vw;
+				}
+			}
+		}
+	}
+</style>

+ 244 - 0
pages/fetchPacket/index.vue

@@ -0,0 +1,244 @@
+<template>
+	<view class="fetchPacketIndex">
+		<navigation-bar-view ref="nav" :maxTimer="60"></navigation-bar-view>
+		<!-- <view class="label-box">请选择您的取出方式</view> -->
+		<view class="content">
+			<view class="scan-code-box">
+				<image class="scan-code-bg" :src="require('../../static/images/icon-scan-code-bg.png')" mode="aspectFit"></image>
+				<image class="scan-code" :src="codeUrl" mode="aspectFit"></image>
+			</view>
+			<view class="message">点开微信”扫一扫“</view>
+			<view class="message">Scan QR Code via WeChat</view>
+			<!-- 			<view class="item">
+				<view class="label" style="margin-bottom: 2vw;">微信扫码</view>
+				<view class="img">
+					<image :src="codeUrl" mode="aspectFit"></image>
+				</view>
+				<view class="message">微信/支付宝扫码</view>
+			</view>
+			<view class="item">
+				<view class="label">手机号验证</view>
+				<view class="cell">
+					<input class="input-box" placeholder="请输入存放手机号码后四位"  type="number" @input="changePhone" />
+				</view>
+				<view class="cell">
+					<input class="input-box" placeholder="请输入取货码"  type="number" @input="changeCode" />
+					<view class="code-btn" @click="getCode">确认</view>
+				</view>
+			</view> -->
+		</view>
+
+		<view class="take-out-the-process">
+			<image class="icon" :src="require('../../static/images/icon-take-out.png')" mode="aspectFit"></image>
+		</view>
+	</view>
+</template>
+
+<script>
+	import navigationBarView from '../../components/navigationBarView.vue';
+
+	export default {
+		components: {
+			navigationBarView
+		},
+		data() {
+			return {
+				countDownStr: '获取验证码',
+				body: {
+					phone: '',
+					rentSn: ''
+				},
+				codeUrl: ''
+			}
+		},
+
+		onLoad() {
+			this.getData();
+		},
+		onHide() {
+			const $this = this;
+			$this.$nextTick(function() {
+				$this.$refs.nav.clearTimer();
+			})
+		},
+
+		methods: {
+			getData() {
+				let sn = uni.getStorageSync('sn');
+				this.codeUrl = `../../static/TakeStore/take_${sn}.png`
+				console.log(this.codeUrl)
+				this.$api.deviceInfo({
+					deviceSn: sn
+				}).then(res => {
+					this.codeUrl = res.data.takeUrl
+				})
+			},
+
+			changePhone(e) {
+				this.body.phone = e.detail.value;
+			},
+			changeCode(e) {
+				this.body.rentSn = e.detail.value;
+			},
+
+			getCode() {
+				if (!this.body.phone) {
+					uni.showToast({
+						title: '请输入手机号后四位',
+						icon: 'none'
+					})
+					return
+				}
+				if (!this.body.rentSn) {
+					uni.showToast({
+						title: '请输入取货码',
+						icon: 'none'
+					})
+					return
+				}
+				// 977114
+				let sn = uni.getStorageSync('sn');
+				this.$api.offorderOfflineInfo({
+					mobile: this.body.phone,
+					rentSn: this.body.rentSn,
+					deviceSn: sn
+				}).then(res => {
+					uni.redirectTo({
+						url: '/pages/order/details?mobile=' + this.body.phone + '&rentSn=' + this.body.rentSn
+					})
+				})
+
+			},
+		}
+	}
+</script>
+
+<style lang="scss">
+	.fetchPacketIndex {
+		min-height: 100vh;
+		background-color: #F8F8F8;
+
+		.label-box {
+			padding: 15.2vw 5vw 5.2vw;
+			color: #222222;
+			font-size: 4.2vw;
+		}
+
+		.content {
+			display: flex;
+			align-items: center;
+			justify-content: space-between;
+			flex-direction: column;
+			// background-color: red;
+			margin-top: 29.2vw;
+			// padding: 0 5vw;
+
+			.scan-code-box {
+				position: relative;
+				display: flex;
+				align-items: center;
+				justify-content: center;
+				width: 39.7vw;
+				height: 39.6vw;
+				margin-bottom: 8.3vw;
+
+				.scan-code-bg {
+					position: absolute;
+					top: 0;
+					left: 0;
+					width: 39.7vw;
+					height: 39.6vw;
+				}
+
+				.scan-code {
+					position: relative;
+					width: 29.2vw;
+					height: 29.2vw;
+				}
+			}
+
+			.message {
+				text-align: center;
+				font-size: 4.2vw;
+				line-height: 5.8vw;
+				color: #253B56;
+			}
+
+			// .item {
+			// 	display: flex;
+			// 	align-items: center;
+			// 	flex-direction: column;
+			// 	width: 42.5vw;
+			// 	height: 60.4vw;
+			// 	border-radius: 1.7vw;
+			// 	background-color: #FFFFFF;
+
+			// 	.label {
+			// 		margin: 11.3vw 0 5vw;
+			// 		color: #222222;
+			// 		font-size: 4.2vw;
+			// 		line-height: 4.2vw;
+			// 	}
+
+			// 	.message {
+			// 		color: #666;
+			// 		font-size: 3.2vw;
+			// 		line-height: 3.2vw;
+			// 	}
+
+			// 	.img {
+			// 		width: 30vw;
+			// 		height: 30vw;
+
+			// 		image {
+			// 			width: 100%;
+			// 			height: 100%;
+			// 		}
+			// 	}
+
+			// 	.cell {
+			// 		display: flex;
+			// 		align-items: center;
+			// 		width: 35.2vw;
+			// 		margin-bottom: 11rpx;
+
+			// 		.input-box {
+			// 			flex: 1;
+			// 			height: 7.5vw;
+			// 			line-height: 7.5vw;
+			// 			border: 0.2vw solid #DCDCDC;
+			// 			border-radius: .8vw;
+			// 			padding: 0 1vw;
+			// 			background-color: #F4F4F4;
+			// 			font-size: 2.5vw;
+			// 		}
+
+			// 		.code-btn {
+			// 			display: flex;
+			// 			align-items: center;
+			// 			justify-content: center;
+			// 			width: 15vw;
+			// 			height: 7.5vw;
+			// 			border-radius: .8vw;
+			// 			background-color: #FDD002;
+			// 			margin-left: 1.9vw;
+			// 			font-size: 2.5vw;
+			// 		}
+			// 	}
+			// }
+		}
+
+		.take-out-the-process {
+			position: fixed;
+			bottom: 0;
+			left: 0;
+			right: 0;
+
+			.icon {
+				width: 100vw;
+				height: 43.75vw;
+				vertical-align: top;
+			}
+		}
+	}
+</style>

+ 210 - 0
pages/fetchPacket/success.vue

@@ -0,0 +1,210 @@
+<template>
+	<view class="fetchPacket">
+		<view class="nav-box">
+			<text>取件成功</text>
+			<view class="countdown">{{timer}}s</view>
+		</view>
+		<view class="header">
+			<image class="icon" :src="require('../../static/images/icon-success-fetch.png')"></image>
+			<view class="label">主人取件成功啦~</view>
+			<view class="message">记得把格口关上哦~</view>
+			<view class="btn" @click="toIndexPage">返回主页</view>
+		</view>
+		<view class="center-banner">
+			<swiper style="height: 40vw;" autoplay>
+				<block v-for="(item, i) in centerBanner" :key="i">
+					<swiper-item>
+						<image class="banner-img" :src="item.image" mode="aspectFill"></image>
+					</swiper-item>
+				</block>
+			</swiper>
+		</view>
+
+		<view class="btn-box">
+			<view class="btn" @click="bagStorage">
+				<image class="bg" :src="require('../../static/images/icon-storage-bg.png')"></image>
+				<image class="icon" :src="require('../../static/images/icon-storage.png')"></image>
+				<view class="label">存物</view>
+			</view>
+			<view class="btn" @click="fetchPacket">
+				<image class="bg" :src="require('../../static/images/icon-fetch-bg.png')"></image>
+				<image class="icon" :src="require('../../static/images/icon-fetch.png')"></image>
+				<view class="label">取物</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	let timer;
+	export default {
+		data() {
+			return {
+				centerBanner: [],
+				date: {},
+				timer: 60
+			}
+		},
+		onLoad() {
+			this.countdown()
+			this.getCenterBanner();
+		},
+		onHide() {
+			clearInterval(timer);
+		},
+		methods: {
+			countdown() {
+				const $this = this;
+				timer = setInterval(function() {
+					$this.timer--
+					if ($this.timer == 0) {
+						clearInterval(timer);
+						uni.reLaunch({
+							url: '/pages/index/index'
+						});
+						return;
+					}
+				}, 1000)
+			},
+			getCenterBanner() {
+				this.$api.bannerList({
+					type: 3
+				}).then(res => {
+					console.log(res);
+					this.centerBanner = res.data;
+				})
+			},
+
+			bagStorage() {
+				uni.redirectTo({
+					url: '/pages/bagStorage/login'
+				})
+			},
+
+			fetchPacket() {
+				uni.redirectTo({
+					url: '/pages/fetchPacket/index'
+				})
+			},
+			
+			toIndexPage() {
+				uni.reLaunch({
+					url: '/pages/index/index'
+				});
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	.fetchPacket {
+		min-height: 100vh;
+		background-color: #F4F4F4;
+
+		.nav-box {
+			position: relative;
+			display: flex;
+			align-items: center;
+			justify-content: center;
+			height: 9.8vw;
+			font-weight: 500;
+			color: #666666;
+			font-size: 3.8vw;
+
+			.countdown {
+				position: absolute;
+				// top: 3.8vw;
+				right: 5.2vw;
+				color: #666666;
+				font-size: 3.3vw;
+			}
+		}
+
+		.header {
+			display: flex;
+			align-items: center;
+			flex-direction: column;
+			padding: 11.3vw 0 4.6vw;
+			background-color: #FFFFFF;
+			
+			.icon {
+				width: 33.8vw;
+				height: 11.3vw;
+			}
+			
+			.label {
+				margin-top: 5.2vw;
+				font-weight: 500;
+				font-size: 4.2vw;
+				line-height: 4.2vw;
+			}
+			
+			.message {
+				margin-top: 1.9vw;
+				color: #999999;
+				font-size: 2.9vw;
+			}
+			
+			.btn {
+				display: flex;
+				align-items: center;
+				justify-content: center;
+				width: 22.9vw;
+				height: 7.1vw;
+				border-radius: 1.7vw;
+				background-color: #FDD002;
+				margin-top: 5.4vw;
+				font-size: 2.5vw;
+			}
+		}
+
+		.center-banner {
+			// width: 100vw;
+			padding: 2.5vw 2.1vw;
+
+			.banner-img {
+				width: calc(100vw - 4.2vw);
+				height: 40vw;
+				border-radius: .8vw;
+				vertical-align: top;
+			}
+		}
+
+		.btn-box {
+			display: flex;
+			align-items: center;
+			justify-content: space-between;
+			padding: 0 2.1vw;
+
+			.btn {
+				position: relative;
+				display: flex;
+				align-items: center;
+				flex-direction: column;
+				justify-content: center;
+				width: 46.7vw;
+				height: 55.8vw;
+
+				.bg {
+					position: absolute;
+					top: 0;
+					width: 100%;
+					height: 100%;
+				}
+
+				.icon {
+					position: relative;
+					width: 19.2vw;
+					height: 17.3vw;
+					margin-bottom: 4.2vw;
+				}
+
+				.label {
+					position: relative;
+					color: #182B10;
+					font-size: 6.3vw;
+				}
+			}
+		}
+	}
+</style>

+ 662 - 0
pages/index/index.vue

@@ -0,0 +1,662 @@
+<template>
+	<view class="index">
+		<view class="header" @click="openInfoPopup">
+			<view class="icon"></view>
+
+			<view class="info">
+				<view class="title">
+					<text>{{body.stationName}}</text>
+					<text class="right">{{date}}</text>
+				</view>
+				<view class="number">
+					<text>{{body.deviceSn}}</text>
+				</view>
+			</view>
+
+		</view>
+		<view class="header-banner">
+			<swiper style="height: 56.25vw;" autoplay>
+				<block v-for="(item, i) in headerBanner" :key="i">
+					<swiper-item>
+						<view class="banner-img" :style="getHeaderBannreStyle(item.image)"></view>
+						<!-- <image class="" :src="item.image" mode="aspectFill"></image> -->
+					</swiper-item>
+				</block>
+			</swiper>
+		</view>
+		<!-- 		<view class="center-banner">
+			<swiper style="height: 40vw;" autoplay>
+				<block v-for="(item, i) in centerBanner" :key="i">
+					<swiper-item>
+						<view class="banner-img" :style="getHeaderBannreStyle(item.image)"></view>
+					</swiper-item>
+				</block>
+			</swiper>
+		</view> -->
+
+		<view class="btn-box">
+	<!-- 		<view class="btn" v-if="body.scanImage">
+				<image class="bg" :src="body.scanImage"></image>
+			</view> -->
+			<view class="btn" @click="bagStorage">
+				<image class="bg" :src="require('../../static/images/icon-storage-bg.png')"></image>
+				<!-- 			<image class="icon" :src="require('../../static/images/icon-storage.png')"></image>
+				<view class="label">存物</view> -->
+			</view>
+		<!-- 	<view class="btn" v-if="body.takeImage">
+				<image class="bg" :src="body.takeImage"></image>
+			</view> -->
+			<view class="btn" @click="fetchPacket">
+				<image class="bg" :src="require('../../static/images/icon-fetch-bg.png')"></image>
+				<!-- 		<image class="icon" :src="require('../../static/images/icon-fetch.png')"></image>
+				<view class="label">取物</view> -->
+			</view>
+		</view>
+
+		<image class="terms-icon" :src="require('../../static/images/icon-terms.png')" mode="aspectFill"></image>
+		<!-- <view class="welcome">欢迎使用木桩储物柜</view> -->
+
+		<uni-popup ref="statusPopup" type="center">
+			<!-- :class="reportStatus.status == 1 ? 'success' : 'fail'" -->
+			<view class="status-box">
+				<!-- <image class="delete-icon" src="../../static/images/icon-delete.png" @click="closeStatusPopup"></image> -->
+				<image class="icon" :src="require('../../static/images/icon-success.png')" v-if="reportStatus.status == 1"></image>
+				<image class="icon" :src="require('../../static/images/icon-fail.png')" v-else></image>
+				<view class="label">
+					<text>{{reportStatus.msg}}</text>
+					<!-- 		<text v-if="reportStatus.status == 1">开箱成功</text>
+					<text v-if="reportStatus.status == 2">未找到该订单</text>
+					<text v-if="reportStatus.status == 4">开箱失败</text> -->
+				</view>
+				<view class="clear-btn" @click="closeStatusPopup">知道了</view>
+			</view>
+		</uni-popup>
+
+		<uni-popup ref="infoPopup" type="center">
+			<view class="info-body">
+				<image class="delete-icon-info" :src="require('../../static/images/icon-delete-info.png')" @click="deleteInfoPopup"></image>
+				<view class="top">
+					<view class="cell">
+						<view class="label-box">
+							<image class="icon" :src="require('../../static/images/icon-address.png')"></image>
+							<text>柜机地址</text>
+						</view>
+						<view class="address">{{body.stationAddress}}</view>
+					</view>
+					<view class="line"></view>
+					<view class="cell">
+						<view class="label-box" @touchstart="startAdminLogin" @touchend="endAdminLogin">
+							<image class="icon" :src="require('../../static/images/icon-sn.png')"></image>
+							<text style="margin-right: 2.3vw;">柜机编号</text>
+							<text style="color: #FFFFFF;">{{body.deviceSn}}</text>
+						</view>
+					</view>
+				</view>
+				<view class="bottom">
+					<view class="label-box">
+						<view class="label">扫描下方二维码</view>
+						<view class="message">获取木桩柜详细信息</view>
+					</view>
+					<view class="qrcode">
+						<image :src="body.url"></image>
+					</view>
+				</view>
+			</view>
+		</uni-popup>
+
+		<uni-popup ref="bindPopup" type="center">
+			<view class="bind-body">
+				<view class="title">绑定设备号</view>
+				<view class="input-box">
+					<!--  -->
+					<input placeholder="请输入要绑定的设备号" placeholder-style="color: #B7B7B7" @input="changeBind" />
+				</view>
+				<view class="bind-btn" @click="bindDevice">绑定</view>
+			</view>
+		</uni-popup>
+	</view>
+</template>
+
+<script>
+	import uniPopup from '@/components/uni-popup/uni-popup.vue'
+	import uniPopupMessage from '@/components/uni-popup/uni-popup-message.vue'
+	import uniPopupDialog from '@/components/uni-popup/uni-popup-dialog.vue'
+
+	export default {
+		data() {
+			return {
+				headerBanner: [],
+				centerBanner: [],
+				date: '',
+				reportStatus: {},
+				body: {},
+				msg: '',
+				timer: '',
+				timer1: '',
+				deviceSn: '',
+				isNoBind: true
+			}
+		},
+		onLoad() {
+			const $this = this;
+			setInterval(function() {
+				let date = new Date();
+				let y = date.getFullYear();
+				let m = date.getMonth() + 1;
+				let d = date.getDate();
+				let h = date.getHours();
+				let mm = date.getMinutes();
+				$this.date =
+					`${y}-${m > 9 ? m : '0' + m}-${d > 9 ? d : '0' + d} ${h > 9 ? h : '0' + h}:${mm > 9 ? mm : '0' + mm}`
+			}, 1000)
+
+			this.getHeaderBanner();
+			this.getCenterBanner();
+			// uni.removeStorageSync('sn');
+			// uni.setStorageSync('sn', '862607052911665');
+			let sn = uni.getStorageSync('sn');
+			
+
+			if (!sn) {
+				plus.device.getInfo({
+					success: function(e) {
+						console.log('getDeviceInfo success: ', e.uuid);
+						$this.$api.deviceGetDeviceSn({
+							uuid: e.uuid
+						}).then(res => {
+							console.log('AAAA', res)
+							$this.uuid = e.uuid;
+							if (res.deviceSn) {
+								uni.setStorageSync('sn', res.deviceSn);
+								$this.getData()
+							} else {
+								$this.isNoBind = true
+							}
+
+							// $this.getStatus()
+						}, err => {
+							console.log("SASAERR", err)
+						})
+					},
+					fail: function(e) {
+						console.log('getDeviceInfo failed: ', e);
+					}
+				});
+			} else {
+				console.log("SSAASS")
+				this.getData()
+			}
+		},
+		onShow() {
+			console.log("SA")
+
+			clearInterval(this.timer);
+			uni.setStorageSync('sn', '862607052911665')
+			if (uni.getStorageSync('sn')) {
+				// this.getStatus()
+			}
+			// const $this = this;
+			// $this.$nextTick(function() {
+			// 	$this.$refs.statusPopup.open()
+			// 	setInterval(function() {
+			// 		$this.$refs.statusPopup.close()
+
+			// 	}, 10000)
+			// })
+		},
+		onHide() {
+			clearInterval(this.timer);
+		},
+		methods: {
+			startAdminLogin() {
+				this.adminTime = new Date().getTime();
+			},
+			endAdminLogin() {
+				let lastTime = new Date().getTime();
+				if (this.adminTime && (lastTime - this.adminTime > 4000)) {
+					this.adminLogin();
+					this.adminTime = 0;
+				}
+			},
+			getHeaderBannreStyle(e) {
+				return {
+					backgroundImage: `url(${e})`
+				}
+			},
+			getData() {
+				let sn = uni.getStorageSync('sn');
+				this.$api.deviceInfo({
+					deviceSn: sn
+				}).then(res => {
+					this.body = res.data;
+				})
+			},
+
+			closeStatusPopup() {
+				const $this = this;
+				clearInterval(this.timer1)
+				$this.$nextTick(function() {
+					$this.$refs.statusPopup.close()
+				})
+			},
+
+			getStatus() {
+				const $this = this;
+				this.timer = setInterval(function() {
+					let sn = uni.getStorageSync('sn');
+					$this.$api.deviceReportStatus({
+						deviceSn: sn
+					}).then(res => {
+						console.log(res);
+						if (res.report) {
+							console.log("@@@@", res);
+							$this.reportStatus = res.report;
+							clearTimeout(this.timer1);
+							if (res.report.status == 3) {
+								// uni.setStorageSync('timeoutOrder', res.order)
+								uni.navigateTo({
+									url: '/pages/order/details?orderSn=' + res.report.orderSn
+								})
+							} else {
+								$this.$nextTick(function() {
+									console.log("SSSS1")
+									clearInterval(this.timer1)
+									$this.$refs.statusPopup.close()
+									$this.$refs.statusPopup.open()
+									$this.hideStatus();
+								})
+							}
+						}
+					})
+				}, 3000)
+			},
+
+
+			hideStatus() {
+				const $this = this;
+				this.timer1 = setTimeout(function() {
+					clearInterval(this.timer1)
+					$this.$nextTick(function() {
+						$this.$refs.statusPopup.close()
+					})
+				}, 10000)
+			},
+
+			getHeaderBanner() {
+				this.$api.bannerList({
+					type: 2
+				}).then(res => {
+					console.log(res);
+					this.headerBanner = res.data;
+				})
+			},
+			getCenterBanner() {
+				this.$api.bannerList({
+					type: 3
+				}).then(res => {
+					console.log(res);
+					this.centerBanner = res.data;
+				})
+			},
+
+			bagStorage() {
+				uni.navigateTo({
+					url: '/pages/bagStorage/login'
+				})
+			},
+
+			fetchPacket() {
+				uni.navigateTo({
+					url: '/pages/fetchPacket/index'
+				})
+			},
+
+			openInfoPopup() {
+				let sn = uni.getStorageSync('sn');
+
+				if (!this.isNoBind) {
+					this.$refs.infoPopup.open();
+				} else {
+					this.$refs.bindPopup.open();
+				}
+			},
+
+			deleteInfoPopup() {
+				const $this = this;
+				$this.$nextTick(function() {
+					$this.$refs.infoPopup.close()
+				})
+			},
+
+			// 管理员登录
+			adminLogin() {
+				console.log("管理员登录")
+				clearInterval(this.timer);
+				uni.navigateTo({
+					url: '/pages/admin/login'
+				})
+			},
+
+			// 绑定设备号
+			changeBind(e) {
+				this.deviceSn = e.detail.value;
+			},
+
+			// 绑定设备号
+			bindDevice() {
+				uni.showLoading({
+					title: '绑定中...'
+				})
+				this.$api.deviceBindDevice({
+					uuid: this.uuid,
+					deviceSn: this.deviceSn
+				}).then(res => {
+					uni.setStorageSync('sn', this.deviceSn);
+					this.getData()
+					this.$refs.bindPopup.close();
+					uni.hideLoading()
+				}, err => {
+					uni.hideLoading()
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	.index {
+		min-height: 100vh;
+		background-color: #FFF;
+
+		.header {
+			display: flex;
+			align-items: center;
+			height: 10vw;
+			padding: 0 4.2vw 0 2.1vw;
+			background-color: #FFFFFF;
+
+			.icon {
+				width: 6.3vw;
+				height: 6.3vw;
+				border-radius: 50%;
+				background-color: #FEE306;
+				margin-right: 1.7vw;
+			}
+
+			.info {
+				flex: 1;
+
+				.title {
+					display: flex;
+					justify-content: space-between;
+					font-size: 2.9vw;
+					line-height: 2.9vw;
+				}
+
+				.number {
+					display: flex;
+					justify-content: space-between;
+					margin-top: 1.5vw;
+					font-size: 1.7vw;
+					line-height: 1.7vw;
+				}
+			}
+		}
+
+		.header-banner {
+			width: 100vw;
+			height: 56.25vw;
+
+			.banner-img {
+				width: 100vw;
+				height: 56.25vw;
+				vertical-align: top;
+				background-repeat: no-repeat;
+				background-size: cover;
+			}
+		}
+
+		.center-banner {
+			// width: 100vw;
+			height: 35vw;
+			margin: 2.5vw 2.1vw;
+
+			.banner-img {
+				width: calc(100vw - 4.2vw);
+				height: 35vw;
+				border-radius: .8vw;
+				vertical-align: top;
+				background-repeat: no-repeat;
+				background-size: cover;
+			}
+		}
+
+		.btn-box {
+			display: flex;
+			align-items: center;
+			justify-content: space-between;
+			padding: 2.5vw 2.5vw;
+
+			.btn {
+				position: relative;
+				display: flex;
+				align-items: center;
+				flex-direction: column;
+				justify-content: center;
+				width: 46.25vw;
+				height: 70.4vw;
+
+				.bg {
+					position: absolute;
+					top: 0;
+					width: 46.25vw;
+					height: 70.4vw;
+				}
+
+				.icon {
+					position: relative;
+					width: 19.2vw;
+					height: 17.3vw;
+					margin-bottom: 4.2vw;
+				}
+
+				.label {
+					position: relative;
+					color: #182B10;
+					font-size: 6.3vw;
+				}
+			}
+		}
+
+		.terms-icon {
+			width: 100vw;
+			height: 38.96vw;
+			vertical-align: top;
+		}
+
+		.status-box {
+			position: relative;
+			display: flex;
+			align-items: center;
+			justify-content: center;
+			flex-direction: column;
+			width: 77.6vw;
+			min-height: 51.2vw;
+			background-color: #FFFFFF;
+			border-radius: 5vw;
+			font-size: 4.2vw;
+			padding: 10vw 0;
+
+			.icon {
+				width: 20vw;
+				height: 20vw;
+				margin-bottom: 6.8vw;
+			}
+
+			.clear-btn {
+				display: flex;
+				align-items: center;
+				justify-content: center;
+				width: 31.1vw;
+				height: 9.2vw;
+				margin-top: 10.8vw;
+				color: #FFFFFF;
+				border-radius: 9.2vw;
+				font-size: 3.9vw;
+				background: linear-gradient(to bottom, #FEE704, #FDD001);
+			}
+
+			.label {
+				padding: 0 10vw;
+				text-align: center;
+			}
+		}
+
+		.info-body {
+			position: relative;
+			border-radius: 8rpx;
+			background-color: #FFFFFF;
+			width: 72.9vw;
+
+			.delete-icon-info {
+				position: absolute;
+				width: 7vw;
+				height: 12.5vw;
+				top: -12.5vw;
+				right: 0;
+			}
+
+			.top {
+				border-radius: 8rpx 8rpx 0 0;
+				padding: 7.3vw 5.2vw 9.4vw;
+				background: linear-gradient(to bottom, #FEE704, #FDD001);
+
+				.cell {
+					// min-height: 18.8vw;
+
+					.label-box {
+						display: flex;
+						align-items: center;
+						font-weight: 500;
+						color: #B86000;
+						font-size: 3.8vw;
+						line-height: 3.8vw;
+
+						.icon {
+							width: 4.2vw;
+							height: 4.2vw;
+							margin-right: 1.9vw;
+						}
+					}
+
+					.address {
+						color: #B86000;
+						font-size: 2.9vw;
+						margin-top: 1.9vw;
+						margin-left: 6.1vw;
+					}
+				}
+
+				.line {
+					margin: 5.8vw 0;
+					height: 2rpx;
+					background-color: #FFFFFF;
+					opacity: .4;
+				}
+			}
+
+			.bottom {
+				display: flex;
+				align-items: center;
+				flex-direction: column;
+				justify-content: center;
+				height: 58.3vw;
+
+				.label-box {
+					text-align: center;
+					padding: 1.7vw 1.7vw .8vw;
+					border-radius: 4rpx;
+					background-color: #F4F4F4;
+
+					.label {
+						font-size: 3.8vw;
+						line-height: 3.8vw;
+						margin-bottom: 1vw;
+					}
+
+					.message {
+						color: #454545;
+						font-size: 2.5vw;
+						line-height: 2.5vw;
+					}
+				}
+
+				.qrcode {
+					display: flex;
+					align-items: center;
+					justify-content: center;
+					width: 30vw;
+					height: 30vw;
+					border: 4rpx solid #999999;
+					border-radius: 8rpx;
+					margin-top: 1.5vw;
+
+					image {
+						width: 26.7vw;
+						height: 26.7vw;
+					}
+				}
+			}
+		}
+
+		.welcome {
+			margin-top: 1.3vw;
+			width: 100vw;
+			text-align: center;
+			font-size: 3.3vw;
+			color: #444;
+		}
+
+		.bind-body {
+			display: flex;
+			align-items: center;
+			flex-direction: column;
+			width: 70vw;
+			height: 60vw;
+			background: #FFFFFF;
+			border-radius: 3vw;
+
+			.title {
+				margin-top: 6.3vw;
+				text-align: center;
+				border-radius: 4rpx;
+				background-color: #F4F4F4;
+			}
+
+			.input-box {
+				padding: 4.3vw 0;
+				margin: 4.3vw 4.3vw 0;
+				border-bottom: 2rpx solid #999999;
+
+				input {
+					font-size: 4.3vw;
+				}
+			}
+
+			.bind-btn {
+				display: flex;
+				align-items: center;
+				justify-content: center;
+				width: 50vw;
+				height: 11.5vw;
+				margin: 8.1vw 0;
+				border-radius: 11.5vw;
+				font-weight: 500;
+				font-size: 4.3vw;
+				background: linear-gradient(to right, #FEE704, #FDD001);
+			}
+		}
+
+
+	}
+</style>

+ 376 - 0
pages/order/details.vue

@@ -0,0 +1,376 @@
+<template>
+	<view class="orderDetail">
+		<navigation-bar-view ref="nav" :maxTimer="options.isAdmin ? 0 : 60"></navigation-bar-view>
+		<view class="header-bg"></view>
+		<block v-if="order.rentSn">
+			<view class="code">{{order.rentSn}}</view>
+			<view class="label-box">取物码</view>
+		</block>
+		<view style="height: 3.3vw;" v-else></view>
+		<view class="group">
+			<view class="top">
+				<view class="line"></view>
+				<view class="label">存放信息</view>
+			</view>
+			<view class="content">
+				<view class="cell">
+					<view class="label">租赁状态:</view>
+					<view class="message">
+						<text v-if="order.rentStatus == 1">租赁中</text>
+						<text v-if="order.rentStatus == 2">已取出</text>
+						<text v-if="order.rentStatus == 0">未开始</text>
+					</view>
+				</view>
+				<view class="cell">
+					<view class="label">格口类型:</view>
+					<view class="message">
+						<text v-if="order.cabinetType == 1">小格子</text>
+						<text v-if="order.cabinetType == 2">中格子</text>
+						<text v-if="order.cabinetType == 3">大格子</text>
+						<text v-if="order.rentType == 1">(预存{{order.rentTimes / 60}}小时)</text>
+						<text v-if="order.rentType == 2">(剩余{{order.remainNums}}次)</text>
+					</view>
+				</view>
+				<view class="cell">
+					<view class="label">存放时间:</view>
+					<view class="message">{{order.payTime}}</view>
+				</view>
+				<view class="cell">
+					<view class="label">存放箱号:</view>
+					<view class="message">{{order.caseSn}}</view>
+				</view>
+				<view class="cell">
+					<view class="label">联系方式:</view>
+					<view class="message">{{order.mobile}}</view>
+				</view>
+			</view>
+		</view>
+		<view class="group">
+			<view class="top">
+				<view class="line"></view>
+				<view class="label">订单信息</view>
+			</view>
+			<view class="content">
+				<view class="cell">
+					<view class="label">订单金额:</view>
+					<view class="message">¥{{order.payAmount}}</view>
+				</view>
+				<view class="cell">
+					<view class="label">支付方式:</view>
+					<view class="message">
+						<text v-if="order.payType == 1">微信支付</text>
+						<text v-if="order.payType == 2">支付宝支付</text>
+					</view>
+				</view>
+				<view class="cell">
+					<view class="label">订单编号:</view>
+					<view class="message">{{order.orderSn}}</view>
+				</view>
+				<view class="cell">
+					<view class="label">下单时间:</view>
+					<view class="message">{{order.createTime}}</view>
+				</view>
+				<view class="cell">
+					<view class="label">支付时间:</view>
+					<view class="message">{{order.payTime}}</view>
+				</view>
+				<view class="cell">
+					<view class="label">最迟时间:</view>
+					<view class="message">{{order.endTime}}</view>
+				</view>
+			</view>
+		</view>
+
+		<block v-if="options.isAdmin">
+			<view class="footer-btns" v-if="order.rentStatus == 1">
+				<view class="btn right" @click="closeOrder">结束订单</view>
+			</view>
+		</block>
+		<block v-else>
+			<block v-if="order.rentStatus == 1">
+				<block v-if="getOvertimeStatus()">
+					<view class="footer-btns">
+						<view class="btn right" @click="renew">你已超时,请先续费(¥{{order.renewalPrice}}/小时)</view>
+					</view>
+				</block>
+				<block v-else>
+					<view class="footer-btns" v-if="order.rentType == 1">
+						<view class="btn left" @click="openLocker(1)">临时取物</view>
+						<view class="btn right" @click="openLocker(2)">结束取物</view>
+					</view>
+					<view class="footer-btns" v-if="order.rentType == 2">
+						<view class="btn left" @click="openLocker(1)" v-if="order.remainNums > 1">临时取物</view>
+						<view class="btn right" @click="openLocker(2)">结束取物</view>
+					</view>
+				</block>
+			</block>
+		</block>
+
+		<pay-code-popup ref="payCode" :orderSn="renewalOrderSn" :type="payType" @success="paySuccess"></pay-code-popup>
+	</view>
+</template>
+
+<script>
+	import payCodePopup from '../../components/payCodePopup.vue';
+	import navigationBarView from '../../components/navigationBarView.vue'
+
+	export default {
+		components: {
+			payCodePopup,
+			navigationBarView
+		},
+		data() {
+			return {
+				order: {
+					endTime: ''
+				},
+				options: {},
+				payType: '',
+				renewalOrderSn: ''
+			}
+		},
+
+		onLoad(options) {
+			this.options = options;
+			if (options.isAdmin) {
+				this.getAdminData()
+			} else {
+				if (options.orderSn) {
+					this.order.orderSn = options.orderSn;
+					this.getNewOrder();
+				} else {
+					this.getData();
+				}
+			}
+
+			const $this = this;
+			this.$nextTick(function() {
+				$this.$refs.payCode.clearTimer();
+			})
+		},
+
+		onHide() {
+			const $this = this;
+			this.$nextTick(function() {
+				$this.$refs.payCode.clearTimer();
+				$this.$refs.nav.clearTimer();
+			})
+		},
+
+		methods: {
+			getAdminData() {
+				this.$api.managerDetail({
+					orderId: this.options.id
+				}).then(res => {
+					res.data.remainNums = res.data.remainNums || res.data.rentNums;
+					this.order = res.data
+				})
+			},
+			getData() {
+				this.options.deviceSn = uni.getStorageSync('sn');
+				this.$api.offorderOfflineInfo(this.options).then(res => {
+					res.data.remainNums = res.data.remainNums || res.data.rentNums;
+					this.order = res.data
+				})
+			},
+
+			getOvertimeStatus() {
+				let endTime = this.order.endTime.replace(/\-/g, '/');
+				return new Date().getTime() > new Date(endTime).getTime();
+			},
+
+			renew() {
+				this.$api.offorderRenewal({
+					orderSn: this.order.orderSn
+				}).then(res => {
+					this.renewalOrderSn = res.order.renewalOrderSn;
+					const $this = this;
+					this.payType = '1';
+					this.$nextTick(function() {
+						console.log("SSS1");
+						$this.$refs.payCode.init(res)
+					})
+				})
+			},
+
+			paySuccess(e) {
+				if (e == 1) {
+					uni.showToast({
+						title: '续费成功'
+					})
+					this.getNewOrder();
+				}
+			},
+
+			openLocker(e) {
+				uni.showLoading({
+					title: "开箱中..."
+				})
+				this.$api.offorderOpenLocker({
+					orderSn: this.order.orderSn,
+					type: e
+				}).then(res => {
+					uni.hideLoading()
+					uni.redirectTo({
+						url: '/pages/fetchPacket/success'
+					})
+				}, err => {
+					uni.hideLoading()
+				})
+			},
+
+			getNewOrder() {
+				this.$api.offlineInfoByorder({
+					orderSn: this.order.orderSn
+				}).then(res => {
+					res.data.remainNums = res.data.remainNums || res.data.rentNums;
+					this.order = res.data
+				})
+			},
+
+			closeOrder() {
+				const _ = this;
+				uni.showModal({
+					title: '提示',
+					content: '确认结束这个订单?',
+					success: (r) => {
+						if (r.confirm) {
+							_.$api.managerEndOrder({
+								orderSn: this.order.orderSn
+							}).then(res => {
+								uni.showToast({
+									title: '操作成功'
+								})
+								_.getAdminData()
+							})
+						}
+					}
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	.orderDetail {
+		padding-top: 1rpx;
+		min-height: 100vh;
+		background-color: #F8F8F8;
+
+		.header-bg {
+			position: absolute;
+			top: 0;
+			width: 100vw;
+			height: 50vw;
+			overflow: hidden;
+
+			&:after {
+				width: 140%;
+				height: 50vw;
+				position: absolute;
+				left: -20%;
+				top: 0;
+				content: '';
+				border-radius: 0 0 50% 50%;
+				background: linear-gradient(to right, #FEE704, #FDD001);
+			}
+		}
+
+		.code {
+			position: relative;
+			margin-top: 1.7vw;
+			text-align: center;
+			font-weight: bold;
+			font-size: 9.2vw;
+			line-height: 9.2vw;
+		}
+
+		.label-box {
+			position: relative;
+			margin-top: 28rpx;
+			text-align: center;
+			font-size: 30rpx;
+			line-height: 30rpx;
+		}
+
+		.group {
+			position: relative;
+			padding: 0 3.3vw;
+			margin: 3.3vw 4vw 0;
+			background-color: #FFFFFF;
+			border-radius: 1.6vw;
+			padding-bottom: 0.9vw;
+
+			.top {
+				display: flex;
+				align-items: center;
+				height: 10vw;
+				border-bottom: 2rpx solid #F8F8F8;
+				margin-bottom: 2.3vw;
+
+				.line {
+					width: 4rpx;
+					height: 3.2vw;
+					margin-right: 1.3vw;
+					border-radius: 4rpx;
+					background-color: #FDD302;
+				}
+
+				.label {
+					font-weight: bold;
+					font-size: 4vw;
+				}
+			}
+
+			.cell {
+				display: flex;
+				align-items: center;
+				margin-bottom: 4vw;
+				font-size: 3.5vw;
+				line-height: 3.5vw;
+
+				.label {
+					color: #333333;
+				}
+
+				.message {
+					color: #AAAAAA;
+				}
+			}
+		}
+
+		.footer-btns {
+			display: flex;
+			align-items: center;
+			justify-content: space-between;
+			width: calc(100vw - 8vw);
+			padding: 2.3vw 0;
+			margin: 0 4vw;
+
+			.btn {
+				flex: 1;
+				display: flex;
+				align-items: center;
+				justify-content: center;
+				height: 11.5vw;
+				border-radius: 11.5vw;
+				margin-right: 4vw;
+				font-weight: 500;
+				font-size: 4vw;
+
+				&:last-child {
+					margin: 0;
+				}
+
+				&.left {
+					color: #FFFFFF;
+					background: linear-gradient(to right, #43F62D, #22E151, #01CB75);
+				}
+
+				&.right {
+					background: linear-gradient(to right, #FEE704, #FDD001);
+				}
+			}
+		}
+	}
+</style>

+ 261 - 0
pages/order/list.vue

@@ -0,0 +1,261 @@
+<template>
+	<view class="orderList">
+		<view class="nav">
+			<navigation-bar-view ref="nav"></navigation-bar-view>
+			<view class="header">
+				<view class="search-box">
+					<input placeholder="请输入手机号" @input="changeMobile"/>
+				</view>
+				<view class="search-btn" @click="search">搜索</view>
+			</view>
+			
+		</view>
+		
+		<view style="height: 21.8vw"></view>
+
+		<block v-for="(item, i) in list" :key="i">
+			<view class="cell" @click="toDetail(item)">
+				<view class="top">
+					<view class="order-sn">订单号:{{item.orderSn}}</view>
+					<view class="status">
+						<text v-if="item.rentStatus == 1">租赁中</text>
+						<text v-if="item.rentStatus == 2">已取出</text>
+						<text v-if="item.rentStatus == 0">未开始</text>
+					</view>
+				</view>
+				<view class="center">
+					<view class="take-code" v-if="item.rentSn">
+						<view class="label">取物码:</view>
+						<view class="code">{{item.rentSn}}</view>
+					</view>
+					<view class="message">
+						<text>格口类型:</text>
+						<text v-if="item.cabinetType == 1">小格子</text>
+						<text v-if="item.cabinetType == 2">中格子</text>
+						<text v-if="item.cabinetType == 3">大格子</text>
+						<text v-if="item.rentType == 1">(预存{{item.rentTimes / 60}}小时)</text>
+						<text v-if="item.rentType == 2">(预存{{item.rentNums}}次)</text>
+					</view>
+					<view class="message">
+						<text>存放箱号:</text>
+						<text>{{item.caseSn}}</text>
+					</view>
+					<view class="message">存放时间:{{item.payTime}}</view>
+					<view class="message">联系方式:{{item.mobile}}</view>
+				</view>
+				<!-- <view class="bottom"> -->
+				<!-- <view class="btn">取消订单</view> -->
+				<!-- <view class="btn">删除订单</view> -->
+				<!-- </view> -->
+			</view>
+		</block>
+		<view style="height: 3.3vw;"></view>
+	</view>
+</template>
+
+<script>
+	import navigationBarView from '../../components/navigationBarView.vue';
+	export default {
+		components: {
+			navigationBarView
+		},
+		data() {
+			return {
+				list: [],
+				page: 1,
+				mobile: ''
+			}
+		},
+		onLoad() {
+			this.getData()
+		},
+
+		onPullDownRefresh() {
+			this.page = 1;
+			this.getData()
+		},
+
+		onReachBottom() {
+			this.page++
+			this.getData();
+		},
+
+
+		methods: {
+			getData() {
+				uni.showLoading({
+					title: "加载中..."
+				})
+				let sn = uni.getStorageSync('sn');
+				this.$api.managerDeviceList({
+					deviceSn: sn,
+					page: this.page,
+					mobile: this.mobile
+				}).then(res => {
+					let list = this.list;
+					if (this.page == 1) {
+						list = []
+					} else if (!res.page.data.length) {
+						this.page--
+					}
+					for (let i = 0; i < res.page.data.length; i++) {
+						list.push(res.page.data[i])
+					}
+					this.list = list;
+					uni.stopPullDownRefresh()
+
+				}, err => {
+
+				})
+			},
+			
+			changeMobile(e) {
+				this.mobile = e.detail.value;
+			},
+			
+			search() {
+				this.page = 1;
+				this.getData();
+			},
+
+			toDetail(e) {
+				console.log(e);
+				uni.navigateTo({
+					url: '/pages/order/details?isAdmin=1&id=' + e.id
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	.orderList {
+		min-height: 100vh;
+		background-color: #eee;
+
+		.nav {
+			position: fixed;
+			top: 0;
+			left: 0;
+			background-color: #FFFFFF;
+		}
+
+		.header {
+			position: fixed;
+			top: 11.3vw;
+			display: flex;
+			align-items: center;
+			justify-content: space-around;
+			width: 100vw;
+			height: 10.5vw;
+			background-color: #FFFFFF;
+
+			.search-box {
+				flex: 1;
+				border-radius: 1vw;
+				margin-left: 3.3vw;
+
+				input {
+					font-size: 3.2vw;
+				}
+			}
+
+			.search-btn {
+				display: flex;
+				align-items: center;
+				justify-content: center;
+				margin-right: 3.3vw;
+				width: 16vw;
+				height: 6.6vw;
+				border-radius: 6.6vw;
+				background: linear-gradient(to right, #FEE704, #FDD001);
+				font-size: 3.2vw;
+			}
+
+			// .title {
+			// 	display: flex;
+			// 	align-items: center;
+			// 	font-size: 3.5vw;
+			// 	color: #161920;
+			// }
+		}
+
+		.cell {
+			padding: 0 3.3vw;
+			border-radius: 1.6vw;
+			background-color: #FFFFFF;
+			margin: 3.3vw 4vw 0;
+
+			.top {
+				display: flex;
+				align-items: center;
+				justify-content: space-between;
+				height: 10.7vw;
+				border-bottom: .3vw solid #eee;
+
+				.order-sn {
+					color: #999999;
+					font-size: 3.5vw;
+				}
+
+				.status {
+					display: flex;
+					align-items: center;
+					justify-content: center;
+					width: 16vw;
+					height: 5.6vw;
+					border-radius: 5.6vw;
+					background: linear-gradient(to right, #FEE704, #FDD001);
+					font-size: 3.2vw;
+				}
+			}
+
+			.center {
+				padding-top: 4.5vw;
+				padding-bottom: 4.5vw;
+
+				.take-code {
+					display: flex;
+					align-items: center;
+					margin-bottom: 4.4vw;
+					font-weight: bold;
+					line-height: 4vw;
+
+					.label {
+						font-size: 4vw;
+					}
+
+					.code {
+						color: #FFB706;
+						font-size: 4.8vw;
+					}
+				}
+
+				.message {
+					margin-bottom: 3.1vw;
+					color: #666666;
+					font-size: 3.5vw;
+					line-height: 3.5vw;
+				}
+			}
+
+			.bottom {
+				display: flex;
+				justify-content: flex-end;
+				padding-bottom: 3.2vw;
+
+				.btn {
+					display: flex;
+					align-items: center;
+					justify-content: center;
+					width: 22.7vw;
+					height: 8.3vw;
+					border-radius: 8.3vw;
+					border: .3vw solid #CCCCCC;
+					color: #222222;
+					font-size: 3.5vw;
+				}
+			}
+		}
+	}
+</style>

BIN
static/TakeStore/store_862607052911665.png


BIN
static/TakeStore/store_862607052969937.png


BIN
static/TakeStore/store_862607052976122.png


BIN
static/TakeStore/store_862607052978334.png


BIN
static/TakeStore/store_862607052995395.png


BIN
static/TakeStore/store_862607052998829.png


BIN
static/TakeStore/store_862607053003694.png


BIN
static/TakeStore/store_862607053020359.png


BIN
static/TakeStore/store_862607053060660.png


BIN
static/TakeStore/store_862607053062807.png


BIN
static/TakeStore/store_862607053062971.png


BIN
static/TakeStore/store_862607053063177.png


BIN
static/TakeStore/store_862607053077425.png


BIN
static/TakeStore/store_862607053077938.png


BIN
static/TakeStore/store_862607053088349.png


BIN
static/TakeStore/store_862607053102132.png


BIN
static/TakeStore/store_867032053822800.png


BIN
static/TakeStore/store_867032053835778.png


BIN
static/TakeStore/store_867032053852286.png


BIN
static/TakeStore/store_867032053868381.png


BIN
static/TakeStore/store_867032053869892.png


BIN
static/TakeStore/store_867032053869900.png


BIN
static/TakeStore/take_862607052911665.png


BIN
static/TakeStore/take_862607052969937.png


BIN
static/TakeStore/take_862607052976122.png


BIN
static/TakeStore/take_862607052978334.png


BIN
static/TakeStore/take_862607052995395.png


BIN
static/TakeStore/take_862607052998829.png


BIN
static/TakeStore/take_862607053003694.png


BIN
static/TakeStore/take_862607053020359.png


BIN
static/TakeStore/take_862607053060660.png


BIN
static/TakeStore/take_862607053062807.png


BIN
static/TakeStore/take_862607053062971.png


BIN
static/TakeStore/take_862607053063177.png


BIN
static/TakeStore/take_862607053077425.png


BIN
static/TakeStore/take_862607053077938.png


BIN
static/TakeStore/take_862607053088349.png


BIN
static/TakeStore/take_862607053102132.png


BIN
static/TakeStore/take_867032053822800.png


BIN
static/TakeStore/take_867032053835778.png


BIN
static/TakeStore/take_867032053852286.png


BIN
static/TakeStore/take_867032053868381.png


BIN
static/TakeStore/take_867032053869892.png


BIN
static/TakeStore/take_867032053869900.png


BIN
static/images/icon-address.png


BIN
static/images/icon-arrow-left-block.png


BIN
static/images/icon-arrow-right-grey.png


BIN
static/images/icon-back-bg.png


BIN
static/images/icon-big-box-popup.png


BIN
static/images/icon-big-box-selected.png


BIN
static/images/icon-big-box.png


BIN
static/images/icon-delete-info.png


BIN
static/images/icon-delete.png


BIN
static/images/icon-fail.png


BIN
static/images/icon-fetch-bg.png


BIN
static/images/icon-fetch.png


BIN
static/images/icon-middle-box-popup.png


BIN
static/images/icon-middle-box-selected.png


BIN
static/images/icon-middle-box.png


BIN
static/images/icon-scan-code-bg.png


BIN
static/images/icon-selected.png


BIN
static/images/icon-sn.png


BIN
static/images/icon-storage-bg.png


BIN
static/images/icon-storage-process.png


BIN
static/images/icon-storage.png


BIN
static/images/icon-sub-box-popup.png


BIN
static/images/icon-sub-box-selected.png


BIN
static/images/icon-sub-box.png


BIN
static/images/icon-success-fetch.png


BIN
static/images/icon-success.png


BIN
static/images/icon-take-out.png


Certains fichiers n'ont pas été affichés car il y a eu trop de fichiers modifiés dans ce diff