소스 검색

no message

py 2 년 전
부모
커밋
58425edafc
100개의 변경된 파일과 8658개의 추가작업 그리고 373개의 파일을 삭제
  1. 5 1
      api/coupon.js
  2. 3 1
      api/expressOrder.js
  3. 3 1
      api/order.js
  4. 11 0
      package-lock.json
  5. 1 0
      package.json
  6. 7 2
      pages-buy/dry-mod/menu.vue
  7. 45 28
      pages-my/my-ticket.vue
  8. 222 0
      pages-my/search-list.vue
  9. 1 1
      pages-my/ticket-centre.vue
  10. 56 7
      pages-order/express-info.vue
  11. 32 14
      pages-order/group-info.vue
  12. 108 81
      pages-order/laundry-info.vue
  13. 155 0
      pages-order/module/select-address.vue
  14. 451 0
      pages-order/takeout-info.vue
  15. 52 34
      pages-order/ticket-info.vue
  16. 1 1
      pages-takeout/confirm-mod/select-address.vue
  17. 13 1
      pages.json
  18. 428 184
      pages/index/index.vue
  19. 181 17
      pages/order/index.vue
  20. BIN
      static/img/index/lq-bg.png
  21. BIN
      static/img/index/lqgd.png
  22. BIN
      static/img/order/bg.png
  23. BIN
      static/img/order/bottom.png
  24. BIN
      static/img/order/fz.png
  25. BIN
      static/img/order/lxkf.png
  26. BIN
      static/img/order/qxdd.png
  27. BIN
      static/img/order/qzf.png
  28. BIN
      static/img/order/top.png
  29. BIN
      static/img/order/xgdd.png
  30. BIN
      static/img/order/yhq.png
  31. BIN
      static/img/order/zlyd.png
  32. 13 0
      uni_modules/uv-qrcode/changelog.md
  33. 1 0
      uni_modules/uv-qrcode/components/uv-qrcode/cache.js
  34. 241 0
      uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/bridge/bridge-weex.js
  35. 18 0
      uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-2d/FillStyleLinearGradient.js
  36. 8 0
      uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-2d/FillStylePattern.js
  37. 17 0
      uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-2d/FillStyleRadialGradient.js
  38. 666 0
      uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-2d/RenderingContext.js
  39. 11 0
      uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-webgl/ActiveInfo.js
  40. 21 0
      uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-webgl/Buffer.js
  41. 21 0
      uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-webgl/Framebuffer.js
  42. 298 0
      uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-webgl/GLenum.js
  43. 142 0
      uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-webgl/GLmethod.js
  44. 23 0
      uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-webgl/GLtype.js
  45. 21 0
      uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-webgl/Program.js
  46. 21 0
      uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-webgl/Renderbuffer.js
  47. 1191 0
      uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-webgl/RenderingContext.js
  48. 22 0
      uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-webgl/Shader.js
  49. 11 0
      uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-webgl/ShaderPrecisionFormat.js
  50. 22 0
      uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-webgl/Texture.js
  51. 22 0
      uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-webgl/UniformLocation.js
  52. 3 0
      uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-webgl/classUtils.js
  53. 74 0
      uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/env/canvas.js
  54. 96 0
      uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/env/image.js
  55. 24 0
      uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/env/tool.js
  56. 39 0
      uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/index.js
  57. 85 0
      uni_modules/uv-qrcode/components/uv-qrcode/props.js
  58. 33 0
      uni_modules/uv-qrcode/components/uv-qrcode/qrcode.js
  59. 41 0
      uni_modules/uv-qrcode/components/uv-qrcode/queue.js
  60. 39 0
      uni_modules/uv-qrcode/components/uv-qrcode/uv-qrcode.vue
  61. 87 0
      uni_modules/uv-qrcode/package.json
  62. 21 0
      uni_modules/uv-qrcode/readme.md
  63. 76 0
      uni_modules/uv-ui-tools/changelog.md
  64. 6 0
      uni_modules/uv-ui-tools/components/uv-ui-tools/uv-ui-tools.vue
  65. 79 0
      uni_modules/uv-ui-tools/index.js
  66. 7 0
      uni_modules/uv-ui-tools/index.scss
  67. 34 0
      uni_modules/uv-ui-tools/libs/config/config.js
  68. 32 0
      uni_modules/uv-ui-tools/libs/css/color.scss
  69. 100 0
      uni_modules/uv-ui-tools/libs/css/common.scss
  70. 23 0
      uni_modules/uv-ui-tools/libs/css/components.scss
  71. 111 0
      uni_modules/uv-ui-tools/libs/css/variable.scss
  72. 40 0
      uni_modules/uv-ui-tools/libs/css/vue.scss
  73. 134 0
      uni_modules/uv-ui-tools/libs/function/colorGradient.js
  74. 29 0
      uni_modules/uv-ui-tools/libs/function/debounce.js
  75. 167 0
      uni_modules/uv-ui-tools/libs/function/digit.js
  76. 734 0
      uni_modules/uv-ui-tools/libs/function/index.js
  77. 75 0
      uni_modules/uv-ui-tools/libs/function/platform.js
  78. 287 0
      uni_modules/uv-ui-tools/libs/function/test.js
  79. 30 0
      uni_modules/uv-ui-tools/libs/function/throttle.js
  80. 132 0
      uni_modules/uv-ui-tools/libs/luch-request/adapters/index.js
  81. 51 0
      uni_modules/uv-ui-tools/libs/luch-request/core/InterceptorManager.js
  82. 201 0
      uni_modules/uv-ui-tools/libs/luch-request/core/Request.js
  83. 20 0
      uni_modules/uv-ui-tools/libs/luch-request/core/buildFullPath.js
  84. 33 0
      uni_modules/uv-ui-tools/libs/luch-request/core/defaults.js
  85. 6 0
      uni_modules/uv-ui-tools/libs/luch-request/core/dispatchRequest.js
  86. 126 0
      uni_modules/uv-ui-tools/libs/luch-request/core/mergeConfig.js
  87. 16 0
      uni_modules/uv-ui-tools/libs/luch-request/core/settle.js
  88. 64 0
      uni_modules/uv-ui-tools/libs/luch-request/helpers/buildURL.js
  89. 14 0
      uni_modules/uv-ui-tools/libs/luch-request/helpers/combineURLs.js
  90. 14 0
      uni_modules/uv-ui-tools/libs/luch-request/helpers/isAbsoluteURL.js
  91. 197 0
      uni_modules/uv-ui-tools/libs/luch-request/index.d.ts
  92. 2 0
      uni_modules/uv-ui-tools/libs/luch-request/index.js
  93. 135 0
      uni_modules/uv-ui-tools/libs/luch-request/utils.js
  94. 264 0
      uni_modules/uv-ui-tools/libs/luch-request/utils/clone.js
  95. 13 0
      uni_modules/uv-ui-tools/libs/mixin/button.js
  96. 172 0
      uni_modules/uv-ui-tools/libs/mixin/mixin.js
  97. 8 0
      uni_modules/uv-ui-tools/libs/mixin/mpMixin.js
  98. 13 0
      uni_modules/uv-ui-tools/libs/mixin/mpShare.js
  99. 47 0
      uni_modules/uv-ui-tools/libs/mixin/openType.js
  100. 59 0
      uni_modules/uv-ui-tools/libs/mixin/touch.js

+ 5 - 1
api/coupon.js

@@ -9,4 +9,8 @@ export const couponGrant = (data) => request(newsUrl + 'grant', 'post', { ...dat
 // 我的优惠卷
 export const couponMember = (data) => request(newsUrl + 'member', 'post', { ...data },false)
 // 优惠卷使用规则
-export const couponRule = (data) => request(newsUrl + 'rule', 'post', { ...data },false)
+export const couponRule = (data) => request(newsUrl + 'rule', 'post', { ...data },false)
+// 优惠卷可使用商家
+export const couponShop = (data) => request(newsUrl + 'shop', 'post', { ...data },false)
+// 首页弹窗优惠卷
+export const couponHome = (data) => request(newsUrl + 'home', 'post', { ...data },false)

+ 3 - 1
api/expressOrder.js

@@ -8,4 +8,6 @@ export const expressOrderInfo = (data) => request(newsUrl + 'info', 'post', { ..
 // 取消订单
 export const expressOrderCancel = (data) => request(newsUrl + 'cancel', 'post', { ...data },false)
 // 获取订单状态_copy
-export const expressOrderStatus = (data) => request(newsUrl + 'status', 'post', { ...data },false)
+export const expressOrderStatus = (data) => request(newsUrl + 'status', 'post', { ...data },false)
+// 修改订单收货地址
+export const expressOrderAddress = (data) => request(newsUrl + 'address', 'post', { ...data },false)

+ 3 - 1
api/order.js

@@ -8,4 +8,6 @@ export const orderInfo = (data) => request(newsUrl + 'info', 'post', { ...data }
 // 取消订单
 export const orderCancel = (data) => request(newsUrl + 'cancel', 'post', { ...data },false)
 // 获取订单状态
-export const orderStatus = (data) => request(newsUrl + 'status', 'post', { ...data },false)
+export const orderStatus = (data) => request(newsUrl + 'status', 'post', { ...data },false)
+// 支付订单
+export const orderPay = (data) => request(newsUrl + 'pay', 'post', { ...data },false)

+ 11 - 0
package-lock.json

@@ -9,6 +9,7 @@
         "jweixin-module": "^1.6.0",
         "uni-read-pages": "1.0.5",
         "uni-simple-router": "2.0.7",
+        "uniapp-qrcode": "^1.0.2",
         "uploading-oss": "1.0.3",
         "wecomjsdk": "1.0.2"
       },
@@ -138,6 +139,11 @@
       "resolved": "https://registry.npmmirror.com/uni-simple-router/-/uni-simple-router-2.0.7.tgz",
       "integrity": "sha512-8FKv5dw7Eoonm0gkO8udprrxzin0fNUI0+AvIphFkFRH5ZmP5ZWJ2pvnWzb2NiiqQSECTSU5VSB7HhvOSwD5eA=="
     },
+    "node_modules/uniapp-qrcode": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/uniapp-qrcode/-/uniapp-qrcode-1.0.2.tgz",
+      "integrity": "sha512-jcWwWz4yXsO7if/+78MMXj5VUdZTLu2D6L/IKb4mJkIw87oF11pO3WS/jS27SUcPCrX/BKcir5a2R1uvkaoR9g=="
+    },
     "node_modules/uploading-oss": {
       "version": "1.0.3",
       "resolved": "https://registry.npmjs.org/uploading-oss/-/uploading-oss-1.0.3.tgz",
@@ -277,6 +283,11 @@
       "resolved": "https://registry.npmmirror.com/uni-simple-router/-/uni-simple-router-2.0.7.tgz",
       "integrity": "sha512-8FKv5dw7Eoonm0gkO8udprrxzin0fNUI0+AvIphFkFRH5ZmP5ZWJ2pvnWzb2NiiqQSECTSU5VSB7HhvOSwD5eA=="
     },
+    "uniapp-qrcode": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/uniapp-qrcode/-/uniapp-qrcode-1.0.2.tgz",
+      "integrity": "sha512-jcWwWz4yXsO7if/+78MMXj5VUdZTLu2D6L/IKb4mJkIw87oF11pO3WS/jS27SUcPCrX/BKcir5a2R1uvkaoR9g=="
+    },
     "uploading-oss": {
       "version": "1.0.3",
       "resolved": "https://registry.npmjs.org/uploading-oss/-/uploading-oss-1.0.3.tgz",

+ 1 - 0
package.json

@@ -4,6 +4,7 @@
     "jweixin-module": "^1.6.0",
     "uni-read-pages": "1.0.5",
     "uni-simple-router": "2.0.7",
+    "uniapp-qrcode": "^1.0.2",
     "uploading-oss": "1.0.3",
     "wecomjsdk": "1.0.2"
   },

+ 7 - 2
pages-buy/dry-mod/menu.vue

@@ -77,7 +77,8 @@
 		methods:{
 			
 			getTypeList(){
-				getLaundry().then((res)=>{
+				let school_id = uni.getStorageSync('school_id');
+				getLaundry({school_id: school_id}).then((res)=>{
 					if(res.code === 1){
 						this.typeList = res.data;
 						this.type = this.typeList[0].id;
@@ -85,7 +86,7 @@
 						this.typeList.forEach((v)=>{
 							v.num = 0
 						})
-						laundryList().then((res)=>{
+						laundryList({school_id: school_id}).then((res)=>{
 							if(res.code === 1){
 								this.menuList = res.data
 								getShopIngList({type:3}).then((res)=>{
@@ -114,8 +115,12 @@
 										}
 									}
 								})
+							}else {
+								tools.error(res.msg)
 							}
 						})
+					}else {
+						tools.error(res.msg)
 					}
 				})
 			},

+ 45 - 28
pages-my/my-ticket.vue

@@ -2,15 +2,15 @@
 	<view class="my-ticket flex-common-css iPhone-bottom">
 		<Nav title="我的优惠券" titleColor="#333" bgckgroundBox='#fff'></Nav>
 		<view class="tab-box flex-justify-around bgc-f ">
-			<view class="tab-but flex-1 flex-direction align-items-center" 
-				v-for="(item, index) in tabList" :key="index" @click="tabStitle(item.status)">
+			<view class="tab-but flex-1 flex-direction align-items-center" v-for="(item, index) in tabList" :key="index"
+				@click="tabStitle(item.status)">
 				<view class="fs-32 mb-18" :class="status==item.status?'fc-41ABF5':'fc-3'">
 					{{item.name}}
 				</view>
 				<view v-show="status==item.status" class="tab-hr bgc-41ABF5"></view>
 			</view>
 		</view>
-		
+
 		<view v-if="itemData.length === 0" class="scroll-view-css">
 			<EnBlank :customSrc='true'>
 				<template v-slot:blankImg>
@@ -18,7 +18,7 @@
 				</template>
 			</EnBlank>
 		</view>
-		
+
 		<scroll-view v-else :scroll-y="true" class="scroll-view-css" @scrolltolower="scrolltolower">
 			<view class="list-box">
 				<view class="item-box display-flex mb-20" v-for="(item,index) in itemData" :key="index">
@@ -34,8 +34,7 @@
 					</view>
 					<view class="item-hr" :class="status == 1?'':'item-hr-two'"></view>
 					<view class="item-right flex-1 bgc-f">
-						<view class="fs-28 mb-12 ticket-name text-overflow-ellipsis"
-							:class="status == 1?'fc-3':'fc-9'">
+						<view class="fs-28 mb-12 ticket-name text-overflow-ellipsis" :class="status == 1?'fc-3':'fc-9'">
 							{{item.name}}
 						</view>
 						<view class="fs-24 mb-12" :class="status == 1?'fc-FB3D03':'fc-9'">
@@ -65,19 +64,32 @@
 </template>
 
 <script>
-	import {couponMember} from '@/api/coupon.js';
+	import {
+		couponMember
+	} from '@/api/coupon.js';
 	import tools from "@/service/tools";
 	import EnBlank from "@/components/en-utils/en-blank/en-blank";
-	
+
 	export default {
-		components: {EnBlank},
+		components: {
+			EnBlank
+		},
 		data() {
 			return {
-				tabList: [{name:'待使用',status:1}, {name:'已使用',status:2},{name:'已过期',status:3},],
+				tabList: [{
+					name: '待使用',
+					status: 1
+				}, {
+					name: '已使用',
+					status: 2
+				}, {
+					name: '已过期',
+					status: 3
+				}, ],
 				status: 1,
-				page:1,
+				page: 1,
 				itemData: [],
-				total:0,
+				total: 0,
 			};
 		},
 		onShow() {
@@ -86,48 +98,53 @@
 			this.getList();
 		},
 		methods: {
-			getList(){
-				couponMember({page:this.page,status:this.status}).then((res)=>{
-					if(res.code === 1){
-						this.itemData = [...this.itemData,...res.data.items];
+			getList() {
+				couponMember({
+					page: this.page,
+					status: this.status
+				}).then((res) => {
+					if (res.code === 1) {
+						this.itemData = [...this.itemData, ...res.data.items];
 						this.total = res.data.total;
 					}
 				})
 			},
 			tabStitle(status) {
-				if(this.status != status){
+				if (this.status != status) {
 					this.status = status
 					this.page = 1;
 					this.itemData = [];
 					this.getList();
 				}
-				
 			},
 			scrolltolower() {
-				if(this.itemData.length < this.total){
+				if (this.itemData.length < this.total) {
 					this.page += 1;
 					this.getList();
 				}
 			},
-			goToUrl(type,item) {
-				if(type == 0) {
+			goToUrl(type, item) {
+				if (type == 0) {
 					// 去使用
-					if(item.scene == 1){
+					if (item.scene == 1) {
 						// 去外卖
-					}else{
 						uni.navigateTo({
-							url:'/pages-takeout/replace-take'
+							url: `/pages-my/search-list?ticketId=` + item.id
+						})
+					} else {
+						uni.navigateTo({
+							url: '/pages-takeout/replace-take'
 						})
 					}
-				}else if(type == 1) {
+				} else if (type == 1) {
 					// 规则
 					uni.navigateTo({
-						url:'/pages-my/rule-info?id=' + item.id
+						url: '/pages-my/rule-info?id=' + item.id
 					})
-				}else {
+				} else {
 					// 领券中心
 					uni.navigateTo({
-						url:'/pages-my/ticket-centre'
+						url: '/pages-my/ticket-centre'
 					})
 				}
 			}

+ 222 - 0
pages-my/search-list.vue

@@ -0,0 +1,222 @@
+<template>
+	<view class="seacrh-record-index iPhone-bottom flex-common-css box-border-box">
+		<view class="seacrh-bg"></view>
+		<Nav title='可用商家' bgckgroundBox='transparent'></Nav>
+		<scroll-view scroll-y="true" class="scroll-view-css seacrh-info box-border-box p-24"
+			@scrolltolower="scrolltolower">
+			<view class="goos-list-box box-border-box p-24 display-flex" v-for="(item,i) in list" :key="i"
+				@click="toShop(item)">
+				<image class="left-img" :src="item.shop_logo" mode="aspectFill"></image>
+				<view class="flex-1">
+					<view class="align-items-center mb-8">
+						<view class="right-box-title fs-32 fw-600 text-overflow-ellipsis-one">{{item.shop_name}}</view>
+						<image class="right-box-title-img" src="@/static/img/toRight.png" mode=""></image>
+					</view>
+					<view class="align-items-center mb-8">
+						<image class="img-x mr-12" src="@/static/img/my/wdpj.png" mode=""></image>
+						<view class="fs-26 fw-600 fc-FF7F00 mr-12">{{item.shop_score}}分</view>
+						<view class="fc-6 fs-24 mr-12">| 预计{{item.delivery_time}}分钟 |</view>
+						<view class="fc-6 fs-24 mr-12">{{item.shop_sales}}人购买</view>
+					</view>
+					<view class="align-items-center flex-wrap-wrap">
+						<view class="quan-list display-flex mr-12 mb-12" v-for="(info1,index1) in item.coupon"
+							:key="index1">
+							<view class="quan-list-1 fs-24 fc-f">券</view>
+							<view class="quan-list-2 fs-24 fc-FB3D03">{{info1.money}}元</view>
+						</view>
+					</view>
+					<view class="goods-items-list display-flex">
+						<view class="goods-items-list-box" v-for="(info2,index2) in item.goods" :key="index2">
+							<image class="mb-12" :src="info2.goods_image" mode="aspectFill"></image>
+							<view class="mb-8 fw-600 text-overflow-ellipsis-one fs-26">{{info2.goods_name}}</view>
+							<view class="">
+								<span class="fs-24 fc-FB3D03">¥</span>
+								<span class="fs-32 fc-FB3D03 fw-b">{{info2.price}}</span>
+							</view>
+						</view>
+					</view>
+				</view>
+			</view>
+		</scroll-view>
+	</view>
+</template>
+
+<script>
+	import {
+		couponShop
+	} from '@/api/coupon.js'
+	export default {
+		data() {
+			return {
+				fromData: {
+					id: '',
+					operate_id: '',
+					page: 1,
+				},
+				list: [],
+				total: 0,
+			}
+		},
+		onLoad(e) {
+			this.fromData.operate_id = uni.getStorageSync('operate_id');
+			this.fromData.id = e.ticketId
+			this.fromData.page = 1;
+			this.list = [];
+			this.getList()
+		},
+		methods: {
+			search() {
+				this.fromData.page = 1;
+				this.list = [];
+				this.getList();
+			},
+			getList() {
+				couponShop(this.fromData).then((res) => {
+					if (res.code === 1) {
+						this.list = [...this.list, ...res.data.items];
+						this.total = res.data.total;
+					}
+				})
+			},
+			scrolltolower() {
+				if (this.list.length < this.total) {
+					this.fromData.page += 1;
+					this.getList();
+				}
+			},
+			toShop(item) {
+				uni.navigateTo({
+					url: '/pages-takeout/shop?shop_id=' + item.shop_id
+				})
+			},
+		},
+	}
+</script>
+
+<style scoped lang="scss">
+	.seacrh-record-index {
+		position: relative;
+
+
+
+		.seacrh-bg {
+			position: absolute;
+			top: 0;
+			left: 0;
+			width: 100%;
+			height: 376rpx;
+			filter: blur(80rpx);
+			background-image: linear-gradient(to right, #C9F7FC, #F9F6E0, #F6F5F3);
+			z-index: -1;
+		}
+
+		.s-input {
+			margin-top: 24rpx;
+			width: 100%;
+			height: 72rpx;
+			padding: 0 24rpx;
+			box-sizing: border-box;
+			position: relative;
+
+			.input-icon {
+				position: absolute;
+				left: 48rpx;
+				top: 20rpx;
+			}
+
+			input {
+				font-size: 32rpx;
+				width: 100%;
+				height: 72rpx;
+				background: #FFFFFF;
+				border-radius: 200rpx;
+				box-sizing: border-box;
+				padding: 0 126rpx 0 78rpx;
+			}
+
+			.input-buttom {
+				width: 120rpx;
+				height: 60rpx;
+				background: linear-gradient(90deg, #57CAFF 0%, #41ABF5 100%);
+				border-radius: 200rpx;
+				text-align: center;
+				line-height: 60rpx;
+				position: absolute;
+				right: 30rpx;
+				top: 6rpx;
+			}
+		}
+
+		.seacrh-info {
+			margin-top: 20rpx;
+			// border-radius: 24rpx 24rpx 0rpx 0rpx;
+		}
+
+
+		.goos-list-box {
+			width: 100%;
+			min-height: 100rpx;
+			background: #FFFFFF;
+			box-shadow: 0rpx 0rpx 20rpx 0rpx rgba(51, 51, 51, 0.1);
+			border-radius: 20rpx;
+			margin-bottom: 20rpx;
+
+			.goods-items-list {
+				width: 530rpx;
+				overflow-y: scroll;
+
+				.goods-items-list-box {
+					width: 140rpx;
+					margin-right: 16rpx;
+
+					image {
+						width: 140rpx;
+						height: 140rpx;
+						border-radius: 12rpx
+					}
+				}
+			}
+
+			.left-img {
+				width: 100rpx;
+				height: 100rpx;
+				border-radius: 12rpx;
+				margin-right: 16rpx;
+			}
+
+			.img-x {
+				width: 24rpx;
+				height: 24rpx;
+			}
+
+			.right-box-title {
+				width: 438rpx;
+			}
+
+			.right-box-title-img {
+				width: 32rpx;
+				height: 32rpx;
+				margin-left: auto;
+			}
+
+			.quan-list {
+				.quan-list-1 {
+					width: 32rpx;
+					height: 34rpx;
+					background: #FB3D03;
+					border-radius: 5rpx 0rpx 0rpx 5rpx;
+					text-align: center;
+				}
+
+				.quan-list-2 {
+					box-sizing: border-box;
+					padding: 0 2rpx;
+					height: 34rpx;
+					border-radius: 0 5rpx 5rpx 0;
+					border: 1rpx solid #FB3D03;
+					text-align: center;
+				}
+			}
+		}
+	}
+</style>

+ 1 - 1
pages-my/ticket-centre.vue

@@ -158,7 +158,7 @@
 
 	.ball-two {
 		width: 24rpx;
-		height: 24rpx;
+		height: 24rpx; 
 		border-radius: 50%;
 		position: absolute;
 		background: #F5F5F5;

+ 56 - 7
pages-order/express-info.vue

@@ -31,14 +31,14 @@
 							去支付
 						</view>
 					</view>
-					<view class="w-33 flex-direction align-items-center"
+<!-- 					<view @click="setAddress" class="w-33 flex-direction align-items-center"
 						v-show="infoData.order_status == 1 || infoData.order_status == 2">
 						<image class="mb-4 icon" src="@/static/img/order/xgdd.png" mode=""></image>
 						<view class="fs-24 fc-3">
-							修改订单信息
+							修改收货地址
 						</view>
-					</view>
-					<view class="w-33 flex-direction align-items-center"
+					</view> -->
+					<view @click="goToUrl" class="w-33 flex-direction align-items-center"
 						v-show="infoData.order_status == 4 || infoData.order_status == 6">
 						<image class="mb-4 icon" src="@/static/img/order/zlyd.png" mode=""></image>
 						<view class="fs-24 fc-41ABF5">
@@ -46,6 +46,7 @@
 						</view>
 					</view>
 					<view class="w-33 flex-direction align-items-center">
+						<button class="item-box-button" open-type="contact" :bindcontact="handleContact"></button>
 						<image class="mb-4 icon" src="@/static/img/order/lxkf.png" mode=""></image>
 						<view class="fs-24 fc-3">
 							联系客服
@@ -200,20 +201,25 @@
 				</view>
 			</view>
 		</scroll-view>
+		<SelectAddress ref="selectAddress" @giveAddress='giveAddress'></SelectAddress>
 	</view>
 </template>
 
 <script>
 	import {
 		expressOrderInfo,
-		expressOrderCancel
+		expressOrderCancel,
+		expressOrderAddress
 	} from "@/api/expressOrder.js"
 	import {
 		getExpressPay
 	} from "@/api/express.js"
 	import tools from "@/service/tools";
+	import SelectAddress from "./module/select-address.vue";
 	export default {
-		components: {},
+		components: {
+			SelectAddress
+		},
 		data() {
 			return {
 				goodsData: [{
@@ -229,7 +235,8 @@
 					m: '',
 					s: '',
 				},
-				isAJAX: false
+				isAJAX: false,
+				address_id: ''
 			};
 		},
 		onLoad(data) {
@@ -240,6 +247,32 @@
 		},
 		mounted() {},
 		methods: {
+			goToUrl() {
+				// 再来一单
+				uni.navigateTo({
+					url: '/pages-takeout/replace-take'
+				})
+			},
+			setAddress() {
+				this.$refs.selectAddress.getList();
+			},
+			giveAddress(e) {
+				this.address_id = e;
+				this.expressOrderAddress()
+			},
+			expressOrderAddress() {
+				expressOrderAddress({
+					order_id: this.infoData.id,
+					address_id: this.address_id
+				}).then((res) => {
+					if (res.code == 1) {
+						tools.success(res.msg)
+						this.expressOrderInfo(this.infoData.id)
+					} else {
+						tools.error(res.msg)
+					}
+				})
+			},
 			pay() {
 				this.getExpressPay(this.infoData.id)
 			},
@@ -350,6 +383,22 @@
 
 	.w-33 {
 		width: 33%;
+		position: relative;
+	}
+
+	.item-box-button {
+		position: absolute;
+		width: 100%;
+		height: 88rpx;
+		top: 0;
+		left: 0;
+		z-index: 100;
+		background-color: transparent;
+		border: none !important;
+	}
+
+	button::after {
+		border: none !important;
 	}
 
 	.p-24-24-0 {

+ 32 - 14
pages-order/group-info.vue

@@ -24,25 +24,22 @@
 					感谢你对君子校园的信任,期待你再次光临
 				</view>
 				<view class="align-items-center flex-wrap-wrap">
-					<view @click="pay" class="w-33 flex-direction align-items-center" v-show="infoData.order_status == 1">
+					<view @click="pay" class="w-33 flex-direction align-items-center"
+						v-show="infoData.order_status == 1">
 						<image class="mb-4 icon" src="@/static/img/order/qzf.png" mode=""></image>
 						<view class="fs-24 fc-41ABF5">
 							去支付
 						</view>
 					</view>
-					<view class="w-33 flex-direction align-items-center" v-show="infoData.order_status == 1 || infoData.order_status == 2">
-						<image class="mb-4 icon" src="@/static/img/order/xgdd.png" mode=""></image>
-						<view class="fs-24 fc-3">
-							修改订单信息
-						</view>
-					</view>
-					<view class="w-33 flex-direction align-items-center" v-show="infoData.order_status == 4 || infoData.order_status == 6">
+					<view @click="goToUrl" class="w-33 flex-direction align-items-center"
+						v-show="infoData.order_status == 4 || infoData.order_status == 6">
 						<image class="mb-4 icon" src="@/static/img/order/zlyd.png" mode=""></image>
 						<view class="fs-24 fc-41ABF5">
 							再来一单
 						</view>
 					</view>
 					<view class="w-33 flex-direction align-items-center">
+						<button class="item-box-button" open-type="contact" :bindcontact="handleContact"></button>
 						<image class="mb-4 icon" src="@/static/img/order/lxkf.png" mode=""></image>
 						<view class="fs-24 fc-3">
 							联系客服
@@ -53,7 +50,7 @@
 		</view>
 		<scroll-view :scroll-y="true" class="scroll-view-css p-24 box-border-box" @scrolltolower="scrolltolower">
 			<view class="bgc-f b-rad-20 p-24 box-border-box mb-20">
-<!-- 				<view class="w-420 fc-3 fs-32 fw-600 text-overflow-ellipsis-one mb-24">
+				<!-- 				<view class="w-420 fc-3 fs-32 fw-600 text-overflow-ellipsis-one mb-24">
 					{{infoData.site_name}}
 				</view> -->
 				<view class="goods-box">
@@ -68,7 +65,7 @@
 									¥{{infoData.goods_price}}
 								</view>
 							</view>
-			<!-- 				<view class="mb-2 fs-24 fc-9">
+							<!-- 				<view class="mb-2 fs-24 fc-9">
 								{{item.goods_name}}
 							</view> -->
 							<view class="fs-24 fc-9">
@@ -77,7 +74,7 @@
 						</view>
 					</view>
 				</view>
-<!-- 				<view class="align-items-center flex-justify-space mb-24">
+				<!-- 				<view class="align-items-center flex-justify-space mb-24">
 					<view class="fs-28 fc-3">
 						打包费
 					</view>
@@ -93,7 +90,7 @@
 						打包费
 					</view>
 				</view> -->
-<!-- 				<view class="align-items-center flex-justify-space pb-36 b-b-F9F9F9 mb-22">
+				<!-- 				<view class="align-items-center flex-justify-space pb-36 b-b-F9F9F9 mb-22">
 					<view class="align-items-center">
 						<image class="mr-6 icon-right" src="@/static/img/order/yhq.png" mode=""></image>
 						<view class="fs-28 fc-3">
@@ -128,7 +125,7 @@
 						{{infoData.address}}
 					</view>
 				</view>
-<!-- 				<view class="display-flex flex-justify-space mb-26">
+				<!-- 				<view class="display-flex flex-justify-space mb-26">
 					<view class="fs-28 fc-9">
 						配送时间
 					</view>
@@ -136,7 +133,7 @@
 						预约配送
 					</view>
 				</view> -->
-<!-- 				<view class="display-flex flex-justify-space pb-20 b-b-F9F9F9 mb-26" v-show="infoData.order_status == 3">
+				<!-- 				<view class="display-flex flex-justify-space pb-20 b-b-F9F9F9 mb-26" v-show="infoData.order_status == 3">
 					<view class="fs-28 fc-9">
 						骑手信息
 					</view>
@@ -218,6 +215,11 @@
 		},
 		mounted() {},
 		methods: {
+			goToUrl() {
+				uni.navigateTo({
+					url: '/pages-buy/group'
+				})
+			},
 			pay() {
 				this.groupPay(this.infoData.id)
 			},
@@ -312,6 +314,7 @@
 
 	.w-33 {
 		width: 33%;
+		position: relative;
 	}
 
 	.p-24-24-0 {
@@ -337,6 +340,21 @@
 		width: 300rpx;
 	}
 
+	.item-box-button {
+		position: absolute;
+		width: 100%;
+		height: 88rpx;
+		top: 0;
+		left: 0;
+		z-index: 100;
+		background-color: transparent;
+		border: none !important;
+	}
+
+	button::after {
+		border: none !important;
+	}
+
 	.icon-right {
 		width: 32rpx;
 		height: 32rpx;

+ 108 - 81
pages-order/laundry-info.vue

@@ -5,7 +5,7 @@
 		<view class="p-24-24-0 box-border-box">
 			<view class="mb-24" v-show="infoData.order_status == 1">
 				<view class="fs-40 fc-3 mb-8">
-					{{infoData.order_status_str}},剩余{{time}}
+					{{infoData.order_status_str}},剩余{{time.m}}:{{time.s}}
 				</view>
 				<view class="fs-24 fc-FB3D03">
 					10分钟内未支付,订单将自动取消
@@ -24,31 +24,29 @@
 					感谢你对君子校园的信任,期待你再次光临
 				</view>
 				<view class="align-items-center flex-wrap-wrap">
-					<view class="w-33 flex-direction align-items-center" v-show="infoData.order_status == 1">
+					<view class="w-33 flex-direction align-items-center" @click="pay"
+						v-show="infoData.order_status == 1">
 						<image class="mb-4 icon" src="@/static/img/order/qzf.png" mode=""></image>
 						<view class="fs-24 fc-41ABF5">
 							去支付
 						</view>
 					</view>
-					<view class="w-33 flex-direction align-items-center" v-show="infoData.order_status == 1 || infoData.order_status == 2">
-						<image class="mb-4 icon" src="@/static/img/order/xgdd.png" mode=""></image>
-						<view class="fs-24 fc-3">
-							修改订单信息
-						</view>
-					</view>
-					<view class="w-33 flex-direction align-items-center" v-show="infoData.order_status == 4 || infoData.order_status == 6">
+					<view @click="goToUrl" class="w-33 flex-direction align-items-center"
+						v-show="infoData.order_status == 4 || infoData.order_status == 6">
 						<image class="mb-4 icon" src="@/static/img/order/zlyd.png" mode=""></image>
 						<view class="fs-24 fc-41ABF5">
 							再来一单
 						</view>
 					</view>
 					<view class="w-33 flex-direction align-items-center">
+						<button class="item-box-button" open-type="contact" :bindcontact="handleContact"></button>
 						<image class="mb-4 icon" src="@/static/img/order/lxkf.png" mode=""></image>
 						<view class="fs-24 fc-3">
 							联系客服
 						</view>
 					</view>
-					<view class="w-33 flex-direction align-items-center" v-show="infoData.order_status == 2" @click="cancelOrder">
+					<view class="w-33 flex-direction align-items-center" v-show="infoData.order_status == 2"
+						@click="cancelOrder">
 						<image class="mb-4 icon" src="@/static/img/order/qxdd.png" mode=""></image>
 						<view class="fs-24 fc-3">
 							取消订单
@@ -74,9 +72,6 @@
 									¥{{item.goods_money}}
 								</view>
 							</view>
-			<!-- 				<view class="mb-2 fs-24 fc-9">
-								{{item.goods_name}}
-							</view> -->
 							<view class="fs-24 fc-9">
 								x{{item.goods_num}}
 							</view>
@@ -91,33 +86,6 @@
 					<image v-if="goodsShow" class="icon-right" src="@/static/img/order/top.png" mode=""></image>
 					<image v-else class="icon-right" src="@/static/img/order/bottom.png" mode=""></image>
 				</view>
-<!-- 				<view class="align-items-center flex-justify-space mb-24">
-					<view class="fs-28 fc-3">
-						打包费
-					</view>
-					<view class="fs-32 fc-3">
-						打包费
-					</view>
-				</view>
-				<view class="align-items-center flex-justify-space mb-24">
-					<view class="fs-28 fc-3">
-						配送费
-					</view>
-					<view class="fs-32 fc-3">
-						打包费
-					</view>
-				</view> -->
-<!-- 				<view class="align-items-center flex-justify-space pb-36 b-b-F9F9F9 mb-22">
-					<view class="align-items-center">
-						<image class="mr-6 icon-right" src="@/static/img/order/yhq.png" mode=""></image>
-						<view class="fs-28 fc-3">
-							优惠券
-						</view>
-					</view>
-					<view class="fs-32 fc-FB3D03">
-						-¥{{infoData.coupon_money}}
-					</view>
-				</view> -->
 				<view class="align-items-center flex-justify-end">
 					<view class="fs-28 fc-9">
 						共{{infoData.goods_number}}件,
@@ -134,30 +102,6 @@
 				</view>
 			</view>
 			<view class="bgc-f b-rad-20 p-24 box-border-box mb-20">
-<!-- 				<view class="display-flex flex-justify-space mb-26">
-					<view class="fs-28 fc-9">
-						配送地址
-					</view>
-					<view class="fs-28 fc-3 w-480 text-align-right">
-						{{infoData.school_name}}{{infoData.dorm_name}}{{infoData.address}}{{infoData.consignee}}{{infoData.consignee_tel}}
-					</view>
-				</view> -->
-<!-- 				<view class="display-flex flex-justify-space mb-26">
-					<view class="fs-28 fc-9">
-						配送时间
-					</view>
-					<view class="fs-28 fc-3 w-480 text-align-right">
-						预约配送
-					</view>
-				</view> -->
-<!-- 				<view class="display-flex flex-justify-space pb-20 b-b-F9F9F9 mb-26" v-show="infoData.order_status == 3">
-					<view class="fs-28 fc-9">
-						骑手信息
-					</view>
-					<view class="fs-28 fc-3 w-480 text-align-right">
-						{{infoData.rider.rider_name}}{{infoData.rider.phone}}
-					</view>
-				</view> -->
 				<view class="display-flex flex-justify-space mb-26">
 					<view class="fs-28 fc-9">
 						订单编号
@@ -201,7 +145,8 @@
 <script>
 	import {
 		laundryOrderInfo,
-		laundryOrderCancel
+		laundryOrderCancel,
+		laundryPay
 	} from "@/api/laundryOrder.js"
 	export default {
 		components: {},
@@ -214,7 +159,13 @@
 				}],
 				goodsShow: true,
 				infoData: {},
-				time: ''
+				time: {
+					day: '',
+					h: "",
+					m: '',
+					s: '',
+				},
+				isAJAX: false
 			};
 		},
 		onLoad(data) {
@@ -225,13 +176,52 @@
 		},
 		mounted() {},
 		methods: {
+			goToUrl() {
+				uni.navigateTo({
+					url:'/pages-buy/dry-clean'
+				})
+			},
+			pay() {
+				this.getExpressPay(this.infoData.id)
+			},
+			getExpressPay(id) {
+				// 干洗支付
+				getExpressPay({
+					order_id: id
+				}).then((ret) => {
+					if (ret.code === 1) {
+						uni.requestPayment({
+							provider: "wxpay", //支付类型-固定值
+							timeStamp: ret.data.wx_pay.timeStamp + "", // 时间戳(单位:秒)
+							nonceStr: ret.data.wx_pay.nonceStr, // 随机字符串
+							package: ret.data.wx_pay.package, // 固定值
+							signType: ret.data.wx_pay.signType, //固定值
+							paySign: ret.data.wx_pay.paySign, //签名
+							success: (ren) => {
+								tools.success("支付成功");
+								this.isAJAX = false;
+								this.laundryOrderInfo(this.infoData.id)
+							},
+							fail: (err) => {
+								this.isAJAX = false;
+								tools.error("支付失败");
+							},
+						});
+					} else {
+						this.isAJAX = false;
+						tools.error("支付失败");
+					}
+				})
+			},
 			cancelOrder() {
-				// 代取取消订单
-				laundryOrderCancel({order_id: infoData.id}).then((res) => {
-					if(res.code == 1) {
+				// 干洗取消订单
+				laundryOrderCancel({
+					order_id: infoData.id
+				}).then((res) => {
+					if (res.code == 1) {
 						tools.success(res.msg)
 						this.laundryOrderInfo(infoData.id)
-					}else {
+					} else {
 						tools.error(res.msg)
 					}
 				})
@@ -249,20 +239,41 @@
 					if (res.code == 1) {
 						this.infoData = res.data
 						if (this.infoData.order_status == 1) {
-							setInterval(() => {
-								let currentDate = new Date(); //获取当前时间
-								let createDate = new Date(res.data.created_at); //格式化订单创建时候的时间
-								createDate.setMinutes(createDate.getMinutes() + 10)
-								let disDate = (currentDate - createDate) / 1000; //计算相隔分钟
-								let m = parseInt(disDate / 60 % 60)
-								m = m < 10 ? "0" + m : m
-								let s = parseInt(disDate % 60)
-								s = s < 10 ? "0" + s : s
-								this.time = m + ":" + s
-							}, 1000)
+							let createDate = new Date(res.data.created_at); //格式化订单创建时候的时间
+							createDate.setMinutes(createDate.getMinutes() + 10)
+							this.setCountDown(createDate)
 						}
 					}
 				})
+			},
+			setCountDown(sTime) {
+				let end = new Date(sTime).getTime();
+				let now = new Date().getTime();
+				let msec = end - now;
+				this.time.day = parseInt(msec / 1000 / 60 / 60 / 24);
+				let h = parseInt(msec / 1000 / 60 / 60 % 24);
+				let m = parseInt(msec / 1000 / 60 % 60);
+				let s = parseInt(msec / 1000 % 60);
+				this.time.h = h > 9 ? h : '0' + h;
+				this.time.m = m > 9 ? m : '0' + m;
+				this.time.s = s > 9 ? s : '0' + s;
+				msec -= 1000;
+				if (this.time.day >= 1) {
+					this.showTime = true;
+				} else {
+					this.showTime = false;
+				};
+				if (msec >= 0) {
+					setTimeout(() => {
+						this.setCountDown(sTime);
+					}, 1000);
+				} else {
+					this.isTimeEnd = true;
+					this.bText = '活动结束';
+					this.time.h = '--';
+					this.time.m = '--';
+					this.time.s = '--';
+				};
 			}
 		},
 	}
@@ -280,6 +291,22 @@
 
 	.w-33 {
 		width: 33%;
+		position: relative;
+	}
+
+	.item-box-button {
+		position: absolute;
+		width: 100%;
+		height: 88rpx;
+		top: 0;
+		left: 0;
+		z-index: 100;
+		background-color: transparent;
+		border: none !important;
+	}
+
+	button::after {
+		border: none !important;
 	}
 
 	.p-24-24-0 {

+ 155 - 0
pages-order/module/select-address.vue

@@ -0,0 +1,155 @@
+<template>
+	<view>
+		<uni-popup ref="popupAddress" type="bottom">
+			<view class="pop-address box-border-box p-24">
+				<view class="text-align-center fs-36 fw-600 box-title mb-32">
+					选择收货地址
+					<uni-icons @click="closeCoupon" class="box-close" type="closeempty" size="20"></uni-icons>
+				</view>
+				
+				
+				<view v-if="list.length === 0" class="scroll-view-css">
+					<EnBlank :customSrc='true'>
+						<template v-slot:blankImg>
+							<image class="black-custom-img" src="@/static/img/common/no-order.png" mode=""></image>
+						</template>
+					</EnBlank>
+				</view>
+				
+				<view v-else class="scroll-view-css">
+					<view class="item-box flex-justify-space align-items-center mb-20" v-for="(item,index) in list" :key="index" @click.stop="select(item)">
+						<image v-if="id==item.id" class="s-icon" src="@/static/img/common/y-select.png" mode=""></image>
+						<image v-else class="s-icon"src="@/static/img/common/n-select.png" mode=""></image>
+						
+						
+						<view class="">
+							<view class="fs-34 fw-600 w556 mb-12">
+								<span v-if="item.is_default == 1" class="list-box-only fs-24 fc-FE9E11 text-align-center mr-8">默认</span>
+								{{item.address}}{{item.school_name}}{{item.dorm_name}}
+							</view>
+							<view class="p-b-20">
+								<span class="mr-24 fs-28 fc-9">{{item.consignee}}</span><span class="fs-28 fc-9">{{item.phone}}</span>
+							</view>
+						</view>
+						
+						<image class="edit-img" src="@/static/img/common/edit.png" mode="" @click.stop="toEdit(1,item)"></image>
+					</view>
+				</view>
+				
+				<view class="box-border-box p-24 bgc-f" @click="toEdit(2)">
+					<view class="add-box text-align-center fs-34 fc-f">新增地址</view>
+				</view>
+			</view>
+			
+			
+		</uni-popup>
+	</view>
+</template>
+
+<script>
+	import {getAddressList} from '@/api/member.js'
+	import EnBlank from "@/components/en-utils/en-blank/en-blank";
+	import tools from "@/service/tools.js";
+	
+	export default {
+		components:{EnBlank,},
+		data(){
+			return{
+				id:'',
+				list:[],
+			}
+		},
+		onShow() {
+			this.list = [];
+			getAddressList().then((res)=>{
+				if(res.code === 1){
+					this.list = res.data;
+				}
+			})
+		},
+		methods:{
+			getList(){
+				getAddressList().then((res)=>{
+					if(res.code === 1){
+						this.list = res.data;
+						this.openPop();
+					}
+				})
+			},
+			select(item){
+				if(item.id != this.id){
+					this.$emit('giveAddress',item);
+					this.closeCoupon();
+				}
+			},
+			openPop(){
+				this.$refs.popupAddress.open();
+			},
+			closeCoupon(){
+				this.list = [];
+				this.$refs.popupAddress.close();
+			},
+			toEdit(type,item){
+				if(type === 1){
+					uni.navigateTo({
+						url:"pages-address/edit-add?id=" + item.id
+					})
+				}else{
+					uni.navigateTo({
+						url:"pages-address/edit-add"
+					})
+				}
+			},
+		},
+	}
+</script>
+
+<style scoped lang="scss">
+	.add-box{
+		width: 100%;
+		height: 80rpx;
+		line-height: 80rpx;
+		background-color: #2F80ED;
+		border-radius: 200rpx;
+		
+	}
+	.w556{
+		width: 556rpx;
+	}
+	.list-box-only{
+		width: 64rpx;
+		height: 34rpx;
+		line-height: 34rpx;
+		border-radius: 8rpx;
+		border: 2rpx solid #FE9E11;
+	}
+	
+	.item-box{
+		border-bottom: 1rpx solid #f9f9f9;
+		.s-icon{
+			width: 32rpx;
+			height: 32rpx;
+		}
+		.edit-img{
+			width: 48rpx;
+			height: 48rpx;
+		}
+	}
+	
+	.pop-address{
+		width: 100%;
+		height: 50vh;
+		background-color: #fff;
+		border-radius: 24rpx 24rpx 0rpx 0rpx;
+		padding-top: 32rpx !important;
+		display: flex;
+		flex-direction: column;
+		.box-title{
+			position: relative;
+			.box-close{
+				position: absolute;
+				right: 22rpx;
+			}
+		}
+	}
+</style>

+ 451 - 0
pages-order/takeout-info.vue

@@ -0,0 +1,451 @@
+<template>
+	<view class="flex-common-css">
+		<Nav title=" " leftIconColor="#333" titleColor="#333" bgckgroundBox='transparent'></Nav>
+		<image class="bg-img" src="@/static/img/order/bg.png" mode=""></image>
+		<view class="p-24-24-0 box-border-box">
+			<view class="mb-24" v-if="infoData.order_status == 1">
+				<view class="fs-40 fc-3 mb-8">
+					{{infoData.order_status_str}},剩余{{time.m}}:{{time.s}}
+				</view>
+				<view class="fs-24 fc-FB3D03">
+					10分钟内未支付,订单将自动取消
+				</view>
+			</view>
+			<view class="mb-24" v-else>
+				<view class="fs-48 fc-3 fw-600">
+					{{infoData.order_status_str}}
+				</view>
+			</view>
+			<view class="bgc-f b-rad-20 p-24 box-border-box">
+				<view class="p-b-20 mb-24 b-b-F9F9F9 fs-32 fc-3" v-show="infoData.order_status == 1">
+					请尽快支付
+				</view>
+				<view class="p-b-20 mb-24 b-b-F9F9F9 fs-32 fc-3" v-show="infoData.order_status == 3 || infoData.order_status == 7 || infoData.order_status == 8 || infoData.order_status == 9 || infoData.order_status == 10">
+					感谢你对君子校园的信任,期待你再次光临
+				</view>
+				<view class="align-items-center flex-wrap-wrap">
+					<view class="w-33 flex-direction align-items-center" @click="pay"
+						v-show="infoData.order_status == 1">
+						<image class="mb-4 icon" src="@/static/img/order/qzf.png" mode=""></image>
+						<view class="fs-24 fc-41ABF5">
+							去支付
+						</view>
+					</view>
+					<!-- 					<view @click="setAddress" class="w-33 flex-direction align-items-center"
+						v-show="infoData.order_status == 1 || infoData.order_status == 2">
+						<image class="mb-4 icon" src="@/static/img/order/xgdd.png" mode=""></image>
+						<view class="fs-24 fc-3">
+							修改收货地址
+						</view>
+					</view> -->
+					<view @click="goToUrl" class="w-33 flex-direction align-items-center"
+						v-show="infoData.order_status == 3 || infoData.order_status == 7 || infoData.order_status == 8 || infoData.order_status == 9 || infoData.order_status == 10">
+						<image class="mb-4 icon" src="@/static/img/order/zlyd.png" mode=""></image>
+						<view class="fs-24 fc-41ABF5">
+							再来一单
+						</view>
+					</view>
+					<view class="w-33 flex-direction align-items-center">
+						<button class="item-box-button" open-type="contact" :bindcontact="handleContact"></button>
+						<image class="mb-4 icon" src="@/static/img/order/lxkf.png" mode=""></image>
+						<view class="fs-24 fc-3">
+							联系客服
+						</view>
+					</view>
+					<view class="w-33 flex-direction align-items-center" v-show="infoData.order_status == 2 || infoData.order_status == 4"
+						@click="cancelOrder">
+						<image class="mb-4 icon" src="@/static/img/order/qxdd.png" mode=""></image>
+						<view class="fs-24 fc-3">
+							取消订单
+						</view>
+					</view>
+				</view>
+			</view>
+		</view>
+		<scroll-view :scroll-y="true" class="scroll-view-css p-24 box-border-box" @scrolltolower="scrolltolower">
+			<view class="bgc-f b-rad-20 p-24 box-border-box mb-20">
+				<view class="w-420 fc-3 fs-32 fw-600 text-overflow-ellipsis-one mb-24">
+					{{infoData.shop_name}}
+				</view>
+				<view class="goods-box" :class="infoData.item.length >= 4 && goodsShow?'goodsShowOne':'goodsShowTwo'">
+					<view class="align-items-center flex-justify-space mb-20" v-for="(item,index) in infoData.item">
+						<image class="goods-img mr-16" :src="item.goods_image" mode="aspectFit"></image>
+						<view class="">
+							<view class="align-items-center flex-justify-space mb-2">
+								<view class="fs-28 fc-3 w-376 text-overflow-ellipsis-one mr-36">
+									{{item.goods_name}}
+								</view>
+								<view class="fs-32 fc-3 fw-600">
+									¥{{item.goods_price}}
+								</view>
+							</view>
+							<view class="mb-2 fs-24 fc-9">
+								{{item.goods_attr}}
+							</view>
+							<view class="fs-24 fc-9">
+								x{{item.goods_number}}
+							</view>
+						</view>
+					</view>
+				</view>
+				<view class="align-items-center flex-justify-center p-24 b-b-F9F9F9 mb-32" @click="openGoods"
+					v-if="infoData.item.length > 4">
+					<view class="fs-24 fc-9 mr-4">
+						{{goodsShow?'展开':'收起'}}{{infoData.item.length - 4}}件商品
+					</view>
+					<image v-if="goodsShow" class="icon-right" src="@/static/img/order/top.png" mode=""></image>
+					<image v-else class="icon-right" src="@/static/img/order/bottom.png" mode=""></image>
+				</view>
+				<view class="align-items-center flex-justify-space mb-24">
+					<view class="fs-28 fc-3">
+						打包费
+					</view>
+					<view class="fs-32 fc-3">
+						{{infoData.pack_price}}
+					</view>
+				</view>
+				<view class="align-items-center flex-justify-space mb-24">
+					<view class="fs-28 fc-3">
+						配送费
+					</view>
+					<view class="fs-32 fc-3">
+						{{infoData.delivery_money}}
+					</view>
+				</view>
+				<view class="align-items-center flex-justify-space pb-36 b-b-F9F9F9 mb-22">
+					<view class="align-items-center">
+						<image class="mr-6 icon-right" src="@/static/img/order/yhq.png" mode=""></image>
+						<view class="fs-28 fc-3">
+							优惠券
+						</view>
+					</view>
+					<view class="fs-32 fc-FB3D03">
+						-¥{{infoData.coupon_money}}
+					</view>
+				</view>
+				<view class="align-items-center flex-justify-end">
+					<view class="fs-28 fc-9">
+						共{{infoData.goods_number}}件,
+					</view>
+					<view class="fs-28 fc-3">
+						金额
+					</view>
+					<view class="fs-24 fw-600 fc-3">
+						¥
+					</view>
+					<view class="fs-36  fw-600 fc-3">
+						{{infoData.pay_money}}
+					</view>
+				</view>
+			</view>
+			<view class="bgc-f b-rad-20 p-24 box-border-box mb-20">
+				<view class="display-flex flex-justify-space mb-26">
+					<view class="fs-28 fc-9">
+						配送地址
+					</view>
+					<view class="fs-28 fc-3 w-480 text-align-right">
+						{{infoData.school_name}}{{infoData.dorm_name}}{{infoData.address}}{{infoData.consignee}}{{infoData.consignee_tel}}
+					</view>
+				</view>
+				<view class="display-flex flex-justify-space mb-26">
+					<view class="fs-28 fc-9">
+						配送时间
+					</view>
+					<view class="fs-28 fc-3 w-480 text-align-right">
+						{{infoData.time}}
+					</view>
+				</view>
+				<view class="display-flex flex-justify-space pb-20 b-b-F9F9F9 mb-26"
+					v-show="infoData.order_status == 6">
+					<view class="fs-28 fc-9">
+						骑手信息
+					</view>
+					<view class="fs-28 fc-3 w-480 text-align-right">
+						{{infoData.rider.rider_name}}{{infoData.rider.phone}}
+					</view>
+				</view>
+				<view class="display-flex flex-justify-space mb-26">
+					<view class="fs-28 fc-9">
+						订单编号
+					</view>
+					<view class="align-items-center flex-justify-end">
+						<view class="fs-28 fc-3 w-480 mr-8 text-align-right">
+							{{infoData.order_sn}}
+						</view>
+						<image class="icon-fz" src="@/static/img/order/fz.png" mode=""></image>
+					</view>
+				</view>
+				<view class="display-flex flex-justify-space mb-26">
+					<view class="fs-28 fc-9">
+						下单时间
+					</view>
+					<view class="fs-28 fc-3 w-480 text-align-right">
+						{{infoData.created_at}}
+					</view>
+				</view>
+				<view class="display-flex flex-justify-space mb-26">
+					<view class="fs-28 fc-9">
+						支付方式
+					</view>
+					<view class="fs-28 fc-3 w-480 text-align-right">
+						{{infoData.pay_type_str}}
+					</view>
+				</view>
+				<view class="display-flex flex-justify-space mb-26">
+					<view class="fs-28 fc-9">
+						备注
+					</view>
+					<view class="fs-28 fc-3 w-480 text-align-right">
+						{{infoData.note?infoData.note:'无'}}
+					</view>
+				</view>
+			</view>
+		</scroll-view>
+		<SelectAddress ref="selectAddress" @giveAddress='giveAddress'></SelectAddress>
+	</view>
+</template>
+
+<script>
+	import {
+		orderInfo,
+		orderCancel,
+		orderPay
+	} from "@/api/order.js"
+	import tools from "@/service/tools";
+	import SelectAddress from "./module/select-address.vue";
+	export default {
+		components: {
+			SelectAddress
+		},
+		data() {
+			return {
+				goodsData: [{
+					name: '1'
+				}, {
+					name: '2'
+				}],
+				goodsShow: true,
+				infoData: {},
+				time: {
+					day: '',
+					h: "",
+					m: '',
+					s: '',
+				},
+				isAJAX: false,
+				address_id: ''
+			};
+		},
+		onLoad(data) {
+			if (data) {
+				console.log(data);
+				this.orderInfo(data.orderId)
+			}
+		},
+		mounted() {},
+		methods: {
+			goToUrl() {
+				// 再来一单
+				uni.navigateTo({
+					url: '/pages-takeout/takeout'
+				})
+			},
+			setAddress() {
+				this.$refs.selectAddress.getList();
+			},
+			giveAddress(e) {
+				this.address_id = e;
+				this.expressOrderAddress()
+			},
+			expressOrderAddress() {
+				expressOrderAddress({
+					order_id: this.infoData.id,
+					address_id: this.address_id
+				}).then((res) => {
+					if (res.code == 1) {
+						tools.success(res.msg)
+						this.orderInfo(this.infoData.id)
+					} else {
+						tools.error(res.msg)
+					}
+				})
+			},
+			pay() {
+				this.orderPay(this.infoData.id)
+			},
+			orderPay(id) {
+				// 支付
+				orderPay({
+					order_id: id
+				}).then((ret) => {
+					if (ret.code === 1) {
+						uni.requestPayment({
+							provider: "wxpay", //支付类型-固定值
+							timeStamp: ret.data.wx_pay.timeStamp + "", // 时间戳(单位:秒)
+							nonceStr: ret.data.wx_pay.nonceStr, // 随机字符串
+							package: ret.data.wx_pay.package, // 固定值
+							signType: ret.data.wx_pay.signType, //固定值
+							paySign: ret.data.wx_pay.paySign, //签名
+							success: (ren) => {
+								tools.success("支付成功");
+								this.isAJAX = false;
+								this.orderInfo(this.infoData.id)
+							},
+							fail: (err) => {
+								this.isAJAX = false;
+								tools.error("支付失败");
+							},
+						});
+					} else {
+						this.isAJAX = false;
+						tools.error("支付失败");
+					}
+				})
+			},
+			cancelOrder() {
+				// 代取取消订单
+				orderCancel({
+					order_id: infoData.id
+				}).then((res) => {
+					if (res.code == 1) {
+						tools.success(res.msg)
+						this.orderInfo(this.infoData.id)
+					} else {
+						tools.error(res.msg)
+					}
+				})
+			},
+			openGoods() {
+				this.goodsShow = !this.goodsShow
+			},
+			scrolltolower() {
+				// console.log('触底');
+			},
+			orderInfo(id) {
+				orderInfo({
+					order_id: id
+				}).then((res) => {
+					if (res.code == 1) {
+						this.infoData = res.data
+						if (this.infoData.order_status == 1) {
+							let createDate = new Date(res.data.created_at); //格式化订单创建时候的时间
+							createDate.setMinutes(createDate.getMinutes() + 10)
+							this.setCountDown(createDate)
+						}
+					}
+				})
+			},
+			setCountDown(sTime) {
+				let end = new Date(sTime).getTime();
+				let now = new Date().getTime();
+				let msec = end - now;
+				this.time.day = parseInt(msec / 1000 / 60 / 60 / 24);
+				let h = parseInt(msec / 1000 / 60 / 60 % 24);
+				let m = parseInt(msec / 1000 / 60 % 60);
+				let s = parseInt(msec / 1000 % 60);
+				this.time.h = h > 9 ? h : '0' + h;
+				this.time.m = m > 9 ? m : '0' + m;
+				this.time.s = s > 9 ? s : '0' + s;
+				msec -= 1000;
+				if (this.time.day >= 1) {
+					this.showTime = true;
+				} else {
+					this.showTime = false;
+				};
+				if (msec >= 0) {
+					setTimeout(() => {
+						this.setCountDown(sTime);
+					}, 1000);
+				} else {
+					this.isTimeEnd = true;
+					this.bText = '活动结束';
+					this.time.h = '--';
+					this.time.m = '--';
+					this.time.s = '--';
+				};
+			}
+		},
+	}
+</script>
+
+<style lang="scss" scoped>
+	.bg-img {
+		position: fixed;
+		left: 0;
+		top: 0;
+		z-index: -1;
+		width: 100%;
+		height: 320rpx;
+	}
+
+	.w-33 {
+		width: 33%;
+		position: relative;
+	}
+
+	.item-box-button {
+		position: absolute;
+		width: 100%;
+		height: 88rpx;
+		top: 0;
+		left: 0;
+		z-index: 100;
+		background-color: transparent;
+		border: none !important;
+	}
+
+	button::after {
+		border: none !important;
+	}
+
+	.p-24-24-0 {
+		padding: 24rpx 24rpx 0;
+	}
+
+	.icon {
+		width: 48rpx;
+		height: 48rpx;
+	}
+
+	.w-420 {
+		width: 420rpx;
+	}
+
+	.goods-img {
+		width: 108rpx;
+		height: 108rpx;
+		border-radius: 8rpx;
+	}
+
+	.w-376 {
+		width: 376rpx;
+	}
+
+	.icon-right {
+		width: 32rpx;
+		height: 32rpx;
+	}
+
+	.w-480 {
+		width: 480rpx;
+	}
+
+	.icon-fz {
+		width: 24rpx;
+		height: 24rpx;
+	}
+
+	.goods-box {
+		overflow: hidden;
+	}
+
+	.goodsShowOne {
+		max-height: 508rpx;
+		transition: all .5s linear;
+	}
+
+	.goodsShowTwo {
+		height: auto;
+		transition: all .5s linear;
+	}
+</style>

+ 52 - 34
pages-order/ticket-info.vue

@@ -5,7 +5,7 @@
 		<view class="p-24-24-0 box-border-box">
 			<view class="mb-24" v-show="infoData.order_status == 1">
 				<view class="fs-40 fc-3 mb-8">
-					{{infoData.order_status_str}},剩余{{time}}
+					{{infoData.order_status_str}},剩余{{time.m}}:{{time.s}}
 				</view>
 				<view class="fs-24 fc-FB3D03">
 					10分钟内未支付,订单将自动取消
@@ -24,25 +24,22 @@
 					感谢你对君子校园的信任,期待你再次光临
 				</view>
 				<view class="align-items-center flex-wrap-wrap">
-					<view @click="pay" class="w-33 flex-direction align-items-center" v-show="infoData.order_status == 1">
+					<view @click="pay" class="w-33 flex-direction align-items-center"
+						v-show="infoData.order_status == 1">
 						<image class="mb-4 icon" src="@/static/img/order/qzf.png" mode=""></image>
 						<view class="fs-24 fc-41ABF5">
 							去支付
 						</view>
 					</view>
-					<view class="w-33 flex-direction align-items-center" v-show="infoData.order_status == 1 || infoData.order_status == 2">
-						<image class="mb-4 icon" src="@/static/img/order/xgdd.png" mode=""></image>
-						<view class="fs-24 fc-3">
-							修改订单信息
-						</view>
-					</view>
-					<view class="w-33 flex-direction align-items-center" v-show="infoData.order_status == 4 || infoData.order_status == 6">
+					<view @click="goToUrl" class="w-33 flex-direction align-items-center"
+						v-show="infoData.order_status == 4 || infoData.order_status == 6">
 						<image class="mb-4 icon" src="@/static/img/order/zlyd.png" mode=""></image>
 						<view class="fs-24 fc-41ABF5">
 							再来一单
 						</view>
 					</view>
 					<view class="w-33 flex-direction align-items-center">
+						<button class="item-box-button" open-type="contact" :bindcontact="handleContact"></button>
 						<image class="mb-4 icon" src="@/static/img/order/lxkf.png" mode=""></image>
 						<view class="fs-24 fc-3">
 							联系客服
@@ -53,7 +50,7 @@
 		</view>
 		<scroll-view :scroll-y="true" class="scroll-view-css p-24 box-border-box" @scrolltolower="scrolltolower">
 			<view class="bgc-f b-rad-20 p-24 box-border-box mb-20">
-<!-- 				<view class="w-420 fc-3 fs-32 fw-600 text-overflow-ellipsis-one mb-24">
+				<!-- 				<view class="w-420 fc-3 fs-32 fw-600 text-overflow-ellipsis-one mb-24">
 					{{infoData.site_name}}
 				</view> -->
 				<view class="goods-box">
@@ -68,7 +65,7 @@
 									¥{{infoData.goods_price}}
 								</view>
 							</view>
-			<!-- 				<view class="mb-2 fs-24 fc-9">
+							<!-- 				<view class="mb-2 fs-24 fc-9">
 								{{item.goods_name}}
 							</view> -->
 							<view class="fs-24 fc-9">
@@ -77,7 +74,7 @@
 						</view>
 					</view>
 				</view>
-<!-- 				<view class="align-items-center flex-justify-space mb-24">
+				<!-- 				<view class="align-items-center flex-justify-space mb-24">
 					<view class="fs-28 fc-3">
 						打包费
 					</view>
@@ -93,7 +90,7 @@
 						打包费
 					</view>
 				</view> -->
-<!-- 				<view class="align-items-center flex-justify-space pb-36 b-b-F9F9F9 mb-22">
+				<!-- 				<view class="align-items-center flex-justify-space pb-36 b-b-F9F9F9 mb-22">
 					<view class="align-items-center">
 						<image class="mr-6 icon-right" src="@/static/img/order/yhq.png" mode=""></image>
 						<view class="fs-28 fc-3">
@@ -128,7 +125,7 @@
 						{{infoData.address}}
 					</view>
 				</view>
-<!-- 				<view class="display-flex flex-justify-space mb-26">
+				<!-- 				<view class="display-flex flex-justify-space mb-26">
 					<view class="fs-28 fc-9">
 						配送时间
 					</view>
@@ -136,7 +133,7 @@
 						预约配送
 					</view>
 				</view> -->
-<!-- 				<view class="display-flex flex-justify-space pb-20 b-b-F9F9F9 mb-26" v-show="infoData.order_status == 3">
+				<!-- 				<view class="display-flex flex-justify-space pb-20 b-b-F9F9F9 mb-26" v-show="infoData.order_status == 3">
 					<view class="fs-28 fc-9">
 						骑手信息
 					</view>
@@ -202,11 +199,11 @@
 					name: '2'
 				}],
 				infoData: {},
-				time:{
-					day:'',
-					h:"",
-					m:'',
-					s:'',
+				time: {
+					day: '',
+					h: "",
+					m: '',
+					s: '',
 				},
 			};
 		},
@@ -217,6 +214,11 @@
 		},
 		mounted() {},
 		methods: {
+			goToUrl() {
+				uni.navigateTo({
+					url: '/pages-buy/ticket'
+				})
+			},
 			pay() {
 				this.ticketPay(this.infoData.id)
 			},
@@ -260,20 +262,20 @@
 						this.infoData = res.data
 						if (this.infoData.order_status == 1) {
 							// setInterval(() => {
-								let currentDate = new Date(); //获取当前时间
-								let createDate = new Date(res.data.created_at); //格式化订单创建时候的时间
-								createDate.setMinutes(createDate.getMinutes() + 10)
-								console.log(createDate,'----------------');
-								let disDate = (currentDate - createDate) / 1000; //计算相隔分钟
-								let m = parseInt(disDate  / 60 % 60, 10);//计算剩余的分钟数
-								let s = parseInt(disDate  % 60, 10);//计算剩余的秒数
-								this.time = m + ":" + s
+							let currentDate = new Date(); //获取当前时间
+							let createDate = new Date(res.data.created_at); //格式化订单创建时候的时间
+							createDate.setMinutes(createDate.getMinutes() + 10)
+							console.log(createDate, '----------------');
+							let disDate = (currentDate - createDate) / 1000; //计算相隔分钟
+							let m = parseInt(disDate / 60 % 60, 10); //计算剩余的分钟数
+							let s = parseInt(disDate % 60, 10); //计算剩余的秒数
+							this.time = m + ":" + s
 							// }, 1000)
 						}
 					}
 				})
 			},
-			setCountDown(sTime){
+			setCountDown(sTime) {
 				let end = new Date(sTime.replace(/-/g, "/")).getTime();
 				let now = new Date().getTime();
 				let msec = end - now;
@@ -285,16 +287,16 @@
 				this.time.m = m > 9 ? m : '0' + m;
 				this.time.s = s > 9 ? s : '0' + s;
 				msec -= 1000;
-				if(this.time.day >= 1){
+				if (this.time.day >= 1) {
 					this.showTime = true;
-				}else{
+				} else {
 					this.showTime = false;
 				};
-				if(msec>=0){
-					setTimeout(()=>{
+				if (msec >= 0) {
+					setTimeout(() => {
 						this.setCountDown(sTime);
 					}, 1000);
-				}else{
+				} else {
 					this.isTimeEnd = true;
 					this.bText = '活动结束';
 					this.time.h = '--';
@@ -318,6 +320,22 @@
 
 	.w-33 {
 		width: 33%;
+		position: relative;
+	}
+
+	.item-box-button {
+		position: absolute;
+		width: 100%;
+		height: 88rpx;
+		top: 0;
+		left: 0;
+		z-index: 100;
+		background-color: transparent;
+		border: none !important;
+	}
+
+	button::after {
+		border: none !important;
 	}
 
 	.p-24-24-0 {

+ 1 - 1
pages-takeout/confirm-mod/select-address.vue

@@ -3,7 +3,7 @@
 		<uni-popup ref="popupAddress" type="bottom">
 			<view class="pop-address box-border-box p-24">
 				<view class="text-align-center fs-36 fw-600 box-title mb-32">
-					选择收获地址
+					选择收货地址
 					<uni-icons @click="closeCoupon" class="box-close" type="closeempty" size="20"></uni-icons>
 				</view>
 				

+ 13 - 1
pages.json

@@ -218,6 +218,12 @@
 		{
 			"root": "pages-order",
 			"pages": [
+				{
+					"path": "takeout-info",
+					"style": {
+						"navigationBarTitleText": "外卖详情"
+					}
+				},
 				{
 					"path": "express-info",
 					"style": {
@@ -372,6 +378,12 @@
 					"style": {
 						"navigationBarTitleText": "公告详情"
 					}
+				},
+				{
+					"path": "search-list",
+					"style": {
+						"navigationBarTitleText": "可用商家"
+					}
 				}
 			]
 		}
@@ -397,7 +409,7 @@
 		"current": 0,
 		"list": [{
 			"name": "列表调试",
-			"path": "pages/order/index",
+			"path": "pages-my/my-ticket",
 			"query": ""
 		}]
 	}

+ 428 - 184
pages/index/index.vue

@@ -1,41 +1,43 @@
 <template>
 	<view class="index-box">
 		<image class="bg-img" src="@/static/img/index/index-bg.png" mode="aspectFit"></image>
-		
+
 		<view class="">
 			<Nav :leftShow='false' :customNav='true' :bgckgroundBox='bgckgroundBox'>
 				<template>
 					<view slot="custom" class="align-items-center" @click="toSelectSchool()">
 						<uni-icons type="location-filled" size="20"></uni-icons>
-						<view class="fs-32 w-220 fw-600 ml-10 text-overflow-ellipsis-one">{{schoolData.school_name||''}}</view>
+						<view class="fs-32 w-220 fw-600 ml-10 text-overflow-ellipsis-one">{{schoolData.school_name||''}}
+						</view>
 						<image class="nav-icon ml-10" src="@/static/img/index/index-right.png" mode="aspectFit"></image>
 					</view>
 				</template>
 			</Nav>
 		</view>
-		
+
 		<!-- 搜索 -->
 		<view class="index-search box-border-box" @click="toUrl(1)"
-		:style="[{'top': BarH + 'px','background':bgckgroundSearch}]">
+			:style="[{'top': BarH + 'px','background':bgckgroundSearch}]">
 			<view class="index-search-box box-border-box align-items-center">
 				<uni-icons type="search" size="20" color="#000"></uni-icons>
 				<view class="fs-28 fc-9 ml-10">搜索店铺名称或者商品名称</view>
 				<view class="fs-28 fc-f index-search-box-buttom">搜索</view>
 			</view>
 		</view>
-		
-		
+
+
 		<view class="index-box-1 ">
 			<!-- 轮播 -->
 			<view class="box-border-box plr-24">
-				<swiper class="swiper mb-32 " circular indicator-dots indicator-active-color="#4FB3EF" :autoplay="true" :interval="3000" :duration="500">
+				<swiper class="swiper mb-32 " circular indicator-dots indicator-active-color="#4FB3EF" :autoplay="true"
+					:interval="3000" :duration="500">
 					<swiper-item v-for="(item,i) in bannerList" :key="i">
 						<image class="swiper-item" :src="item.image" mode="aspectFill"></image>
 					</swiper-item>
 				</swiper>
 			</view>
-			
-			
+
+
 			<!-- 导航 -->
 			<view class="box-border-box plr-24">
 				<view class="nav-list flex-wrap-wrap box-border-box mb-22">
@@ -45,14 +47,15 @@
 					</view>
 				</view>
 			</view>
-			
-			
+
+
 			<!-- 通知 -->
 			<view class="box-border-box plr-24">
 				<view class="msg-box align-items-center box-border-box mb-32">
 					<image class="image-1" src="@/static/img/index/index-tz.png" mode="scaleToFill"></image>
 					<view class="box-1 fs-20 fc-41ABF5">公告</view>
-					<swiper class="tz-swiper" :vertical="true" circular :autoplay="true" :interval="3000" :duration="500">
+					<swiper class="tz-swiper" :vertical="true" circular :autoplay="true" :interval="3000"
+						:duration="500">
 						<swiper-item v-for="(item,i) in noticeList" :key="i" @click="toNoticeDet(item)">
 							<view class="tz-swiper-item">{{item.title}}</view>
 						</swiper-item>
@@ -60,41 +63,47 @@
 					<image class="image-2" src="@/static/img/toRight.png" mode="scaleToFill"></image>
 				</view>
 			</view>
-			
-			
+
+
 			<!-- 限时秒杀 -->
 			<view class="box-border-box plr-24" v-if="seckillGoodsList.length > 0">
 				<view class="xsms-box mb-32">
 					<image class="image-title" src="@/static/img/index/index-xsms.png" mode="scaleToFill"></image>
 					<view class="xsms-box-list-f box-border-box plr-12">
 						<view class="xsms-box-list display-flex ">
-							<view class="xsms-box-list-item box-border-box p-8" v-for="(item,i) in seckillGoodsList" :key="i" @click="toShop(item)">
-								<image class="xsms-box-list-item-img-1 mb-4" :src="item.goods_image" mode="aspectFill"></image>
+							<view class="xsms-box-list-item box-border-box p-8" v-for="(item,i) in seckillGoodsList"
+								:key="i" @click="toShop(item)">
+								<image class="xsms-box-list-item-img-1 mb-4" :src="item.goods_image" mode="aspectFill">
+								</image>
 								<view class="text-overflow-ellipsis-one fs-26 mb-4">{{item.goods_name}}</view>
 								<view class="mb-4">
-									<span class="fs-20 fw-b fc-FB3D03">¥</span><span class="fs-32 fw-b fc-FB3D03">{{item.seckill_money}}</span>
+									<span class="fs-20 fw-b fc-FB3D03">¥</span><span
+										class="fs-32 fw-b fc-FB3D03">{{item.seckill_money}}</span>
 								</view>
 								<view class="fs-20 fc-9 text-line-through">¥{{item.line_price}}</view>
-								<image class="xsms-box-list-item-img-2" src="@/static/img/index/index-q.png" mode="scaleToFill"></image>
+								<image class="xsms-box-list-item-img-2" src="@/static/img/index/index-q.png"
+									mode="scaleToFill"></image>
 							</view>
 						</view>
 					</view>
 				</view>
 			</view>
-			
-			
+
+
 			<!-- 类型选择 -->
 			<view class="type-list-box display-flex" :style="[{'background':bgckgroundType}]">
-				<view class="type-item-box view-nowrap" :class="category_id==item.id?'s-type':'n-type'" 
-				v-for="(item,i) in typeList" :key="i" @click="selectType(item.id)">{{item.name}}</view>
+				<view class="type-item-box view-nowrap" :class="category_id==item.id?'s-type':'n-type'"
+					v-for="(item,i) in typeList" :key="i" @click="selectType(item.id)">{{item.name}}</view>
 			</view>
 			<!-- 商品列表 -->
 			<view class="box-border-box plr-24">
-				<view class="goos-list-box box-border-box p-24 display-flex" v-for="(item,i) in goodsList" :key="i" @click="toShop(item)">
+				<view class="goos-list-box box-border-box p-24 display-flex" v-for="(item,i) in goodsList" :key="i"
+					@click="toShop(item)">
 					<image class="left-img" :src="item.shop_logo" mode="aspectFill"></image>
 					<view class="flex-1">
 						<view class="align-items-center mb-8">
-							<view class="right-box-title fs-32 fw-600 text-overflow-ellipsis-one">{{item.shop_name}}</view>
+							<view class="right-box-title fs-32 fw-600 text-overflow-ellipsis-one">{{item.shop_name}}
+							</view>
 							<image class="right-box-title-img" src="@/static/img/toRight.png" mode=""></image>
 						</view>
 						<view class="align-items-center mb-8">
@@ -104,7 +113,8 @@
 							<view class="fc-6 fs-24 mr-12">{{item.shop_sales}}人购买</view>
 						</view>
 						<view class="align-items-center flex-wrap-wrap">
-							<view class="quan-list display-flex mr-12 mb-12" v-for="(info1,index1) in item.coupon" :key="index1">
+							<view class="quan-list display-flex mr-12 mb-12" v-for="(info1,index1) in item.coupon"
+								:key="index1">
 								<view class="quan-list-1 fs-24 fc-f">券</view>
 								<view class="quan-list-2 fs-24 fc-FB3D03">{{info1.money}}元</view>
 							</view>
@@ -123,83 +133,163 @@
 				</view>
 			</view>
 		</view>
+		<uni-popup ref="popup" type="center" border-radius="10px 10px 10px 10px" :is-mask-click="false">
+			<view class="roll-pop">
+				<image class="lq-bg" src="@/static/img/index/lq-bg.png" mode=""></image>
+				<view class="coupon-box">
+					<view class="item-box display-flex mb-20" v-for="(item,index) in couponData" :key="index">
+						<view class="item-right flex-direction flex-justify-center flex-1 bgc-FCE7E2">
+							<view class="fs-28 mb-12 ticket-name text-overflow-ellipsis fc-3 fw-600">
+								{{item.name}}
+							</view>
+							<view class="fs-24 fc-6">
+								有效时间:{{item.start_time}} - {{item.end_time}}
+							</view>
+						</view>
+						<view class="item-hr"></view>
+						<view class="item-left flex-direction align-items-center flex-justify-center bgc-FCE7E2">
+							<view class="align-items-center">
+								<view class="fs-30 fw-600 fc-FB3D03">¥</view>
+								<view class="fs-48 fw-600 fc-FB3D03">{{item.money}}</view>
+							</view>
+							<view class="fs-24 mb-18 fc-6">
+								{{item.desc}}
+							</view>
+							<view class="but-box fs-28 fc-f" @click="receive(item)">立即领取</view>
+							<view class="ball"></view>
+							<view class="ball-two"></view>
+						</view>
+					</view>
+				</view>
+				<uni-icons @click="gbPOp" class="pop-gb" color='#fff' type="close" size="30"></uni-icons>
+			</view>
+		</uni-popup>
 	</view>
 
 </template>
 <script>
-  import tools from "@/service/tools";
-  import {getNotice,getBanner,} from '@/api/common.js';
-  import {getSeckillGoods} from '@/api/seckill.js'
-  import {getTakeaway} from '@/api/category.js';
-  import {getGoodsList} from '@/api/goods.js';
-  export default {
+	import tools from "@/service/tools";
+	import {
+		getNotice,
+		getBanner,
+	} from '@/api/common.js';
+	import {
+		getSeckillGoods
+	} from '@/api/seckill.js'
+	import {
+		getTakeaway
+	} from '@/api/category.js';
+	import {
+		getGoodsList
+	} from '@/api/goods.js';
+	import {
+		couponHome
+	} from '@/api/coupon.js'
+	export default {
 		data() {
 			return {
-				BarH:0,
-				bgckgroundBox:'transparent',
-				bgckgroundSearch:'',
-				bgckgroundType:'',
-				navList:[
-					{name:"外卖",img:require('@/static/img/index/index-wm.png'),type:2},
-					{name:"代取",img:require('@/static/img/index/index-dq.png'),type:3},
-					{name:"校友圈",img:require('@/static/img/index/index-xyq.png'),type:7},
-					{name:"团购",img:require('@/static/img/index/index-tg.png'),type:5},
-					{name:"票务",img:require('@/static/img/index/index-pw.png'),type:4},
-					{name:"干洗",img:require('@/static/img/index/index-gx.png'),type:6},
-					{name:"租凭",img:require('@/static/img/index/index-zp.png'),},
-					{name:"二手市场",img:require('@/static/img/index/index-esss.png'),},
-					{name:"回收",img:require('@/static/img/index/index-hs.png'),},
-					{name:"实习岗位",img:require('@/static/img/index/index-sxgw.png'),},
+				BarH: 0,
+				bgckgroundBox: 'transparent',
+				bgckgroundSearch: '',
+				bgckgroundType: '',
+				navList: [{
+						name: "外卖",
+						img: require('@/static/img/index/index-wm.png'),
+						type: 2
+					},
+					{
+						name: "代取",
+						img: require('@/static/img/index/index-dq.png'),
+						type: 3
+					},
+					{
+						name: "校友圈",
+						img: require('@/static/img/index/index-xyq.png'),
+						type: 7
+					},
+					{
+						name: "团购",
+						img: require('@/static/img/index/index-tg.png'),
+						type: 5
+					},
+					{
+						name: "票务",
+						img: require('@/static/img/index/index-pw.png'),
+						type: 4
+					},
+					{
+						name: "干洗",
+						img: require('@/static/img/index/index-gx.png'),
+						type: 6
+					},
+					{
+						name: "租凭",
+						img: require('@/static/img/index/index-zp.png'),
+					},
+					{
+						name: "二手市场",
+						img: require('@/static/img/index/index-esss.png'),
+					},
+					{
+						name: "回收",
+						img: require('@/static/img/index/index-hs.png'),
+					},
+					{
+						name: "实习岗位",
+						img: require('@/static/img/index/index-sxgw.png'),
+					},
 				],
-				
-				schoolData:{
-					school_name:'',
+
+				schoolData: {
+					school_name: '',
 				},
-				noticeList:[],
-				bannerList:[],
-				seckillGoodsList:[],
-				
-				typeList:[],//分类数组
-				category_id:0, //分类id
-				
-				goodsList:[],
-				total:0,
-				page:1,
+				noticeList: [],
+				bannerList: [],
+				seckillGoodsList: [],
+
+				typeList: [], //分类数组
+				category_id: 0, //分类id
+
+				goodsList: [],
+				total: 0,
+				page: 1,
+				couponData: []
 			}
 		},
-		
+
 		onShow() {
 			let lon = uni.getStorageSync('lon');
 			let lat = uni.getStorageSync('lat');
-			if(!lon||!lat){
+			if (!lon || !lat) {
 				uni.getLocation({
-					type:"gcj02",
-					success:(res)=>{
-						if(res.errMsg === 'getLocation:ok'){
-							uni.setStorageSync('lon',res.longitude);
-							uni.setStorageSync('lat',res.latitude);
-						}else{
+					type: "gcj02",
+					success: (res) => {
+						if (res.errMsg === 'getLocation:ok') {
+							uni.setStorageSync('lon', res.longitude);
+							uni.setStorageSync('lat', res.latitude);
+						} else {
 							tools.error('位置授权失败,请检查是否开始授权')
 						}
 					},
-					fail:(res)=>{
+					fail: (res) => {
 						tools.error('位置授权失败,请检查是否开始授权')
 					},
 				})
 			}
-			
+
 			let school_id = uni.getStorageSync('school_id');
 			let operate_id = uni.getStorageSync('operate_id');
 			let school_name = uni.getStorageSync('school_name');
-			if(!school_id||!operate_id){
-				setTimeout(()=>{
+			if (!school_id || !operate_id) {
+				setTimeout(() => {
 					uni.reLaunch({
-						url:'/pages-address/select-school?type=1'
+						url: '/pages-address/select-school?type=1'
 					})
-				},1000)
-			}else{
+				}, 1000)
+			} else {
 				this.schoolData.school_name = school_name;
 			}
+
 			this.getBanner();
 			this.getNotice();
 			this.getSeckillGoods();
@@ -209,15 +299,15 @@
 			this.getGoodsList();
 		},
 		onPageScroll(e) {
-			if(e.scrollTop>1){
+			if (e.scrollTop > 1) {
 				this.bgckgroundBox = '#fff';
 				this.bgckgroundSearch = '#fff';
-				if(e.scrollTop>500){
+				if (e.scrollTop > 500) {
 					this.bgckgroundType = '#fff';
-				}else{
+				} else {
 					this.bgckgroundType = '';
 				}
-			}else{
+			} else {
 				this.bgckgroundBox = 'transparent';
 				this.bgckgroundSearch = '';
 				this.bgckgroundType = '';
@@ -225,135 +315,192 @@
 		},
 		onReachBottom() {
 			console.log('触底刷新');
-			if(this.goodsList.length < this.total){
+			if (this.goodsList.length < this.total) {
 				this.page += 1;
 				this.getGoodsList();
 			}
 		},
 		created() {
 			uni.getSystemInfo({
-			  success: (e) =>{
-				let statusBarH = e.statusBarHeight + 10
-			    let custom = 0;
-			    custom = wx.getMenuButtonBoundingClientRect()	  
-			    let customBarH = custom.height;
-				this.BarH = statusBarH + customBarH;
-			  }
+				success: (e) => {
+					let statusBarH = e.statusBarHeight + 10
+					let custom = 0;
+					custom = wx.getMenuButtonBoundingClientRect()
+					let customBarH = custom.height;
+					this.BarH = statusBarH + customBarH;
+				}
 			})
 		},
+		mounted() {
+			this.couponHome()
+			this.$refs.popup.open()
+			uni.hideTabBar()
+		},
 		methods: {
-			getBanner(){
-				getBanner().then((res)=>{
-					if(res.code === 1){
+			couponHome() {
+				let operate_id = uni.getStorageSync('operate_id');
+				couponHome({
+					operate_id: operate_id
+				}).then((res) => {
+					if (res.code == 1) {
+						this.couponData = res.data
+					}
+				})
+			},
+			gbPOp() {
+				uni.showTabBar()
+				this.$refs.popup.close()
+			},
+			getBanner() {
+				getBanner().then((res) => {
+					if (res.code === 1) {
 						this.bannerList = res.data;
 					}
 				})
 			},
-			getNotice(){
-				getNotice().then((res)=>{
-					if(res.code === 1){
+			getNotice() {
+				getNotice().then((res) => {
+					if (res.code === 1) {
 						this.noticeList = res.data;
 					}
 				})
 			},
-			getSeckillGoods(){
+			getSeckillGoods() {
 				let operate_id = uni.getStorageSync('operate_id');
-				getSeckillGoods({operate_id:operate_id}).then((res)=>{
-					if(res.code === 1){
+				getSeckillGoods({
+					operate_id: operate_id
+				}).then((res) => {
+					if (res.code === 1) {
 						this.seckillGoodsList = res.data
 					}
 				})
 			},
-			getTakeaway(){
-				getTakeaway().then((res)=>{
-					if(res.code === 1){
+			getTakeaway() {
+				getTakeaway().then((res) => {
+					if (res.code === 1) {
 						this.typeList = res.data;
-						this.typeList.unshift({name:"全部",id:0})
+						this.typeList.unshift({
+							name: "全部",
+							id: 0
+						})
 					}
 				})
 			},
-			getGoodsList(){
+			getGoodsList() {
 				let operate_id = uni.getStorageSync('operate_id');
-				getGoodsList({page:this.page,operate_id:operate_id,category_id:this.category_id}).then((res)=>{
-					if(res.code === 1){
-						this.goodsList = [...this.goodsList,...res.data.items];
+				getGoodsList({
+					page: this.page,
+					operate_id: operate_id,
+					category_id: this.category_id
+				}).then((res) => {
+					if (res.code === 1) {
+						this.goodsList = [...this.goodsList, ...res.data.items];
 						this.total = res.data.total;
 					}
 				})
 			},
-			selectType(id){
-				if(this.category_id != id){
+			selectType(id) {
+				if (this.category_id != id) {
 					this.category_id = id;
 					this.page = 1;
 					this.goodsList = [];
 					this.getGoodsList();
 				}
 			},
-			toUrl(type){
-				if(type === 1){
+			toUrl(type) {
+				if (type === 1) {
 					// 去搜索
 					uni.navigateTo({
-						url:'/pages/index/search-record'
+						url: '/pages/index/search-record'
 					})
-				}else if(type === 2){
+				} else if (type === 2) {
 					// 去外卖
 					uni.navigateTo({
-						url:'/pages-takeout/takeout'
+						url: '/pages-takeout/takeout'
 					})
-				}else if(type === 3){
+				} else if (type === 3) {
 					// 去外卖
 					uni.navigateTo({
-						url:'/pages-takeout/replace-take'
+						url: '/pages-takeout/replace-take'
 					})
-				}else if(type === 4){
+				} else if (type === 4) {
 					// 去票务
 					uni.navigateTo({
-						url:'/pages-buy/ticket'
+						url: '/pages-buy/ticket'
 					})
-				}else if(type === 5){
+				} else if (type === 5) {
 					// 去团购
 					uni.navigateTo({
-						url:'/pages-buy/group'
+						url: '/pages-buy/group'
 					})
-				}else if(type === 6){
+				} else if (type === 6) {
 					// 去干洗
 					uni.navigateTo({
-						url:'/pages-buy/dry-clean'
+						url: '/pages-buy/dry-clean'
 					})
-				}else if(type === 7){
+				} else if (type === 7) {
 					// 去校友圈
 					uni.navigateTo({
-						url:'/pages-school/school-circle'
+						url: '/pages-school/school-circle'
 					})
-				}else{
+				} else {
 					tools.error('暂未开放')
 				}
 			},
-			toSelectSchool(){
+			toSelectSchool() {
 				uni.navigateTo({
-					url:'/pages-address/select-school?type=1'
+					url: '/pages-address/select-school?type=1'
 				})
 			},
-			toShop(item){
+			toShop(item) {
 				uni.navigateTo({
-					url:'/pages-takeout/shop?shop_id=' + item.shop_id
+					url: '/pages-takeout/shop?shop_id=' + item.shop_id
 				})
 			},
-			toNoticeDet(item){
+			toNoticeDet(item) {
 				uni.navigateTo({
-					url: '/pages-my/notice/info?id=' +item.id
+					url: '/pages-my/notice/info?id=' + item.id
 				})
 			},
 		},
 	}
 </script>
 <style lang="scss" scoped>
-	.index-box{
-		.w-220{
+	.roll-pop {
+		position: relative;
+		width: 100vw;
+		height: 1000rpx;
+
+		.lq-bg {
+			width: 100vw;
+			height: 1000rpx;
+			position: absolute;
+			top: 0;
+			left: 0;
+		}
+
+		.pop-gb {
+			width: 56rpx;
+			height: 56rpx;
+			position: absolute;
+			bottom: -52rpx;
+			left: calc((100% - 28rpx) / 2);
+		}
+	}
+
+	.coupon-box {
+		padding: 246rpx 82rpx 0 92rpx;
+		box-sizing: border-box;
+	}
+
+	.index-box {
+		.w-220 {
 			width: 220rpx;
 		}
+
 		position: relative;
-		.bg-img{
+
+		.bg-img {
 			width: 100%;
 			height: 1220rpx;
 			position: absolute;
@@ -361,64 +508,80 @@
 			left: 0;
 			z-index: -1;
 		}
-		.nav-icon{
+
+		.nav-icon {
 			width: 32rpx;
 			height: 32rpx;
 		}
-		.index-box-1{
+
+		.index-box-1 {
 			width: 100%;
+
 			// height: 3000rpx;
-			.swiper{
+			.swiper {
 				width: 702rpx;
 				height: 220rpx;
 				border-radius: 20rpx;
-				.swiper-item{
+
+				.swiper-item {
 					width: 702rpx;
 					height: 220rpx;
 					border-radius: 20rpx;
 				}
 			}
-			.nav-list{
+
+			.nav-list {
 				padding: 0 22rpx;
-				.nav-list-item{
+
+				.nav-list-item {
 					margin-right: 52rpx;
 					margin-bottom: 16rpx;
-					image{
+
+					image {
 						width: 88rpx;
 						height: 88rpx;
 						margin: 0 auto;
 					}
 				}
-				.nav-list-item:nth-child(7){
+
+				.nav-list-item:nth-child(7) {
 					margin-right: 42rpx !important;
 				}
-				.nav-list-item:nth-child(8){
+
+				.nav-list-item:nth-child(8) {
 					margin-right: 46rpx !important;
 				}
-				.nav-list-item:nth-child(9){
+
+				.nav-list-item:nth-child(9) {
 					margin-right: 44rpx !important;
 				}
-				.nav-list-item:nth-child(5),.nav-list-item:nth-child(10){
+
+				.nav-list-item:nth-child(5),
+				.nav-list-item:nth-child(10) {
 					margin-right: 0;
 				}
 			}
-			.msg-box{
+
+			.msg-box {
 				width: 100%;
 				height: 66rpx;
 				background: #F7F8FC;
 				border-radius: 12rpx;
-				padding: 0 14rpx ;
-				.image-1{
+				padding: 0 14rpx;
+
+				.image-1 {
 					width: 72rpx;
 					height: 32rpx;
 					margin-right: 10rpx;
 				}
-				.image-2{
+
+				.image-2 {
 					width: 40rpx;
 					height: 40rpx;
 					margin-left: auto;
 				}
-				.box-1{
+
+				.box-1 {
 					width: 50rpx;
 					height: 26rpx;
 					border-radius: 2rpx;
@@ -427,45 +590,54 @@
 					line-height: 26rpx;
 					margin-right: 10rpx;
 				}
-				.tz-swiper{
+
+				.tz-swiper {
 					width: 444rpx;
 					height: 66rpx;
-					.tz-swiper-item{
+
+					.tz-swiper-item {
 						width: 444rpx;
 						height: 66rpx;
 						line-height: 66rpx;
 					}
 				}
 			}
-			.xsms-box{
-				.image-title{
+
+			.xsms-box {
+				.image-title {
 					width: 100%;
 					height: 92rpx;
 				}
-				.xsms-box-list-f{
+
+				.xsms-box-list-f {
 					width: 100%;
 					height: 310rpx;
-					background: linear-gradient( 180deg, #ABDEFE 4%, #C9EAFF 30%, #C9EAFF 100%);
+					background: linear-gradient(180deg, #ABDEFE 4%, #C9EAFF 30%, #C9EAFF 100%);
 					border-radius: 0rpx 0rpx 20rpx 20rpx;
 				}
-				.xsms-box-list{
+
+				.xsms-box-list {
 					overflow-y: scroll;
-					.xsms-box-list-item:last-child{
+
+					.xsms-box-list-item:last-child {
 						margin-right: 0;
 					}
-					.xsms-box-list-item{
+
+					.xsms-box-list-item {
 						width: 180rpx;
 						height: 300rpx;
 						background: #FFFFFF;
 						border-radius: 8rpx;
 						margin-right: 8rpx;
 						position: relative;
-						.xsms-box-list-item-img-1{
+
+						.xsms-box-list-item-img-1 {
 							width: 164rpx;
 							height: 175rpx;
 							border-radius: 9rpx;
 						}
-						.xsms-box-list-item-img-2{
+
+						.xsms-box-list-item-img-2 {
 							position: absolute;
 							width: 62rpx;
 							height: 36rpx;
@@ -475,15 +647,16 @@
 					}
 				}
 			}
-			.type-list-box{
+
+			.type-list-box {
 				position: sticky;
 				left: 0;
 				// top: calc(var(BarH)px + 93rpx);
 				top: calc(86px + 93rpx);
 				padding: 0 24rpx 24rpx 24rpx;
 				overflow-x: scroll;
-				
-				.type-item-box{
+
+				.type-item-box {
 					margin-right: 16rpx;
 					padding: 0 24rpx;
 					// min-width: 300rpx;
@@ -493,67 +666,79 @@
 					text-align: center;
 					font-size: 28rpx;
 				}
-				.type-item-box:last-child{
+
+				.type-item-box:last-child {
 					margin-right: 0;
 				}
-				.s-type{
+
+				.s-type {
 					color: #fff;
 					font-weight: 600;
-					background: linear-gradient( 280deg, #44B1F7 0%, #96D6F4 100%);
+					background: linear-gradient(280deg, #44B1F7 0%, #96D6F4 100%);
 				}
-				.n-type{
+
+				.n-type {
 					color: #666;
 					background-color: #fff;
 				}
 			}
-			
-			.goos-list-box{
+
+			.goos-list-box {
 				width: 100%;
 				min-height: 100rpx;
 				background: #FFFFFF;
-				box-shadow: 0rpx 0rpx 20rpx 0rpx rgba(51,51,51,0.1);
+				box-shadow: 0rpx 0rpx 20rpx 0rpx rgba(51, 51, 51, 0.1);
 				border-radius: 20rpx;
 				margin-bottom: 20rpx;
-				.goods-items-list{
+
+				.goods-items-list {
 					width: 530rpx;
 					overflow-y: scroll;
-					.goods-items-list-box{
+
+					.goods-items-list-box {
 						width: 140rpx;
 						margin-right: 16rpx;
-						image{
+
+						image {
 							width: 140rpx;
 							height: 140rpx;
 							border-radius: 12rpx
 						}
 					}
 				}
-				.left-img{
+
+				.left-img {
 					width: 100rpx;
 					height: 100rpx;
 					border-radius: 12rpx;
 					margin-right: 16rpx;
 				}
-				.img-x{
+
+				.img-x {
 					width: 24rpx;
 					height: 24rpx;
 				}
-				.right-box-title{
+
+				.right-box-title {
 					width: 438rpx;
 				}
-				.right-box-title-img{
+
+				.right-box-title-img {
 					width: 32rpx;
 					height: 32rpx;
 					margin-left: auto;
 				}
-				.quan-list{
-					.quan-list-1{
+
+				.quan-list {
+					.quan-list-1 {
 						width: 32rpx;
 						height: 34rpx;
 						background: #FB3D03;
 						border-radius: 5rpx 0rpx 0rpx 5rpx;
 						text-align: center;
 					}
-					.quan-list-2{
+
+					.quan-list-2 {
 						box-sizing: border-box;
 						padding: 0 2rpx;
 						height: 34rpx;
@@ -564,22 +749,24 @@
 				}
 			}
 		}
-		
-		.index-search{
+
+		.index-search {
 			position: sticky;
 			left: 0;
-			z-index: 100;
+			z-index: 10;
 			padding: 0 24rpx 20rpx 24rpx;
-			.index-search-box{
+
+			.index-search-box {
 				width: 100%;
 				height: 72rpx;
 				padding: 0 6rpx 0 24rpx;
 				border-radius: 200rpx;
 				border: 2rpx solid #4FB3EF;
-				.index-search-box-buttom{
+
+				.index-search-box-buttom {
 					width: 120rpx;
 					height: 60rpx;
-					background: linear-gradient( 90deg, #57CAFF 0%, #41ABF5 100%);
+					background: linear-gradient(90deg, #57CAFF 0%, #41ABF5 100%);
 					border-radius: 200rpx;
 					margin-left: auto;
 					line-height: 60rpx;
@@ -589,4 +776,61 @@
 		}
 	}
 
-</style>
+	.item-hr {
+		width: 0px;
+		height: auto;
+		border-right: 1rpx dashed #FB7850;
+	}
+
+	.item-hr-two {
+		width: 0px;
+		height: auto;
+		border-right: 1rpx dashed #999;
+	}
+
+	.item-left {
+		width: 200rpx;
+		height: auto;
+		padding: 20rpx 24rpx;
+		box-sizing: border-box;
+		position: relative;
+		border-radius: 0 20rpx 20rpx 0;
+	}
+
+	.ball {
+		width: 24rpx;
+		height: 24rpx;
+		border-radius: 50%;
+		position: absolute;
+		top: -12rpx;
+		left: -12rpx;
+		background: #fff;
+		z-index: 2;
+	}
+
+	.ball-two {
+		width: 24rpx;
+		height: 24rpx;
+		border-radius: 50%;
+		position: absolute;
+		background: #fff;
+		z-index: 10;
+		bottom: -12rpx;
+		left: -12rpx;
+	}
+
+	.item-right {
+		padding: 24rpx;
+		box-sizing: border-box;
+		border-radius: 20rpx 0 0 20rpx;
+		position: relative;
+	}
+	.but-box {
+		width: 152rpx;
+		height: 52rpx;
+		line-height: 52rpx;
+		text-align: center;
+		background: linear-gradient( 225deg, #FB3D03 0%, #FF6901 100%);
+		border-radius: 200rpx;
+	}
+</style>

+ 181 - 17
pages/order/index.vue

@@ -1,6 +1,6 @@
 <template>
 	<view class="flex-common-css iPhone-bottom box-border-box">
-		<Nav :leftShow='false' :customNav='true' bgckgroundBox='#fff'>
+		<Nav class="nav-b" :leftShow='false' :customNav='true' bgckgroundBox='#fff'>
 			<template>
 				<view slot="custom" class="text-align-center fw-600 fs-36">
 					我的订单
@@ -38,10 +38,16 @@
 						<view class="align-items-center">
 							<image v-if="item.site_logo" class="shops-img" :src="item.site_logo" mode="aspectFit">
 							</image>
+							<image v-else-if="item.shop_logo" class="shops-img" :src="item.shop_logo" mode="aspectFit">
+							</image>
 							<image v-else class="shops-img" src="@/static/img/logo/logo.png" mode=""></image>
 							<view v-if="item.site_name" class="fs-32 fc-3 fw-600 shops-name text-overflow-ellipsis-one">
 								{{item.site_name}}
 							</view>
+							<view @click="goToShop(item)" v-else-if="item.shop_name"
+								class="fs-32 fc-3 fw-600 shops-name text-overflow-ellipsis-one">
+								{{item.shop_name}}
+							</view>
 							<view v-else class="fs-32 fc-3 fw-600 shops-name text-overflow-ellipsis-one">
 								君子校园
 							</view>
@@ -55,7 +61,7 @@
 						<view class="goods-box" v-if="type == 1 || type == 2 || type == 5">
 							<view class="" v-if="item.item.length == 1">
 								<view class="align-items-center" v-for="(itemGoods,indexGoods) in item.item">
-									<image class="goods-img flex-shrink0" :src="itemGoods.goods_img" mode="">
+									<image class="goods-img flex-shrink0" :src="itemGoods.goods_img" mode="aspectFit">
 									</image>
 									<view class="fs-28 fc-6 text-overflow-ellipsis">
 										{{itemGoods.goods_name}}
@@ -64,7 +70,7 @@
 							</view>
 							<view class="align-items-center goods-two" v-else>
 								<view class="flex-direction" v-for="(itemGoods,indexGoods) in item.item">
-									<image class="goods-img flex-shrink0" :src="itemGoods.goods_img" mode="">
+									<image class="goods-img flex-shrink0" :src="itemGoods.goods_img" mode="aspectFit">
 									</image>
 									<view
 										class="fs-28 fc-6 text-overflow-ellipsis-one goods-two-name text-align-center">
@@ -75,7 +81,7 @@
 						</view>
 						<view class="goods-box" v-else>
 							<view class="align-items-center">
-								<image class="goods-img flex-shrink0" :src="item.goods_img" mode="">
+								<image class="goods-img flex-shrink0" :src="item.goods_img" mode="aspectFit">
 								</image>
 								<view class="fs-28 fc-6 text-overflow-ellipsis">
 									{{item.goods_name}}
@@ -96,10 +102,15 @@
 						</view>
 					</view>
 					<view class="align-items-center flex-justify-end">
-						<view class="item-but but-class-two fs-28 mr-18"
+						<view class="item-but but-class-two fs-28 mr-18" @click="assess(item)"
 							v-if="type == 1 && item.order_status == 7 && item.is_comment == 0">
 							评价
 						</view>
+						<view class="item-but but-class-two fs-28 mr-18" @click.stop="tackOut(item)"
+							v-if="type == 1 && item.order_status == 2 || type == 1 && item.order_status == 4">
+							<!-- 外卖 -->
+							取消订单
+						</view>
 						<view class="item-but but-class-two fs-28 mr-18" @click.stop="cancel(item)"
 							v-if="type == 5 && item.order_status == 2">
 							<!-- 干洗 -->
@@ -114,6 +125,15 @@
 							v-if="item.order_status == 1">
 							立即支付
 						</view>
+						<view class="item-but but-class-one fs-28" @click.stop="openCode(item)"
+							v-if="type == 5 && item.order_status == 2 || type == 5 && item.order_status == 3 || type == 5 && item.order_status == 4">
+							二维码
+						</view>
+						<view @click.stop="goToUrl('takeOut')" class="item-but but-class-one fs-28"
+							v-if="type == 1 && item.order_status == 3 || type == 1 && item.order_status == 7 || type == 1 && item.order_status == 8 || type == 1 && item.order_status == 9 || type == 1 && item.order_status == 10">
+							<!-- 外卖 -->
+							再来一单
+						</view>
 						<view @click.stop="goToUrl('express')" class="item-but but-class-one fs-28"
 							v-if="type == 2 && item.order_status == 4">
 							<!-- 代取 -->
@@ -129,7 +149,8 @@
 							<!-- 票务 -->
 							再来一单
 						</view>
-						<view class="item-but but-class-one fs-28" v-if="type == 5 && item.order_status == 5">
+						<view @click.stop="goToUrl('laundry')" class="item-but but-class-one fs-28"
+							v-if="type == 5 && item.order_status == 5">
 							<!-- 干洗 -->
 							再来一单
 						</view>
@@ -137,12 +158,25 @@
 				</view>
 			</view>
 		</scroll-view>
+		<uni-popup ref="popup" border-radius="10px 10px 10px 10px" @maskClick=maskClick>
+			<view class="bgc-f b-rad-20">
+				<!-- <UniQrcode :text="qrcodeData"></UniQrcode> -->
+				<uv-qrcode class="b-rad-20" ref="qrcode" :value="qrcodeData" :options="options2"></uv-qrcode>
+			</view>
+		</uni-popup>
 	</view>
 </template>
 
 <script>
+	import UniQrcode from 'uniapp-qrcode'
 	import tools from '@/service/tools';
 	import EnBlank from "@/components/en-utils/en-blank/en-blank";
+	import {
+		orderStatus,
+		orderList,
+		orderCancel,
+		orderPay
+	} from "@/api/order.js"
 	import {
 		getExpressPay
 	} from "@/api/express.js"
@@ -151,9 +185,6 @@
 		expressOrderList,
 		expressOrderCancel
 	} from "@/api/expressOrder.js"
-	import {
-		orderStatus
-	} from "@/api/order.js"
 	import {
 		groupPay
 	} from '@/api/groupOrder.js';
@@ -171,7 +202,8 @@
 	import {
 		laundryOrderStatus,
 		laundryOrderList,
-		laundryOrderCancel
+		laundryOrderCancel,
+		laundryPay
 	} from "@/api/laundryOrder.js"
 	export default {
 		components: {
@@ -206,15 +238,41 @@
 				total: 0,
 				navTypeData: [],
 				navTypeKey: 0,
-				isAjax: false
+				isAjax: false,
+				qrcodeData: '',
+				options2: {}
 			};
 		},
 		onShow() {
 			this.resetList();
 		},
 		methods: {
+			openCode(item) {
+				let m_id = uni.getStorageSync('m_id');
+				this.qrcodeData = m_id + "_" + item.order_sn
+				this.options2 = {
+					size: 300,
+					margin: 10
+				}
+				uni.hideTabBar()
+				this.$refs.popup.open('center')
+			},
+			maskClick() {
+				this.qrcodeData = ''
+				uni.showTabBar()
+			},
+			goToShop(item) {
+				// 进入店铺
+				uni.navigateTo({
+					url: '/pages-takeout/shop?shop_id=' + item.shop_id
+				})
+			},
 			goToUrl(type) {
-				if (type == 'express') {
+				if (type == 'takeOut') {
+					uni.navigateTo({
+						url: '/pages-takeout/takeout'
+					})
+				} else if (type == 'express') {
 					uni.navigateTo({
 						url: '/pages-takeout/replace-take'
 					})
@@ -226,12 +284,16 @@
 					uni.navigateTo({
 						url: '/pages-buy/ticket'
 					})
+				} else if (type == 'laundry') {
+					uni.navigateTo({
+						url: '/pages-buy/dry-clean'
+					})
 				}
 			},
 			goToInfo(item) {
 				if (this.type === 1) {
 					uni.navigateTo({
-						url: `/pages-order/express-info`
+						url: `/pages-order/takeout-info?orderId=` + item.id
 					})
 				} else if (this.type === 2) {
 					uni.navigateTo({
@@ -254,7 +316,7 @@
 			orderPay(item) {
 				// 立即支付
 				if (this.type === 1) {
-
+					this.orderPay(item.id)
 				} else if (this.type === 2) {
 					this.getExpressPay(item.id)
 				} else if (this.type === 3) {
@@ -262,7 +324,7 @@
 				} else if (this.type === 4) {
 					this.ticketPay(item.id)
 				} else if (this.type === 5) {
-					this.laundryOrderList()
+					this.laundryPay(item.id)
 				}
 			},
 			navTypeClick(key) {
@@ -271,7 +333,7 @@
 					this.page = 1
 					this.list = []
 					if (this.type === 1) {
-
+						this.orderList()
 					} else if (this.type === 2) {
 						this.expressOrderList()
 					} else if (this.type === 3) {
@@ -295,6 +357,28 @@
 					this.resetList();
 				}
 			},
+			assess(item) {
+				// 外卖评价
+				uni.navigateTo({
+					url: `/pages-my/appraise?orderId=` + item.id + '&shopName=' + item.shop_name + '&shopLogo=' +
+						item.shop_logo
+				})
+			},
+			tackOut(item) {
+				// 外卖取消订单
+				orderCancel({
+					order_id: item.id
+				}).then((res) => {
+					if (res.code == 1) {
+						tools.success(res.msg)
+						this.page = 1;
+						this.list = [];
+						this.orderList()
+					} else {
+						tools.error(res.msg)
+					}
+				})
+			},
 			expressCancel(item) {
 				// 代取取消订单
 				expressOrderCancel({
@@ -328,7 +412,7 @@
 			scrolltolower() {
 				++this.page
 				if (this.type === 1) {
-
+					this.orderList()
 				} else if (this.type === 2) {
 					this.expressOrderList()
 				} else if (this.type === 3) {
@@ -343,6 +427,7 @@
 			getList() {
 				if (this.type === 1) {
 					this.orderStatus()
+					this.orderList()
 				} else if (this.type === 2) {
 					this.expressOrderStatus()
 					this.expressOrderList()
@@ -397,6 +482,19 @@
 					}
 				})
 			},
+			orderList() {
+				// 外卖订单列表
+				orderList({
+					status: this.navTypeKey,
+					page: this.page
+				}).then((res) => {
+					if (res.code == 1) {
+						if (res.data.items.length > 0) {
+							this.list.push(...res.data.items)
+						}
+					}
+				})
+			},
 			expressOrderList() {
 				// 代取订单列表
 				expressOrderList({
@@ -449,6 +547,37 @@
 					}
 				})
 			},
+			orderPay(id) {
+				// 外卖支付
+				orderPay({
+					order_id: id
+				}).then((ret) => {
+					if (ret.code === 1) {
+						uni.requestPayment({
+							provider: "wxpay", //支付类型-固定值
+							timeStamp: ret.data.wx_pay.timeStamp + "", // 时间戳(单位:秒)
+							nonceStr: ret.data.wx_pay.nonceStr, // 随机字符串
+							package: ret.data.wx_pay.package, // 固定值
+							signType: ret.data.wx_pay.signType, //固定值
+							paySign: ret.data.wx_pay.paySign, //签名
+							success: (ren) => {
+								tools.success("支付成功");
+								this.isAJAX = false;
+								this.page = 1;
+								this.list = [];
+								this.orderList()
+							},
+							fail: (err) => {
+								this.isAJAX = false;
+								tools.error("支付失败");
+							},
+						});
+					} else {
+						this.isAJAX = false;
+						tools.error("支付失败");
+					}
+				})
+			},
 			getExpressPay(id) {
 				// 代取支付
 				getExpressPay({
@@ -541,12 +670,47 @@
 						tools.error("支付失败");
 					}
 				})
+			},
+			laundryPay(id) {
+				// 干洗支付
+				laundryPay({
+					order_id: id
+				}).then((ret) => {
+					if (ret.code === 1) {
+						uni.requestPayment({
+							provider: "wxpay", //支付类型-固定值
+							timeStamp: ret.data.wx_pay.timeStamp + "", // 时间戳(单位:秒)
+							nonceStr: ret.data.wx_pay.nonceStr, // 随机字符串
+							package: ret.data.wx_pay.package, // 固定值
+							signType: ret.data.wx_pay.signType, //固定值
+							paySign: ret.data.wx_pay.paySign, //签名
+							success: (ren) => {
+								tools.success("支付成功");
+								this.isAJAX = false;
+								this.page = 1;
+								this.list = [];
+								this.laundryOrderList()
+							},
+							fail: (err) => {
+								this.isAJAX = false;
+								tools.error("支付失败");
+							},
+						});
+					} else {
+						this.isAJAX = false;
+						tools.error("支付失败");
+					}
+				})
 			}
 		},
 	}
 </script>
 
 <style lang="scss" scoped>
+	.nav-b{
+		position: relative;
+		z-index: -1 !important;
+	}
 	.nav-box {
 		padding: 26rpx 44rpx;
 		overflow-x: scroll;

BIN
static/img/index/lq-bg.png


BIN
static/img/index/lqgd.png


BIN
static/img/order/bg.png


BIN
static/img/order/bottom.png


BIN
static/img/order/fz.png


BIN
static/img/order/lxkf.png


BIN
static/img/order/qxdd.png


BIN
static/img/order/qzf.png


BIN
static/img/order/top.png


BIN
static/img/order/xgdd.png


BIN
static/img/order/yhq.png


BIN
static/img/order/zlyd.png


+ 13 - 0
uni_modules/uv-qrcode/changelog.md

@@ -0,0 +1,13 @@
+## 1.0.5(2023-12-19)
+1. 优化
+## 1.0.4(2023-07-17)
+1. 优化文档
+2. 优化其他
+## 1.0.3(2023-06-26)
+1. H5增加属性h5SaveTip 保存二维码时候是否显示提示
+## 1.0.2(2023-06-01)
+1. 修复点击触发两次事件的BUG 
+## 1.0.1(2023-05-23)
+1. 修复在部分平台不显示加载效果的BUG
+## 1.0.0(2023-05-17)
+1. 新增uv-qrcode组件

+ 1 - 0
uni_modules/uv-qrcode/components/uv-qrcode/cache.js

@@ -0,0 +1 @@
+export const cacheImageList = [];

+ 241 - 0
uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/bridge/bridge-weex.js

@@ -0,0 +1,241 @@
+const isWeex = typeof WXEnvironment !== 'undefined';
+const isWeexIOS = isWeex && /ios/i.test(WXEnvironment.platform);
+const isWeexAndroid = isWeex && !isWeexIOS;
+
+import GLmethod from '../context-webgl/GLmethod';
+
+const GCanvasModule =
+    (typeof weex !== 'undefined' && weex.requireModule) ? (weex.requireModule('gcanvas')) :
+        (typeof __weex_require__ !== 'undefined') ? (__weex_require__('@weex-module/gcanvas')) : {};
+
+let isDebugging = false;
+
+let isComboDisabled = false;
+
+const logCommand = (function () {
+    const methodQuery = [];
+    Object.keys(GLmethod).forEach(key => {
+        methodQuery[GLmethod[key]] = key;
+    })
+    const queryMethod = (id) => {
+        return methodQuery[parseInt(id)] || 'NotFoundMethod';
+    }
+    const logCommand = (id, cmds) => {
+        const mId = cmds.split(',')[0];
+        const mName = queryMethod(mId);
+        console.log(`=== callNative - componentId:${id}; method: ${mName}; cmds: ${cmds}`);
+    }
+    return logCommand;
+})();
+
+function joinArray(arr, sep) {
+    let res = '';
+    for (let i = 0; i < arr.length; i++) {
+        if (i !== 0) {
+            res += sep;
+        }
+        res += arr[i];
+    }
+    return res;
+}
+
+const commandsCache = {}
+
+const GBridge = {
+
+    callEnable: (ref, configArray) => {
+
+        commandsCache[ref] = [];
+
+        return GCanvasModule.enable({
+            componentId: ref,
+            config: configArray
+        });
+    },
+
+    callEnableDebug: () => {
+        isDebugging = true;
+    },
+
+    callEnableDisableCombo: () => {
+        isComboDisabled = true;
+    },
+
+    callSetContextType: function (componentId, context_type) {
+        GCanvasModule.setContextType(context_type, componentId);
+    },
+
+    callReset: function(id){
+        GCanvasModule.resetComponent && canvasModule.resetComponent(componentId);
+    },
+
+    render: isWeexIOS ? function (componentId) {
+        return GCanvasModule.extendCallNative({
+            contextId: componentId,
+            type: 0x60000001
+        });
+    } : function (componentId) {
+        return callGCanvasLinkNative(componentId, 0x60000001, 'render');
+    },
+
+    render2d: isWeexIOS ? function (componentId, commands, callback) {
+
+        if (isDebugging) {
+            console.log('>>> >>> render2d ===');
+            console.log('>>> commands: ' + commands);
+        }
+		
+        GCanvasModule.render([commands, callback?true:false], componentId, callback);
+
+    } : function (componentId, commands,callback) {
+
+        if (isDebugging) {
+            console.log('>>> >>> render2d ===');
+            console.log('>>> commands: ' + commands);
+        }
+
+        callGCanvasLinkNative(componentId, 0x20000001, commands);
+		if(callback){
+		callback();
+		}
+    },
+
+    callExtendCallNative: isWeexIOS ? function (componentId, cmdArgs) {
+
+        throw 'should not be here anymore ' + cmdArgs;
+
+    } : function (componentId, cmdArgs) {
+
+        throw 'should not be here anymore ' + cmdArgs;
+
+    },
+
+
+    flushNative: isWeexIOS ? function (componentId) {
+
+        const cmdArgs = joinArray(commandsCache[componentId], ';');
+        commandsCache[componentId] = [];
+
+        if (isDebugging) {
+            console.log('>>> >>> flush native ===');
+            console.log('>>> commands: ' + cmdArgs);
+        }
+
+        const result = GCanvasModule.extendCallNative({
+            "contextId": componentId,
+            "type": 0x60000000,
+            "args": cmdArgs
+        });
+
+        const res = result && result.result;
+
+        if (isDebugging) {
+            console.log('>>> result: ' + res);
+        }
+
+        return res;
+
+    } : function (componentId) {
+
+        const cmdArgs = joinArray(commandsCache[componentId], ';');
+        commandsCache[componentId] = [];
+
+        if (isDebugging) {
+            console.log('>>> >>> flush native ===');
+            console.log('>>> commands: ' + cmdArgs);
+        }
+
+        const result = callGCanvasLinkNative(componentId, 0x60000000, cmdArgs);
+
+        if (isDebugging) {
+            console.log('>>> result: ' + result);
+        }
+
+        return result;
+    },
+
+    callNative: function (componentId, cmdArgs, cache) {
+
+        if (isDebugging) {
+            logCommand(componentId, cmdArgs);
+        }
+
+        commandsCache[componentId].push(cmdArgs);
+
+        if (!cache || isComboDisabled) {
+            return GBridge.flushNative(componentId);
+        } else {
+            return undefined;
+        }
+    },
+
+    texImage2D(componentId, ...args) {
+        if (isWeexIOS) {
+            if (args.length === 6) {
+                const [target, level, internalformat, format, type, image] = args;
+                GBridge.callNative(
+                    componentId,
+                    GLmethod.texImage2D + ',' + 6 + ',' + target + ',' + level + ',' + internalformat + ',' + format + ',' + type + ',' + image.src
+                )
+            } else if (args.length === 9) {
+                const [target, level, internalformat, width, height, border, format, type, image] = args;
+                GBridge.callNative(
+                    componentId,
+                    GLmethod.texImage2D + ',' + 9 + ',' + target + ',' + level + ',' + internalformat + ',' + width + ',' + height + ',' + border + ',' +
+                    + format + ',' + type + ',' + (image ? image.src : 0)
+                )
+            }
+        } else if (isWeexAndroid) {
+            if (args.length === 6) {
+                const [target, level, internalformat, format, type, image] = args;
+                GCanvasModule.texImage2D(componentId, target, level, internalformat, format, type, image.src);
+            } else if (args.length === 9) {
+                const [target, level, internalformat, width, height, border, format, type, image] = args;
+                GCanvasModule.texImage2D(componentId, target, level, internalformat, width, height, border, format, type, (image ? image.src : 0));
+            }
+        }
+    },
+
+    texSubImage2D(componentId, target, level, xoffset, yoffset, format, type, image) {
+        if (isWeexIOS) {
+            if (arguments.length === 8) {
+                GBridge.callNative(
+                    componentId,
+                    GLmethod.texSubImage2D + ',' + 6 + ',' + target + ',' + level + ',' + xoffset + ',' + yoffset, + ',' + format + ',' + type + ',' + image.src
+                )
+            }
+        } else if (isWeexAndroid) {
+            GCanvasModule.texSubImage2D(componentId, target, level, xoffset, yoffset, format, type, image.src);
+        }
+    },
+
+    bindImageTexture(componentId, src, imageId) {
+        GCanvasModule.bindImageTexture([src, imageId], componentId);
+    },
+
+    perloadImage([url, id], callback) {
+        GCanvasModule.preLoadImage([url, id], function (image) {
+            image.url = url;
+            image.id = id;
+            callback(image);
+        });
+    },
+	
+	measureText(text, fontStyle, componentId) {
+	    return GCanvasModule.measureText([text, fontStyle], componentId);
+	},
+	
+	getImageData (componentId, x, y, w, h, callback) {
+		GCanvasModule.getImageData([x, y,w,h],componentId,callback);
+	},
+	
+	putImageData (componentId, data, x, y, w, h, callback) {
+		GCanvasModule.putImageData([x, y,w,h,data],componentId,callback);
+	},
+	
+	toTempFilePath(componentId, x, y, width, height, destWidth, destHeight, fileType, quality, callback){ 
+		GCanvasModule.toTempFilePath([x, y, width,height, destWidth, destHeight, fileType, quality], componentId, callback);
+	}
+}
+
+export default GBridge;

+ 18 - 0
uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-2d/FillStyleLinearGradient.js

@@ -0,0 +1,18 @@
+class FillStyleLinearGradient {
+
+    constructor(x0, y0, x1, y1) {
+        this._start_pos = { _x: x0, _y: y0 };
+        this._end_pos = { _x: x1, _y: y1 };
+        this._stop_count = 0;
+        this._stops = [0, 0, 0, 0, 0];
+    }
+
+    addColorStop = function (pos, color) {
+        if (this._stop_count < 5 && 0.0 <= pos && pos <= 1.0) {
+            this._stops[this._stop_count] = { _pos: pos, _color: color };
+            this._stop_count++;
+        }
+    }
+}
+
+export default FillStyleLinearGradient;

+ 8 - 0
uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-2d/FillStylePattern.js

@@ -0,0 +1,8 @@
+class FillStylePattern {
+    constructor(img, pattern) {
+        this._style = pattern;
+        this._img = img;
+    }
+}
+
+export default FillStylePattern;

+ 17 - 0
uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-2d/FillStyleRadialGradient.js

@@ -0,0 +1,17 @@
+class FillStyleRadialGradient {
+    constructor(x0, y0, r0, x1, y1, r1) {
+        this._start_pos = { _x: x0, _y: y0, _r: r0 };
+        this._end_pos = { _x: x1, _y: y1, _r: r1 };
+        this._stop_count = 0;
+        this._stops = [0, 0, 0, 0, 0];
+    }
+
+    addColorStop(pos, color) {
+        if (this._stop_count < 5 && 0.0 <= pos && pos <= 1.0) {
+            this._stops[this._stop_count] = { _pos: pos, _color: color };
+            this._stop_count++;
+        }
+    }
+}
+
+export default FillStyleRadialGradient;

+ 666 - 0
uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-2d/RenderingContext.js

@@ -0,0 +1,666 @@
+import FillStylePattern from './FillStylePattern';
+import FillStyleLinearGradient from './FillStyleLinearGradient';
+import FillStyleRadialGradient from './FillStyleRadialGradient';
+import GImage from '../env/image.js';
+import {
+	ArrayBufferToBase64,
+	Base64ToUint8ClampedArray
+} from '../env/tool.js';
+
+export default class CanvasRenderingContext2D {
+
+	_drawCommands = '';
+
+	_globalAlpha = 1.0;
+
+	_fillStyle = 'rgb(0,0,0)';
+	_strokeStyle = 'rgb(0,0,0)';
+
+	_lineWidth = 1;
+	_lineCap = 'butt';
+	_lineJoin = 'miter';
+
+	_miterLimit = 10;
+
+	_globalCompositeOperation = 'source-over';
+
+	_textAlign = 'start';
+	_textBaseline = 'alphabetic';
+
+	_font = '10px sans-serif';
+
+	_savedGlobalAlpha = [];
+
+	timer = null;
+	componentId = null;
+
+	_notCommitDrawImageCache = [];
+	_needRedrawImageCache = [];
+	_redrawCommands = '';
+	_autoSaveContext = true;
+	// _imageMap = new GHashMap();
+	// _textureMap = new GHashMap();
+
+	constructor() {
+		this.className = 'CanvasRenderingContext2D';
+		//this.save()
+	}
+
+	setFillStyle(value) {
+		this.fillStyle = value;
+	}
+
+	set fillStyle(value) {
+		this._fillStyle = value;
+
+		if (typeof(value) == 'string') {
+			this._drawCommands = this._drawCommands.concat("F" + value + ";");
+		} else if (value instanceof FillStylePattern) {
+			const image = value._img;
+			if (!image.complete) {
+				image.onload = () => {
+					var index = this._needRedrawImageCache.indexOf(image);
+					if (index > -1) {
+						this._needRedrawImageCache.splice(index, 1);
+						CanvasRenderingContext2D.GBridge.bindImageTexture(this.componentId, image.src, image._id);
+						this._redrawflush(true);
+					}
+				}
+				this._notCommitDrawImageCache.push(image);
+			} else {
+				CanvasRenderingContext2D.GBridge.bindImageTexture(this.componentId, image.src, image._id);
+			}
+
+			//CanvasRenderingContext2D.GBridge.bindImageTexture(this.componentId, image.src, image._id);
+			this._drawCommands = this._drawCommands.concat("G" + image._id + "," + value._style + ";");
+		} else if (value instanceof FillStyleLinearGradient) {
+			var command = "D" + value._start_pos._x.toFixed(2) + "," + value._start_pos._y.toFixed(2) + "," +
+				value._end_pos._x.toFixed(2) + "," + value._end_pos._y.toFixed(2) + "," +
+				value._stop_count;
+			for (var i = 0; i < value._stop_count; ++i) {
+				command += ("," + value._stops[i]._pos + "," + value._stops[i]._color);
+			}
+			this._drawCommands = this._drawCommands.concat(command + ";");
+		} else if (value instanceof FillStyleRadialGradient) {
+			var command = "H" + value._start_pos._x.toFixed(2) + "," + value._start_pos._y.toFixed(2) + "," + value._start_pos._r
+				.toFixed(2) + "," +
+				value._end_pos._x.toFixed(2) + "," + value._end_pos._y.toFixed(2) + "," + value._end_pos._r.toFixed(2) + "," +
+				value._stop_count;
+			for (var i = 0; i < value._stop_count; ++i) {
+				command += ("," + value._stops[i]._pos + "," + value._stops[i]._color);
+			}
+			this._drawCommands = this._drawCommands.concat(command + ";");
+		}
+	}
+
+	get fillStyle() {
+		return this._fillStyle;
+	}
+
+	get globalAlpha() {
+		return this._globalAlpha;
+	}
+
+	setGlobalAlpha(value) {
+		this.globalAlpha = value;
+	}
+
+	set globalAlpha(value) {
+		this._globalAlpha = value;
+		this._drawCommands = this._drawCommands.concat("a" + value.toFixed(2) + ";");
+	}
+
+
+	get strokeStyle() {
+		return this._strokeStyle;
+	}
+
+	setStrokeStyle(value) {
+		this.strokeStyle = value;
+	}
+
+	set strokeStyle(value) {
+
+		this._strokeStyle = value;
+
+		if (typeof(value) == 'string') {
+			this._drawCommands = this._drawCommands.concat("S" + value + ";");
+		} else if (value instanceof FillStylePattern) {
+			CanvasRenderingContext2D.GBridge.bindImageTexture(this.componentId, image.src, image._id);
+			this._drawCommands = this._drawCommands.concat("G" + image._id + "," + value._style + ";");
+		} else if (value instanceof FillStyleLinearGradient) {
+			var command = "D" + value._start_pos._x.toFixed(2) + "," + value._start_pos._y.toFixed(2) + "," +
+				value._end_pos._x.toFixed(2) + "," + value._end_pos._y.toFixed(2) + "," +
+				value._stop_count;
+
+			for (var i = 0; i < value._stop_count; ++i) {
+				command += ("," + value._stops[i]._pos + "," + value._stops[i]._color);
+			}
+			this._drawCommands = this._drawCommands.concat(command + ";");
+		} else if (value instanceof FillStyleRadialGradient) {
+			var command = "H" + value._start_pos._x.toFixed(2) + "," + value._start_pos._y.toFixed(2) + "," + value._start_pos._r
+				.toFixed(2) + "," +
+				value._end_pos._x.toFixed(2) + "," + value._end_pos._y + ",".toFixed(2) + value._end_pos._r.toFixed(2) + "," +
+				value._stop_count;
+
+			for (var i = 0; i < value._stop_count; ++i) {
+				command += ("," + value._stops[i]._pos + "," + value._stops[i]._color);
+			}
+			this._drawCommands = this._drawCommands.concat(command + ";");
+		}
+	}
+
+	get lineWidth() {
+		return this._lineWidth;
+	}
+
+	setLineWidth(value) {
+		this.lineWidth = value;
+	}
+
+	set lineWidth(value) {
+		this._lineWidth = value;
+		this._drawCommands = this._drawCommands.concat("W" + value + ";");
+	}
+
+	get lineCap() {
+		return this._lineCap;
+	}
+
+	setLineCap(value) {
+		this.lineCap = value;
+	}
+
+	set lineCap(value) {
+		this._lineCap = value;
+		this._drawCommands = this._drawCommands.concat("C" + value + ";");
+	}
+
+	get lineJoin() {
+		return this._lineJoin;
+	}
+
+	setLineJoin(value) {
+		this.lineJoin = value
+	}
+
+	set lineJoin(value) {
+		this._lineJoin = value;
+		this._drawCommands = this._drawCommands.concat("J" + value + ";");
+	}
+
+	get miterLimit() {
+		return this._miterLimit;
+	}
+
+	setMiterLimit(value) {
+		this.miterLimit = value
+	}
+
+	set miterLimit(value) {
+		this._miterLimit = value;
+		this._drawCommands = this._drawCommands.concat("M" + value + ";");
+	}
+
+	get globalCompositeOperation() {
+		return this._globalCompositeOperation;
+	}
+
+	set globalCompositeOperation(value) {
+
+		this._globalCompositeOperation = value;
+		let mode = 0;
+		switch (value) {
+			case "source-over":
+				mode = 0;
+				break;
+			case "source-atop":
+				mode = 5;
+				break;
+			case "source-in":
+				mode = 0;
+				break;
+			case "source-out":
+				mode = 2;
+				break;
+			case "destination-over":
+				mode = 4;
+				break;
+			case "destination-atop":
+				mode = 4;
+				break;
+			case "destination-in":
+				mode = 4;
+				break;
+			case "destination-out":
+				mode = 3;
+				break;
+			case "lighter":
+				mode = 1;
+				break;
+			case "copy":
+				mode = 2;
+				break;
+			case "xor":
+				mode = 6;
+				break;
+			default:
+				mode = 0;
+		}
+
+		this._drawCommands = this._drawCommands.concat("B" + mode + ";");
+	}
+
+	get textAlign() {
+		return this._textAlign;
+	}
+
+	setTextAlign(value) {
+		this.textAlign = value
+	}
+
+	set textAlign(value) {
+
+		this._textAlign = value;
+		let Align = 0;
+		switch (value) {
+			case "start":
+				Align = 0;
+				break;
+			case "end":
+				Align = 1;
+				break;
+			case "left":
+				Align = 2;
+				break;
+			case "center":
+				Align = 3;
+				break;
+			case "right":
+				Align = 4;
+				break;
+			default:
+				Align = 0;
+		}
+
+		this._drawCommands = this._drawCommands.concat("A" + Align + ";");
+	}
+
+	get textBaseline() {
+		return this._textBaseline;
+	}
+
+	setTextBaseline(value) {
+		this.textBaseline = value
+	}
+
+	set textBaseline(value) {
+		this._textBaseline = value;
+		let baseline = 0;
+		switch (value) {
+			case "alphabetic":
+				baseline = 0;
+				break;
+			case "middle":
+				baseline = 1;
+				break;
+			case "top":
+				baseline = 2;
+				break;
+			case "hanging":
+				baseline = 3;
+				break;
+			case "bottom":
+				baseline = 4;
+				break;
+			case "ideographic":
+				baseline = 5;
+				break;
+			default:
+				baseline = 0;
+				break;
+		}
+
+		this._drawCommands = this._drawCommands.concat("E" + baseline + ";");
+	}
+
+	get font() {
+		return this._font;
+	}
+
+	setFontSize(size) {
+		var str = this._font;
+		var strs = str.trim().split(/\s+/);
+		for (var i = 0; i < strs.length; i++) {
+			var values = ["normal", "italic", "oblique", "normal", "small-caps", "normal", "bold",
+				"bolder", "lighter", "100", "200", "300", "400", "500", "600", "700", "800", "900",
+				"normal", "ultra-condensed", "extra-condensed", "condensed", "semi-condensed",
+				"semi-expanded", "expanded", "extra-expanded", "ultra-expanded"
+			];
+
+			if (-1 == values.indexOf(strs[i].trim())) {
+				if (typeof size === 'string') {
+					strs[i] = size;
+				} else if (typeof size === 'number') {
+					strs[i] = String(size) + 'px';
+				}
+				break;
+			}
+		}
+		this.font = strs.join(" ");
+	}
+
+	set font(value) {
+		this._font = value;
+		this._drawCommands = this._drawCommands.concat("j" + value + ";");
+	}
+
+	setTransform(a, b, c, d, tx, ty) {
+		this._drawCommands = this._drawCommands.concat("t" +
+			(a === 1 ? "1" : a.toFixed(2)) + "," +
+			(b === 0 ? "0" : b.toFixed(2)) + "," +
+			(c === 0 ? "0" : c.toFixed(2)) + "," +
+			(d === 1 ? "1" : d.toFixed(2)) + "," + tx.toFixed(2) + "," + ty.toFixed(2) + ";");
+	}
+
+	transform(a, b, c, d, tx, ty) {
+		this._drawCommands = this._drawCommands.concat("f" +
+			(a === 1 ? "1" : a.toFixed(2)) + "," +
+			(b === 0 ? "0" : b.toFixed(2)) + "," +
+			(c === 0 ? "0" : c.toFixed(2)) + "," +
+			(d === 1 ? "1" : d.toFixed(2)) + "," + tx + "," + ty + ";");
+	}
+
+	resetTransform() {
+		this._drawCommands = this._drawCommands.concat("m;");
+	}
+
+	scale(a, d) {
+		this._drawCommands = this._drawCommands.concat("k" + a.toFixed(2) + "," +
+			d.toFixed(2) + ";");
+	}
+
+	rotate(angle) {
+		this._drawCommands = this._drawCommands
+			.concat("r" + angle.toFixed(6) + ";");
+	}
+
+	translate(tx, ty) {
+		this._drawCommands = this._drawCommands.concat("l" + tx.toFixed(2) + "," + ty.toFixed(2) + ";");
+	}
+
+	save() {
+		this._savedGlobalAlpha.push(this._globalAlpha);
+		this._drawCommands = this._drawCommands.concat("v;");
+	}
+
+	restore() {
+		this._drawCommands = this._drawCommands.concat("e;");
+		this._globalAlpha = this._savedGlobalAlpha.pop();
+	}
+
+	createPattern(img, pattern) {
+		if (typeof img === 'string') {
+			var imgObj = new GImage();
+			imgObj.src = img;
+			img = imgObj;
+		}
+		return new FillStylePattern(img, pattern);
+	}
+
+	createLinearGradient(x0, y0, x1, y1) {
+		return new FillStyleLinearGradient(x0, y0, x1, y1);
+	}
+
+	createRadialGradient = function(x0, y0, r0, x1, y1, r1) {
+		return new FillStyleRadialGradient(x0, y0, r0, x1, y1, r1);
+	};
+
+	createCircularGradient = function(x0, y0, r0) {
+		return new FillStyleRadialGradient(x0, y0, 0, x0, y0, r0);
+	};
+
+	strokeRect(x, y, w, h) {
+		this._drawCommands = this._drawCommands.concat("s" + x + "," + y + "," + w + "," + h + ";");
+	}
+
+
+	clearRect(x, y, w, h) {
+		this._drawCommands = this._drawCommands.concat("c" + x + "," + y + "," + w +
+			"," + h + ";");
+	}
+
+	clip() {
+		this._drawCommands = this._drawCommands.concat("p;");
+	}
+
+	resetClip() {
+		this._drawCommands = this._drawCommands.concat("q;");
+	}
+
+	closePath() {
+		this._drawCommands = this._drawCommands.concat("o;");
+	}
+
+	moveTo(x, y) {
+		this._drawCommands = this._drawCommands.concat("g" + x.toFixed(2) + "," + y.toFixed(2) + ";");
+	}
+
+	lineTo(x, y) {
+		this._drawCommands = this._drawCommands.concat("i" + x.toFixed(2) + "," + y.toFixed(2) + ";");
+	}
+
+	quadraticCurveTo = function(cpx, cpy, x, y) {
+		this._drawCommands = this._drawCommands.concat("u" + cpx + "," + cpy + "," + x + "," + y + ";");
+	}
+
+	bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y, ) {
+		this._drawCommands = this._drawCommands.concat(
+			"z" + cp1x.toFixed(2) + "," + cp1y.toFixed(2) + "," + cp2x.toFixed(2) + "," + cp2y.toFixed(2) + "," +
+			x.toFixed(2) + "," + y.toFixed(2) + ";");
+	}
+
+	arcTo(x1, y1, x2, y2, radius) {
+		this._drawCommands = this._drawCommands.concat("h" + x1 + "," + y1 + "," + x2 + "," + y2 + "," + radius + ";");
+	}
+
+	beginPath() {
+		this._drawCommands = this._drawCommands.concat("b;");
+	}
+
+
+	fillRect(x, y, w, h) {
+		this._drawCommands = this._drawCommands.concat("n" + x + "," + y + "," + w +
+			"," + h + ";");
+	}
+
+	rect(x, y, w, h) {
+		this._drawCommands = this._drawCommands.concat("w" + x + "," + y + "," + w + "," + h + ";");
+	}
+
+	fill() {
+		this._drawCommands = this._drawCommands.concat("L;");
+	}
+
+	stroke(path) {
+		this._drawCommands = this._drawCommands.concat("x;");
+	}
+
+	arc(x, y, radius, startAngle, endAngle, anticlockwise) {
+
+		let ianticlockwise = 0;
+		if (anticlockwise) {
+			ianticlockwise = 1;
+		}
+
+		this._drawCommands = this._drawCommands.concat(
+			"y" + x.toFixed(2) + "," + y.toFixed(2) + "," +
+			radius.toFixed(2) + "," + startAngle + "," + endAngle + "," + ianticlockwise +
+			";"
+		);
+	}
+
+	fillText(text, x, y) {
+		let tmptext = text.replace(/!/g, "!!");
+		tmptext = tmptext.replace(/,/g, "!,");
+		tmptext = tmptext.replace(/;/g, "!;");
+		this._drawCommands = this._drawCommands.concat("T" + tmptext + "," + x + "," + y + ",0.0;");
+	}
+
+	strokeText = function(text, x, y) {
+		let tmptext = text.replace(/!/g, "!!");
+		tmptext = tmptext.replace(/,/g, "!,");
+		tmptext = tmptext.replace(/;/g, "!;");
+		this._drawCommands = this._drawCommands.concat("U" + tmptext + "," + x + "," + y + ",0.0;");
+	}
+
+	measureText(text) {
+		return CanvasRenderingContext2D.GBridge.measureText(text, this.font, this.componentId);
+	}
+
+	isPointInPath = function(x, y) {
+		throw new Error('GCanvas not supported yet');
+	}
+
+	drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh) {
+		if (typeof image === 'string') {
+			var imgObj = new GImage();
+			imgObj.src = image;
+			image = imgObj;
+		}
+		if (image instanceof GImage) {
+			if (!image.complete) {
+				imgObj.onload = () => {
+					var index = this._needRedrawImageCache.indexOf(image);
+					if (index > -1) {
+						this._needRedrawImageCache.splice(index, 1);
+						CanvasRenderingContext2D.GBridge.bindImageTexture(this.componentId, image.src, image._id);
+						this._redrawflush(true);
+					}
+				}
+				this._notCommitDrawImageCache.push(image);
+			} else {
+				CanvasRenderingContext2D.GBridge.bindImageTexture(this.componentId, image.src, image._id);
+			}
+			var srcArgs = [image, sx, sy, sw, sh, dx, dy, dw, dh];
+			var args = [];
+			for (var arg in srcArgs) {
+				if (typeof(srcArgs[arg]) != 'undefined') {
+					args.push(srcArgs[arg]);
+				}
+			}
+			this.__drawImage.apply(this, args);
+			//this.__drawImage(image,sx, sy, sw, sh, dx, dy, dw, dh);
+		}
+	}
+
+	__drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh) {
+		const numArgs = arguments.length;
+
+		function drawImageCommands() {
+
+			if (numArgs === 3) {
+				const x = parseFloat(sx) || 0.0;
+				const y = parseFloat(sy) || 0.0;
+
+				return ("d" + image._id + ",0,0," +
+					image.width + "," + image.height + "," +
+					x + "," + y + "," + image.width + "," + image.height + ";");
+			} else if (numArgs === 5) {
+				const x = parseFloat(sx) || 0.0;
+				const y = parseFloat(sy) || 0.0;
+				const width = parseInt(sw) || image.width;
+				const height = parseInt(sh) || image.height;
+
+				return ("d" + image._id + ",0,0," +
+					image.width + "," + image.height + "," +
+					x + "," + y + "," + width + "," + height + ";");
+			} else if (numArgs === 9) {
+				sx = parseFloat(sx) || 0.0;
+				sy = parseFloat(sy) || 0.0;
+				sw = parseInt(sw) || image.width;
+				sh = parseInt(sh) || image.height;
+				dx = parseFloat(dx) || 0.0;
+				dy = parseFloat(dy) || 0.0;
+				dw = parseInt(dw) || image.width;
+				dh = parseInt(dh) || image.height;
+
+				return ("d" + image._id + "," +
+					sx + "," + sy + "," + sw + "," + sh + "," +
+					dx + "," + dy + "," + dw + "," + dh + ";");
+			}
+		}
+		this._drawCommands += drawImageCommands();
+	}
+
+	_flush(reserve, callback) {
+		const commands = this._drawCommands;
+		this._drawCommands = '';
+		CanvasRenderingContext2D.GBridge.render2d(this.componentId, commands, callback);
+		this._needRender = false;
+	}
+
+	_redrawflush(reserve, callback) {
+		const commands = this._redrawCommands;
+		CanvasRenderingContext2D.GBridge.render2d(this.componentId, commands, callback);
+		if (this._needRedrawImageCache.length == 0) {
+			this._redrawCommands = '';
+		}
+	}
+
+	draw(reserve, callback) {
+		if (!reserve) {
+			this._globalAlpha = this._savedGlobalAlpha.pop();
+			this._savedGlobalAlpha.push(this._globalAlpha);
+			this._redrawCommands = this._drawCommands;
+			this._needRedrawImageCache = this._notCommitDrawImageCache;
+			if (this._autoSaveContext) {
+				this._drawCommands = ("v;" + this._drawCommands);
+				this._autoSaveContext = false;
+			} else {
+				this._drawCommands = ("e;X;v;" + this._drawCommands);
+			}
+		} else {
+			this._needRedrawImageCache = this._needRedrawImageCache.concat(this._notCommitDrawImageCache);
+			this._redrawCommands += this._drawCommands;
+			if (this._autoSaveContext) {
+				this._drawCommands = ("v;" + this._drawCommands);
+				this._autoSaveContext = false;
+			}
+		}
+		this._notCommitDrawImageCache = [];
+		if (this._flush) {
+			this._flush(reserve, callback);
+		}
+	}
+
+	getImageData(x, y, w, h, callback) {
+		CanvasRenderingContext2D.GBridge.getImageData(this.componentId, x, y, w, h, function(res) {
+			res.data = Base64ToUint8ClampedArray(res.data);
+			if (typeof(callback) == 'function') {
+				callback(res);
+			}
+		});
+	}
+
+	putImageData(data, x, y, w, h, callback) {
+		if (data instanceof Uint8ClampedArray) {
+			data = ArrayBufferToBase64(data);
+			CanvasRenderingContext2D.GBridge.putImageData(this.componentId, data, x, y, w, h, function(res) {
+				if (typeof(callback) == 'function') {
+					callback(res);
+				}
+			});
+		}
+	}
+
+	toTempFilePath(x, y, width, height, destWidth, destHeight, fileType, quality, callback) {
+		CanvasRenderingContext2D.GBridge.toTempFilePath(this.componentId, x, y, width, height, destWidth, destHeight,
+			fileType, quality,
+			function(res) {
+				if (typeof(callback) == 'function') {
+					callback(res);
+				}
+			});
+	}
+}

+ 11 - 0
uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-webgl/ActiveInfo.js

@@ -0,0 +1,11 @@
+export default class WebGLActiveInfo {
+    className = 'WebGLActiveInfo';
+
+    constructor({
+        type, name, size
+    }) {
+        this.type = type;
+        this.name = name;
+        this.size = size;
+    }
+}

+ 21 - 0
uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-webgl/Buffer.js

@@ -0,0 +1,21 @@
+import {getTransferedObjectUUID} from './classUtils';
+
+const name = 'WebGLBuffer';
+
+function uuid(id) {
+    return getTransferedObjectUUID(name, id);
+}
+
+export default class WebGLBuffer {
+    className = name;
+
+    constructor(id) {
+        this.id = id;
+    }
+
+    static uuid = uuid;
+
+    uuid() {
+        return uuid(this.id);
+    }
+}

+ 21 - 0
uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-webgl/Framebuffer.js

@@ -0,0 +1,21 @@
+import {getTransferedObjectUUID} from './classUtils';
+
+const name = 'WebGLFrameBuffer';
+
+function uuid(id) {
+    return getTransferedObjectUUID(name, id);
+}
+
+export default class WebGLFramebuffer {
+    className = name;
+
+    constructor(id) {
+        this.id = id;
+    }
+
+    static uuid = uuid;
+
+    uuid() {
+        return uuid(this.id);
+    }
+}

+ 298 - 0
uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-webgl/GLenum.js

@@ -0,0 +1,298 @@
+export default {
+    "DEPTH_BUFFER_BIT": 256,
+    "STENCIL_BUFFER_BIT": 1024,
+    "COLOR_BUFFER_BIT": 16384,
+    "POINTS": 0,
+    "LINES": 1,
+    "LINE_LOOP": 2,
+    "LINE_STRIP": 3,
+    "TRIANGLES": 4,
+    "TRIANGLE_STRIP": 5,
+    "TRIANGLE_FAN": 6,
+    "ZERO": 0,
+    "ONE": 1,
+    "SRC_COLOR": 768,
+    "ONE_MINUS_SRC_COLOR": 769,
+    "SRC_ALPHA": 770,
+    "ONE_MINUS_SRC_ALPHA": 771,
+    "DST_ALPHA": 772,
+    "ONE_MINUS_DST_ALPHA": 773,
+    "DST_COLOR": 774,
+    "ONE_MINUS_DST_COLOR": 775,
+    "SRC_ALPHA_SATURATE": 776,
+    "FUNC_ADD": 32774,
+    "BLEND_EQUATION": 32777,
+    "BLEND_EQUATION_RGB": 32777,
+    "BLEND_EQUATION_ALPHA": 34877,
+    "FUNC_SUBTRACT": 32778,
+    "FUNC_REVERSE_SUBTRACT": 32779,
+    "BLEND_DST_RGB": 32968,
+    "BLEND_SRC_RGB": 32969,
+    "BLEND_DST_ALPHA": 32970,
+    "BLEND_SRC_ALPHA": 32971,
+    "CONSTANT_COLOR": 32769,
+    "ONE_MINUS_CONSTANT_COLOR": 32770,
+    "CONSTANT_ALPHA": 32771,
+    "ONE_MINUS_CONSTANT_ALPHA": 32772,
+    "BLEND_COLOR": 32773,
+    "ARRAY_BUFFER": 34962,
+    "ELEMENT_ARRAY_BUFFER": 34963,
+    "ARRAY_BUFFER_BINDING": 34964,
+    "ELEMENT_ARRAY_BUFFER_BINDING": 34965,
+    "STREAM_DRAW": 35040,
+    "STATIC_DRAW": 35044,
+    "DYNAMIC_DRAW": 35048,
+    "BUFFER_SIZE": 34660,
+    "BUFFER_USAGE": 34661,
+    "CURRENT_VERTEX_ATTRIB": 34342,
+    "FRONT": 1028,
+    "BACK": 1029,
+    "FRONT_AND_BACK": 1032,
+    "TEXTURE_2D": 3553,
+    "CULL_FACE": 2884,
+    "BLEND": 3042,
+    "DITHER": 3024,
+    "STENCIL_TEST": 2960,
+    "DEPTH_TEST": 2929,
+    "SCISSOR_TEST": 3089,
+    "POLYGON_OFFSET_FILL": 32823,
+    "SAMPLE_ALPHA_TO_COVERAGE": 32926,
+    "SAMPLE_COVERAGE": 32928,
+    "NO_ERROR": 0,
+    "INVALID_ENUM": 1280,
+    "INVALID_VALUE": 1281,
+    "INVALID_OPERATION": 1282,
+    "OUT_OF_MEMORY": 1285,
+    "CW": 2304,
+    "CCW": 2305,
+    "LINE_WIDTH": 2849,
+    "ALIASED_POINT_SIZE_RANGE": 33901,
+    "ALIASED_LINE_WIDTH_RANGE": 33902,
+    "CULL_FACE_MODE": 2885,
+    "FRONT_FACE": 2886,
+    "DEPTH_RANGE": 2928,
+    "DEPTH_WRITEMASK": 2930,
+    "DEPTH_CLEAR_VALUE": 2931,
+    "DEPTH_FUNC": 2932,
+    "STENCIL_CLEAR_VALUE": 2961,
+    "STENCIL_FUNC": 2962,
+    "STENCIL_FAIL": 2964,
+    "STENCIL_PASS_DEPTH_FAIL": 2965,
+    "STENCIL_PASS_DEPTH_PASS": 2966,
+    "STENCIL_REF": 2967,
+    "STENCIL_VALUE_MASK": 2963,
+    "STENCIL_WRITEMASK": 2968,
+    "STENCIL_BACK_FUNC": 34816,
+    "STENCIL_BACK_FAIL": 34817,
+    "STENCIL_BACK_PASS_DEPTH_FAIL": 34818,
+    "STENCIL_BACK_PASS_DEPTH_PASS": 34819,
+    "STENCIL_BACK_REF": 36003,
+    "STENCIL_BACK_VALUE_MASK": 36004,
+    "STENCIL_BACK_WRITEMASK": 36005,
+    "VIEWPORT": 2978,
+    "SCISSOR_BOX": 3088,
+    "COLOR_CLEAR_VALUE": 3106,
+    "COLOR_WRITEMASK": 3107,
+    "UNPACK_ALIGNMENT": 3317,
+    "PACK_ALIGNMENT": 3333,
+    "MAX_TEXTURE_SIZE": 3379,
+    "MAX_VIEWPORT_DIMS": 3386,
+    "SUBPIXEL_BITS": 3408,
+    "RED_BITS": 3410,
+    "GREEN_BITS": 3411,
+    "BLUE_BITS": 3412,
+    "ALPHA_BITS": 3413,
+    "DEPTH_BITS": 3414,
+    "STENCIL_BITS": 3415,
+    "POLYGON_OFFSET_UNITS": 10752,
+    "POLYGON_OFFSET_FACTOR": 32824,
+    "TEXTURE_BINDING_2D": 32873,
+    "SAMPLE_BUFFERS": 32936,
+    "SAMPLES": 32937,
+    "SAMPLE_COVERAGE_VALUE": 32938,
+    "SAMPLE_COVERAGE_INVERT": 32939,
+    "COMPRESSED_TEXTURE_FORMATS": 34467,
+    "DONT_CARE": 4352,
+    "FASTEST": 4353,
+    "NICEST": 4354,
+    "GENERATE_MIPMAP_HINT": 33170,
+    "BYTE": 5120,
+    "UNSIGNED_BYTE": 5121,
+    "SHORT": 5122,
+    "UNSIGNED_SHORT": 5123,
+    "INT": 5124,
+    "UNSIGNED_INT": 5125,
+    "FLOAT": 5126,
+    "DEPTH_COMPONENT": 6402,
+    "ALPHA": 6406,
+    "RGB": 6407,
+    "RGBA": 6408,
+    "LUMINANCE": 6409,
+    "LUMINANCE_ALPHA": 6410,
+    "UNSIGNED_SHORT_4_4_4_4": 32819,
+    "UNSIGNED_SHORT_5_5_5_1": 32820,
+    "UNSIGNED_SHORT_5_6_5": 33635,
+    "FRAGMENT_SHADER": 35632,
+    "VERTEX_SHADER": 35633,
+    "MAX_VERTEX_ATTRIBS": 34921,
+    "MAX_VERTEX_UNIFORM_VECTORS": 36347,
+    "MAX_VARYING_VECTORS": 36348,
+    "MAX_COMBINED_TEXTURE_IMAGE_UNITS": 35661,
+    "MAX_VERTEX_TEXTURE_IMAGE_UNITS": 35660,
+    "MAX_TEXTURE_IMAGE_UNITS": 34930,
+    "MAX_FRAGMENT_UNIFORM_VECTORS": 36349,
+    "SHADER_TYPE": 35663,
+    "DELETE_STATUS": 35712,
+    "LINK_STATUS": 35714,
+    "VALIDATE_STATUS": 35715,
+    "ATTACHED_SHADERS": 35717,
+    "ACTIVE_UNIFORMS": 35718,
+    "ACTIVE_ATTRIBUTES": 35721,
+    "SHADING_LANGUAGE_VERSION": 35724,
+    "CURRENT_PROGRAM": 35725,
+    "NEVER": 512,
+    "LESS": 513,
+    "EQUAL": 514,
+    "LEQUAL": 515,
+    "GREATER": 516,
+    "NOTEQUAL": 517,
+    "GEQUAL": 518,
+    "ALWAYS": 519,
+    "KEEP": 7680,
+    "REPLACE": 7681,
+    "INCR": 7682,
+    "DECR": 7683,
+    "INVERT": 5386,
+    "INCR_WRAP": 34055,
+    "DECR_WRAP": 34056,
+    "VENDOR": 7936,
+    "RENDERER": 7937,
+    "VERSION": 7938,
+    "NEAREST": 9728,
+    "LINEAR": 9729,
+    "NEAREST_MIPMAP_NEAREST": 9984,
+    "LINEAR_MIPMAP_NEAREST": 9985,
+    "NEAREST_MIPMAP_LINEAR": 9986,
+    "LINEAR_MIPMAP_LINEAR": 9987,
+    "TEXTURE_MAG_FILTER": 10240,
+    "TEXTURE_MIN_FILTER": 10241,
+    "TEXTURE_WRAP_S": 10242,
+    "TEXTURE_WRAP_T": 10243,
+    "TEXTURE": 5890,
+    "TEXTURE_CUBE_MAP": 34067,
+    "TEXTURE_BINDING_CUBE_MAP": 34068,
+    "TEXTURE_CUBE_MAP_POSITIVE_X": 34069,
+    "TEXTURE_CUBE_MAP_NEGATIVE_X": 34070,
+    "TEXTURE_CUBE_MAP_POSITIVE_Y": 34071,
+    "TEXTURE_CUBE_MAP_NEGATIVE_Y": 34072,
+    "TEXTURE_CUBE_MAP_POSITIVE_Z": 34073,
+    "TEXTURE_CUBE_MAP_NEGATIVE_Z": 34074,
+    "MAX_CUBE_MAP_TEXTURE_SIZE": 34076,
+    "TEXTURE0": 33984,
+    "TEXTURE1": 33985,
+    "TEXTURE2": 33986,
+    "TEXTURE3": 33987,
+    "TEXTURE4": 33988,
+    "TEXTURE5": 33989,
+    "TEXTURE6": 33990,
+    "TEXTURE7": 33991,
+    "TEXTURE8": 33992,
+    "TEXTURE9": 33993,
+    "TEXTURE10": 33994,
+    "TEXTURE11": 33995,
+    "TEXTURE12": 33996,
+    "TEXTURE13": 33997,
+    "TEXTURE14": 33998,
+    "TEXTURE15": 33999,
+    "TEXTURE16": 34000,
+    "TEXTURE17": 34001,
+    "TEXTURE18": 34002,
+    "TEXTURE19": 34003,
+    "TEXTURE20": 34004,
+    "TEXTURE21": 34005,
+    "TEXTURE22": 34006,
+    "TEXTURE23": 34007,
+    "TEXTURE24": 34008,
+    "TEXTURE25": 34009,
+    "TEXTURE26": 34010,
+    "TEXTURE27": 34011,
+    "TEXTURE28": 34012,
+    "TEXTURE29": 34013,
+    "TEXTURE30": 34014,
+    "TEXTURE31": 34015,
+    "ACTIVE_TEXTURE": 34016,
+    "REPEAT": 10497,
+    "CLAMP_TO_EDGE": 33071,
+    "MIRRORED_REPEAT": 33648,
+    "FLOAT_VEC2": 35664,
+    "FLOAT_VEC3": 35665,
+    "FLOAT_VEC4": 35666,
+    "INT_VEC2": 35667,
+    "INT_VEC3": 35668,
+    "INT_VEC4": 35669,
+    "BOOL": 35670,
+    "BOOL_VEC2": 35671,
+    "BOOL_VEC3": 35672,
+    "BOOL_VEC4": 35673,
+    "FLOAT_MAT2": 35674,
+    "FLOAT_MAT3": 35675,
+    "FLOAT_MAT4": 35676,
+    "SAMPLER_2D": 35678,
+    "SAMPLER_CUBE": 35680,
+    "VERTEX_ATTRIB_ARRAY_ENABLED": 34338,
+    "VERTEX_ATTRIB_ARRAY_SIZE": 34339,
+    "VERTEX_ATTRIB_ARRAY_STRIDE": 34340,
+    "VERTEX_ATTRIB_ARRAY_TYPE": 34341,
+    "VERTEX_ATTRIB_ARRAY_NORMALIZED": 34922,
+    "VERTEX_ATTRIB_ARRAY_POINTER": 34373,
+    "VERTEX_ATTRIB_ARRAY_BUFFER_BINDING": 34975,
+    "IMPLEMENTATION_COLOR_READ_TYPE": 35738,
+    "IMPLEMENTATION_COLOR_READ_FORMAT": 35739,
+    "COMPILE_STATUS": 35713,
+    "LOW_FLOAT": 36336,
+    "MEDIUM_FLOAT": 36337,
+    "HIGH_FLOAT": 36338,
+    "LOW_INT": 36339,
+    "MEDIUM_INT": 36340,
+    "HIGH_INT": 36341,
+    "FRAMEBUFFER": 36160,
+    "RENDERBUFFER": 36161,
+    "RGBA4": 32854,
+    "RGB5_A1": 32855,
+    "RGB565": 36194,
+    "DEPTH_COMPONENT16": 33189,
+    "STENCIL_INDEX8": 36168,
+    "DEPTH_STENCIL": 34041,
+    "RENDERBUFFER_WIDTH": 36162,
+    "RENDERBUFFER_HEIGHT": 36163,
+    "RENDERBUFFER_INTERNAL_FORMAT": 36164,
+    "RENDERBUFFER_RED_SIZE": 36176,
+    "RENDERBUFFER_GREEN_SIZE": 36177,
+    "RENDERBUFFER_BLUE_SIZE": 36178,
+    "RENDERBUFFER_ALPHA_SIZE": 36179,
+    "RENDERBUFFER_DEPTH_SIZE": 36180,
+    "RENDERBUFFER_STENCIL_SIZE": 36181,
+    "FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE": 36048,
+    "FRAMEBUFFER_ATTACHMENT_OBJECT_NAME": 36049,
+    "FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL": 36050,
+    "FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE": 36051,
+    "COLOR_ATTACHMENT0": 36064,
+    "DEPTH_ATTACHMENT": 36096,
+    "STENCIL_ATTACHMENT": 36128,
+    "DEPTH_STENCIL_ATTACHMENT": 33306,
+    "NONE": 0,
+    "FRAMEBUFFER_COMPLETE": 36053,
+    "FRAMEBUFFER_INCOMPLETE_ATTACHMENT": 36054,
+    "FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT": 36055,
+    "FRAMEBUFFER_INCOMPLETE_DIMENSIONS": 36057,
+    "FRAMEBUFFER_UNSUPPORTED": 36061,
+    "FRAMEBUFFER_BINDING": 36006,
+    "RENDERBUFFER_BINDING": 36007,
+    "MAX_RENDERBUFFER_SIZE": 34024,
+    "INVALID_FRAMEBUFFER_OPERATION": 1286,
+    "UNPACK_FLIP_Y_WEBGL": 37440,
+    "UNPACK_PREMULTIPLY_ALPHA_WEBGL": 37441,
+    "CONTEXT_LOST_WEBGL": 37442,
+    "UNPACK_COLORSPACE_CONVERSION_WEBGL": 37443,
+    "BROWSER_DEFAULT_WEBGL": 37444
+};

+ 142 - 0
uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-webgl/GLmethod.js

@@ -0,0 +1,142 @@
+let i = 1;
+
+const GLmethod = {};
+
+GLmethod.activeTexture = i++;         //1
+GLmethod.attachShader = i++;
+GLmethod.bindAttribLocation = i++;
+GLmethod.bindBuffer = i++;
+GLmethod.bindFramebuffer = i++;
+GLmethod.bindRenderbuffer = i++;
+GLmethod.bindTexture = i++;
+GLmethod.blendColor = i++;
+GLmethod.blendEquation = i++;
+GLmethod.blendEquationSeparate = i++; //10
+GLmethod.blendFunc = i++;
+GLmethod.blendFuncSeparate = i++;
+GLmethod.bufferData = i++;
+GLmethod.bufferSubData = i++;
+GLmethod.checkFramebufferStatus = i++;
+GLmethod.clear = i++;
+GLmethod.clearColor = i++;
+GLmethod.clearDepth = i++;
+GLmethod.clearStencil = i++;
+GLmethod.colorMask = i++;              //20
+GLmethod.compileShader = i++;
+GLmethod.compressedTexImage2D = i++;
+GLmethod.compressedTexSubImage2D = i++;
+GLmethod.copyTexImage2D = i++;
+GLmethod.copyTexSubImage2D = i++;
+GLmethod.createBuffer = i++;
+GLmethod.createFramebuffer = i++;
+GLmethod.createProgram = i++;
+GLmethod.createRenderbuffer = i++;
+GLmethod.createShader = i++;           //30
+GLmethod.createTexture = i++;
+GLmethod.cullFace = i++;
+GLmethod.deleteBuffer = i++;
+GLmethod.deleteFramebuffer = i++;
+GLmethod.deleteProgram = i++;
+GLmethod.deleteRenderbuffer = i++;
+GLmethod.deleteShader = i++;
+GLmethod.deleteTexture = i++;
+GLmethod.depthFunc = i++;
+GLmethod.depthMask = i++;              //40
+GLmethod.depthRange = i++;
+GLmethod.detachShader = i++;
+GLmethod.disable = i++;
+GLmethod.disableVertexAttribArray = i++;
+GLmethod.drawArrays = i++;
+GLmethod.drawArraysInstancedANGLE = i++;
+GLmethod.drawElements = i++;
+GLmethod.drawElementsInstancedANGLE = i++;
+GLmethod.enable = i++;
+GLmethod.enableVertexAttribArray = i++;    //50
+GLmethod.flush = i++;
+GLmethod.framebufferRenderbuffer = i++;
+GLmethod.framebufferTexture2D = i++;
+GLmethod.frontFace = i++;
+GLmethod.generateMipmap = i++;
+GLmethod.getActiveAttrib = i++;
+GLmethod.getActiveUniform = i++;
+GLmethod.getAttachedShaders = i++;
+GLmethod.getAttribLocation = i++;
+GLmethod.getBufferParameter = i++;         //60
+GLmethod.getContextAttributes = i++;
+GLmethod.getError = i++;
+GLmethod.getExtension = i++;
+GLmethod.getFramebufferAttachmentParameter = i++;
+GLmethod.getParameter = i++;
+GLmethod.getProgramInfoLog = i++;
+GLmethod.getProgramParameter = i++;
+GLmethod.getRenderbufferParameter = i++;
+GLmethod.getShaderInfoLog = i++;
+GLmethod.getShaderParameter = i++;         //70
+GLmethod.getShaderPrecisionFormat = i++;
+GLmethod.getShaderSource = i++;
+GLmethod.getSupportedExtensions = i++;
+GLmethod.getTexParameter = i++;
+GLmethod.getUniform = i++;
+GLmethod.getUniformLocation = i++;
+GLmethod.getVertexAttrib = i++;
+GLmethod.getVertexAttribOffset = i++;
+GLmethod.isBuffer = i++;
+GLmethod.isContextLost = i++;              //80
+GLmethod.isEnabled = i++;
+GLmethod.isFramebuffer = i++;
+GLmethod.isProgram = i++;
+GLmethod.isRenderbuffer = i++;
+GLmethod.isShader = i++;
+GLmethod.isTexture = i++;
+GLmethod.lineWidth = i++;
+GLmethod.linkProgram = i++;
+GLmethod.pixelStorei = i++;
+GLmethod.polygonOffset = i++;              //90
+GLmethod.readPixels = i++;
+GLmethod.renderbufferStorage = i++;
+GLmethod.sampleCoverage = i++;
+GLmethod.scissor = i++;
+GLmethod.shaderSource = i++;
+GLmethod.stencilFunc = i++;
+GLmethod.stencilFuncSeparate = i++;
+GLmethod.stencilMask = i++;
+GLmethod.stencilMaskSeparate = i++;
+GLmethod.stencilOp = i++;                  //100
+GLmethod.stencilOpSeparate = i++;
+GLmethod.texImage2D = i++;
+GLmethod.texParameterf = i++;
+GLmethod.texParameteri = i++;
+GLmethod.texSubImage2D = i++;
+GLmethod.uniform1f = i++;
+GLmethod.uniform1fv = i++;
+GLmethod.uniform1i = i++;
+GLmethod.uniform1iv = i++;
+GLmethod.uniform2f = i++;                  //110
+GLmethod.uniform2fv = i++;
+GLmethod.uniform2i = i++;
+GLmethod.uniform2iv = i++;
+GLmethod.uniform3f = i++;
+GLmethod.uniform3fv = i++;
+GLmethod.uniform3i = i++;
+GLmethod.uniform3iv = i++;
+GLmethod.uniform4f = i++;
+GLmethod.uniform4fv = i++;
+GLmethod.uniform4i = i++;                  //120
+GLmethod.uniform4iv = i++;
+GLmethod.uniformMatrix2fv = i++;
+GLmethod.uniformMatrix3fv = i++;
+GLmethod.uniformMatrix4fv = i++;
+GLmethod.useProgram = i++;
+GLmethod.validateProgram = i++;
+GLmethod.vertexAttrib1f = i++; //new
+GLmethod.vertexAttrib2f = i++; //new
+GLmethod.vertexAttrib3f = i++; //new
+GLmethod.vertexAttrib4f = i++; //new       //130
+GLmethod.vertexAttrib1fv = i++; //new
+GLmethod.vertexAttrib2fv = i++; //new
+GLmethod.vertexAttrib3fv = i++; //new
+GLmethod.vertexAttrib4fv = i++; //new
+GLmethod.vertexAttribPointer = i++;
+GLmethod.viewport = i++;
+
+export default GLmethod;

+ 23 - 0
uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-webgl/GLtype.js

@@ -0,0 +1,23 @@
+const GLtype = {};
+
+[
+    "GLbitfield",    
+    "GLboolean",
+    "GLbyte",
+    "GLclampf",
+    "GLenum",
+    "GLfloat",
+    "GLint",
+    "GLintptr",
+    "GLsizei",
+    "GLsizeiptr",
+    "GLshort",
+    "GLubyte",
+    "GLuint",
+    "GLushort"
+].sort().map((typeName, i) => GLtype[typeName] = 1 >> (i + 1));
+
+export default GLtype;
+
+
+

+ 21 - 0
uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-webgl/Program.js

@@ -0,0 +1,21 @@
+import {getTransferedObjectUUID} from './classUtils';
+
+const name = 'WebGLProgram';
+
+function uuid(id) {
+    return getTransferedObjectUUID(name, id);
+}
+
+export default class WebGLProgram {
+    className = name;
+
+    constructor(id) {
+        this.id = id;
+    }
+
+    static uuid = uuid;
+
+    uuid() {
+        return uuid(this.id);
+    }
+}

+ 21 - 0
uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-webgl/Renderbuffer.js

@@ -0,0 +1,21 @@
+import {getTransferedObjectUUID} from './classUtils';
+
+const name = 'WebGLRenderBuffer';
+
+function uuid(id) {
+    return getTransferedObjectUUID(name, id);
+}
+
+export default class WebGLRenderbuffer {
+    className = name;
+
+    constructor(id) {
+        this.id = id;
+    }
+
+    static uuid = uuid;
+
+    uuid() {
+        return uuid(this.id);
+    }
+}

+ 1191 - 0
uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-webgl/RenderingContext.js

@@ -0,0 +1,1191 @@
+import GLenum from './GLenum';
+import ActiveInfo from './ActiveInfo';
+import Buffer from './Buffer';
+import Framebuffer from './Framebuffer';
+import Renderbuffer from './Renderbuffer';
+import Texture from './Texture';
+import Program from './Program';
+import Shader from './Shader';
+import ShaderPrecisionFormat from './ShaderPrecisionFormat';
+import UniformLocation from './UniformLocation';
+import GLmethod from './GLmethod';
+
+const processArray = (array, checkArrayType = false) => {
+
+    function joinArray(arr, sep) {
+        let res = '';
+        for (let i = 0; i < arr.length; i++) {
+            if (i !== 0) {
+                res += sep;
+            }
+            res += arr[i];
+        }
+        return res;
+    }
+
+    let type = 'Float32Array';
+    if (checkArrayType) {
+        if (array instanceof Uint8Array) {
+            type = 'Uint8Array'
+        } else if (array instanceof Uint16Array) {
+            type = 'Uint16Array';
+        } else if (array instanceof Uint32Array) {
+            type = 'Uint32Array';
+        } else if (array instanceof Float32Array) {
+            type = 'Float32Array';
+        } else {
+            throw new Error('Check array type failed. Array type is ' + typeof array);
+        }
+    }
+
+    const ArrayTypes = {
+        Uint8Array: 1,
+        Uint16Array: 2,
+        Uint32Array: 4,
+        Float32Array: 14
+    };
+    return ArrayTypes[type] + ',' + btoa(joinArray(array, ','))
+}
+
+export default class WebGLRenderingContext {
+
+    // static GBridge = null;
+
+    className = 'WebGLRenderingContext';
+
+    constructor(canvas, type, attrs) {
+        this._canvas = canvas;
+        this._type = type;
+        this._version = 'WebGL 1.0';
+        this._attrs = attrs;
+        this._map = new Map();
+
+        Object.keys(GLenum)
+            .forEach(name => Object.defineProperty(this, name, {
+                value: GLenum[name]
+            }));
+    }
+
+    get canvas() {
+        return this._canvas;
+    }
+
+    activeTexture = function (textureUnit) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.activeTexture + ',' + textureUnit,
+            true
+        );
+    }
+
+    attachShader = function (progarm, shader) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.attachShader + ',' + progarm.id + ',' + shader.id,
+            true
+        );
+    }
+
+    bindAttribLocation = function (program, index, name) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.bindAttribLocation + ',' + program.id + ',' + index + ',' + name,
+            true
+        )
+    }
+
+    bindBuffer = function (target, buffer) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.bindBuffer + ',' + target + ',' + (buffer ? buffer.id : 0),
+            true
+        );
+    }
+
+    bindFramebuffer = function (target, framebuffer) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.bindFramebuffer + ',' + target + ',' + (framebuffer ? framebuffer.id : 0),
+            true
+        )
+    }
+
+    bindRenderbuffer = function (target, renderBuffer) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.bindRenderbuffer + ',' + target + ',' + (renderBuffer ? renderBuffer.id : 0),
+            true
+        )
+    }
+
+    bindTexture = function (target, texture) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.bindTexture + ',' + target + ',' + (texture ? texture.id : 0),
+            true
+        )
+    }
+
+    blendColor = function (r, g, b, a) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.blendColor + ',' + target + ',' + r + ',' + g + ',' + b + ',' + a,
+            true
+        )
+    }
+
+    blendEquation = function (mode) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.blendEquation + ',' + mode,
+            true
+        )
+    }
+
+    blendEquationSeparate = function (modeRGB, modeAlpha) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.blendEquationSeparate + ',' + modeRGB + ',' + modeAlpha,
+            true
+        )
+    }
+
+
+    blendFunc = function (sfactor, dfactor) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.blendFunc + ',' + sfactor + ',' + dfactor,
+            true
+        );
+    }
+
+    blendFuncSeparate = function (srcRGB, dstRGB, srcAlpha, dstAlpha) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.blendFuncSeparate + ',' + srcRGB + ',' + dstRGB + ',' + srcAlpha + ',' + dstAlpha,
+            true
+        );
+    }
+
+    bufferData = function (target, data, usage) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.bufferData + ',' + target + ',' + processArray(data, true) + ',' + usage,
+            true
+        )
+    }
+
+    bufferSubData = function (target, offset, data) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.bufferSubData + ',' + target + ',' + offset + ',' + processArray(data, true),
+            true
+        )
+    }
+
+    checkFramebufferStatus = function (target) {
+        const result = WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.checkFramebufferStatus + ',' + target
+        );
+        return Number(result);
+    }
+
+    clear = function (mask) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.clear + ',' + mask
+        );
+        this._canvas._needRender = true;
+    }
+
+    clearColor = function (r, g, b, a) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.clearColor + ',' + r + ',' + g + ',' + b,
+            true
+        )
+    }
+
+    clearDepth = function (depth) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.clearDepth + ',' + depth,
+            true
+        )
+    }
+
+    clearStencil = function (s) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.clearStencil + ',' + s
+        );
+    }
+
+    colorMask = function (r, g, b, a) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.colorMask + ',' + r + ',' + g + ',' + b + ',' + a
+        )
+    }
+
+    compileShader = function (shader) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.compileShader + ',' + shader.id,
+            true
+        )
+    }
+
+    compressedTexImage2D = function (target, level, internalformat, width, height, border, pixels) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.compressedTexImage2D + ',' + target + ',' + level + ',' + internalformat + ',' +
+            width + ',' + height + ',' + border + ',' + processArray(pixels),
+            true
+        )
+    }
+
+    compressedTexSubImage2D = function (target, level, xoffset, yoffset, width, height, format, pixels) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.compressedTexSubImage2D + ',' + target + ',' + level + ',' + xoffset + ',' + yoffset + ',' +
+            width + ',' + height + ',' + format + ',' + processArray(pixels),
+            true
+        )
+    }
+
+
+    copyTexImage2D = function (target, level, internalformat, x, y, width, height, border) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.copyTexImage2D + ',' + target + ',' + level + ',' + internalformat + ',' + x + ',' + y + ',' +
+            width + ',' + height + ',' + border,
+            true
+        );
+    }
+
+    copyTexSubImage2D = function (target, level, xoffset, yoffset, x, y, width, height) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.copyTexSubImage2D + ',' + target + ',' + level + ',' + xoffset + ',' + yoffset + ',' + x + ',' + y + ',' +
+            width + ',' + height
+        );
+    }
+
+    createBuffer = function () {
+        const result = WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.createBuffer + ''
+        );
+        const buffer = new Buffer(result);
+        this._map.set(buffer.uuid(), buffer);
+        return buffer;
+    }
+
+    createFramebuffer = function () {
+        const result = WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.createFramebuffer + ''
+        );
+        const framebuffer = new Framebuffer(result);
+        this._map.set(framebuffer.uuid(), framebuffer);
+        return framebuffer;
+    }
+
+
+    createProgram = function () {
+        const id = WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.createProgram + ''
+        );
+        const program = new Program(id);
+        this._map.set(program.uuid(), program);
+        return program;
+    }
+
+    createRenderbuffer = function () {
+        const id = WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.createRenderbuffer + ''
+        )
+        const renderBuffer = new Renderbuffer(id);
+        this._map.set(renderBuffer.uuid(), renderBuffer);
+        return renderBuffer;
+    }
+
+    createShader = function (type) {
+        const id = WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.createShader + ',' + type
+        )
+        const shader = new Shader(id, type);
+        this._map.set(shader.uuid(), shader);
+        return shader;
+    }
+
+    createTexture = function () {
+        const id = WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.createTexture + ''
+        );
+        const texture = new Texture(id);
+        this._map.set(texture.uuid(), texture);
+        return texture;
+    }
+
+    cullFace = function (mode) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.cullFace + ',' + mode,
+            true
+        )
+    }
+
+
+    deleteBuffer = function (buffer) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.deleteBuffer + ',' + buffer.id,
+            true
+        )
+    }
+
+    deleteFramebuffer = function (framebuffer) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.deleteFramebuffer + ',' + framebuffer.id,
+            true
+        )
+    }
+
+    deleteProgram = function (program) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.deleteProgram + ',' + program.id,
+            true
+        )
+    }
+
+    deleteRenderbuffer = function (renderbuffer) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.deleteRenderbuffer + ',' + renderbuffer.id,
+            true
+        )
+    }
+
+    deleteShader = function (shader) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.deleteShader + ',' + shader.id,
+            true
+        )
+    }
+
+    deleteTexture = function (texture) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.deleteTexture + ',' + texture.id,
+            true
+        )
+    }
+
+    depthFunc = function (func) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.depthFunc + ',' + func
+        )
+    }
+
+    depthMask = function (flag) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.depthMask + ',' + Number(flag),
+            true
+        )
+    }
+
+    depthRange = function (zNear, zFar) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.depthRange + ',' + zNear + ',' + zFar,
+            true
+        )
+    }
+
+    detachShader = function (program, shader) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.detachShader + ',' + program.id + ',' + shader.id,
+            true
+        )
+    }
+
+    disable = function (cap) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.disable + ',' + cap,
+            true
+        )
+    }
+
+    disableVertexAttribArray = function (index) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.disableVertexAttribArray + ',' + index,
+            true
+        );
+    }
+
+    drawArrays = function (mode, first, count) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.drawArrays + ',' + mode + ',' + first + ',' + count
+        )
+        this._canvas._needRender = true;
+    }
+
+    drawElements = function (mode, count, type, offset) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.drawElements + ',' + mode + ',' + count + ',' + type + ',' + offset + ';'
+        );
+        this._canvas._needRender = true;
+    }
+
+    enable = function (cap) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.enable + ',' + cap,
+            true
+        );
+    }
+
+    enableVertexAttribArray = function (index) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.enableVertexAttribArray + ',' + index,
+            true
+        )
+    }
+
+
+    flush = function () {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.flush + ''
+        )
+    }
+
+    framebufferRenderbuffer = function (target, attachment, textarget, texture, level) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.framebufferRenderbuffer + ',' + target + ',' + attachment + ',' + textarget + ',' + (texture ? texture.id : 0) + ',' + level,
+            true
+        )
+    }
+
+    framebufferTexture2D = function (target, attachment, textarget, texture, level) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.framebufferTexture2D + ',' + target + ',' + attachment + ',' + textarget + ',' + (texture ? texture.id : 0) + ',' + level,
+            true
+        )
+    }
+
+    frontFace = function (mode) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.frontFace + ',' + mode,
+            true
+        )
+    }
+
+    generateMipmap = function (target) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.generateMipmap + ',' + target,
+            true
+        )
+    }
+
+    getActiveAttrib = function (progarm, index) {
+        const resultString = WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.getActiveAttrib + ',' + progarm.id + ',' + index
+        )
+        const [type, size, name] = resultString.split(',');
+        return new ActiveInfo({
+            type: Number(type),
+            size: Number(size),
+            name
+        });
+    }
+
+    getActiveUniform = function (progarm, index) {
+        const resultString = WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.getActiveUniform + ',' + progarm.id + ',' + index
+        );
+        const [type, size, name] = resultString.split(',');
+        return new ActiveInfo({
+            type: Number(type),
+            size: Number(size),
+            name
+        })
+    }
+
+    getAttachedShaders = function (progarm) {
+        const result = WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.getAttachedShaders + ',' + progarm.id
+        );
+        const [type, ...ids] = result;
+        return ids.map(id => this._map.get(Shader.uuid(id)));
+    }
+
+    getAttribLocation = function (progarm, name) {
+        return WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.getAttribLocation + ',' + progarm.id + ',' + name
+        )
+    }
+
+    getBufferParameter = function (target, pname) {
+        const result = WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.getBufferParameter + ',' + target + ',' + pname
+        );
+        const [type, res] = getBufferParameter;
+        return res;
+    }
+
+    getError = function () {
+        const result = WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.getError + ''
+        )
+        return result;
+    }
+
+    getExtension = function (name) {
+        return null;
+    }
+
+    getFramebufferAttachmentParameter = function (target, attachment, pname) {
+        const result = WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.getFramebufferAttachmentParameter + ',' + target + ',' + attachment + ',' + pname
+        )
+        switch (pname) {
+            case GLenum.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
+                return this._map.get(Renderbuffer.uuid(result)) || this._map.get(Texture.uuid(result)) || null;
+            default:
+                return result;
+        }
+    }
+
+    getParameter = function (pname) {
+        const result = WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.getParameter + ',' + pname
+        )
+        switch (pname) {
+            case GLenum.VERSION:
+                return this._version;
+            case GLenum.ARRAY_BUFFER_BINDING: // buffer
+            case GLenum.ELEMENT_ARRAY_BUFFER_BINDING: // buffer
+                return this._map.get(Buffer.uuid(result)) || null;
+            case GLenum.CURRENT_PROGRAM: // program
+                return this._map.get(Program.uuid(result)) || null;
+            case GLenum.FRAMEBUFFER_BINDING: // framebuffer
+                return this._map.get(Framebuffer.uuid(result)) || null;
+            case GLenum.RENDERBUFFER_BINDING: // renderbuffer
+                return this._map.get(Renderbuffer.uuid(result)) || null;
+            case GLenum.TEXTURE_BINDING_2D: // texture
+            case GLenum.TEXTURE_BINDING_CUBE_MAP: // texture
+                return this._map.get(Texture.uuid(result)) || null;
+            case GLenum.ALIASED_LINE_WIDTH_RANGE: // Float32Array
+            case GLenum.ALIASED_POINT_SIZE_RANGE: // Float32Array
+            case GLenum.BLEND_COLOR: // Float32Array
+            case GLenum.COLOR_CLEAR_VALUE: // Float32Array
+            case GLenum.DEPTH_RANGE: // Float32Array
+            case GLenum.MAX_VIEWPORT_DIMS: // Int32Array
+            case GLenum.SCISSOR_BOX: // Int32Array
+            case GLenum.VIEWPORT: // Int32Array            
+            case GLenum.COMPRESSED_TEXTURE_FORMATS: // Uint32Array
+            default:
+                const [type, ...res] = result.split(',');
+                if (res.length === 1) {
+                    return Number(res[0]);
+                } else {
+                    return res.map(Number);
+                }
+        }
+    }
+
+    getProgramInfoLog = function (progarm) {
+        return WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.getProgramInfoLog + ',' + progarm.id
+        )
+    }
+
+    getProgramParameter = function (program, pname) {
+        const res = WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.getProgramParameter + ',' + program.id + ',' + pname
+        );
+
+        const [type, result] = res.split(',').map(i => parseInt(i));
+
+        if (type === 1) {
+            return Boolean(result);
+        } else if (type === 2) {
+            return result;
+        } else {
+            throw new Error('Unrecongized program paramater ' + res + ', type: ' + typeof res);
+        }
+    }
+
+
+    getRenderbufferParameter = function (target, pname) {
+        const result = WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.getRenderbufferParameter + ',' + target + ',' + pname
+        )
+        return result;
+    }
+
+
+    getShaderInfoLog = function (shader) {
+        return WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.getShaderInfoLog + ',' + shader.id
+        );
+    }
+
+    getShaderParameter = function (shader, pname) {
+        return WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.getShaderParameter + ',' + shader.id + ',' + pname
+        )
+    }
+
+    getShaderPrecisionFormat = function (shaderType, precisionType) {
+        const [rangeMin, rangeMax, precision] = WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.getShaderPrecisionFormat + ',' + shaderType + ',' + precisionType
+        );
+        const shaderPrecisionFormat = new ShaderPrecisionFormat({
+            rangeMin: Number(rangeMin),
+            rangeMax: Number(rangeMax),
+            precision: Number(precision)
+        });
+        return shaderPrecisionFormat;
+    }
+
+    getShaderSource = function (shader) {
+        const result = WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.getShaderSource + ',' + shader.id
+        );
+        return result;
+    }
+
+    getSupportedExtensions = function () {
+        return Object.keys({});
+    }
+
+    getTexParameter = function (target, pname) {
+        const result = WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.getTexParameter + ',' + target + ',' + pname
+        )
+        return result;
+    }
+
+    getUniformLocation = function (program, name) {
+        const id = WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.getUniformLocation + ',' + program.id + ',' + name
+        );
+        if (id === -1) {
+            return null;
+        } else {
+            return new UniformLocation(Number(id));
+        }
+    }
+
+    getVertexAttrib = function (index, pname) {
+        const result = WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.getVertexAttrib + ',' + index + ',' + pname
+        );
+        switch (pname) {
+            case GLenum.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
+                return this._map.get(Buffer.uuid(result)) || null;
+            case GLenum.CURRENT_VERTEX_ATTRIB: // Float32Array
+            default:
+                return result;
+        }
+    }
+
+    getVertexAttribOffset = function (index, pname) {
+        const result = WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.getVertexAttribOffset + ',' + index + ',' + pname
+        )
+        return Number(result);
+    }
+
+    isBuffer = function (buffer) {
+        const result = WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.isBuffer + ',' + buffer.id
+        )
+        return Boolean(result);
+    }
+
+    isContextLost = function () {
+        return false;
+    }
+
+    isEnabled = function (cap) {
+        const result = WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.isEnabled + ',' + cap
+        )
+        return Boolean(result);
+    }
+
+    isFramebuffer = function (framebuffer) {
+        const result = WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.isFramebuffer + ',' + framebuffer.id
+        )
+        return Boolean(result);
+    }
+
+    isProgram = function (program) {
+        const result = WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.isProgram + ',' + program.id
+        )
+        return Boolean(result);
+    }
+
+    isRenderbuffer = function (renderBuffer) {
+        const result = WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.isRenderbuffer + ',' + renderbuffer.id
+        )
+        return Boolean(result);
+    }
+
+    isShader = function (shader) {
+        const result = WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.isShader + ',' + shader.id
+        )
+        return Boolean(result);
+    }
+
+    isTexture = function (texture) {
+        const result = WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.isTexture + ',' + texture.id
+        );
+        return Boolean(result);
+    }
+
+    lineWidth = function (width) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.lineWidth + ',' + width,
+            true
+        )
+    }
+
+    linkProgram = function (program) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.linkProgram + ',' + program.id,
+            true
+        );
+    }
+
+
+    pixelStorei = function (pname, param) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.pixelStorei + ',' + pname + ',' + Number(param)
+        )
+    }
+
+    polygonOffset = function (factor, units) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.polygonOffset + ',' + factor + ',' + units
+        )
+    }
+
+    readPixels = function (x, y, width, height, format, type, pixels) {
+        const result = WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.readPixels + ',' + x + ',' + y + ',' + width + ',' + height + ',' + format + ',' + type
+        )
+        return result;
+    }
+
+    renderbufferStorage = function (target, internalFormat, width, height) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.renderbufferStorage + ',' + target + ',' + internalFormat + ',' + width + ',' + height,
+            true
+        )
+    }
+
+    sampleCoverage = function (value, invert) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.sampleCoverage + ',' + value + ',' + Number(invert),
+            true
+        )
+    }
+
+    scissor = function (x, y, width, height) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.scissor + ',' + x + ',' + y + ',' + width + ',' + height,
+            true
+        )
+    }
+
+    shaderSource = function (shader, source) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.shaderSource + ',' + shader.id + ',' + source
+        )
+    }
+
+    stencilFunc = function (func, ref, mask) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.stencilFunc + ',' + func + ',' + ref + ',' + mask,
+            true
+        )
+    }
+
+    stencilFuncSeparate = function (face, func, ref, mask) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.stencilFuncSeparate + ',' + face + ',' + func + ',' + ref + ',' + mask,
+            true
+        )
+    }
+
+    stencilMask = function (mask) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.stencilMask + ',' + mask,
+            true
+        )
+    }
+
+    stencilMaskSeparate = function (face, mask) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.stencilMaskSeparate + ',' + face + ',' + mask,
+            true
+        )
+    }
+
+    stencilOp = function (fail, zfail, zpass) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.stencilOp + ',' + fail + ',' + zfail + ',' + zpass
+        )
+    }
+
+    stencilOpSeparate = function (face, fail, zfail, zpass) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.stencilOp + ',' + face + ',' + fail + ',' + zfail + ',' + zpass,
+            true
+        )
+    }
+
+    texImage2D = function (...args) {
+        WebGLRenderingContext.GBridge.texImage2D(this._canvas.id, ...args);
+    }
+
+
+    texParameterf = function (target, pname, param) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.texParameterf + ',' + target + ',' + pname + ',' + param,
+            true
+        )
+    }
+
+    texParameteri = function (target, pname, param) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.texParameteri + ',' + target + ',' + pname + ',' + param
+        )
+    }
+
+    texSubImage2D = function (...args) {
+        WebGLRenderingContext.GBridge.texSubImage2D(this._canvas.id, ...args);
+    }
+
+    uniform1f = function (location, v0) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.uniform1f + ',' + location.id + ',' + v0
+        )
+    }
+
+    uniform1fv = function (location, value) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.uniform1fv + ',' + location.id + ',' + processArray(value),
+            true
+        )
+    }
+
+    uniform1i = function (location, v0) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.uniform1i + ',' + location.id + ',' + v0,
+            // true
+        )
+    }
+
+    uniform1iv = function (location, value) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.uniform1iv + ',' + location.id + ',' + processArray(value),
+            true
+        )
+    }
+
+    uniform2f = function (location, v0, v1) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.uniform2f + ',' + location.id + ',' + v0 + ',' + v1,
+            true
+        )
+    }
+
+    uniform2fv = function (location, value) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.uniform2fv + ',' + location.id + ',' + processArray(value),
+            true
+        )
+    }
+
+    uniform2i = function (location, v0, v1) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.uniform2i + ',' + location.id + ',' + v0 + ',' + v1,
+            true
+        )
+    }
+
+    uniform2iv = function (location, value) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.uniform2iv + ',' + location.id + ',' + processArray(value),
+            true
+        )
+    }
+
+    uniform3f = function (location, v0, v1, v2) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.uniform3f + ',' + location.id + ',' + v0 + ',' + v1 + ',' + v2,
+            true
+        )
+    }
+
+    uniform3fv = function (location, value) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.uniform3fv + ',' + location.id + ',' + processArray(value),
+            true
+        )
+    }
+
+    uniform3i = function (location, v0, v1, v2) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.uniform3i + ',' + location.id + ',' + v0 + ',' + v1 + ',' + v2,
+            true
+        )
+    }
+
+    uniform3iv = function (location, value) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.uniform3iv + ',' + location.id + ',' + processArray(value),
+            true
+        )
+    }
+
+    uniform4f = function (location, v0, v1, v2, v3) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.uniform4f + ',' + location.id + ',' + v0 + ',' + v1 + ',' + v2 + ',' + v3,
+            true
+        )
+    }
+
+    uniform4fv = function (location, value) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.uniform4fv + ',' + location.id + ',' + processArray(value),
+            true
+        )
+    }
+
+    uniform4i = function (location, v0, v1, v2, v3) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.uniform4i + ',' + location.id + ',' + v0 + ',' + v1 + ',' + v2 + ',' + v3,
+            true
+        )
+    }
+
+    uniform4iv = function (location, value) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.uniform4iv + ',' + location.id + ',' + processArray(value, true),
+            true
+        )
+    }
+
+    uniformMatrix2fv = function (location, transpose, value) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.uniformMatrix2fv + ',' + location.id + ',' + Number(transpose) + ',' + processArray(value),
+            true
+        )
+    }
+
+    uniformMatrix3fv = function (location, transpose, value) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.uniformMatrix3fv + ',' + location.id + ',' + Number(transpose) + ',' + processArray(value),
+            true
+        )
+    }
+
+    uniformMatrix4fv = function (location, transpose, value) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.uniformMatrix4fv + ',' + location.id + ',' + Number(transpose) + ',' + processArray(value),
+            true
+        );
+    }
+
+    useProgram = function (progarm) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.useProgram + ',' + progarm.id + '',
+            true
+        )
+    }
+
+
+    validateProgram = function (program) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.validateProgram + ',' + program.id,
+            true
+        )
+    }
+
+    vertexAttrib1f = function (index, v0) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.vertexAttrib1f + ',' + index + ',' + v0,
+            true
+        )
+    }
+
+    vertexAttrib2f = function (index, v0, v1) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.vertexAttrib2f + ',' + index + ',' + v0 + ',' + v1,
+            true
+        )
+    }
+
+    vertexAttrib3f = function (index, v0, v1, v2) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.vertexAttrib3f + ',' + index + ',' + v0 + ',' + v1 + ',' + v2,
+            true
+        )
+    }
+
+    vertexAttrib4f = function (index, v0, v1, v2, v3) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.vertexAttrib4f + ',' + index + ',' + v0 + ',' + v1 + ',' + v2 + ',' + v3,
+            true
+        )
+    }
+
+    vertexAttrib1fv = function (index, value) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.vertexAttrib1fv + ',' + index + ',' + processArray(value),
+            true
+        )
+    }
+
+    vertexAttrib2fv = function (index, value) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.vertexAttrib2fv + ',' + index + ',' + processArray(value),
+            true
+        )
+    }
+
+    vertexAttrib3fv = function (index, value) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.vertexAttrib3fv + ',' + index + ',' + processArray(value),
+            true
+        )
+    }
+
+    vertexAttrib4fv = function (index, value) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.vertexAttrib4fv + ',' + index + ',' + processArray(value),
+            true
+        )
+    }
+
+    vertexAttribPointer = function (index, size, type, normalized, stride, offset) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.vertexAttribPointer + ',' + index + ',' + size + ',' + type + ',' + Number(normalized) + ',' + stride + ',' + offset,
+            true
+        )
+    }
+
+    viewport = function (x, y, width, height) {
+        WebGLRenderingContext.GBridge.callNative(
+            this._canvas.id,
+            GLmethod.viewport + ',' + x + ',' + y + ',' + width + ',' + height,
+            true
+        )
+    }
+}

+ 22 - 0
uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-webgl/Shader.js

@@ -0,0 +1,22 @@
+import {getTransferedObjectUUID} from './classUtils';
+
+const name = 'WebGLShader';
+
+function uuid(id) {
+    return getTransferedObjectUUID(name, id);
+}
+
+export default class WebGLShader {
+    className = name;
+
+    constructor(id, type) {
+        this.id = id;
+        this.type = type;
+    }
+
+    static uuid = uuid;
+
+    uuid() {
+        return uuid(this.id);
+    }
+}

+ 11 - 0
uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-webgl/ShaderPrecisionFormat.js

@@ -0,0 +1,11 @@
+export default class WebGLShaderPrecisionFormat {
+    className = 'WebGLShaderPrecisionFormat';
+
+    constructor({
+        rangeMin, rangeMax, precision
+    }) {
+        this.rangeMin = rangeMin;
+        this.rangeMax = rangeMax;
+        this.precision = precision;
+    }
+}

+ 22 - 0
uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-webgl/Texture.js

@@ -0,0 +1,22 @@
+import {getTransferedObjectUUID} from './classUtils';
+
+const name = 'WebGLTexture';
+
+function uuid(id) {
+    return getTransferedObjectUUID(name, id);
+}
+
+export default class WebGLTexture {
+    className = name;
+
+    constructor(id, type) {
+        this.id = id;
+        this.type = type;
+    }
+
+    static uuid = uuid;
+
+    uuid() {
+        return uuid(this.id);
+    }
+}

+ 22 - 0
uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-webgl/UniformLocation.js

@@ -0,0 +1,22 @@
+import {getTransferedObjectUUID} from './classUtils';
+
+const name = 'WebGLUniformLocation';
+
+function uuid(id) {
+    return getTransferedObjectUUID(name, id);
+}
+
+export default class WebGLUniformLocation {
+    className = name;
+
+    constructor(id, type) {
+        this.id = id;
+        this.type = type;
+    }
+
+    static uuid = uuid;
+
+    uuid() {
+        return uuid(this.id);
+    }
+}

+ 3 - 0
uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/context-webgl/classUtils.js

@@ -0,0 +1,3 @@
+export function getTransferedObjectUUID(name, id) {
+    return `${name.toLowerCase()}-${id}`;
+}

+ 74 - 0
uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/env/canvas.js

@@ -0,0 +1,74 @@
+import GContext2D from '../context-2d/RenderingContext';
+import GContextWebGL from '../context-webgl/RenderingContext';
+
+export default class GCanvas {
+
+    // static GBridge = null;
+
+    id = null;
+
+    _needRender = true;
+
+    constructor(id, { disableAutoSwap }) {
+        this.id = id;
+
+        this._disableAutoSwap = disableAutoSwap;
+        if (disableAutoSwap) {
+            this._swapBuffers = () => {
+                GCanvas.GBridge.render(this.id);
+            }
+        }
+    }
+
+    getContext(type) {
+
+        let context = null;
+
+        if (type.match(/webgl/i)) {
+            context = new GContextWebGL(this);
+
+            context.componentId = this.id;
+
+            if (!this._disableAutoSwap) {
+                const render = () => {
+                    if (this._needRender) {
+                        GCanvas.GBridge.render(this.id);
+                        this._needRender = false;
+                    }
+                }
+                setInterval(render, 16);
+            }
+
+            GCanvas.GBridge.callSetContextType(this.id, 1); // 0 for 2d; 1 for webgl
+        } else if (type.match(/2d/i)) {
+            context = new GContext2D(this);
+
+            context.componentId = this.id;
+
+//             const render = ( callback ) => {
+// 
+//                 const commands = context._drawCommands;
+//                 context._drawCommands = '';
+// 
+//                 GCanvas.GBridge.render2d(this.id, commands, callback);
+//                 this._needRender = false;
+//             }
+// 			//draw方法触发
+// 			context._flush = render;
+//             //setInterval(render, 16);
+
+            GCanvas.GBridge.callSetContextType(this.id, 0);
+        } else {
+            throw new Error('not supported context ' + type);
+        }
+
+        return context;
+
+    }
+
+    reset() {
+        GCanvas.GBridge.callReset(this.id);
+    }
+
+
+}

+ 96 - 0
uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/env/image.js

@@ -0,0 +1,96 @@
+let incId = 1;
+
+const noop = function () { };
+
+class GImage {
+
+    static GBridge = null;
+
+    constructor() {
+        this._id = incId++;
+        this._width = 0;
+        this._height = 0;
+        this._src = undefined;
+        this._onload = noop;
+        this._onerror = noop;
+        this.complete = false;
+    }
+
+    get width() {
+        return this._width;
+    }
+    set width(v) {
+        this._width = v;
+    }
+
+    get height() {
+        return this._height;
+    }
+
+    set height(v) {
+        this._height = v;
+    }
+
+    get src() {
+        return this._src;
+    }
+
+    set src(v) {
+
+        if (v.startsWith('//')) {
+            v = 'http:' + v;
+        }
+
+        this._src = v;
+
+        GImage.GBridge.perloadImage([this._src, this._id], (data) => {
+            if (typeof data === 'string') {
+                data = JSON.parse(data);
+            }
+            if (data.error) {
+                var evt = { type: 'error', target: this };
+                this.onerror(evt);
+            } else {
+                this.complete = true;
+                this.width = typeof data.width === 'number' ? data.width : 0;
+                this.height = typeof data.height === 'number' ? data.height : 0;
+                var evt = { type: 'load', target: this };
+                this.onload(evt);
+            }
+        });
+    }
+
+    addEventListener(name, listener) {
+        if (name === 'load') {
+            this.onload = listener;
+        } else if (name === 'error') {
+            this.onerror = listener;
+        }
+    }
+
+    removeEventListener(name, listener) {
+        if (name === 'load') {
+            this.onload = noop;
+        } else if (name === 'error') {
+            this.onerror = noop;
+        }
+    }
+
+    get onload() {
+        return this._onload;
+    }
+
+    set onload(v) {
+        this._onload = v;
+    }
+
+    get onerror() {
+        return this._onerror;
+    }
+
+    set onerror(v) {
+        this._onerror = v;
+    }
+}
+
+export default GImage;

+ 24 - 0
uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/env/tool.js

@@ -0,0 +1,24 @@
+
+export function ArrayBufferToBase64 (buffer) {
+    var binary = '';
+    var bytes = new Uint8ClampedArray(buffer);
+    for (var len = bytes.byteLength, i = 0; i < len; i++) {
+        binary += String.fromCharCode(bytes[i]);
+    }
+    return btoa(binary);
+}
+	
+export function Base64ToUint8ClampedArray(base64String) {
+	const padding = '='.repeat((4 - base64String.length % 4) % 4);
+	const base64 = (base64String + padding)
+		.replace(/\-/g, '+')
+		.replace(/_/g, '/');
+
+	const rawData = atob(base64);
+	const outputArray = new Uint8ClampedArray(rawData.length);
+
+	for (let i = 0; i < rawData.length; ++i) {
+		outputArray[i] = rawData.charCodeAt(i);
+	}
+	return outputArray;
+}

+ 39 - 0
uni_modules/uv-qrcode/components/uv-qrcode/gcanvas/index.js

@@ -0,0 +1,39 @@
+import GCanvas from './env/canvas';
+import GImage from './env/image';
+
+import GWebGLRenderingContext from './context-webgl/RenderingContext';
+import GContext2D from './context-2d/RenderingContext';
+
+import GBridgeWeex from './bridge/bridge-weex';
+
+export let Image = GImage;
+
+export let WeexBridge = GBridgeWeex;
+
+export function enable(el, { bridge, debug, disableAutoSwap, disableComboCommands } = {}) {
+
+    const GBridge = GImage.GBridge = GCanvas.GBridge = GWebGLRenderingContext.GBridge = GContext2D.GBridge = bridge;
+
+    GBridge.callEnable(el.ref, [
+        0,      // renderMode: 0--RENDERMODE_WHEN_DIRTY, 1--RENDERMODE_CONTINUOUSLY
+        -1,     // hybridLayerType:  0--LAYER_TYPE_NONE 1--LAYER_TYPE_SOFTWARE 2--LAYER_TYPE_HARDWARE
+        false,  // supportScroll
+        false,  // newCanvasMode
+        1,      // compatible
+        'white',// clearColor
+        false   // sameLevel: newCanvasMode = true && true => GCanvasView and Webview is same level
+    ]);
+
+    if (debug === true) {
+        GBridge.callEnableDebug();
+    }
+    if (disableComboCommands) {
+        GBridge.callEnableDisableCombo();
+    }
+
+    var canvas = new GCanvas(el.ref, { disableAutoSwap });
+    canvas.width = el.style.width;
+    canvas.height = el.style.height;
+
+    return canvas;
+};

+ 85 - 0
uni_modules/uv-qrcode/components/uv-qrcode/props.js

@@ -0,0 +1,85 @@
+export default {
+	props: {
+		//二维码内容
+		value: {
+			type: [String, Number]
+		},
+		//选项
+		options: {
+			type: Object,
+			default: () => {
+				return {};
+			}
+		},
+		//二维码大小
+		size: {
+			type: [String, Number],
+			default: 200
+		},
+		//导出的文件类型
+		fileType: {
+			type: String,
+			default: 'png'
+		},
+		//是否初始化组件后就开始生成
+		start: {
+			type: Boolean,
+			default: true
+		},
+		//是否数据发生改变自动重绘
+		auto: {
+			type: Boolean,
+			default: true
+		},
+		//隐藏组件
+		hide: {
+			type: Boolean,
+			default: false
+		},
+		/**
+		 * canvas 类型,微信小程序默认使用2d,非2d微信官方已放弃维护,问题比较多
+		 * 注意:微信小程序type2d手机上正常,PC上微信内打开小程序toDataURL报错,看后期微信官方团队会不会做兼容,不兼容的话只能在自行判断在PC使用非2d,或者直接提示用户请在手机上操作,微信团队的海报中心小程序就是这么做的
+		 */
+		type: {
+			type: String,
+			default: () => {
+				// #ifdef MP-WEIXIN
+				return '2d';
+				// #endif
+				// #ifndef MP-WEIXIN
+				return 'normal';
+				// #endif
+			}
+		},
+		//队列绘制,主要针对NVue端
+		queue: {
+			type: Boolean,
+			default: false
+		},
+		//是否队列加载图片,可减少canvas发起的网络资源请求,节省服务器资源
+		isQueueLoadImage: {
+			type: Boolean,
+			default: false
+		},
+		//loading态
+		loading: {
+			type: Boolean,
+			default: undefined
+		},
+		//H5保存即自动下载(在支持的环境下),默认false为仅弹层提示用户需要长按图片保存,不会自动下载
+		h5SaveIsDownload: {
+			type: Boolean,
+			default: false
+		},
+		//H5下载名称
+		h5DownloadName: {
+			type: String,
+			default: 'uvQRCode'
+		},
+		// H5保存二维码时候是否显示提示
+		h5SaveTip: {
+			type: Boolean,
+			default: true
+		}
+	}
+}

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 33 - 0
uni_modules/uv-qrcode/components/uv-qrcode/qrcode.js


+ 41 - 0
uni_modules/uv-qrcode/components/uv-qrcode/queue.js

@@ -0,0 +1,41 @@
+function Queue() {
+  let waitingQueue = this.waitingQueue = [];
+  let isRunning = this.isRunning = false; // 记录是否有未完成的任务
+
+  function execute(task, resolve, reject) {
+    task()
+      .then((data) => {
+        resolve(data);
+      })
+      .catch((e) => {
+        reject(e);
+      })
+      .finally(() => {
+        // 等待任务队列中如果有任务,则触发它;否则设置isRunning = false,表示无任务状态
+        if (waitingQueue.length) {
+          const next = waitingQueue.shift();
+          execute(next.task, next.resolve, next.reject);
+        } else {
+          isRunning = false;
+        }
+      });
+  }
+  this.exec = function(task) {
+    return new Promise((resolve, reject) => {
+      if (isRunning) {
+        waitingQueue.push({
+          task,
+          resolve,
+          reject
+        });
+      } else {
+        isRunning = true;
+        execute(task, resolve, reject);
+      }
+    });
+  }
+}
+
+/* 队列实例,某些平台一起使用多个组件时需要通过队列逐一绘制,否则部分绘制方法异常,nvue端的iOS gcanvas尤其明显,在不通过队列绘制时会出现图片丢失的情况 */
+export const queueDraw = new Queue();
+export const queueLoadImage = new Queue();

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 39 - 0
uni_modules/uv-qrcode/components/uv-qrcode/uv-qrcode.vue


+ 87 - 0
uni_modules/uv-qrcode/package.json

@@ -0,0 +1,87 @@
+{
+  "id": "uv-qrcode",
+  "displayName": "uv-qrcode 二维码 全面兼容vue3+2、app、h5、小程序等多端",
+  "version": "1.0.5",
+  "description": "该组件是超级强大二维码生成功能,可扩展性高。自定义二维码样式,如随机颜色、圆点、方块、块与块之间的间距等等,具体请查看文档。",
+  "keywords": [
+    "uv-qrcode",
+    "qrcode",
+    "uvui",
+    "uv-ui",
+    "二维码"
+],
+  "repository": "",
+  "engines": {
+    "HBuilderX": "^3.1.0"
+  },
+  "dcloudext": {
+    "type": "component-vue",
+    "sale": {
+      "regular": {
+        "price": "0.00"
+      },
+      "sourcecode": {
+        "price": "0.00"
+      }
+    },
+    "contact": {
+      "qq": ""
+    },
+    "declaration": {
+    	"ads": "无",
+    	"data": "插件不采集任何数据",
+    	"permissions": "无"
+    },
+    "npmurl": ""
+  },
+  "uni_modules": {
+    "dependencies": [
+			"uv-ui-tools"
+		],
+    "encrypt": [],
+    "platforms": {
+			"cloud": {
+				"tcb": "y",
+				"aliyun": "y"
+			},
+			"client": {
+				"Vue": {
+					"vue2": "y",
+					"vue3": "y"
+				},
+				"App": {
+					"app-vue": "y",
+					"app-nvue": "y"
+				},
+				"H5-mobile": {
+					"Safari": "y",
+					"Android Browser": "y",
+					"微信浏览器(Android)": "y",
+					"QQ浏览器(Android)": "y"
+				},
+				"H5-pc": {
+					"Chrome": "y",
+					"IE": "y",
+					"Edge": "y",
+					"Firefox": "y",
+					"Safari": "y"
+				},
+				"小程序": {
+					"微信": "y",
+					"阿里": "y",
+					"百度": "y",
+					"字节跳动": "y",
+					"QQ": "y",
+					"钉钉": "u",
+					"快手": "u",
+					"飞书": "u",
+					"京东": "u"
+				},
+				"快应用": {
+					"华为": "u",
+					"联盟": "u"
+				}
+			}
+		}
+  }
+}

+ 21 - 0
uni_modules/uv-qrcode/readme.md

@@ -0,0 +1,21 @@
+## QRCode 二维码生成器
+
+> **组件名:uv-qrcode**
+
+超级强大二维码生成组件,可扩展性高。自定义二维码样式,如随机颜色、圆点、方块、块与块之间的间距等等,具体请在下方查看文档。
+
+灵活配置,开箱即用,文档全面,支持自定义二维码风格。
+
+# <a href="https://www.uvui.cn/components/qrcode.html" target="_blank">查看文档</a>
+
+## [下载完整示例项目](https://ext.dcloud.net.cn/plugin?name=uv-ui) <small style="font-size:14px;font-weight:700;">(请不要 下载插件ZIP)</small>
+
+### [更多插件,请关注uv-ui组件库](https://ext.dcloud.net.cn/plugin?name=uv-ui)
+
+<a href="https://ext.dcloud.net.cn/plugin?name=uv-ui" target="_blank">
+
+![image](https://mp-a667b617-c5f1-4a2d-9a54-683a67cff588.cdn.bspapp.com/uv-ui/banner.png)
+
+</a>
+
+#### 如使用过程中有任何问题反馈,或者您对uv-ui有一些好的建议,欢迎加入uv-ui官方交流群:<a href="https://www.uvui.cn/components/addQQGroup.html" target="_blank">官方QQ群</a>

+ 76 - 0
uni_modules/uv-ui-tools/changelog.md

@@ -0,0 +1,76 @@
+## 1.1.25(2024-01-20)
+1.1.20版本更新
+## 1.1.24(2023-12-21)
+1. luch-request更新
+## 1.1.23(2023-12-12)
+1. 1.1.19版本
+## 1.1.22(2023-11-28)
+1. 优化
+## 1.1.21(2023-11-10)
+1. 1.1.17版本
+## 1.1.20(2023-10-30)
+1. 1.1.16版本
+## 1.1.19(2023-10-13)
+1. 兼容vue3
+## 1.1.18(2023-10-12)
+1. 1.1.15版本
+## 1.1.17(2023-09-27)
+1. 1.1.14版本发布
+## 1.1.16(2023-09-15)
+1. 1.1.13版本发布
+## 1.1.15(2023-09-15)
+1. 更新button.js相关按钮支持open-type="agreePrivacyAuthorization"
+## 1.1.14(2023-09-14)
+1. 优化dayjs
+## 1.1.13(2023-09-13)
+1. 优化,$uv中增加unit参数,方便组件中使用
+## 1.1.12(2023-09-10)
+1. 升级版本
+## 1.1.11(2023-09-04)
+1. 1.1.11版本
+## 1.1.10(2023-08-31)
+1. 修复customStyle和customClass存在冲突的问题
+## 1.1.9(2023-08-27)
+1. 版本升级
+2. 优化
+## 1.1.8(2023-08-24)
+1. 版本升级
+## 1.1.7(2023-08-22)
+1. 版本升级
+## 1.1.6(2023-08-18)
+uvui版本:1.1.6
+## 1.0.15(2023-08-14)
+1. 更新uvui版本号
+## 1.0.13(2023-08-06)
+1. 优化
+## 1.0.12(2023-08-06)
+1. 修改版本号
+## 1.0.11(2023-08-06)
+1. 路由增加events参数
+2. 路由拦截修复
+## 1.0.10(2023-08-01)
+1. 优化
+## 1.0.9(2023-06-28)
+优化openType.js
+## 1.0.8(2023-06-15)
+1. 修改支付宝报错的BUG
+## 1.0.7(2023-06-07)
+1. 解决微信小程序使用uvui提示 Some selectors are not allowed in component wxss, including tag name selectors, ID selectors, and attribute selectors
+2. 解决上述提示,需要在uni.scss配置$uvui-nvue-style: false; 然后在APP.vue下面引入uvui内置的基础样式:@import '@/uni_modules/uv-ui-tools/index.scss';
+## 1.0.6(2023-06-04)
+1.  uv-ui-tools 优化工具组件,兼容更多功能
+2.  小程序分享功能优化等
+## 1.0.5(2023-06-02)
+1. 修改扩展使用mixin中方法的问题
+## 1.0.4(2023-05-23)
+1. 兼容百度小程序修改bem函数
+## 1.0.3(2023-05-16)
+1. 优化组件依赖,修改后无需全局引入,组件导入即可使用
+2. 优化部分功能
+## 1.0.2(2023-05-10)
+1. 增加Http请求封装
+2. 优化
+## 1.0.1(2023-05-04)
+1. 修改名称及备注
+## 1.0.0(2023-05-04)
+1. uv-ui工具集首次发布

+ 6 - 0
uni_modules/uv-ui-tools/components/uv-ui-tools/uv-ui-tools.vue

@@ -0,0 +1,6 @@
+<template>
+</template>
+<script>
+</script>
+<style>
+</style>

+ 79 - 0
uni_modules/uv-ui-tools/index.js

@@ -0,0 +1,79 @@
+// 全局挂载引入http相关请求拦截插件
+import Request from './libs/luch-request'
+
+// 引入全局mixin
+import mixin from './libs/mixin/mixin.js'
+// 小程序特有的mixin
+import mpMixin from './libs/mixin/mpMixin.js'
+// #ifdef MP
+import mpShare from './libs/mixin/mpShare.js'
+// #endif
+
+// 路由封装
+import route from './libs/util/route.js'
+// 公共工具函数
+import * as index from './libs/function/index.js'
+// 防抖方法
+import debounce from './libs/function/debounce.js'
+// 节流方法
+import throttle from './libs/function/throttle.js'
+// 规则检验
+import * as test from './libs/function/test.js'
+
+// 颜色渐变相关,colorGradient-颜色渐变,hexToRgb-十六进制颜色转rgb颜色,rgbToHex-rgb转十六进制
+import * as colorGradient from './libs/function/colorGradient.js'
+
+// 配置信息
+import config from './libs/config/config.js'
+// 平台
+import platform from './libs/function/platform'
+
+const $uv = {
+	route,
+	config,
+	test,
+	date: index.timeFormat, // 另名date
+	...index,
+	colorGradient: colorGradient.colorGradient,
+	hexToRgb: colorGradient.hexToRgb,
+	rgbToHex: colorGradient.rgbToHex,
+	colorToRgba: colorGradient.colorToRgba,
+	http: new Request(),
+	debounce,
+	throttle,
+	platform,
+	mixin,
+	mpMixin
+}
+uni.$uv = $uv;
+const install = (Vue,options={}) => {
+		// #ifndef APP-NVUE
+		const cloneMixin = index.deepClone(mixin);
+		delete cloneMixin?.props?.customClass;
+		delete cloneMixin?.props?.customStyle;
+		Vue.mixin(cloneMixin);
+		// #ifdef MP
+		if(options.mpShare){
+			Vue.mixin(mpShare);
+		}
+		// #endif
+		// #endif
+		// #ifdef VUE2
+		// 时间格式化,同时两个名称,date和timeFormat
+		Vue.filter('timeFormat', (timestamp, format) => uni.$uv.timeFormat(timestamp, format));
+		Vue.filter('date', (timestamp, format) => uni.$uv.timeFormat(timestamp, format));
+		// 将多久以前的方法,注入到全局过滤器
+		Vue.filter('timeFrom', (timestamp, format) => uni.$uv.timeFrom(timestamp, format));
+		// 同时挂载到uni和Vue.prototype中
+		// #ifndef APP-NVUE
+		// 只有vue,挂载到Vue.prototype才有意义,因为nvue中全局Vue.prototype和Vue.mixin是无效的
+		Vue.prototype.$uv = $uv;
+		// #endif
+		// #endif
+		// #ifdef VUE3
+		Vue.config.globalProperties.$uv = $uv;
+		// #endif
+}
+export default {
+	install
+}

+ 7 - 0
uni_modules/uv-ui-tools/index.scss

@@ -0,0 +1,7 @@
+// 引入公共基础类
+@import "./libs/css/common.scss";
+
+// 非nvue的样式
+/* #ifndef APP-NVUE */
+@import "./libs/css/vue.scss";
+/* #endif */

+ 34 - 0
uni_modules/uv-ui-tools/libs/config/config.js

@@ -0,0 +1,34 @@
+// 此版本发布于2024-01-20
+const version = '1.1.20'
+
+// 开发环境才提示,生产环境不会提示
+if (process.env.NODE_ENV === 'development') {
+	console.log(`\n %c uvui V${version} https://www.uvui.cn/ \n\n`, 'color: #ffffff; background: #3c9cff; padding:5px 0; border-radius: 5px;');
+}
+
+export default {
+    v: version,
+    version,
+    // 主题名称
+    type: [
+        'primary',
+        'success',
+        'info',
+        'error',
+        'warning'
+    ],
+    // 颜色部分,本来可以通过scss的:export导出供js使用,但是奈何nvue不支持
+    color: {
+        'uv-primary': '#2979ff',
+        'uv-warning': '#ff9900',
+        'uv-success': '#19be6b',
+        'uv-error': '#fa3534',
+        'uv-info': '#909399',
+        'uv-main-color': '#303133',
+        'uv-content-color': '#606266',
+        'uv-tips-color': '#909399',
+        'uv-light-color': '#c0c4cc'
+    },
+	// 默认单位,可以通过配置为rpx,那么在用于传入组件大小参数为数值时,就默认为rpx
+	unit: 'px'
+}

+ 32 - 0
uni_modules/uv-ui-tools/libs/css/color.scss

@@ -0,0 +1,32 @@
+$uv-main-color: #303133 !default;
+$uv-content-color: #606266 !default;
+$uv-tips-color: #909193 !default;
+$uv-light-color: #c0c4cc !default;
+$uv-border-color: #dadbde !default;
+$uv-bg-color: #f3f4f6 !default;
+$uv-disabled-color: #c8c9cc !default;
+
+$uv-primary: #3c9cff !default;
+$uv-primary-dark: #398ade !default;
+$uv-primary-disabled: #9acafc !default;
+$uv-primary-light: #ecf5ff !default;
+
+$uv-warning: #f9ae3d !default;
+$uv-warning-dark: #f1a532 !default;
+$uv-warning-disabled: #f9d39b !default;
+$uv-warning-light: #fdf6ec !default;
+
+$uv-success: #5ac725 !default;
+$uv-success-dark: #53c21d !default;
+$uv-success-disabled: #a9e08f !default;
+$uv-success-light: #f5fff0;
+
+$uv-error: #f56c6c !default;
+$uv-error-dark: #e45656 !default;
+$uv-error-disabled: #f7b2b2 !default;
+$uv-error-light: #fef0f0 !default;
+
+$uv-info: #909399 !default;
+$uv-info-dark: #767a82 !default;
+$uv-info-disabled: #c4c6c9 !default;
+$uv-info-light: #f4f4f5 !default;

+ 100 - 0
uni_modules/uv-ui-tools/libs/css/common.scss

@@ -0,0 +1,100 @@
+// 超出行数,自动显示行尾省略号,最多5行
+// 来自uvui的温馨提示:当您在控制台看到此报错,说明需要在App.vue的style标签加上【lang="scss"】
+@for $i from 1 through 5 {
+	.uv-line-#{$i} {
+		/* #ifdef APP-NVUE */
+		// nvue下,可以直接使用lines属性,这是weex特有样式
+		lines: $i;
+		text-overflow: ellipsis;
+		overflow: hidden;
+		flex: 1;
+		/* #endif */
+
+		/* #ifndef APP-NVUE */
+		// vue下,单行和多行显示省略号需要单独处理
+		@if $i == '1' {
+			overflow: hidden;
+			white-space: nowrap;
+			text-overflow: ellipsis;
+		} @else {
+			display: -webkit-box!important;
+			overflow: hidden;
+			text-overflow: ellipsis;
+			word-break: break-all;
+			-webkit-line-clamp: $i;
+			-webkit-box-orient: vertical!important;
+		}
+		/* #endif */
+	}
+}
+$uv-bordercolor: #dadbde;
+@if variable-exists(uv-border-color) {
+	$uv-bordercolor: $uv-border-color;
+}
+
+// 此处加上!important并非随意乱用,而是因为目前*.nvue页面编译到H5时,
+// App.vue的样式会被uni-app的view元素的自带border属性覆盖,导致无效
+// 综上,这是uni-app的缺陷导致我们为了多端兼容,而必须要加上!important
+// 移动端兼容性较好,直接使用0.5px去实现细边框,不使用伪元素形式实现
+.uv-border {
+	border-width: 0.5px!important;
+	border-color: $uv-bordercolor!important;
+    border-style: solid;
+}
+
+.uv-border-top {
+	border-top-width: 0.5px!important;
+	border-color: $uv-bordercolor!important;
+    border-top-style: solid;
+}
+
+.uv-border-left {
+	border-left-width: 0.5px!important;
+	border-color: $uv-bordercolor!important;
+    border-left-style: solid;
+}
+
+.uv-border-right {
+	border-right-width: 0.5px!important;
+	border-color: $uv-bordercolor!important;
+    border-right-style: solid;
+}
+
+.uv-border-bottom {
+	border-bottom-width: 0.5px!important;
+	border-color: $uv-bordercolor!important;
+    border-bottom-style: solid;
+}
+
+.uv-border-top-bottom {
+	border-top-width: 0.5px!important;
+	border-bottom-width: 0.5px!important;
+	border-color: $uv-bordercolor!important;
+    border-top-style: solid;
+    border-bottom-style: solid;
+}
+
+// 去除button的所有默认样式,让其表现跟普通的view、text元素一样
+.uv-reset-button {
+	padding: 0;
+	background-color: transparent;
+	/* #ifndef APP-PLUS */
+	font-size: inherit;
+	line-height: inherit;
+	color: inherit;
+	/* #endif */
+	/* #ifdef APP-NVUE */
+	border-width: 0;
+	/* #endif */
+}
+
+/* #ifndef APP-NVUE */
+.uv-reset-button::after {
+   border: none;
+}
+/* #endif */
+
+.uv-hover-class {
+	opacity: 0.7;
+}
+

+ 23 - 0
uni_modules/uv-ui-tools/libs/css/components.scss

@@ -0,0 +1,23 @@
+@mixin flex($direction: row) {
+	/* #ifndef APP-NVUE */
+	display: flex;
+	/* #endif */
+	flex-direction: $direction;
+}
+
+/* #ifndef APP-NVUE */
+// 由于uvui是基于nvue环境进行开发的,此环境中普通元素默认为flex-direction: column;
+// 所以在非nvue中,需要对元素进行重置为flex-direction: column; 否则可能会表现异常
+$uvui-nvue-style: true !default;
+@if $uvui-nvue-style == true {
+	view, scroll-view, swiper-item {
+		display: flex;
+		flex-direction: column;
+		flex-shrink: 0;
+		flex-grow: 0;
+		flex-basis: auto;
+		align-items: stretch;
+		align-content: flex-start;
+	}
+}
+/* #endif */

+ 111 - 0
uni_modules/uv-ui-tools/libs/css/variable.scss

@@ -0,0 +1,111 @@
+// 超出行数,自动显示行尾省略号,最多5行
+// 来自uvui的温馨提示:当您在控制台看到此报错,说明需要在App.vue的style标签加上【lang="scss"】
+@if variable-exists(show-lines) {
+	@for $i from 1 through 5 {
+		.uv-line-#{$i} {
+			/* #ifdef APP-NVUE */
+			// nvue下,可以直接使用lines属性,这是weex特有样式
+			lines: $i;
+			text-overflow: ellipsis;
+			overflow: hidden;
+			flex: 1;
+			/* #endif */
+
+			/* #ifndef APP-NVUE */
+			// vue下,单行和多行显示省略号需要单独处理
+			@if $i == '1' {
+				overflow: hidden;
+				white-space: nowrap;
+				text-overflow: ellipsis;
+			} @else {
+				display: -webkit-box!important;
+				overflow: hidden;
+				text-overflow: ellipsis;
+				word-break: break-all;
+				-webkit-line-clamp: $i;
+				-webkit-box-orient: vertical!important;
+			}
+			/* #endif */
+		}
+	}
+}
+@if variable-exists(show-border) {
+	$uv-bordercolor: #dadbde;
+	@if variable-exists(uv-border-color) {
+		$uv-bordercolor: $uv-border-color;
+	}
+	// 此处加上!important并非随意乱用,而是因为目前*.nvue页面编译到H5时,
+	// App.vue的样式会被uni-app的view元素的自带border属性覆盖,导致无效
+	// 综上,这是uni-app的缺陷导致我们为了多端兼容,而必须要加上!important
+	// 移动端兼容性较好,直接使用0.5px去实现细边框,不使用伪元素形式实现
+	@if variable-exists(show-border-surround) {
+		.uv-border {
+			border-width: 0.5px!important;
+			border-color: $uv-bordercolor!important;
+			border-style: solid;
+		}
+	}
+	@if variable-exists(show-border-top) {
+		.uv-border-top {
+			border-top-width: 0.5px!important;
+			border-color: $uv-bordercolor!important;
+			border-top-style: solid;
+		}
+	}
+	@if variable-exists(show-border-left) {
+		.uv-border-left {
+			border-left-width: 0.5px!important;
+			border-color: $uv-bordercolor!important;
+			border-left-style: solid;
+		}
+	}
+	@if variable-exists(show-border-right) {
+		.uv-border-right {
+			border-right-width: 0.5px!important;
+			border-color: $uv-bordercolor!important;
+			border-right-style: solid;
+		}
+	}
+	@if variable-exists(show-border-bottom) {
+		.uv-border-bottom {
+			border-bottom-width: 0.5px!important;
+			border-color: $uv-bordercolor!important;
+				border-bottom-style: solid;
+		}
+	}
+	@if variable-exists(show-border-top-bottom) {
+		.uv-border-top-bottom {
+			border-top-width: 0.5px!important;
+			border-bottom-width: 0.5px!important;
+			border-color: $uv-bordercolor!important;
+			border-top-style: solid;
+			border-bottom-style: solid;
+		}
+	}
+}
+@if variable-exists(show-reset-button) {
+	// 去除button的所有默认样式,让其表现跟普通的view、text元素一样
+	.uv-reset-button {
+		padding: 0;
+		background-color: transparent;
+		/* #ifndef APP-PLUS */
+		font-size: inherit;
+		line-height: inherit;
+		color: inherit;
+		/* #endif */
+		/* #ifdef APP-NVUE */
+		border-width: 0;
+		/* #endif */
+	}
+
+	/* #ifndef APP-NVUE */
+	.uv-reset-button::after {
+		 border: none;
+	}
+	/* #endif */
+}
+@if variable-exists(show-hover) {
+	.uv-hover-class {
+		opacity: 0.7;
+	}
+}

+ 40 - 0
uni_modules/uv-ui-tools/libs/css/vue.scss

@@ -0,0 +1,40 @@
+// 历遍生成4个方向的底部安全区
+@each $d in top, right, bottom, left {
+	.uv-safe-area-inset-#{$d} {
+		padding-#{$d}: 0;
+		padding-#{$d}: constant(safe-area-inset-#{$d});  
+		padding-#{$d}: env(safe-area-inset-#{$d});  
+	}
+}
+
+//提升H5端uni.toast()的层级,避免被uvui的modal等遮盖
+/* #ifdef H5 */
+uni-toast {
+    z-index: 10090;
+}
+uni-toast .uni-toast {
+   z-index: 10090;
+}
+/* #endif */
+
+// 隐藏scroll-view的滚动条
+::-webkit-scrollbar {
+    display: none;  
+    width: 0 !important;  
+    height: 0 !important;  
+    -webkit-appearance: none;  
+    background: transparent;  
+}
+
+$uvui-nvue-style: true !default;
+@if $uvui-nvue-style == false {
+	view, scroll-view, swiper-item {
+		display: flex;
+		flex-direction: column;
+		flex-shrink: 0;
+		flex-grow: 0;
+		flex-basis: auto;
+		align-items: stretch;
+		align-content: flex-start;
+	}
+}

+ 134 - 0
uni_modules/uv-ui-tools/libs/function/colorGradient.js

@@ -0,0 +1,134 @@
+/**
+ * 求两个颜色之间的渐变值
+ * @param {string} startColor 开始的颜色
+ * @param {string} endColor 结束的颜色
+ * @param {number} step 颜色等分的份额
+ * */
+function colorGradient(startColor = 'rgb(0, 0, 0)', endColor = 'rgb(255, 255, 255)', step = 10) {
+    const startRGB = hexToRgb(startColor, false) // 转换为rgb数组模式
+    const startR = startRGB[0]
+    const startG = startRGB[1]
+    const startB = startRGB[2]
+
+    const endRGB = hexToRgb(endColor, false)
+    const endR = endRGB[0]
+    const endG = endRGB[1]
+    const endB = endRGB[2]
+
+    const sR = (endR - startR) / step // 总差值
+    const sG = (endG - startG) / step
+    const sB = (endB - startB) / step
+    const colorArr = []
+    for (let i = 0; i < step; i++) {
+        // 计算每一步的hex值
+        let hex = rgbToHex(`rgb(${Math.round((sR * i + startR))},${Math.round((sG * i + startG))},${Math.round((sB
+			* i + startB))})`)
+        // 确保第一个颜色值为startColor的值
+        if (i === 0) hex = rgbToHex(startColor)
+        // 确保最后一个颜色值为endColor的值
+        if (i === step - 1) hex = rgbToHex(endColor)
+        colorArr.push(hex)
+    }
+    return colorArr
+}
+
+// 将hex表示方式转换为rgb表示方式(这里返回rgb数组模式)
+function hexToRgb(sColor, str = true) {
+    const reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/
+    sColor = String(sColor).toLowerCase()
+    if (sColor && reg.test(sColor)) {
+        if (sColor.length === 4) {
+            let sColorNew = '#'
+            for (let i = 1; i < 4; i += 1) {
+                sColorNew += sColor.slice(i, i + 1).concat(sColor.slice(i, i + 1))
+            }
+            sColor = sColorNew
+        }
+        // 处理六位的颜色值
+        const sColorChange = []
+        for (let i = 1; i < 7; i += 2) {
+            sColorChange.push(parseInt(`0x${sColor.slice(i, i + 2)}`))
+        }
+        if (!str) {
+            return sColorChange
+        }
+        return `rgb(${sColorChange[0]},${sColorChange[1]},${sColorChange[2]})`
+    } if (/^(rgb|RGB)/.test(sColor)) {
+        const arr = sColor.replace(/(?:\(|\)|rgb|RGB)*/g, '').split(',')
+        return arr.map((val) => Number(val))
+    }
+    return sColor
+}
+
+// 将rgb表示方式转换为hex表示方式
+function rgbToHex(rgb) {
+    const _this = rgb
+    const reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/
+    if (/^(rgb|RGB)/.test(_this)) {
+        const aColor = _this.replace(/(?:\(|\)|rgb|RGB)*/g, '').split(',')
+        let strHex = '#'
+        for (let i = 0; i < aColor.length; i++) {
+            let hex = Number(aColor[i]).toString(16)
+            hex = String(hex).length == 1 ? `${0}${hex}` : hex // 保证每个rgb的值为2位
+            if (hex === '0') {
+                hex += hex
+            }
+            strHex += hex
+        }
+        if (strHex.length !== 7) {
+            strHex = _this
+        }
+        return strHex
+    } if (reg.test(_this)) {
+        const aNum = _this.replace(/#/, '').split('')
+        if (aNum.length === 6) {
+            return _this
+        } if (aNum.length === 3) {
+            let numHex = '#'
+            for (let i = 0; i < aNum.length; i += 1) {
+                numHex += (aNum[i] + aNum[i])
+            }
+            return numHex
+        }
+    } else {
+        return _this
+    }
+}
+
+/**
+* JS颜色十六进制转换为rgb或rgba,返回的格式为 rgba(255,255,255,0.5)字符串
+* sHex为传入的十六进制的色值
+* alpha为rgba的透明度
+*/
+function colorToRgba(color, alpha) {
+    color = rgbToHex(color)
+    // 十六进制颜色值的正则表达式
+    const reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/
+    /* 16进制颜色转为RGB格式 */
+    let sColor = String(color).toLowerCase()
+    if (sColor && reg.test(sColor)) {
+        if (sColor.length === 4) {
+            let sColorNew = '#'
+            for (let i = 1; i < 4; i += 1) {
+                sColorNew += sColor.slice(i, i + 1).concat(sColor.slice(i, i + 1))
+            }
+            sColor = sColorNew
+        }
+        // 处理六位的颜色值
+        const sColorChange = []
+        for (let i = 1; i < 7; i += 2) {
+            sColorChange.push(parseInt(`0x${sColor.slice(i, i + 2)}`))
+        }
+        // return sColorChange.join(',')
+        return `rgba(${sColorChange.join(',')},${alpha})`
+    }
+
+    return sColor
+}
+
+export {
+    colorGradient,
+    hexToRgb,
+    rgbToHex,
+    colorToRgba
+}

+ 29 - 0
uni_modules/uv-ui-tools/libs/function/debounce.js

@@ -0,0 +1,29 @@
+let timeout = null
+
+/**
+ * 防抖原理:一定时间内,只有最后一次操作,再过wait毫秒后才执行函数
+ *
+ * @param {Function} func 要执行的回调函数
+ * @param {Number} wait 延时的时间
+ * @param {Boolean} immediate 是否立即执行
+ * @return null
+ */
+function debounce(func, wait = 500, immediate = false) {
+    // 清除定时器
+    if (timeout !== null) clearTimeout(timeout)
+    // 立即执行,此类情况一般用不到
+    if (immediate) {
+        const callNow = !timeout
+        timeout = setTimeout(() => {
+            timeout = null
+        }, wait)
+        if (callNow) typeof func === 'function' && func()
+    } else {
+        // 设置定时器,当最后一次操作后,timeout不会再被清除,所以在延时wait毫秒后执行func回调方法
+        timeout = setTimeout(() => {
+            typeof func === 'function' && func()
+        }, wait)
+    }
+}
+
+export default debounce

+ 167 - 0
uni_modules/uv-ui-tools/libs/function/digit.js

@@ -0,0 +1,167 @@
+let _boundaryCheckingState = true; // 是否进行越界检查的全局开关
+
+/**
+ * 把错误的数据转正
+ * @private
+ * @example strip(0.09999999999999998)=0.1
+ */
+function strip(num, precision = 15) {
+  return +parseFloat(Number(num).toPrecision(precision));
+}
+
+/**
+ * Return digits length of a number
+ * @private
+ * @param {*number} num Input number
+ */
+function digitLength(num) {
+  // Get digit length of e
+  const eSplit = num.toString().split(/[eE]/);
+  const len = (eSplit[0].split('.')[1] || '').length - +(eSplit[1] || 0);
+  return len > 0 ? len : 0;
+}
+
+/**
+ * 把小数转成整数,如果是小数则放大成整数
+ * @private
+ * @param {*number} num 输入数
+ */
+function float2Fixed(num) {
+  if (num.toString().indexOf('e') === -1) {
+    return Number(num.toString().replace('.', ''));
+  }
+  const dLen = digitLength(num);
+  return dLen > 0 ? strip(Number(num) * Math.pow(10, dLen)) : Number(num);
+}
+
+/**
+ * 检测数字是否越界,如果越界给出提示
+ * @private
+ * @param {*number} num 输入数
+ */
+function checkBoundary(num) {
+  if (_boundaryCheckingState) {
+    if (num > Number.MAX_SAFE_INTEGER || num < Number.MIN_SAFE_INTEGER) {
+      console.warn(`${num} 超出了精度限制,结果可能不正确`);
+    }
+  }
+}
+
+/**
+ * 把递归操作扁平迭代化
+ * @param {number[]} arr 要操作的数字数组
+ * @param {function} operation 迭代操作
+ * @private
+ */
+function iteratorOperation(arr, operation) {
+  const [num1, num2, ...others] = arr;
+  let res = operation(num1, num2);
+
+  others.forEach((num) => {
+    res = operation(res, num);
+  });
+
+  return res;
+}
+
+/**
+ * 高精度乘法
+ * @export
+ */
+export function times(...nums) {
+  if (nums.length > 2) {
+    return iteratorOperation(nums, times);
+  }
+
+  const [num1, num2] = nums;
+  const num1Changed = float2Fixed(num1);
+  const num2Changed = float2Fixed(num2);
+  const baseNum = digitLength(num1) + digitLength(num2);
+  const leftValue = num1Changed * num2Changed;
+
+  checkBoundary(leftValue);
+
+  return leftValue / Math.pow(10, baseNum);
+}
+
+/**
+ * 高精度加法
+ * @export
+ */
+export function plus(...nums) {
+  if (nums.length > 2) {
+    return iteratorOperation(nums, plus);
+  }
+
+  const [num1, num2] = nums;
+  // 取最大的小数位
+  const baseNum = Math.pow(10, Math.max(digitLength(num1), digitLength(num2)));
+  // 把小数都转为整数然后再计算
+  return (times(num1, baseNum) + times(num2, baseNum)) / baseNum;
+}
+
+/**
+ * 高精度减法
+ * @export
+ */
+export function minus(...nums) {
+  if (nums.length > 2) {
+    return iteratorOperation(nums, minus);
+  }
+
+  const [num1, num2] = nums;
+  const baseNum = Math.pow(10, Math.max(digitLength(num1), digitLength(num2)));
+  return (times(num1, baseNum) - times(num2, baseNum)) / baseNum;
+}
+
+/**
+ * 高精度除法
+ * @export
+ */
+export function divide(...nums) {
+  if (nums.length > 2) {
+    return iteratorOperation(nums, divide);
+  }
+
+  const [num1, num2] = nums;
+  const num1Changed = float2Fixed(num1);
+  const num2Changed = float2Fixed(num2);
+  checkBoundary(num1Changed);
+  checkBoundary(num2Changed);
+  // 重要,这里必须用strip进行修正
+  return times(num1Changed / num2Changed, strip(Math.pow(10, digitLength(num2) - digitLength(num1))));
+}
+
+/**
+ * 四舍五入
+ * @export
+ */
+export function round(num, ratio) {
+  const base = Math.pow(10, ratio);
+  let result = divide(Math.round(Math.abs(times(num, base))), base);
+  if (num < 0 && result !== 0) {
+    result = times(result, -1);
+  }
+  // 位数不足则补0
+  return result;
+}
+
+/**
+ * 是否进行边界检查,默认开启
+ * @param flag 标记开关,true 为开启,false 为关闭,默认为 true
+ * @export
+ */
+export function enableBoundaryChecking(flag = true) {
+  _boundaryCheckingState = flag;
+}
+
+
+export default {
+  times,
+  plus,
+  minus,
+  divide,
+  round,
+  enableBoundaryChecking,
+};
+

+ 734 - 0
uni_modules/uv-ui-tools/libs/function/index.js

@@ -0,0 +1,734 @@
+import { number, empty } from './test.js'
+import { round } from './digit.js'
+/**
+ * @description 如果value小于min,取min;如果value大于max,取max
+ * @param {number} min
+ * @param {number} max
+ * @param {number} value
+ */
+function range(min = 0, max = 0, value = 0) {
+	return Math.max(min, Math.min(max, Number(value)))
+}
+
+/**
+ * @description 用于获取用户传递值的px值  如果用户传递了"xxpx"或者"xxrpx",取出其数值部分,如果是"xxxrpx"还需要用过uni.upx2px进行转换
+ * @param {number|string} value 用户传递值的px值
+ * @param {boolean} unit
+ * @returns {number|string}
+ */
+function getPx(value, unit = false) {
+	if (number(value)) {
+		return unit ? `${value}px` : Number(value)
+	}
+	// 如果带有rpx,先取出其数值部分,再转为px值
+	if (/(rpx|upx)$/.test(value)) {
+		return unit ? `${uni.upx2px(parseInt(value))}px` : Number(uni.upx2px(parseInt(value)))
+	}
+	return unit ? `${parseInt(value)}px` : parseInt(value)
+}
+
+/**
+ * @description 进行延时,以达到可以简写代码的目的 比如: await uni.$uv.sleep(20)将会阻塞20ms
+ * @param {number} value 堵塞时间 单位ms 毫秒
+ * @returns {Promise} 返回promise
+ */
+function sleep(value = 30) {
+	return new Promise((resolve) => {
+		setTimeout(() => {
+			resolve()
+		}, value)
+	})
+}
+/**
+ * @description 运行期判断平台
+ * @returns {string} 返回所在平台(小写)
+ * @link 运行期判断平台 https://uniapp.dcloud.io/frame?id=判断平台
+ */
+function os() {
+	return uni.getSystemInfoSync().platform.toLowerCase()
+}
+/**
+ * @description 获取系统信息同步接口
+ * @link 获取系统信息同步接口 https://uniapp.dcloud.io/api/system/info?id=getsysteminfosync
+ */
+function sys() {
+	return uni.getSystemInfoSync()
+}
+
+/**
+ * @description 取一个区间数
+ * @param {Number} min 最小值
+ * @param {Number} max 最大值
+ */
+function random(min, max) {
+	if (min >= 0 && max > 0 && max >= min) {
+		const gab = max - min + 1
+		return Math.floor(Math.random() * gab + min)
+	}
+	return 0
+}
+
+/**
+ * @param {Number} len uuid的长度
+ * @param {Boolean} firstU 将返回的首字母置为"u"
+ * @param {Nubmer} radix 生成uuid的基数(意味着返回的字符串都是这个基数),2-二进制,8-八进制,10-十进制,16-十六进制
+ */
+function guid(len = 32, firstU = true, radix = null) {
+	const chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('')
+	const uuid = []
+	radix = radix || chars.length
+
+	if (len) {
+		// 如果指定uuid长度,只是取随机的字符,0|x为位运算,能去掉x的小数位,返回整数位
+		for (let i = 0; i < len; i++) uuid[i] = chars[0 | Math.random() * radix]
+	} else {
+		let r
+		// rfc4122标准要求返回的uuid中,某些位为固定的字符
+		uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-'
+		uuid[14] = '4'
+
+		for (let i = 0; i < 36; i++) {
+			if (!uuid[i]) {
+				r = 0 | Math.random() * 16
+				uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r]
+			}
+		}
+	}
+	// 移除第一个字符,并用u替代,因为第一个字符为数值时,该guuid不能用作id或者class
+	if (firstU) {
+		uuid.shift()
+		return `u${uuid.join('')}`
+	}
+	return uuid.join('')
+}
+
+/**
+* @description 获取父组件的参数,因为支付宝小程序不支持provide/inject的写法
+   this.$parent在非H5中,可以准确获取到父组件,但是在H5中,需要多次this.$parent.$parent.xxx
+   这里默认值等于undefined有它的含义,因为最顶层元素(组件)的$parent就是undefined,意味着不传name
+   值(默认为undefined),就是查找最顶层的$parent
+*  @param {string|undefined} name 父组件的参数名
+*/
+function $parent(name = undefined) {
+	let parent = this.$parent
+	// 通过while历遍,这里主要是为了H5需要多层解析的问题
+	while (parent) {
+		// 父组件
+		if (parent.$options && parent.$options.name !== name) {
+			// 如果组件的name不相等,继续上一级寻找
+			parent = parent.$parent
+		} else {
+			return parent
+		}
+	}
+	return false
+}
+
+/**
+ * @description 样式转换
+ * 对象转字符串,或者字符串转对象
+ * @param {object | string} customStyle 需要转换的目标
+ * @param {String} target 转换的目的,object-转为对象,string-转为字符串
+ * @returns {object|string}
+ */
+function addStyle(customStyle, target = 'object') {
+	// 字符串转字符串,对象转对象情形,直接返回
+	if (empty(customStyle) || typeof(customStyle) === 'object' && target === 'object' || target === 'string' &&
+		typeof(customStyle) === 'string') {
+		return customStyle
+	}
+	// 字符串转对象
+	if (target === 'object') {
+		// 去除字符串样式中的两端空格(中间的空格不能去掉,比如padding: 20px 0如果去掉了就错了),空格是无用的
+		customStyle = trim(customStyle)
+		// 根据";"将字符串转为数组形式
+		const styleArray = customStyle.split(';')
+		const style = {}
+		// 历遍数组,拼接成对象
+		for (let i = 0; i < styleArray.length; i++) {
+			// 'font-size:20px;color:red;',如此最后字符串有";"的话,会导致styleArray最后一个元素为空字符串,这里需要过滤
+			if (styleArray[i]) {
+				const item = styleArray[i].split(':')
+				style[trim(item[0])] = trim(item[1])
+			}
+		}
+		return style
+	}
+	// 这里为对象转字符串形式
+	let string = ''
+	for (const i in customStyle) {
+		// 驼峰转为中划线的形式,否则css内联样式,无法识别驼峰样式属性名
+		const key = i.replace(/([A-Z])/g, '-$1').toLowerCase()
+		string += `${key}:${customStyle[i]};`
+	}
+	// 去除两端空格
+	return trim(string)
+}
+
+/**
+ * @description 添加单位,如果有rpx,upx,%,px等单位结尾或者值为auto,直接返回,否则加上px单位结尾
+ * @param {string|number} value 需要添加单位的值
+ * @param {string} unit 添加的单位名 比如px
+ */
+function addUnit(value = 'auto', unit = uni?.$uv?.config?.unit ? uni?.$uv?.config?.unit : 'px') {
+	value = String(value)
+	// 用uvui内置验证规则中的number判断是否为数值
+	return number(value) ? `${value}${unit}` : value
+}
+
+/**
+ * @description 深度克隆
+ * @param {object} obj 需要深度克隆的对象
+ * @param cache 缓存
+ * @returns {*} 克隆后的对象或者原值(不是对象)
+ */
+function deepClone(obj, cache = new WeakMap()) {
+	if (obj === null || typeof obj !== 'object') return obj;
+	if (cache.has(obj)) return cache.get(obj);
+	let clone;
+	if (obj instanceof Date) {
+		clone = new Date(obj.getTime());
+	} else if (obj instanceof RegExp) {
+		clone = new RegExp(obj);
+	} else if (obj instanceof Map) {
+		clone = new Map(Array.from(obj, ([key, value]) => [key, deepClone(value, cache)]));
+	} else if (obj instanceof Set) {
+		clone = new Set(Array.from(obj, value => deepClone(value, cache)));
+	} else if (Array.isArray(obj)) {
+		clone = obj.map(value => deepClone(value, cache));
+	} else if (Object.prototype.toString.call(obj) === '[object Object]') {
+		clone = Object.create(Object.getPrototypeOf(obj));
+		cache.set(obj, clone);
+		for (const [key, value] of Object.entries(obj)) {
+			clone[key] = deepClone(value, cache);
+		}
+	} else {
+		clone = Object.assign({}, obj);
+	}
+	cache.set(obj, clone);
+	return clone;
+}
+
+/**
+ * @description JS对象深度合并
+ * @param {object} target 需要拷贝的对象
+ * @param {object} source 拷贝的来源对象
+ * @returns {object|boolean} 深度合并后的对象或者false(入参有不是对象)
+ */
+function deepMerge(target = {}, source = {}) {
+	target = deepClone(target)
+	if (typeof target !== 'object' || target === null || typeof source !== 'object' || source === null) return target;
+	const merged = Array.isArray(target) ? target.slice() : Object.assign({}, target);
+	for (const prop in source) {
+		if (!source.hasOwnProperty(prop)) continue;
+		const sourceValue = source[prop];
+		const targetValue = merged[prop];
+		if (sourceValue instanceof Date) {
+			merged[prop] = new Date(sourceValue);
+		} else if (sourceValue instanceof RegExp) {
+			merged[prop] = new RegExp(sourceValue);
+		} else if (sourceValue instanceof Map) {
+			merged[prop] = new Map(sourceValue);
+		} else if (sourceValue instanceof Set) {
+			merged[prop] = new Set(sourceValue);
+		} else if (typeof sourceValue === 'object' && sourceValue !== null) {
+			merged[prop] = deepMerge(targetValue, sourceValue);
+		} else {
+			merged[prop] = sourceValue;
+		}
+	}
+	return merged;
+}
+
+/**
+ * @description error提示
+ * @param {*} err 错误内容
+ */
+function error(err) {
+	// 开发环境才提示,生产环境不会提示
+	if (process.env.NODE_ENV === 'development') {
+		console.error(`uvui提示:${err}`)
+	}
+}
+
+/**
+ * @description 打乱数组
+ * @param {array} array 需要打乱的数组
+ * @returns {array} 打乱后的数组
+ */
+function randomArray(array = []) {
+	// 原理是sort排序,Math.random()产生0<= x < 1之间的数,会导致x-0.05大于或者小于0
+	return array.sort(() => Math.random() - 0.5)
+}
+
+// padStart 的 polyfill,因为某些机型或情况,还无法支持es7的padStart,比如电脑版的微信小程序
+// 所以这里做一个兼容polyfill的兼容处理
+if (!String.prototype.padStart) {
+	// 为了方便表示这里 fillString 用了ES6 的默认参数,不影响理解
+	String.prototype.padStart = function(maxLength, fillString = ' ') {
+		if (Object.prototype.toString.call(fillString) !== '[object String]') {
+			throw new TypeError(
+				'fillString must be String'
+			)
+		}
+		const str = this
+		// 返回 String(str) 这里是为了使返回的值是字符串字面量,在控制台中更符合直觉
+		if (str.length >= maxLength) return String(str)
+
+		const fillLength = maxLength - str.length
+		let times = Math.ceil(fillLength / fillString.length)
+		while (times >>= 1) {
+			fillString += fillString
+			if (times === 1) {
+				fillString += fillString
+			}
+		}
+		return fillString.slice(0, fillLength) + str
+	}
+}
+
+/**
+ * @description 格式化时间
+ * @param {String|Number} dateTime 需要格式化的时间戳
+ * @param {String} fmt 格式化规则 yyyy:mm:dd|yyyy:mm|yyyy年mm月dd日|yyyy年mm月dd日 hh时MM分等,可自定义组合 默认yyyy-mm-dd
+ * @returns {string} 返回格式化后的字符串
+ */
+function timeFormat(dateTime = null, formatStr = 'yyyy-mm-dd') {
+	let date
+	// 若传入时间为假值,则取当前时间
+	if (!dateTime) {
+		date = new Date()
+	}
+	// 若为unix秒时间戳,则转为毫秒时间戳(逻辑有点奇怪,但不敢改,以保证历史兼容)
+	else if (/^\d{10}$/.test(dateTime?.toString().trim())) {
+		date = new Date(dateTime * 1000)
+	}
+	// 若用户传入字符串格式时间戳,new Date无法解析,需做兼容
+	else if (typeof dateTime === 'string' && /^\d+$/.test(dateTime.trim())) {
+		date = new Date(Number(dateTime))
+	}
+	// 处理平台性差异,在Safari/Webkit中,new Date仅支持/作为分割符的字符串时间
+	// 处理 '2022-07-10 01:02:03',跳过 '2022-07-10T01:02:03'
+	else if (typeof dateTime === 'string' && dateTime.includes('-') && !dateTime.includes('T')) {
+		date = new Date(dateTime.replace(/-/g, '/'))
+	}
+	// 其他都认为符合 RFC 2822 规范
+	else {
+		date = new Date(dateTime)
+	}
+
+	const timeSource = {
+		'y': date.getFullYear().toString(), // 年
+		'm': (date.getMonth() + 1).toString().padStart(2, '0'), // 月
+		'd': date.getDate().toString().padStart(2, '0'), // 日
+		'h': date.getHours().toString().padStart(2, '0'), // 时
+		'M': date.getMinutes().toString().padStart(2, '0'), // 分
+		's': date.getSeconds().toString().padStart(2, '0') // 秒
+		// 有其他格式化字符需求可以继续添加,必须转化成字符串
+	}
+
+	for (const key in timeSource) {
+		const [ret] = new RegExp(`${key}+`).exec(formatStr) || []
+		if (ret) {
+			// 年可能只需展示两位
+			const beginIndex = key === 'y' && ret.length === 2 ? 2 : 0
+			formatStr = formatStr.replace(ret, timeSource[key].slice(beginIndex))
+		}
+	}
+
+	return formatStr
+}
+
+/**
+ * @description 时间戳转为多久之前
+ * @param {String|Number} timestamp 时间戳
+ * @param {String|Boolean} format
+ * 格式化规则如果为时间格式字符串,超出一定时间范围,返回固定的时间格式;
+ * 如果为布尔值false,无论什么时间,都返回多久以前的格式
+ * @returns {string} 转化后的内容
+ */
+function timeFrom(timestamp = null, format = 'yyyy-mm-dd') {
+	if (timestamp == null) timestamp = Number(new Date())
+	timestamp = parseInt(timestamp)
+	// 判断用户输入的时间戳是秒还是毫秒,一般前端js获取的时间戳是毫秒(13位),后端传过来的为秒(10位)
+	if (timestamp.toString().length == 10) timestamp *= 1000
+	let timer = (new Date()).getTime() - timestamp
+	timer = parseInt(timer / 1000)
+	// 如果小于5分钟,则返回"刚刚",其他以此类推
+	let tips = ''
+	switch (true) {
+		case timer < 300:
+			tips = '刚刚'
+			break
+		case timer >= 300 && timer < 3600:
+			tips = `${parseInt(timer / 60)}分钟前`
+			break
+		case timer >= 3600 && timer < 86400:
+			tips = `${parseInt(timer / 3600)}小时前`
+			break
+		case timer >= 86400 && timer < 2592000:
+			tips = `${parseInt(timer / 86400)}天前`
+			break
+		default:
+			// 如果format为false,则无论什么时间戳,都显示xx之前
+			if (format === false) {
+				if (timer >= 2592000 && timer < 365 * 86400) {
+					tips = `${parseInt(timer / (86400 * 30))}个月前`
+				} else {
+					tips = `${parseInt(timer / (86400 * 365))}年前`
+				}
+			} else {
+				tips = timeFormat(timestamp, format)
+			}
+	}
+	return tips
+}
+
+/**
+ * @description 去除空格
+ * @param String str 需要去除空格的字符串
+ * @param String pos both(左右)|left|right|all 默认both
+ */
+function trim(str, pos = 'both') {
+	str = String(str)
+	if (pos == 'both') {
+		return str.replace(/^\s+|\s+$/g, '')
+	}
+	if (pos == 'left') {
+		return str.replace(/^\s*/, '')
+	}
+	if (pos == 'right') {
+		return str.replace(/(\s*$)/g, '')
+	}
+	if (pos == 'all') {
+		return str.replace(/\s+/g, '')
+	}
+	return str
+}
+
+/**
+ * @description 对象转url参数
+ * @param {object} data,对象
+ * @param {Boolean} isPrefix,是否自动加上"?"
+ * @param {string} arrayFormat 规则 indices|brackets|repeat|comma
+ */
+function queryParams(data = {}, isPrefix = true, arrayFormat = 'brackets') {
+	const prefix = isPrefix ? '?' : ''
+	const _result = []
+	if (['indices', 'brackets', 'repeat', 'comma'].indexOf(arrayFormat) == -1) arrayFormat = 'brackets'
+	for (const key in data) {
+		const value = data[key]
+		// 去掉为空的参数
+		if (['', undefined, null].indexOf(value) >= 0) {
+			continue
+		}
+		// 如果值为数组,另行处理
+		if (value.constructor === Array) {
+			// e.g. {ids: [1, 2, 3]}
+			switch (arrayFormat) {
+				case 'indices':
+					// 结果: ids[0]=1&ids[1]=2&ids[2]=3
+					for (let i = 0; i < value.length; i++) {
+						_result.push(`${key}[${i}]=${value[i]}`)
+					}
+					break
+				case 'brackets':
+					// 结果: ids[]=1&ids[]=2&ids[]=3
+					value.forEach((_value) => {
+						_result.push(`${key}[]=${_value}`)
+					})
+					break
+				case 'repeat':
+					// 结果: ids=1&ids=2&ids=3
+					value.forEach((_value) => {
+						_result.push(`${key}=${_value}`)
+					})
+					break
+				case 'comma':
+					// 结果: ids=1,2,3
+					let commaStr = ''
+					value.forEach((_value) => {
+						commaStr += (commaStr ? ',' : '') + _value
+					})
+					_result.push(`${key}=${commaStr}`)
+					break
+				default:
+					value.forEach((_value) => {
+						_result.push(`${key}[]=${_value}`)
+					})
+			}
+		} else {
+			_result.push(`${key}=${value}`)
+		}
+	}
+	return _result.length ? prefix + _result.join('&') : ''
+}
+
+/**
+ * 显示消息提示框
+ * @param {String} title 提示的内容,长度与 icon 取值有关。
+ * @param {Number} duration 提示的延迟时间,单位毫秒,默认:2000
+ */
+function toast(title, duration = 2000) {
+	uni.showToast({
+		title: String(title),
+		icon: 'none',
+		duration
+	})
+}
+
+/**
+ * @description 根据主题type值,获取对应的图标
+ * @param {String} type 主题名称,primary|info|error|warning|success
+ * @param {boolean} fill 是否使用fill填充实体的图标
+ */
+function type2icon(type = 'success', fill = false) {
+	// 如果非预置值,默认为success
+	if (['primary', 'info', 'error', 'warning', 'success'].indexOf(type) == -1) type = 'success'
+	let iconName = ''
+	// 目前(2019-12-12),info和primary使用同一个图标
+	switch (type) {
+		case 'primary':
+			iconName = 'info-circle'
+			break
+		case 'info':
+			iconName = 'info-circle'
+			break
+		case 'error':
+			iconName = 'close-circle'
+			break
+		case 'warning':
+			iconName = 'error-circle'
+			break
+		case 'success':
+			iconName = 'checkmark-circle'
+			break
+		default:
+			iconName = 'checkmark-circle'
+	}
+	// 是否是实体类型,加上-fill,在icon组件库中,实体的类名是后面加-fill的
+	if (fill) iconName += '-fill'
+	return iconName
+}
+
+/**
+ * @description 数字格式化
+ * @param {number|string} number 要格式化的数字
+ * @param {number} decimals 保留几位小数
+ * @param {string} decimalPoint 小数点符号
+ * @param {string} thousandsSeparator 千分位符号
+ * @returns {string} 格式化后的数字
+ */
+function priceFormat(number, decimals = 0, decimalPoint = '.', thousandsSeparator = ',') {
+	number = (`${number}`).replace(/[^0-9+-Ee.]/g, '')
+	const n = !isFinite(+number) ? 0 : +number
+	const prec = !isFinite(+decimals) ? 0 : Math.abs(decimals)
+	const sep = (typeof thousandsSeparator === 'undefined') ? ',' : thousandsSeparator
+	const dec = (typeof decimalPoint === 'undefined') ? '.' : decimalPoint
+	let s = ''
+
+	s = (prec ? round(n, prec) + '' : `${Math.round(n)}`).split('.')
+	const re = /(-?\d+)(\d{3})/
+	while (re.test(s[0])) {
+		s[0] = s[0].replace(re, `$1${sep}$2`)
+	}
+
+	if ((s[1] || '').length < prec) {
+		s[1] = s[1] || ''
+		s[1] += new Array(prec - s[1].length + 1).join('0')
+	}
+	return s.join(dec)
+}
+
+/**
+ * @description 获取duration值
+ * 如果带有ms或者s直接返回,如果大于一定值,认为是ms单位,小于一定值,认为是s单位
+ * 比如以30位阈值,那么300大于30,可以理解为用户想要的是300ms,而不是想花300s去执行一个动画
+ * @param {String|number} value 比如: "1s"|"100ms"|1|100
+ * @param {boolean} unit  提示: 如果是false 默认返回number
+ * @return {string|number}
+ */
+function getDuration(value, unit = true) {
+	const valueNum = parseInt(value)
+	if (unit) {
+		if (/s$/.test(value)) return value
+		return value > 30 ? `${value}ms` : `${value}s`
+	}
+	if (/ms$/.test(value)) return valueNum
+	if (/s$/.test(value)) return valueNum > 30 ? valueNum : valueNum * 1000
+	return valueNum
+}
+
+/**
+ * @description 日期的月或日补零操作
+ * @param {String} value 需要补零的值
+ */
+function padZero(value) {
+	return `00${value}`.slice(-2)
+}
+
+/**
+ * @description 在uv-form的子组件内容发生变化,或者失去焦点时,尝试通知uv-form执行校验方法
+ * @param {*} instance
+ * @param {*} event
+ */
+function formValidate(instance, event) {
+	const formItem = $parent.call(instance, 'uv-form-item')
+	const form = $parent.call(instance, 'uv-form')
+	// 如果发生变化的input或者textarea等,其父组件中有uv-form-item或者uv-form等,就执行form的validate方法
+	// 同时将form-item的pros传递给form,让其进行精确对象验证
+	if (formItem && form) {
+		form.validateField(formItem.prop, () => {}, event)
+	}
+}
+
+/**
+ * @description 获取某个对象下的属性,用于通过类似'a.b.c'的形式去获取一个对象的的属性的形式
+ * @param {object} obj 对象
+ * @param {string} key 需要获取的属性字段
+ * @returns {*}
+ */
+function getProperty(obj, key) {
+	if (!obj) {
+		return
+	}
+	if (typeof key !== 'string' || key === '') {
+		return ''
+	}
+	if (key.indexOf('.') !== -1) {
+		const keys = key.split('.')
+		let firstObj = obj[keys[0]] || {}
+
+		for (let i = 1; i < keys.length; i++) {
+			if (firstObj) {
+				firstObj = firstObj[keys[i]]
+			}
+		}
+		return firstObj
+	}
+	return obj[key]
+}
+
+/**
+ * @description 设置对象的属性值,如果'a.b.c'的形式进行设置
+ * @param {object} obj 对象
+ * @param {string} key 需要设置的属性
+ * @param {string} value 设置的值
+ */
+function setProperty(obj, key, value) {
+	if (!obj) {
+		return
+	}
+	// 递归赋值
+	const inFn = function(_obj, keys, v) {
+		// 最后一个属性key
+		if (keys.length === 1) {
+			_obj[keys[0]] = v
+			return
+		}
+		// 0~length-1个key
+		while (keys.length > 1) {
+			const k = keys[0]
+			if (!_obj[k] || (typeof _obj[k] !== 'object')) {
+				_obj[k] = {}
+			}
+			const key = keys.shift()
+			// 自调用判断是否存在属性,不存在则自动创建对象
+			inFn(_obj[k], keys, v)
+		}
+	}
+
+	if (typeof key !== 'string' || key === '') {
+
+	} else if (key.indexOf('.') !== -1) { // 支持多层级赋值操作
+		const keys = key.split('.')
+		inFn(obj, keys, value)
+	} else {
+		obj[key] = value
+	}
+}
+
+/**
+ * @description 获取当前页面路径
+ */
+function page() {
+	const pages = getCurrentPages();
+	const route = pages[pages.length - 1]?.route;
+	// 某些特殊情况下(比如页面进行redirectTo时的一些时机),pages可能为空数组
+	return `/${route ? route : ''}`
+}
+
+/**
+ * @description 获取当前路由栈实例数组
+ */
+function pages() {
+	const pages = getCurrentPages()
+	return pages
+}
+
+/**
+ * 获取页面历史栈指定层实例
+ * @param back {number} [0] - 0或者负数,表示获取历史栈的哪一层,0表示获取当前页面实例,-1 表示获取上一个页面实例。默认0。
+ */
+function getHistoryPage(back = 0) {
+	const pages = getCurrentPages()
+	const len = pages.length
+	return pages[len - 1 + back]
+}
+
+
+
+/**
+ * @description 修改uvui内置属性值
+ * @param {object} props 修改内置props属性
+ * @param {object} config 修改内置config属性
+ * @param {object} color 修改内置color属性
+ * @param {object} zIndex 修改内置zIndex属性
+ */
+function setConfig({
+	props = {},
+	config = {},
+	color = {},
+	zIndex = {}
+}) {
+	const {
+		deepMerge,
+	} = uni.$uv
+	uni.$uv.config = deepMerge(uni.$uv.config, config)
+	uni.$uv.props = deepMerge(uni.$uv.props, props)
+	uni.$uv.color = deepMerge(uni.$uv.color, color)
+	uni.$uv.zIndex = deepMerge(uni.$uv.zIndex, zIndex)
+}
+
+export {
+	range,
+	getPx,
+	sleep,
+	os,
+	sys,
+	random,
+	guid,
+	$parent,
+	addStyle,
+	addUnit,
+	deepClone,
+	deepMerge,
+	error,
+	randomArray,
+	timeFormat,
+	timeFrom,
+	trim,
+	queryParams,
+	toast,
+	type2icon,
+	priceFormat,
+	getDuration,
+	padZero,
+	formValidate,
+	getProperty,
+	setProperty,
+	page,
+	pages,
+	getHistoryPage,
+	setConfig
+}

+ 75 - 0
uni_modules/uv-ui-tools/libs/function/platform.js

@@ -0,0 +1,75 @@
+/**
+ * 注意:
+ * 此部分内容,在vue-cli模式下,需要在vue.config.js加入如下内容才有效:
+ * module.exports = {
+ *     transpileDependencies: ['uview-v2']
+ * }
+ */
+
+let platform = 'none'
+
+// #ifdef VUE3
+platform = 'vue3'
+// #endif
+
+// #ifdef VUE2
+platform = 'vue2'
+// #endif
+
+// #ifdef APP-PLUS
+platform = 'plus'
+// #endif
+
+// #ifdef APP-NVUE
+platform = 'nvue'
+// #endif
+
+// #ifdef H5
+platform = 'h5'
+// #endif
+
+// #ifdef MP-WEIXIN
+platform = 'weixin'
+// #endif
+
+// #ifdef MP-ALIPAY
+platform = 'alipay'
+// #endif
+
+// #ifdef MP-BAIDU
+platform = 'baidu'
+// #endif
+
+// #ifdef MP-TOUTIAO
+platform = 'toutiao'
+// #endif
+
+// #ifdef MP-QQ
+platform = 'qq'
+// #endif
+
+// #ifdef MP-KUAISHOU
+platform = 'kuaishou'
+// #endif
+
+// #ifdef MP-360
+platform = '360'
+// #endif
+
+// #ifdef MP
+platform = 'mp'
+// #endif
+
+// #ifdef QUICKAPP-WEBVIEW
+platform = 'quickapp-webview'
+// #endif
+
+// #ifdef QUICKAPP-WEBVIEW-HUAWEI
+platform = 'quickapp-webview-huawei'
+// #endif
+
+// #ifdef QUICKAPP-WEBVIEW-UNION
+platform = 'quckapp-webview-union'
+// #endif
+
+export default platform

+ 287 - 0
uni_modules/uv-ui-tools/libs/function/test.js

@@ -0,0 +1,287 @@
+/**
+ * 验证电子邮箱格式
+ */
+function email(value) {
+    return /^\w+((-\w+)|(\.\w+))*\@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]+$/.test(value)
+}
+
+/**
+ * 验证手机格式
+ */
+function mobile(value) {
+    return /^1([3589]\d|4[5-9]|6[1-2,4-7]|7[0-8])\d{8}$/.test(value)
+}
+
+/**
+ * 验证URL格式
+ */
+function url(value) {
+    return /^((https|http|ftp|rtsp|mms):\/\/)(([0-9a-zA-Z_!~*'().&=+$%-]+: )?[0-9a-zA-Z_!~*'().&=+$%-]+@)?(([0-9]{1,3}.){3}[0-9]{1,3}|([0-9a-zA-Z_!~*'()-]+.)*([0-9a-zA-Z][0-9a-zA-Z-]{0,61})?[0-9a-zA-Z].[a-zA-Z]{2,6})(:[0-9]{1,4})?((\/?)|(\/[0-9a-zA-Z_!~*'().;?:@&=+$,%#-]+)+\/?)$/
+        .test(value)
+}
+
+/**
+ * 验证日期格式
+ */
+function date(value) {
+    if (!value) return false
+    // 判断是否数值或者字符串数值(意味着为时间戳),转为数值,否则new Date无法识别字符串时间戳
+    if (number(value)) value = +value
+    return !/Invalid|NaN/.test(new Date(value).toString())
+}
+
+/**
+ * 验证ISO类型的日期格式
+ */
+function dateISO(value) {
+    return /^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])$/.test(value)
+}
+
+/**
+ * 验证十进制数字
+ */
+function number(value) {
+    return /^[\+-]?(\d+\.?\d*|\.\d+|\d\.\d+e\+\d+)$/.test(value)
+}
+
+/**
+ * 验证字符串
+ */
+function string(value) {
+    return typeof value === 'string'
+}
+
+/**
+ * 验证整数
+ */
+function digits(value) {
+    return /^\d+$/.test(value)
+}
+
+/**
+ * 验证身份证号码
+ */
+function idCard(value) {
+    return /^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/.test(
+        value
+    )
+}
+
+/**
+ * 是否车牌号
+ */
+function carNo(value) {
+    // 新能源车牌
+    const xreg = /^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[A-Z]{1}(([0-9]{5}[DF]$)|([DF][A-HJ-NP-Z0-9][0-9]{4}$))/
+    // 旧车牌
+    const creg = /^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[A-Z]{1}[A-HJ-NP-Z0-9]{4}[A-HJ-NP-Z0-9挂学警港澳]{1}$/
+    if (value.length === 7) {
+        return creg.test(value)
+    } if (value.length === 8) {
+        return xreg.test(value)
+    }
+    return false
+}
+
+/**
+ * 金额,只允许2位小数
+ */
+function amount(value) {
+    // 金额,只允许保留两位小数
+    return /^[1-9]\d*(,\d{3})*(\.\d{1,2})?$|^0\.\d{1,2}$/.test(value)
+}
+
+/**
+ * 中文
+ */
+function chinese(value) {
+    const reg = /^[\u4e00-\u9fa5]+$/gi
+    return reg.test(value)
+}
+
+/**
+ * 只能输入字母
+ */
+function letter(value) {
+    return /^[a-zA-Z]*$/.test(value)
+}
+
+/**
+ * 只能是字母或者数字
+ */
+function enOrNum(value) {
+    // 英文或者数字
+    const reg = /^[0-9a-zA-Z]*$/g
+    return reg.test(value)
+}
+
+/**
+ * 验证是否包含某个值
+ */
+function contains(value, param) {
+    return value.indexOf(param) >= 0
+}
+
+/**
+ * 验证一个值范围[min, max]
+ */
+function range(value, param) {
+    return value >= param[0] && value <= param[1]
+}
+
+/**
+ * 验证一个长度范围[min, max]
+ */
+function rangeLength(value, param) {
+    return value.length >= param[0] && value.length <= param[1]
+}
+
+/**
+ * 是否固定电话
+ */
+function landline(value) {
+    const reg = /^\d{3,4}-\d{7,8}(-\d{3,4})?$/
+    return reg.test(value)
+}
+
+/**
+ * 判断是否为空
+ */
+function empty(value) {
+    switch (typeof value) {
+    case 'undefined':
+        return true
+    case 'string':
+        if (value.replace(/(^[ \t\n\r]*)|([ \t\n\r]*$)/g, '').length == 0) return true
+        break
+    case 'boolean':
+        if (!value) return true
+        break
+    case 'number':
+        if (value === 0 || isNaN(value)) return true
+        break
+    case 'object':
+        if (value === null || value.length === 0) return true
+        for (const i in value) {
+            return false
+        }
+        return true
+    }
+    return false
+}
+
+/**
+ * 是否json字符串
+ */
+function jsonString(value) {
+    if (typeof value === 'string') {
+        try {
+            const obj = JSON.parse(value)
+            if (typeof obj === 'object' && obj) {
+                return true
+            }
+            return false
+        } catch (e) {
+            return false
+        }
+    }
+    return false
+}
+
+/**
+ * 是否数组
+ */
+function array(value) {
+    if (typeof Array.isArray === 'function') {
+        return Array.isArray(value)
+    }
+    return Object.prototype.toString.call(value) === '[object Array]'
+}
+
+/**
+ * 是否对象
+ */
+function object(value) {
+    return Object.prototype.toString.call(value) === '[object Object]'
+}
+
+/**
+ * 是否短信验证码
+ */
+function code(value, len = 6) {
+    return new RegExp(`^\\d{${len}}$`).test(value)
+}
+
+/**
+ * 是否函数方法
+ * @param {Object} value
+ */
+function func(value) {
+    return typeof value === 'function'
+}
+
+/**
+ * 是否promise对象
+ * @param {Object} value
+ */
+function promise(value) {
+    return object(value) && func(value.then) && func(value.catch)
+}
+
+/** 是否图片格式
+ * @param {Object} value
+ */
+function image(value) {
+    const newValue = value.split('?')[0]
+    const IMAGE_REGEXP = /\.(jpeg|jpg|gif|png|svg|webp|jfif|bmp|dpg)/i
+    return IMAGE_REGEXP.test(newValue)
+}
+
+/**
+ * 是否视频格式
+ * @param {Object} value
+ */
+function video(value) {
+    const VIDEO_REGEXP = /\.(mp4|mpg|mpeg|dat|asf|avi|rm|rmvb|mov|wmv|flv|mkv|m3u8)/i
+    return VIDEO_REGEXP.test(value)
+}
+
+/**
+ * 是否为正则对象
+ * @param {Object}
+ * @return {Boolean}
+ */
+function regExp(o) {
+    return o && Object.prototype.toString.call(o) === '[object RegExp]'
+}
+
+export {
+    email,
+    mobile,
+    url,
+    date,
+    dateISO,
+    number,
+    digits,
+    idCard,
+    carNo,
+    amount,
+    chinese,
+    letter,
+    enOrNum,
+    contains,
+    range,
+    rangeLength,
+    empty,
+    jsonString,
+    landline,
+    object,
+    array,
+    code,
+    func,
+    promise,
+    video,
+    image,
+    regExp,
+    string
+}

+ 30 - 0
uni_modules/uv-ui-tools/libs/function/throttle.js

@@ -0,0 +1,30 @@
+let timer; let
+    flag
+/**
+ * 节流原理:在一定时间内,只能触发一次
+ *
+ * @param {Function} func 要执行的回调函数
+ * @param {Number} wait 延时的时间
+ * @param {Boolean} immediate 是否立即执行
+ * @return null
+ */
+function throttle(func, wait = 500, immediate = true) {
+    if (immediate) {
+        if (!flag) {
+            flag = true
+            // 如果是立即执行,则在wait毫秒内开始时执行
+            typeof func === 'function' && func()
+            timer = setTimeout(() => {
+                flag = false
+            }, wait)
+        }
+    } else if (!flag) {
+        flag = true
+        // 如果是非立即执行,则在wait毫秒内的结束处执行
+        timer = setTimeout(() => {
+            flag = false
+            typeof func === 'function' && func()
+        }, wait)
+    }
+}
+export default throttle

+ 132 - 0
uni_modules/uv-ui-tools/libs/luch-request/adapters/index.js

@@ -0,0 +1,132 @@
+import buildURL from '../helpers/buildURL'
+import buildFullPath from '../core/buildFullPath'
+import settle from '../core/settle'
+import {isUndefined} from "../utils"
+
+/**
+ * 返回可选值存在的配置
+ * @param {Array} keys - 可选值数组
+ * @param {Object} config2 - 配置
+ * @return {{}} - 存在的配置项
+ */
+const mergeKeys = (keys, config2) => {
+  let config = {}
+  keys.forEach(prop => {
+    if (!isUndefined(config2[prop])) {
+      config[prop] = config2[prop]
+    }
+  })
+  return config
+}
+export default (config) => {
+  return new Promise((resolve, reject) => {
+    let fullPath = buildURL(buildFullPath(config.baseURL, config.url), config.params, config.paramsSerializer)
+    const _config = {
+      url: fullPath,
+      header: config.header,
+      complete: (response) => {
+        config.fullPath = fullPath
+        response.config = config
+        response.rawData = response.data
+        try {
+          let jsonParseHandle = false
+          const forcedJSONParsingType = typeof config.forcedJSONParsing
+          if (forcedJSONParsingType === 'boolean') {
+            jsonParseHandle = config.forcedJSONParsing
+          } else if (forcedJSONParsingType === 'object') {
+            const includesMethod = config.forcedJSONParsing.include || []
+            jsonParseHandle = includesMethod.includes(config.method)
+          }
+
+          // 对可能字符串不是json 的情况容错
+          if (jsonParseHandle && typeof response.data === 'string') {
+            response.data = JSON.parse(response.data)
+          }
+          // eslint-disable-next-line no-empty
+        } catch (e) {
+        }
+        settle(resolve, reject, response)
+      }
+    }
+    let requestTask
+    if (config.method === 'UPLOAD') {
+      delete _config.header['content-type']
+      delete _config.header['Content-Type']
+      let otherConfig = {
+        // #ifdef MP-ALIPAY
+        fileType: config.fileType,
+        // #endif
+        filePath: config.filePath,
+        name: config.name
+      }
+      const optionalKeys = [
+        // #ifdef APP-PLUS || H5
+        'files',
+        // #endif
+        // #ifdef H5
+        'file',
+        // #endif
+        // #ifdef H5 || APP-PLUS || MP-WEIXIN || MP-ALIPAY || MP-TOUTIAO || MP-KUAISHOU
+        'timeout',
+        // #endif
+        'formData'
+      ]
+      requestTask = uni.uploadFile({..._config, ...otherConfig, ...mergeKeys(optionalKeys, config)})
+    } else if (config.method === 'DOWNLOAD') {
+      const optionalKeys = [
+        // #ifdef H5 || APP-PLUS || MP-WEIXIN || MP-ALIPAY || MP-TOUTIAO || MP-KUAISHOU
+        'timeout',
+        // #endif
+        // #ifdef MP
+        'filePath',
+        // #endif
+      ]
+      requestTask = uni.downloadFile({..._config, ...mergeKeys(optionalKeys, config)})
+    } else {
+      const optionalKeys = [
+        'data',
+        'method',
+        // #ifdef H5 || APP-PLUS || MP-ALIPAY || MP-WEIXIN
+        'timeout',
+        // #endif
+        'dataType',
+        // #ifndef MP-ALIPAY
+        'responseType',
+        // #endif
+        // #ifdef APP-PLUS
+        'sslVerify',
+        // #endif
+        // #ifdef H5
+        'withCredentials',
+        // #endif
+        // #ifdef APP-PLUS
+        'firstIpv4',
+        // #endif
+        // #ifdef MP-WEIXIN
+        'enableHttp2',
+        'enableQuic',
+        // #endif
+        // #ifdef MP-TOUTIAO || MP-WEIXIN
+        'enableCache',
+        // #endif
+        // #ifdef MP-WEIXIN
+        'enableHttpDNS',
+        'httpDNSServiceId',
+        'enableChunked',
+        'forceCellularNetwork',
+        // #endif
+        // #ifdef MP-ALIPAY
+        'enableCookie',
+        // #endif
+        // #ifdef MP-BAIDU
+        'cloudCache',
+        'defer'
+        // #endif
+      ]
+      requestTask = uni.request({..._config, ...mergeKeys(optionalKeys, config)})
+    }
+    if (config.getTask) {
+      config.getTask(requestTask, config)
+    }
+  })
+}

+ 51 - 0
uni_modules/uv-ui-tools/libs/luch-request/core/InterceptorManager.js

@@ -0,0 +1,51 @@
+'use strict'
+
+
+function InterceptorManager() {
+  this.handlers = []
+}
+
+/**
+ * Add a new interceptor to the stack
+ *
+ * @param {Function} fulfilled The function to handle `then` for a `Promise`
+ * @param {Function} rejected The function to handle `reject` for a `Promise`
+ *
+ * @return {Number} An ID used to remove interceptor later
+ */
+InterceptorManager.prototype.use = function use(fulfilled, rejected) {
+  this.handlers.push({
+    fulfilled: fulfilled,
+    rejected: rejected
+  })
+  return this.handlers.length - 1
+}
+
+/**
+ * Remove an interceptor from the stack
+ *
+ * @param {Number} id The ID that was returned by `use`
+ */
+InterceptorManager.prototype.eject = function eject(id) {
+  if (this.handlers[id]) {
+    this.handlers[id] = null
+  }
+}
+
+/**
+ * Iterate over all the registered interceptors
+ *
+ * This method is particularly useful for skipping over any
+ * interceptors that may have become `null` calling `eject`.
+ *
+ * @param {Function} fn The function to call for each interceptor
+ */
+InterceptorManager.prototype.forEach = function forEach(fn) {
+  this.handlers.forEach(h => {
+    if (h !== null) {
+      fn(h)
+    }
+  })
+}
+
+export default InterceptorManager

+ 201 - 0
uni_modules/uv-ui-tools/libs/luch-request/core/Request.js

@@ -0,0 +1,201 @@
+/**
+ * @Class Request
+ * @description luch-request http请求插件
+ * @Author lu-ch
+ * @Email webwork.s@qq.com
+ * 文档: https://www.quanzhan.co/luch-request/
+ * github: https://github.com/lei-mu/luch-request
+ * DCloud: http://ext.dcloud.net.cn/plugin?id=392
+ */
+
+
+import dispatchRequest from './dispatchRequest'
+import InterceptorManager from './InterceptorManager'
+import mergeConfig from './mergeConfig'
+import defaults from './defaults'
+import { isPlainObject } from '../utils'
+import clone from '../utils/clone'
+
+export default class Request {
+  /**
+   * @param {Object} arg - 全局配置
+   * @param {String} arg.baseURL - 全局根路径
+   * @param {Object} arg.header - 全局header
+   * @param {String} arg.method = [GET|POST|PUT|DELETE|CONNECT|HEAD|OPTIONS|TRACE] - 全局默认请求方式
+   * @param {String} arg.dataType = [json] - 全局默认的dataType
+   * @param {String} arg.responseType = [text|arraybuffer] - 全局默认的responseType。支付宝小程序不支持
+   * @param {Object} arg.custom - 全局默认的自定义参数
+   * @param {Number} arg.timeout - 全局默认的超时时间,单位 ms。默认60000。H5(HBuilderX 2.9.9+)、APP(HBuilderX 2.9.9+)、微信小程序(2.10.0)、支付宝小程序
+   * @param {Boolean} arg.sslVerify - 全局默认的是否验证 ssl 证书。默认true.仅App安卓端支持(HBuilderX 2.3.3+)
+   * @param {Boolean} arg.withCredentials - 全局默认的跨域请求时是否携带凭证(cookies)。默认false。仅H5支持(HBuilderX 2.6.15+)
+   * @param {Boolean} arg.firstIpv4 - 全DNS解析时优先使用ipv4。默认false。仅 App-Android 支持 (HBuilderX 2.8.0+)
+   * @param {Function(statusCode):Boolean} arg.validateStatus - 全局默认的自定义验证器。默认statusCode >= 200 && statusCode < 300
+   */
+  constructor(arg = {}) {
+    if (!isPlainObject(arg)) {
+      arg = {}
+      console.warn('设置全局参数必须接收一个Object')
+    }
+    this.config = clone({...defaults, ...arg})
+    this.interceptors = {
+      request: new InterceptorManager(),
+      response: new InterceptorManager()
+    }
+  }
+
+  /**
+   * @Function
+   * @param {Request~setConfigCallback} f - 设置全局默认配置
+   */
+  setConfig(f) {
+    this.config = f(this.config)
+  }
+
+  middleware(config) {
+    config = mergeConfig(this.config, config)
+    let chain = [dispatchRequest, undefined]
+    let promise = Promise.resolve(config)
+
+    this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {
+      chain.unshift(interceptor.fulfilled, interceptor.rejected)
+    })
+
+    this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {
+      chain.push(interceptor.fulfilled, interceptor.rejected)
+    })
+
+    while (chain.length) {
+      promise = promise.then(chain.shift(), chain.shift())
+    }
+
+    return promise
+  }
+
+  /**
+   * @Function
+   * @param {Object} config - 请求配置项
+   * @prop {String} options.url - 请求路径
+   * @prop {Object} options.data - 请求参数
+   * @prop {Object} [options.responseType = config.responseType] [text|arraybuffer] - 响应的数据类型
+   * @prop {Object} [options.dataType = config.dataType] - 如果设为 json,会尝试对返回的数据做一次 JSON.parse
+   * @prop {Object} [options.header = config.header] - 请求header
+   * @prop {Object} [options.method = config.method] - 请求方法
+   * @returns {Promise<unknown>}
+   */
+  request(config = {}) {
+    return this.middleware(config)
+  }
+
+  get(url, options = {}) {
+    return this.middleware({
+      url,
+      method: 'GET',
+      ...options
+    })
+  }
+
+  post(url, data, options = {}) {
+    return this.middleware({
+      url,
+      data,
+      method: 'POST',
+      ...options
+    })
+  }
+
+  // #ifndef MP-ALIPAY || MP-KUAISHOU || MP-JD
+  put(url, data, options = {}) {
+    return this.middleware({
+      url,
+      data,
+      method: 'PUT',
+      ...options
+    })
+  }
+
+  // #endif
+
+  // #ifdef APP-PLUS || H5 || MP-WEIXIN || MP-BAIDU
+  delete(url, data, options = {}) {
+    return this.middleware({
+      url,
+      data,
+      method: 'DELETE',
+      ...options
+    })
+  }
+
+  // #endif
+
+  // #ifdef H5 || MP-WEIXIN
+  connect(url, data, options = {}) {
+    return this.middleware({
+      url,
+      data,
+      method: 'CONNECT',
+      ...options
+    })
+  }
+
+  // #endif
+
+  // #ifdef  H5 || MP-WEIXIN || MP-BAIDU
+  head(url, data, options = {}) {
+    return this.middleware({
+      url,
+      data,
+      method: 'HEAD',
+      ...options
+    })
+  }
+
+  // #endif
+
+  // #ifdef APP-PLUS || H5 || MP-WEIXIN || MP-BAIDU
+  options(url, data, options = {}) {
+    return this.middleware({
+      url,
+      data,
+      method: 'OPTIONS',
+      ...options
+    })
+  }
+
+  // #endif
+
+  // #ifdef H5 || MP-WEIXIN
+  trace(url, data, options = {}) {
+    return this.middleware({
+      url,
+      data,
+      method: 'TRACE',
+      ...options
+    })
+  }
+
+  // #endif
+
+  upload(url, config = {}) {
+    config.url = url
+    config.method = 'UPLOAD'
+    return this.middleware(config)
+  }
+
+  download(url, config = {}) {
+    config.url = url
+    config.method = 'DOWNLOAD'
+    return this.middleware(config)
+  }
+
+  get version () {
+    return '3.1.0'
+  }
+}
+
+
+/**
+ * setConfig回调
+ * @return {Object} - 返回操作后的config
+ * @callback Request~setConfigCallback
+ * @param {Object} config - 全局默认config
+ */

+ 20 - 0
uni_modules/uv-ui-tools/libs/luch-request/core/buildFullPath.js

@@ -0,0 +1,20 @@
+'use strict'
+
+import isAbsoluteURL from '../helpers/isAbsoluteURL'
+import combineURLs from '../helpers/combineURLs'
+
+/**
+ * Creates a new URL by combining the baseURL with the requestedURL,
+ * only when the requestedURL is not already an absolute URL.
+ * If the requestURL is absolute, this function returns the requestedURL untouched.
+ *
+ * @param {string} baseURL The base URL
+ * @param {string} requestedURL Absolute or relative URL to combine
+ * @returns {string} The combined full path
+ */
+export default function buildFullPath(baseURL, requestedURL) {
+  if (baseURL && !isAbsoluteURL(requestedURL)) {
+    return combineURLs(baseURL, requestedURL)
+  }
+  return requestedURL
+}

+ 33 - 0
uni_modules/uv-ui-tools/libs/luch-request/core/defaults.js

@@ -0,0 +1,33 @@
+/**
+ * 默认的全局配置
+ */
+
+
+export default {
+  baseURL: '',
+  header: {},
+  method: 'GET',
+  dataType: 'json',
+  paramsSerializer: null,
+  // #ifndef MP-ALIPAY
+  responseType: 'text',
+  // #endif
+  custom: {},
+  // #ifdef H5 || APP-PLUS || MP-WEIXIN || MP-ALIPAY || MP-TOUTIAO || MP-KUAISHOU
+  timeout: 60000,
+  // #endif
+  // #ifdef APP-PLUS
+  sslVerify: true,
+  // #endif
+  // #ifdef H5
+  withCredentials: false,
+  // #endif
+  // #ifdef APP-PLUS
+  firstIpv4: false,
+  // #endif
+  validateStatus: function validateStatus(status) {
+    return status >= 200 && status < 300
+  },
+  // 是否尝试将响应数据json化
+  forcedJSONParsing: true
+}

+ 6 - 0
uni_modules/uv-ui-tools/libs/luch-request/core/dispatchRequest.js

@@ -0,0 +1,6 @@
+import adapter from '../adapters/index'
+
+
+export default (config) => {
+  return adapter(config)
+}

+ 126 - 0
uni_modules/uv-ui-tools/libs/luch-request/core/mergeConfig.js

@@ -0,0 +1,126 @@
+import {deepMerge, isUndefined} from '../utils'
+
+/**
+ * 合并局部配置优先的配置,如果局部有该配置项则用局部,如果全局有该配置项则用全局
+ * @param {Array} keys - 配置项
+ * @param {Object} globalsConfig - 当前的全局配置
+ * @param {Object} config2 - 局部配置
+ * @return {{}}
+ */
+const mergeKeys = (keys, globalsConfig, config2) => {
+  let config = {}
+  keys.forEach(prop => {
+    if (!isUndefined(config2[prop])) {
+      config[prop] = config2[prop]
+    } else if (!isUndefined(globalsConfig[prop])) {
+      config[prop] = globalsConfig[prop]
+    }
+  })
+  return config
+}
+/**
+ *
+ * @param globalsConfig - 当前实例的全局配置
+ * @param config2 - 当前的局部配置
+ * @return - 合并后的配置
+ */
+export default (globalsConfig, config2 = {}) => {
+  const method = config2.method || globalsConfig.method || 'GET'
+  let config = {
+    baseURL: config2.baseURL || globalsConfig.baseURL || '',
+    method: method,
+    url: config2.url || '',
+    params: config2.params || {},
+    custom: {...(globalsConfig.custom || {}), ...(config2.custom || {})},
+    header: deepMerge(globalsConfig.header || {}, config2.header || {})
+  }
+  const defaultToConfig2Keys = ['getTask', 'validateStatus', 'paramsSerializer', 'forcedJSONParsing']
+  config = {...config, ...mergeKeys(defaultToConfig2Keys, globalsConfig, config2)}
+
+  // eslint-disable-next-line no-empty
+  if (method === 'DOWNLOAD') {
+    const downloadKeys = [
+      // #ifdef H5 || APP-PLUS || MP-WEIXIN || MP-ALIPAY || MP-TOUTIAO || MP-KUAISHOU
+      'timeout',
+      // #endif
+      // #ifdef MP
+      'filePath',
+      // #endif
+    ]
+    config = {...config, ...mergeKeys(downloadKeys, globalsConfig, config2)}
+  } else if (method === 'UPLOAD') {
+    delete config.header['content-type']
+    delete config.header['Content-Type']
+    const uploadKeys = [
+      // #ifdef APP-PLUS || H5
+      'files',
+      // #endif
+      // #ifdef MP-ALIPAY
+      'fileType',
+      // #endif
+      // #ifdef H5
+      'file',
+      // #endif
+      'filePath',
+      'name',
+      // #ifdef H5 || APP-PLUS || MP-WEIXIN || MP-ALIPAY || MP-TOUTIAO || MP-KUAISHOU
+      'timeout',
+      // #endif
+      'formData',
+    ]
+    uploadKeys.forEach(prop => {
+      if (!isUndefined(config2[prop])) {
+        config[prop] = config2[prop]
+      }
+    })
+    // #ifdef H5 || APP-PLUS || MP-WEIXIN || MP-ALIPAY || MP-TOUTIAO || MP-KUAISHOU
+    if (isUndefined(config.timeout) && !isUndefined(globalsConfig.timeout)) {
+      config['timeout'] = globalsConfig['timeout']
+    }
+    // #endif
+  } else {
+    const defaultsKeys = [
+      'data',
+      // #ifdef H5 || APP-PLUS || MP-ALIPAY || MP-WEIXIN
+      'timeout',
+      // #endif
+      'dataType',
+      // #ifndef MP-ALIPAY
+      'responseType',
+      // #endif
+      // #ifdef APP-PLUS
+      'sslVerify',
+      // #endif
+      // #ifdef H5
+      'withCredentials',
+      // #endif
+      // #ifdef APP-PLUS
+      'firstIpv4',
+      // #endif
+      // #ifdef MP-WEIXIN
+      'enableHttp2',
+      'enableQuic',
+      // #endif
+      // #ifdef MP-TOUTIAO || MP-WEIXIN
+      'enableCache',
+      // #endif
+      // #ifdef MP-WEIXIN
+      'enableHttpDNS',
+      'httpDNSServiceId',
+      'enableChunked',
+      'forceCellularNetwork',
+      // #endif
+      // #ifdef MP-ALIPAY
+      'enableCookie',
+      // #endif
+      // #ifdef MP-BAIDU
+      'cloudCache',
+      'defer'
+      // #endif
+
+    ]
+    config = {...config, ...mergeKeys(defaultsKeys, globalsConfig, config2)}
+  }
+
+  return config
+}

+ 16 - 0
uni_modules/uv-ui-tools/libs/luch-request/core/settle.js

@@ -0,0 +1,16 @@
+/**
+ * Resolve or reject a Promise based on response status.
+ *
+ * @param {Function} resolve A function that resolves the promise.
+ * @param {Function} reject A function that rejects the promise.
+ * @param {object} response The response.
+ */
+export default function settle(resolve, reject, response) {
+  const validateStatus = response.config.validateStatus
+  const status = response.statusCode
+  if (status && (!validateStatus || validateStatus(status))) {
+    resolve(response)
+  } else {
+    reject(response)
+  }
+}

+ 64 - 0
uni_modules/uv-ui-tools/libs/luch-request/helpers/buildURL.js

@@ -0,0 +1,64 @@
+'use strict'
+
+import * as utils from './../utils'
+
+function encode(val) {
+  return encodeURIComponent(val).replace(/%40/gi, '@').replace(/%3A/gi, ':').replace(/%24/g, '$').replace(/%2C/gi, ',').replace(/%20/g, '+').replace(/%5B/gi, '[').replace(/%5D/gi, ']')
+}
+
+/**
+ * Build a URL by appending params to the end
+ *
+ * @param {string} url The base of the url (e.g., http://www.google.com)
+ * @param {object} [params] The params to be appended
+ * @returns {string} The formatted url
+ */
+export default function buildURL(url, params, paramsSerializer) {
+  /*eslint no-param-reassign:0*/
+  if (!params) {
+    return url
+  }
+
+  var serializedParams
+  if (paramsSerializer) {
+    serializedParams = paramsSerializer(params)
+  } else if (utils.isURLSearchParams(params)) {
+    serializedParams = params.toString()
+  } else {
+    var parts = []
+
+    utils.forEach(params, function serialize(val, key) {
+      if (val === null || typeof val === 'undefined') {
+        return
+      }
+
+      if (utils.isArray(val)) {
+        key = key + '[]'
+      } else {
+        val = [val]
+      }
+
+      utils.forEach(val, function parseValue(v) {
+        if (utils.isDate(v)) {
+          v = v.toISOString()
+        } else if (utils.isObject(v)) {
+          v = JSON.stringify(v)
+        }
+        parts.push(encode(key) + '=' + encode(v))
+      })
+    })
+
+    serializedParams = parts.join('&')
+  }
+
+  if (serializedParams) {
+    var hashmarkIndex = url.indexOf('#')
+    if (hashmarkIndex !== -1) {
+      url = url.slice(0, hashmarkIndex)
+    }
+
+    url += (url.indexOf('?') === -1 ? '?' : '&') + serializedParams
+  }
+
+  return url
+}

+ 14 - 0
uni_modules/uv-ui-tools/libs/luch-request/helpers/combineURLs.js

@@ -0,0 +1,14 @@
+'use strict'
+
+/**
+ * Creates a new URL by combining the specified URLs
+ *
+ * @param {string} baseURL The base URL
+ * @param {string} relativeURL The relative URL
+ * @returns {string} The combined URL
+ */
+export default function combineURLs(baseURL, relativeURL) {
+  return relativeURL
+    ? baseURL.replace(/\/+$/, '') + '/' + relativeURL.replace(/^\/+/, '')
+    : baseURL
+}

+ 14 - 0
uni_modules/uv-ui-tools/libs/luch-request/helpers/isAbsoluteURL.js

@@ -0,0 +1,14 @@
+'use strict'
+
+/**
+ * Determines whether the specified URL is absolute
+ *
+ * @param {string} url The URL to test
+ * @returns {boolean} True if the specified URL is absolute, otherwise false
+ */
+export default function isAbsoluteURL(url) {
+  // A URL is considered absolute if it begins with "<scheme>://" or "//" (protocol-relative URL).
+  // RFC 3986 defines scheme name as a sequence of characters beginning with a letter and followed
+  // by any combination of letters, digits, plus, period, or hyphen.
+  return /^([a-z][a-z\d+\-.]*:)?\/\//i.test(url)
+}

+ 197 - 0
uni_modules/uv-ui-tools/libs/luch-request/index.d.ts

@@ -0,0 +1,197 @@
+export type HttpTask = UniApp.RequestTask | UniApp.UploadTask | UniApp.DownloadTask;
+
+export type HttpRequestTask = UniApp.RequestTask;
+
+export type HttpUploadTask = UniApp.UploadTask;
+
+export type HttpDownloadTask = UniApp.DownloadTask;
+
+export type HttpMethod =
+    "GET"
+    | "POST"
+    | "PUT"
+    | "DELETE"
+    | "CONNECT"
+    | "HEAD"
+    | "OPTIONS"
+    | "TRACE"
+    | "UPLOAD"
+    | "DOWNLOAD";
+
+export type HttpRequestHeader = Record<string, string>;
+
+export type HttpParams = Record<string, any>;
+
+export type HttpData = Record<string, any>;
+
+export type HttpResponseType = 'arraybuffer' | 'text';
+
+export type HttpCustom = Record<string, any>;
+
+export type HttpFileType = 'image' | 'video' | 'audio';
+
+export type HttpFormData = Record<string, any>;
+
+export type HttpResponseHeader = Record<string, string> & {
+    "set-cookie"?: string[]
+};
+
+export interface HttpRequestConfig<T = HttpTask> {
+    /** @desc 请求服务器接口地址 */
+    url?: string;
+    /** @desc 请求方式,默认为 GET */
+    method?: HttpMethod;
+    /** @desc 请求基地址 */
+    baseURL?: string;
+    /** @desc 请求头信息,不能设置 Referer,App、H5 端会自动带上 cookie,且 H5 端不可手动修改 */
+    header?: HttpRequestHeader;
+    /** @desc 请求查询参数,自动拼接为查询字符串 */
+    params?: HttpParams;
+    /** @desc 请求体参数 */
+    data?: HttpData;
+    /** @desc 超时时间,单位 ms,默认为 60000,仅 H5 (HBuilderX 2.9.9+)、APP (HBuilderX 2.9.9+)、微信小程序 (2.10.0)、支付宝小程序支持 */
+    timeout?: number;
+    /** @desc 跨域请求时是否携带凭证 (cookies),默认为 false,仅 H5 (HBuilderX 2.6.15+) 支持 */
+    withCredentials?: boolean;
+    /** @desc 设置响应的数据类型,支付宝小程序不支持 */
+    responseType?: HttpResponseType;
+    /** @desc 全局自定义验证器 */
+    validateStatus?: ((statusCode: number) => boolean) | null;
+
+
+    /** params 参数自定义处理 */
+    paramsSerializer?: (params: AnyObject) => string | void;
+
+    /** @desc 默认为 json,如果设为 json,会尝试对返回的数据做一次 JSON.parse */
+    dataType?: string;
+    /** @desc DNS 解析时是否优先使用 ipv4,默认为 false,仅 App-Android (HBuilderX 2.8.0+) 支持 */
+    firstIpv4?: boolean;
+    /** @desc 是否验证 SSL 证书,默认为 true,仅 App-Android (HBuilderX 2.3.3+) 支持 */
+    sslVerify?: boolean;
+
+    /** @desc 开启 http2;微信小程序 */
+    enableHttp2?: boolean;
+
+    /** @desc 开启 quic;微信小程序 */
+    enableQuic?: boolean;
+    /** @desc 开启 cache;微信小程序、字节跳动小程序 2.31.0+ */
+    enableCache?: boolean;
+    /** @desc 开启 httpDNS;微信小程序 */
+    enableHttpDNS?: boolean;
+    /** @desc httpDNS 服务商;微信小程序 */
+    httpDNSServiceId?: string;
+    /** @desc 开启 transfer-encoding chunked;微信小程序 */
+    enableChunked?: boolean;
+    /** @desc wifi下使用移动网络发送请求;微信小程序 */
+    forceCellularNetwork?: boolean;
+    /** @desc 开启后可在headers中编辑cookie;支付宝小程序 10.2.33+ */
+    enableCookie?: boolean;
+    /** @desc 是否开启云加速;百度小程序 3.310.11+ */
+    cloudCache?: boolean | object;
+    /** @desc 控制当前请求是否延时至首屏内容渲染后发送;百度小程序 3.310.11+ */
+    defer?: boolean;
+
+    /** @desc 自定义参数 */
+    custom?: HttpCustom;
+
+    /** @desc 返回当前请求的 task 和 options,不要在这里修改 options */
+    getTask?: (task: T, options: HttpRequestConfig<T>) => void;
+
+    /** @desc 需要上传的文件列表,使用 files 时,filePath 和 name 不生效,仅支持 App、H5 (2.6.15+) */
+    files?: { name?: string; file?: File; uri: string; }[];
+    /** @desc 文件类型,仅支付宝小程序支持且为必填项 */
+    fileType?: HttpFileType;
+    /** @desc 要上传的文件对象,仅 H5 (2.6.15+) 支持 */
+    file?: File;
+    /** @desc 要上传文件资源的路径,使用 files 时,filePath 和 name 不生效 */
+    filePath?: string;
+    /** @desc 文件对应的 key,开发者在服务器端通过这个 key 可以获取到文件二进制内容,使用 files 时,filePath 和 name 不生效 */
+    name?: string;
+    /** @desc 请求中其他额外的 form data */
+    formData?: HttpFormData;
+}
+
+export interface HttpResponse<T = any, D = HttpTask> {
+    data: T;
+    statusCode: number;
+    header: HttpResponseHeader;
+    config: HttpRequestConfig<D>;
+    cookies: string[];
+    errMsg: string;
+    rawData: any;
+}
+
+export interface HttpUploadResponse<T = any, D = HttpTask> {
+    data: T;
+    statusCode: number;
+    config: HttpRequestConfig<D>;
+    errMsg: string;
+    rawData: any;
+}
+
+export interface HttpDownloadResponse extends HttpResponse {
+    tempFilePath: string;
+    apFilePath?: string;
+    filePath?: string;
+    fileContent?: string;
+}
+
+export interface HttpError<T = any, D = HttpTask> {
+    data?: T;
+    statusCode?: number;
+    header?: HttpResponseHeader;
+    config: HttpRequestConfig<D>;
+    cookies?: string[];
+    errMsg: string;
+}
+
+export interface HttpPromise<T = any> extends Promise<HttpResponse<T>> {
+}
+
+export interface HttpInterceptorManager<V, E = V> {
+    use(onFulfilled?: (value: V) => V | Promise<V>, onRejected?: (error: E) => T | Promise<E>): void;
+
+    eject(id: number): void;
+}
+
+export abstract class HttpRequestAbstract {
+    constructor(config?: HttpRequestConfig);
+
+    interceptors: {
+        request: HttpInterceptorManager<HttpRequestConfig>;
+        response: HttpInterceptorManager<HttpResponse, HttpError>;
+    }
+
+    request<T = any, R = HttpResponse<T>, D = HttpRequestTask>(config: HttpRequestConfig<D>): Promise<R>;
+
+    get<T = any, R = HttpResponse<T>, D = HttpRequestTask>(url: string, config?: HttpRequestConfig<D>): Promise<R>;
+
+    delete<T = any, R = HttpResponse<T>, D = HttpRequestTask>(url: string, data?: HttpData, config?: HttpRequestConfig<D>): Promise<R>;
+
+    head<T = any, R = HttpResponse<T>, D = HttpRequestTask>(url: string, data?: HttpData, config?: HttpRequestConfig<D>): Promise<R>;
+
+    options<T = any, R = HttpResponse<T>, D = HttpRequestTask>(url: string, data?: HttpData, config?: HttpRequestConfig<D>): Promise<R>;
+
+    post<T = any, R = HttpResponse<T>, D = HttpRequestTask>(url: string, data?: HttpData, config?: HttpRequestConfig<D>): Promise<R>;
+
+    put<T = any, R = HttpResponse<T>, D = HttpRequestTask>(url: string, data?: HttpData, config?: HttpRequestConfig<D>): Promise<R>;
+
+    config: HttpRequestConfig;
+
+    setConfig<D = HttpTask>(onSend: (config: HttpRequestConfig<D>) => HttpRequestConfig<D>): void;
+
+    connect<T = any, R = HttpResponse<T>, D = HttpRequestTask>(url: string, data?: HttpData, config?: HttpRequestConfig<D>): Promise<R>;
+
+    trace<T = any, R = HttpResponse<T>, D = HttpRequestTask>(url: string, data?: HttpData, config?: HttpRequestConfig<D>): Promise<R>;
+
+    upload<T = any, R = HttpUploadResponse<T>, D = HttpUploadTask>(url: string, config?: HttpRequestConfig<D>): Promise<R>;
+
+    download<T = any, R = HttpDownloadResponse<T>, D = HttpDownloadTask>(url: string, config?: HttpRequestConfig<D>): Promise<R>;
+
+    middleware<T = any, R = HttpResponse<T>, D = HttpTask>(config: HttpRequestConfig<D>): Promise<R>;
+}
+
+declare class HttpRequest extends HttpRequestAbstract {
+}
+
+export default HttpRequest;

+ 2 - 0
uni_modules/uv-ui-tools/libs/luch-request/index.js

@@ -0,0 +1,2 @@
+import Request from './core/Request'
+export default Request

+ 135 - 0
uni_modules/uv-ui-tools/libs/luch-request/utils.js

@@ -0,0 +1,135 @@
+'use strict'
+
+// utils is a library of generic helper functions non-specific to axios
+
+var toString = Object.prototype.toString
+
+/**
+ * Determine if a value is an Array
+ *
+ * @param {Object} val The value to test
+ * @returns {boolean} True if value is an Array, otherwise false
+ */
+export function isArray (val) {
+  return toString.call(val) === '[object Array]'
+}
+
+
+/**
+ * Determine if a value is an Object
+ *
+ * @param {Object} val The value to test
+ * @returns {boolean} True if value is an Object, otherwise false
+ */
+export function isObject (val) {
+  return val !== null && typeof val === 'object'
+}
+
+/**
+ * Determine if a value is a Date
+ *
+ * @param {Object} val The value to test
+ * @returns {boolean} True if value is a Date, otherwise false
+ */
+export function isDate (val) {
+  return toString.call(val) === '[object Date]'
+}
+
+/**
+ * Determine if a value is a URLSearchParams object
+ *
+ * @param {Object} val The value to test
+ * @returns {boolean} True if value is a URLSearchParams object, otherwise false
+ */
+export function isURLSearchParams (val) {
+  return typeof URLSearchParams !== 'undefined' && val instanceof URLSearchParams
+}
+
+
+/**
+ * Iterate over an Array or an Object invoking a function for each item.
+ *
+ * If `obj` is an Array callback will be called passing
+ * the value, index, and complete array for each item.
+ *
+ * If 'obj' is an Object callback will be called passing
+ * the value, key, and complete object for each property.
+ *
+ * @param {Object|Array} obj The object to iterate
+ * @param {Function} fn The callback to invoke for each item
+ */
+export function forEach (obj, fn) {
+  // Don't bother if no value provided
+  if (obj === null || typeof obj === 'undefined') {
+    return
+  }
+
+  // Force an array if not already something iterable
+  if (typeof obj !== 'object') {
+    /*eslint no-param-reassign:0*/
+    obj = [obj]
+  }
+
+  if (isArray(obj)) {
+    // Iterate over array values
+    for (var i = 0, l = obj.length; i < l; i++) {
+      fn.call(null, obj[i], i, obj)
+    }
+  } else {
+    // Iterate over object keys
+    for (var key in obj) {
+      if (Object.prototype.hasOwnProperty.call(obj, key)) {
+        fn.call(null, obj[key], key, obj)
+      }
+    }
+  }
+}
+
+/**
+ * 是否为boolean 值
+ * @param val
+ * @returns {boolean}
+ */
+export function isBoolean(val) {
+  return typeof val === 'boolean'
+}
+
+/**
+ * 是否为真正的对象{} new Object
+ * @param {any} obj - 检测的对象
+ * @returns {boolean}
+ */
+export function isPlainObject(obj) {
+  return Object.prototype.toString.call(obj) === '[object Object]'
+}
+
+
+
+/**
+ * Function equal to merge with the difference being that no reference
+ * to original objects is kept.
+ *
+ * @see merge
+ * @param {Object} obj1 Object to merge
+ * @returns {Object} Result of all merge properties
+ */
+export function deepMerge(/* obj1, obj2, obj3, ... */) {
+  let result = {}
+  function assignValue(val, key) {
+    if (typeof result[key] === 'object' && typeof val === 'object') {
+      result[key] = deepMerge(result[key], val)
+    } else if (typeof val === 'object') {
+      result[key] = deepMerge({}, val)
+    } else {
+      result[key] = val
+    }
+  }
+  for (let i = 0, l = arguments.length; i < l; i++) {
+    forEach(arguments[i], assignValue)
+  }
+  return result
+}
+
+export function isUndefined (val) {
+  return typeof val === 'undefined'
+}

+ 264 - 0
uni_modules/uv-ui-tools/libs/luch-request/utils/clone.js

@@ -0,0 +1,264 @@
+/* eslint-disable */
+var clone = (function() {
+  'use strict';
+
+  function _instanceof(obj, type) {
+    return type != null && obj instanceof type;
+  }
+
+  var nativeMap;
+  try {
+    nativeMap = Map;
+  } catch(_) {
+    // maybe a reference error because no `Map`. Give it a dummy value that no
+    // value will ever be an instanceof.
+    nativeMap = function() {};
+  }
+
+  var nativeSet;
+  try {
+    nativeSet = Set;
+  } catch(_) {
+    nativeSet = function() {};
+  }
+
+  var nativePromise;
+  try {
+    nativePromise = Promise;
+  } catch(_) {
+    nativePromise = function() {};
+  }
+
+  /**
+   * Clones (copies) an Object using deep copying.
+   *
+   * This function supports circular references by default, but if you are certain
+   * there are no circular references in your object, you can save some CPU time
+   * by calling clone(obj, false).
+   *
+   * Caution: if `circular` is false and `parent` contains circular references,
+   * your program may enter an infinite loop and crash.
+   *
+   * @param `parent` - the object to be cloned
+   * @param `circular` - set to true if the object to be cloned may contain
+   *    circular references. (optional - true by default)
+   * @param `depth` - set to a number if the object is only to be cloned to
+   *    a particular depth. (optional - defaults to Infinity)
+   * @param `prototype` - sets the prototype to be used when cloning an object.
+   *    (optional - defaults to parent prototype).
+   * @param `includeNonEnumerable` - set to true if the non-enumerable properties
+   *    should be cloned as well. Non-enumerable properties on the prototype
+   *    chain will be ignored. (optional - false by default)
+   */
+  function clone(parent, circular, depth, prototype, includeNonEnumerable) {
+    if (typeof circular === 'object') {
+      depth = circular.depth;
+      prototype = circular.prototype;
+      includeNonEnumerable = circular.includeNonEnumerable;
+      circular = circular.circular;
+    }
+    // maintain two arrays for circular references, where corresponding parents
+    // and children have the same index
+    var allParents = [];
+    var allChildren = [];
+
+    var useBuffer = typeof Buffer != 'undefined';
+
+    if (typeof circular == 'undefined')
+      circular = true;
+
+    if (typeof depth == 'undefined')
+      depth = Infinity;
+
+    // recurse this function so we don't reset allParents and allChildren
+    function _clone(parent, depth) {
+      // cloning null always returns null
+      if (parent === null)
+        return null;
+
+      if (depth === 0)
+        return parent;
+
+      var child;
+      var proto;
+      if (typeof parent != 'object') {
+        return parent;
+      }
+
+      if (_instanceof(parent, nativeMap)) {
+        child = new nativeMap();
+      } else if (_instanceof(parent, nativeSet)) {
+        child = new nativeSet();
+      } else if (_instanceof(parent, nativePromise)) {
+        child = new nativePromise(function (resolve, reject) {
+          parent.then(function(value) {
+            resolve(_clone(value, depth - 1));
+          }, function(err) {
+            reject(_clone(err, depth - 1));
+          });
+        });
+      } else if (clone.__isArray(parent)) {
+        child = [];
+      } else if (clone.__isRegExp(parent)) {
+        child = new RegExp(parent.source, __getRegExpFlags(parent));
+        if (parent.lastIndex) child.lastIndex = parent.lastIndex;
+      } else if (clone.__isDate(parent)) {
+        child = new Date(parent.getTime());
+      } else if (useBuffer && Buffer.isBuffer(parent)) {
+        if (Buffer.from) {
+          // Node.js >= 5.10.0
+          child = Buffer.from(parent);
+        } else {
+          // Older Node.js versions
+          child = new Buffer(parent.length);
+          parent.copy(child);
+        }
+        return child;
+      } else if (_instanceof(parent, Error)) {
+        child = Object.create(parent);
+      } else {
+        if (typeof prototype == 'undefined') {
+          proto = Object.getPrototypeOf(parent);
+          child = Object.create(proto);
+        }
+        else {
+          child = Object.create(prototype);
+          proto = prototype;
+        }
+      }
+
+      if (circular) {
+        var index = allParents.indexOf(parent);
+
+        if (index != -1) {
+          return allChildren[index];
+        }
+        allParents.push(parent);
+        allChildren.push(child);
+      }
+
+      if (_instanceof(parent, nativeMap)) {
+        parent.forEach(function(value, key) {
+          var keyChild = _clone(key, depth - 1);
+          var valueChild = _clone(value, depth - 1);
+          child.set(keyChild, valueChild);
+        });
+      }
+      if (_instanceof(parent, nativeSet)) {
+        parent.forEach(function(value) {
+          var entryChild = _clone(value, depth - 1);
+          child.add(entryChild);
+        });
+      }
+
+      for (var i in parent) {
+        var attrs = Object.getOwnPropertyDescriptor(parent, i);
+        if (attrs) {
+          child[i] = _clone(parent[i], depth - 1);
+        }
+
+        try {
+          var objProperty = Object.getOwnPropertyDescriptor(parent, i);
+          if (objProperty.set === 'undefined') {
+            // no setter defined. Skip cloning this property
+            continue;
+          }
+          child[i] = _clone(parent[i], depth - 1);
+        } catch(e){
+          if (e instanceof TypeError) {
+            // when in strict mode, TypeError will be thrown if child[i] property only has a getter
+            // we can't do anything about this, other than inform the user that this property cannot be set.
+            continue
+          } else if (e instanceof ReferenceError) {
+            //this may happen in non strict mode
+            continue
+          }
+        }
+
+      }
+
+      if (Object.getOwnPropertySymbols) {
+        var symbols = Object.getOwnPropertySymbols(parent);
+        for (var i = 0; i < symbols.length; i++) {
+          // Don't need to worry about cloning a symbol because it is a primitive,
+          // like a number or string.
+          var symbol = symbols[i];
+          var descriptor = Object.getOwnPropertyDescriptor(parent, symbol);
+          if (descriptor && !descriptor.enumerable && !includeNonEnumerable) {
+            continue;
+          }
+          child[symbol] = _clone(parent[symbol], depth - 1);
+          Object.defineProperty(child, symbol, descriptor);
+        }
+      }
+
+      if (includeNonEnumerable) {
+        var allPropertyNames = Object.getOwnPropertyNames(parent);
+        for (var i = 0; i < allPropertyNames.length; i++) {
+          var propertyName = allPropertyNames[i];
+          var descriptor = Object.getOwnPropertyDescriptor(parent, propertyName);
+          if (descriptor && descriptor.enumerable) {
+            continue;
+          }
+          child[propertyName] = _clone(parent[propertyName], depth - 1);
+          Object.defineProperty(child, propertyName, descriptor);
+        }
+      }
+
+      return child;
+    }
+
+    return _clone(parent, depth);
+  }
+
+  /**
+   * Simple flat clone using prototype, accepts only objects, usefull for property
+   * override on FLAT configuration object (no nested props).
+   *
+   * USE WITH CAUTION! This may not behave as you wish if you do not know how this
+   * works.
+   */
+  clone.clonePrototype = function clonePrototype(parent) {
+    if (parent === null)
+      return null;
+
+    var c = function () {};
+    c.prototype = parent;
+    return new c();
+  };
+
+// private utility functions
+
+  function __objToStr(o) {
+    return Object.prototype.toString.call(o);
+  }
+  clone.__objToStr = __objToStr;
+
+  function __isDate(o) {
+    return typeof o === 'object' && __objToStr(o) === '[object Date]';
+  }
+  clone.__isDate = __isDate;
+
+  function __isArray(o) {
+    return typeof o === 'object' && __objToStr(o) === '[object Array]';
+  }
+  clone.__isArray = __isArray;
+
+  function __isRegExp(o) {
+    return typeof o === 'object' && __objToStr(o) === '[object RegExp]';
+  }
+  clone.__isRegExp = __isRegExp;
+
+  function __getRegExpFlags(re) {
+    var flags = '';
+    if (re.global) flags += 'g';
+    if (re.ignoreCase) flags += 'i';
+    if (re.multiline) flags += 'm';
+    return flags;
+  }
+  clone.__getRegExpFlags = __getRegExpFlags;
+
+  return clone;
+})();
+
+export default clone

+ 13 - 0
uni_modules/uv-ui-tools/libs/mixin/button.js

@@ -0,0 +1,13 @@
+export default {
+    props: {
+        lang: String,
+        sessionFrom: String,
+        sendMessageTitle: String,
+        sendMessagePath: String,
+        sendMessageImg: String,
+        showMessageCard: Boolean,
+        appParameter: String,
+        formType: String,
+        openType: String
+    }
+}

+ 172 - 0
uni_modules/uv-ui-tools/libs/mixin/mixin.js

@@ -0,0 +1,172 @@
+import * as index from '../function/index.js';
+import * as test from '../function/test.js';
+import route from '../util/route.js';
+import debounce from '../function/debounce.js';
+import throttle from '../function/throttle.js';
+export default {
+	// 定义每个组件都可能需要用到的外部样式以及类名
+	props: {
+		// 每个组件都有的父组件传递的样式,可以为字符串或者对象形式
+		customStyle: {
+			type: [Object, String],
+			default: () => ({})
+		},
+		customClass: {
+			type: String,
+			default: ''
+		},
+		// 跳转的页面路径
+		url: {
+			type: String,
+			default: ''
+		},
+		// 页面跳转的类型
+		linkType: {
+			type: String,
+			default: 'navigateTo'
+		}
+	},
+	data() {
+		return {}
+	},
+	onLoad() {
+		// getRect挂载到$uv上,因为这方法需要使用in(this),所以无法把它独立成一个单独的文件导出
+		this.$uv.getRect = this.$uvGetRect
+	},
+	created() {
+		// 组件当中,只有created声明周期,为了能在组件使用,故也在created中将方法挂载到$uv
+		this.$uv.getRect = this.$uvGetRect
+	},
+	computed: {
+		$uv() {
+			return {
+				...index,
+				test,
+				route,
+				debounce,
+				throttle,
+				unit: uni?.$uv?.config?.unit
+			}
+		},
+		/**
+		 * 生成bem规则类名
+		 * 由于微信小程序,H5,nvue之间绑定class的差异,无法通过:class="[bem()]"的形式进行同用
+		 * 故采用如下折中做法,最后返回的是数组(一般平台)或字符串(支付宝和字节跳动平台),类似['a', 'b', 'c']或'a b c'的形式
+		 * @param {String} name 组件名称
+		 * @param {Array} fixed 一直会存在的类名
+		 * @param {Array} change 会根据变量值为true或者false而出现或者隐藏的类名
+		 * @returns {Array|string}
+		 */
+		bem() {
+			return function(name, fixed, change) {
+				// 类名前缀
+				const prefix = `uv-${name}--`
+				const classes = {}
+				if (fixed) {
+					fixed.map((item) => {
+						// 这里的类名,会一直存在
+						classes[prefix + this[item]] = true
+					})
+				}
+				if (change) {
+					change.map((item) => {
+						// 这里的类名,会根据this[item]的值为true或者false,而进行添加或者移除某一个类
+						this[item] ? (classes[prefix + item] = this[item]) : (delete classes[prefix + item])
+					})
+				}
+				return Object.keys(classes)
+					// 支付宝,头条小程序无法动态绑定一个数组类名,否则解析出来的结果会带有",",而导致失效
+					// #ifdef MP-ALIPAY || MP-TOUTIAO || MP-LARK || MP-BAIDU
+					.join(' ')
+				// #endif
+			}
+		}
+	},
+	methods: {
+		// 跳转某一个页面
+		openPage(urlKey = 'url') {
+			const url = this[urlKey]
+			if (url) {
+				// 执行类似uni.navigateTo的方法
+				uni[this.linkType]({
+					url
+				})
+			}
+		},
+		// 查询节点信息
+		// 目前此方法在支付宝小程序中无法获取组件跟接点的尺寸,为支付宝的bug(2020-07-21)
+		// 解决办法为在组件根部再套一个没有任何作用的view元素
+		$uvGetRect(selector, all) {
+			return new Promise((resolve) => {
+				uni.createSelectorQuery()
+					.in(this)[all ? 'selectAll' : 'select'](selector)
+					.boundingClientRect((rect) => {
+						if (all && Array.isArray(rect) && rect.length) {
+							resolve(rect)
+						}
+						if (!all && rect) {
+							resolve(rect)
+						}
+					})
+					.exec()
+			})
+		},
+		getParentData(parentName = '') {
+			// 避免在created中去定义parent变量
+			if (!this.parent) this.parent = {}
+			// 这里的本质原理是,通过获取父组件实例(也即类似uv-radio的父组件uv-radio-group的this)
+			// 将父组件this中对应的参数,赋值给本组件(uv-radio的this)的parentData对象中对应的属性
+			// 之所以需要这么做,是因为所有端中,头条小程序不支持通过this.parent.xxx去监听父组件参数的变化
+			// 此处并不会自动更新子组件的数据,而是依赖父组件uv-radio-group去监听data的变化,手动调用更新子组件的方法去重新获取
+			this.parent = this.$uv.$parent.call(this, parentName)
+			if (this.parent.children) {
+				// 如果父组件的children不存在本组件的实例,才将本实例添加到父组件的children中
+				this.parent.children.indexOf(this) === -1 && this.parent.children.push(this)
+			}
+			if (this.parent && this.parentData) {
+				// 历遍parentData中的属性,将parent中的同名属性赋值给parentData
+				Object.keys(this.parentData).map((key) => {
+					this.parentData[key] = this.parent[key]
+				})
+			}
+		},
+		// 阻止事件冒泡
+		preventEvent(e) {
+			e && typeof(e.stopPropagation) === 'function' && e.stopPropagation()
+		},
+		// 空操作
+		noop(e) {
+			this.preventEvent(e)
+		}
+	},
+	onReachBottom() {
+		uni.$emit('uvOnReachBottom')
+	},
+	beforeDestroy() {
+		// 判断当前页面是否存在parent和chldren,一般在checkbox和checkbox-group父子联动的场景会有此情况
+		// 组件销毁时,移除子组件在父组件children数组中的实例,释放资源,避免数据混乱
+		if (this.parent && test.array(this.parent.children)) {
+			// 组件销毁时,移除父组件中的children数组中对应的实例
+			const childrenList = this.parent.children
+			childrenList.map((child, index) => {
+				// 如果相等,则移除
+				if (child === this) {
+					childrenList.splice(index, 1)
+				}
+			})
+		}
+	},
+	// 兼容vue3
+	unmounted() {
+		if (this.parent && test.array(this.parent.children)) {
+			// 组件销毁时,移除父组件中的children数组中对应的实例
+			const childrenList = this.parent.children
+			childrenList.map((child, index) => {
+				// 如果相等,则移除
+				if (child === this) {
+					childrenList.splice(index, 1)
+				}
+			})
+		}
+	}
+}

+ 8 - 0
uni_modules/uv-ui-tools/libs/mixin/mpMixin.js

@@ -0,0 +1,8 @@
+export default {
+    // #ifdef MP-WEIXIN
+    // 将自定义节点设置成虚拟的(去掉自定义组件包裹层),更加接近Vue组件的表现,能更好的使用flex属性
+    options: {
+        virtualHost: true
+    }
+    // #endif
+}

+ 13 - 0
uni_modules/uv-ui-tools/libs/mixin/mpShare.js

@@ -0,0 +1,13 @@
+export default {
+	onLoad() {
+	    // 设置默认的转发参数
+	    uni.$uv.mpShare = {
+	        title: '', // 默认为小程序名称
+	        path: '', // 默认为当前页面路径
+	        imageUrl: '' // 默认为当前页面的截图
+	    }
+	},
+	onShareAppMessage() {
+	    return uni.$uv.mpShare
+	}
+}

+ 47 - 0
uni_modules/uv-ui-tools/libs/mixin/openType.js

@@ -0,0 +1,47 @@
+export default {
+    props: {
+        openType: String
+    },
+		emits: ['getphonenumber','getuserinfo','error','opensetting','launchapp','contact','chooseavatar','addgroupapp','chooseaddress','subscribe','login','im'],
+    methods: {
+        onGetPhoneNumber(event) {
+            this.$emit('getphonenumber', event.detail)
+        },
+        onGetUserInfo(event) {
+            this.$emit('getuserinfo', event.detail)
+        },
+        onError(event) {
+            this.$emit('error', event.detail)
+        },
+        onOpenSetting(event) {
+            this.$emit('opensetting', event.detail)
+        },
+        onLaunchApp(event) {
+            this.$emit('launchapp', event.detail)
+        },
+        onContact(event) {
+            this.$emit('contact', event.detail)
+        },
+        onChooseavatar(event) {
+            this.$emit('chooseavatar', event.detail)
+        },
+        onAgreeprivacyauthorization(event) {
+            this.$emit('agreeprivacyauthorization', event.detail)
+        },
+        onAddgroupapp(event) {
+            this.$emit('addgroupapp', event.detail)
+        },
+        onChooseaddress(event) {
+            this.$emit('chooseaddress', event.detail)
+        },
+        onSubscribe(event) {
+            this.$emit('subscribe', event.detail)
+        },
+        onLogin(event) {
+            this.$emit('login', event.detail)
+        },
+        onIm(event) {
+            this.$emit('im', event.detail)
+        }
+    }
+}

+ 59 - 0
uni_modules/uv-ui-tools/libs/mixin/touch.js

@@ -0,0 +1,59 @@
+const MIN_DISTANCE = 10
+
+function getDirection(x, y) {
+    if (x > y && x > MIN_DISTANCE) {
+        return 'horizontal'
+    }
+    if (y > x && y > MIN_DISTANCE) {
+        return 'vertical'
+    }
+    return ''
+}
+
+export default {
+    methods: {
+        getTouchPoint(e) {
+            if (!e) {
+                return {
+                    x: 0,
+                    y: 0
+                }
+            } if (e.touches && e.touches[0]) {
+                return {
+                    x: e.touches[0].pageX,
+                    y: e.touches[0].pageY
+                }
+            } if (e.changedTouches && e.changedTouches[0]) {
+                return {
+                    x: e.changedTouches[0].pageX,
+                    y: e.changedTouches[0].pageY
+                }
+            }
+            return {
+                x: e.clientX || 0,
+                y: e.clientY || 0
+            }
+        },
+        resetTouchStatus() {
+            this.direction = ''
+            this.deltaX = 0
+            this.deltaY = 0
+            this.offsetX = 0
+            this.offsetY = 0
+        },
+        touchStart(event) {
+            this.resetTouchStatus()
+            const touch = this.getTouchPoint(event)
+            this.startX = touch.x
+            this.startY = touch.y
+        },
+        touchMove(event) {
+            const touch = this.getTouchPoint(event)
+            this.deltaX = touch.x - this.startX
+            this.deltaY = touch.y - this.startY
+            this.offsetX = Math.abs(this.deltaX)
+            this.offsetY = Math.abs(this.deltaY)
+            this.direction =				this.direction || getDirection(this.offsetX, this.offsetY)
+        }
+    }
+}

이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.