Merged
Merge Request #707 · created by 后端研发-苏明海


Test


From test into qa

Merged by 后端研发-苏明海

1 participants









app.js
... ... @@ -718,6 +718,12 @@ App({
718 718 resolve(user_info);
719 719 };
720 720 });
  721 +
  722 +
  723 +
  724 +
  725 +
  726 +
721 727 },
722 728  
723 729  
... ...
app.wxss
... ... @@ -703,9 +703,9 @@ background: #ffe3e2;
703 703 /* 图标字体(ty) */
704 704 @font-face {
705 705 font-family: 'iconfont'; /* Project id 2054717 */
706   - src: url('//at.alicdn.com/t/font_2054717_nzwl8grylfi.woff2?t=1627287108388') format('woff2'),
707   - url('//at.alicdn.com/t/font_2054717_nzwl8grylfi.woff?t=1627287108388') format('woff'),
708   - url('//at.alicdn.com/t/font_2054717_nzwl8grylfi.ttf?t=1627287108388') format('truetype');
  706 + src: url('//at.alicdn.com/t/font_2054717_3fwbtkdbxhl.woff2?t=1627893975776') format('woff2'),
  707 + url('//at.alicdn.com/t/font_2054717_3fwbtkdbxhl.woff?t=1627893975776') format('woff'),
  708 + url('//at.alicdn.com/t/font_2054717_3fwbtkdbxhl.ttf?t=1627893975776') format('truetype');
709 709 }
710 710  
711 711 .iconfont {
... ... @@ -716,6 +716,17 @@ background: #ffe3e2;
716 716 -moz-osx-font-smoothing: grayscale;
717 717 }
718 718  
  719 +.icon-zhuanfa1:before {
  720 + content: "\e614";
  721 +}
  722 +
  723 +
  724 +.icon-zhiwen:before {
  725 + content: "\e6aa";
  726 +}
  727 +
  728 +
  729 +
719 730 .icon-guan:before {
720 731 content: "\e612";
721 732 }
... ...
components/catch/catch.js 0 → 100644
  1 +// pages/user/yhq/qr_code/qr_code.js
  2 +const {
  3 + barcode,
  4 + qrcode
  5 +} = require('../../utils/index.js')
  6 +
  7 +Component({
  8 + data: {
  9 + q_show:0,
  10 + object:null,
  11 + index:0,
  12 + is_fw:0,
  13 +
  14 + barcode_canvas:null,
  15 + qrcode_canvas:null,
  16 + },
  17 + properties: {
  18 + // 这里定义了innerText属性,属性值可以在组件使用时指定
  19 + },
  20 + ready: function () {
  21 + },
  22 +
  23 + methods: {
  24 + //关闭
  25 + close: function (e) {
  26 + this.setData({q_show: 0,barcode_canvas:null,qrcode_canvas:null });
  27 + this.triggerEvent('close',{},{bubbles: true});
  28 + },
  29 +
  30 + //打开
  31 + open:function (e) {
  32 + this.data.index++;
  33 + var list=[{index:this.data.index }];
  34 +
  35 + this.setData({q_show: 1,object:e,barcode_canvas:list,qrcode_canvas:list,is_fw:e.is_fw });
  36 + var val=e.val;
  37 +
  38 + // barcode('barcode'+this.data.index,val, 620, 160,this);
  39 + qrcode('qrcode'+this.data.index, val, 520, 520,this);
  40 + }
  41 + },
  42 +
  43 +
  44 +
  45 +
  46 +})
0 47 \ No newline at end of file
... ...
pages/user/binding_info/binding_info.json renamed to components/catch/catch.json
1 1 {
2   - "navigationBarTitleText": "关联手机号",
3   - "enablePullDownRefresh": false
  2 + "component": true,
  3 + "usingComponents": {}
4 4 }
5 5 \ No newline at end of file
... ...
components/catch/catch.wxml 0 → 100644
  1 +<view class="container">
  2 + <view class="container-wrapper">
  3 + <view>
  4 + <text class="t-icon t-icon-gowudai mgb20"></text>
  5 + <view class="fs28"><slot></slot></view>
  6 + </view>
  7 + <view class="mgt60">
  8 + <text class="btn">进店逛逛</text>
  9 + </view>
  10 + </view>
  11 +</view>
  12 +
... ...
components/catch/catch.wxss 0 → 100644
  1 +@import '../../app.wxss';
  2 +
  3 +
  4 +.container {
  5 + background-color: #f5f5f5;
  6 + position: fixed;
  7 + top: 0;
  8 + bottom: 0;
  9 + left: 0;
  10 + right: 0;
  11 +}
  12 +
  13 +.container-wrapper {
  14 + position: absolute;
  15 + top: 50%;
  16 + left: 50%;
  17 + transform: translate(-50%, -50%);
  18 + text-align: center;
  19 + color: rgb(173,173,173);
  20 +}
  21 +
  22 +.t-icon {
  23 + width: 200rpx;
  24 + height: 200rpx;
  25 +}
  26 +
  27 +.btn {
  28 + display: inline-block;
  29 + padding: 10rpx 50rpx;
  30 + border: 2rpx solid red;
  31 + color: red;
  32 + font-size: 30rpx;
  33 + border-radius: 30rpx;
  34 + box-sizing: border-box;
  35 +}
  36 +
  37 +.mgt60 {
  38 + margin-top: 60rpx;
  39 +}
0 40 \ No newline at end of file
... ...
components/diy_store_select/diy_store_select.js
... ... @@ -44,10 +44,6 @@ Component({
44 44  
45 45 //获取顶部的门店
46 46 getApp().get_user_store(function(){
47   - var top_store=getApp().globalData.pk_store;
48   - if(top_store){
49   - th.setData({top_store:top_store});
50   - }else{
51 47 wx.getLocation({
52 48 type: 'gcj02',
53 49 success: function(res) {
... ... @@ -61,9 +57,12 @@ Component({
61 57 }
62 58 }
63 59 })
64   - }
  60 +
65 61 })
66 62 },
  63 +
  64 +
  65 +
67 66 //-- 设置最近的店为默认的店,一开始加载的时候 --
68 67 set_fir_store_to_def(){
69 68 var th=this;
... ... @@ -74,7 +73,13 @@ Component({
74 73 page:1,
75 74 };
76 75 dd.lat = th.data.lat;
77   - dd.lon = th.data.lon;
  76 + dd.lon = th.data.lon;
  77 +
  78 + var top_store=getApp().globalData.pk_store;
  79 + if(top_store){
  80 + dd.pickup_id=top_store.pickup_id;
  81 + }
  82 +
78 83 //----------获取门店,最近的门店----------------
79 84 getApp().request.promiseGet("/api/weshop/pickup/list", {
80 85 data: dd,
... ... @@ -173,8 +178,7 @@ Component({
173 178 this.deal_pickup(this.data.all_pick_list,func)
174 179 return false;
175 180 }
176   - var th = this,that=this;
177   - var i = getApp().request;
  181 + var th = this,that=this;
178 182 var dd = {
179 183 store_id: o.stoid,
180 184 isstop: 0,
... ...
components/diy_store_select/diy_store_select.wxml
  1 +<wxs module="filters" src="../../utils/filter.wxs"></wxs>
  2 +
1 3 <!-- 如果是自定义模板的时候 -->
2 4 <block wx:if="{{object}}">
3 5 <view class="store_sele1 flex ai_c" bindtap="sele_top_store" style="background-color:{{object.bgcolor}};color: {{object.word_color}};">
... ... @@ -51,7 +53,7 @@
51 53 </view>
52 54 <view>
53 55 <view class="distance fs24 address-val"wx:if="{{item.distance!=null}}">
54   - 距离:{{item.distance>1000?filters.toFix(item.distance/1000,2)+'km':filters.toFix(item.distance,0)+"m"}}</view>
  56 + 距离: {{item.distance>1000?filters.toFix(item.distance/1000,2)+'km':filters.toFix(item.distance,0)+"m"}}</view>
55 57 </view>
56 58 </view>
57 59 <view class="fs24 xc-ash-9f">地址:{{item.fulladdress}}</view>
... ...
components/my_confirm/my_confirm.wxml
... ... @@ -6,8 +6,8 @@
6 6 <view class="shut" bindtap="close_yu_e">ⅹ</view>
7 7 <view class="fs32 xc-black3 flex jc-center ai-center" style="padding: 10rpx 20rpx;min-height:220rpx;"><text>{{title}}</text></view>
8 8 <view class="flex jc-center ai_center" style="width: 100%;height: 75rpx;">
9   - <view bindtap="go_sure" class="fs30 white flex jc-center ai-center ck_btn color color" style="margin-right: 20rpx;">{{s_text}}</view>
10   - <view bindtap='go_cancle' class="fs30 xc-ash flex jc-center ai-center ck_btn"style="background:#ececea;">{{c_text}}</view>
  9 + <view bindtap="go_sure" class="fs30 white flex jc-center ai-center ck_btn" style="margin-right: 20rpx;background:#ececea;">{{s_text}}</view>
  10 + <view bindtap='go_cancle' class="fs30 xc-ash flex jc-center ai-center ck_btn color" >{{c_text}}</view>
11 11 </view>
12 12 </view>
13 13 </view>
... ...
components/my_confirm/my_confirm.wxss
1   -
  1 +@import '../../app.wxss';
2 2 /* 弹窗样式 */
3 3 .xc-pop-up{
4 4 width: 100%;
... ... @@ -23,19 +23,19 @@
23 23  
24 24 .shut{
25 25 display: block;
26   - width: 54rpx;
27   - height: 54rpx;
28   - font-size: 50rpx;
29   - line-height:47rpx;
  26 + width: 45rpx;
  27 + height: 45rpx;
  28 + line-height:36rpx;
30 29 border-radius: 50%;
31 30 -moz-border-radius: 50%;
32 31 -webkit-border-radius: 50%;
  32 + font-size: 40rpx;
33 33 color: #fff;
34 34 text-align: center;
35 35 position: fixed;
36   - margin-top: -23rpx;
37 36 z-index: 66666;
38   - right: 60rpx;
  37 + right: 75rpx;
  38 + top: 465rpx;
39 39 background: #c8162c;
40 40 }
41 41 .xc-qr-frame{
... ... @@ -50,7 +50,7 @@
50 50 margin-left: -280rpx; border-radius:10rpx
51 51 }
52 52  
53   -.ck_btn{width:44%;height:52rpx;line-height:60rpx;background:#f35e73;border-radius:10rpx;}
  53 +.ck_btn{color: #000; width:44%;height:52rpx;line-height:60rpx;background:#f35e73;border-radius:10rpx;}
54 54  
55 55 .fs36{ font-size: 36rpx; }
56 56 .fs30{ font-size: 30rpx; }
... ...
components/qr_code/qr_code.wxml
... ... @@ -24,7 +24,7 @@
24 24 </view>
25 25  
26 26 </view>
27   - <view class="shut" bindtap="close"></view>
  27 + <view class="shut" bindtap="close"><text class="iconfont icon-close"></text></view>
28 28 </view>
29 29 <!-- </scroll-view> -->
30 30 </view>
31 31 \ No newline at end of file
... ...
components/qr_code/qr_code.wxss
  1 +@import '../../app.wxss';
  2 +
1 3 .xc-pop-up{
2 4 width: 100%;
3 5 height: 100%;
... ... @@ -90,36 +92,39 @@ top: 5rpx;
90 92 .qrcode{
91 93 width:520rpx;
92 94 height:520rpx;
93   - margin-top:-27rpx
  95 + margin-top:-18rpx
94 96  
95 97  
96 98 }
97 99 .r-code{
98 100 font-size:28rpx;
99   - padding-left: 25rpx;
100   -margin-top: -5.5rpx;
  101 + margin-top: -5.5rpx;
  102 + text-align: center;
101 103  
102 104 }
103 105  
104 106 .shut{
105   - display: block;
  107 + /* display: block;
106 108 width: 54rpx;
107 109 height: 54rpx;
108 110 border: 2rpx solid #fff;
109 111 font-size: 50rpx;
110   - z-index:55;
111   - line-height:47rpx;
  112 + line-height:54rpx;
112 113 margin-top: 45rpx;
113 114 border-radius: 50%;
114 115 -moz-border-radius: 50%;
115   - -webkit-border-radius: 50%;
  116 + -webkit-border-radius: 50%; */
  117 + z-index:55;
116 118 color: #fff;
117 119 text-align: center;
118 120 position: fixed;
119 121 top:940rpx;
120   - left:345rpx;
121   -
122   -
  122 + left:50%;
  123 + transform: translateX(-50%);
  124 +}
  125 +.icon-close:before {
  126 + content: "\e62e";
  127 + font-size: 50rpx;
123 128 }
124 129  
125 130 .mt{ margin-top:130rpx}
... ...
packageA/pages/myGift/myGift.js
... ... @@ -144,8 +144,9 @@ Page({
144 144 isShowLoading: true,
145 145 })
146 146 .then(function(res) {
  147 + console.log(res);
147 148 if(res.data.code == 0) {
148   -
  149 +
149 150 self.setData({
150 151 isLoading: false
151 152 });
... ... @@ -154,10 +155,12 @@ Page({
154 155 self.setData({
155 156 list: res.data.data
156 157 });
  158 + // console.log(this.data.list);
157 159 } else {
158 160 self.setData({
159 161 'list.pageData': self.data.list.pageData.concat(res.data.data.pageData)
160 162 });
  163 +
161 164 };
162 165  
163 166 if((res.data.data.pageData.length == 0) || (res.data.data.pageSize * res.data.data.page >= res.data.data.total)) {
... ... @@ -312,5 +315,19 @@ Page({
312 315  
313 316 })
314 317 },
  318 +
  319 +
  320 + show_remark:function(e){
  321 + var index=e.currentTarget.dataset.index;
  322 + var item=this.data.list.pageData[index];
  323 + this.setData({
  324 + show_rem_pop:1,
  325 + pop_remark_text:item.lbintro
  326 + })
  327 + },
  328 +
  329 + close_remark:function(){
  330 + this.setData({show_rem_pop:0,})
  331 + }
315 332  
316 333 })
317 334 \ No newline at end of file
... ...
packageA/pages/myGift/myGift.wxml
... ... @@ -8,7 +8,10 @@
8 8 <view class="tab-item" wx:for="{{list.pageData}}">
9 9 <view bindtap="goto" data-url="{{'/packageA/pages/myGiftDetails/myGiftDetails?index=0&id=' + item.id}}">
10 10 <!-- 图片 -->
11   - <view class="img-container"><image src="{{imghost + (item.lburl ? item.lburl:'miniapp/images/default_g_img.gif')}}" class="img" mode="widthFix"/></view>
  11 + <view class="img-container rel">
  12 + <image src="{{imghost + (item.lburl ? item.lburl:'miniapp/images/default_g_img.gif')}}" class="img" mode="widthFix"/>
  13 + <view catchtap="show_remark" data-index="{{index}}" class="lb_remark ellipsis-1" wx:if="{{item.lbintro}}">活动说明:{{item.lbintro}}</view>
  14 + </view>
12 15 <view class="desc-container">
13 16 <!-- 标题 -->
14 17 <view class="mgb10 ellipsis-2 lh taj">{{item.lbtitle}}</view>
... ... @@ -33,7 +36,7 @@
33 36 <view class="fs24 c-a4">已售{{item.salenum}}件</view>
34 37 </view>
35 38 <!-- 时间 -->
36   - <view class="date">活动截止日期 {{filter.format_time(item.expdate)}}</view>
  39 + <view class="date">活动结束日期 {{filter.format_time(item.endtime)}}</view>
37 40 <!-- 按钮 -->
38 41 </view>
39 42 </view>
... ... @@ -52,10 +55,11 @@
52 55 <!-- 标题 -->
53 56 <view class="mgb10 ellipsis-2 lh taj">{{item.lbtitle}}</view>
54 57 <!-- 时间 -->
55   - <view class="date pdb20">活动截止日期 {{filter.format_time(item.endtime)}}</view>
  58 + <view class="date pdb20" wx:if="{{item.lbtype==1}}">兑换截止日期 {{filter.format_time(item.expdate,1)}}</view>
  59 + <view catchtap="show_remark" data-index="{{index}}" wx:if="{{item.lbintro}}" class="date pdb20">活动说明</view>
56 60 </view>
57 61 <!-- 说明 -->
58   - <view class="c-red fs24">*请到线下门店兑换</view>
  62 + <view wx:if="{{item.lbtype==1}}" class="c-red fs24">注:请到线下门店兑换</view>
59 63 </view>
60 64 </view>
61 65 </block>
... ... @@ -68,3 +72,13 @@
68 72 <!-- 引入提示组件 -->
69 73 <warn id="warn"></warn>
70 74 <my_confirm id="my_confirm"></my_confirm>
  75 +<view wx:if="{{show_rem_pop}}">
  76 + <view class="cover-layer" bindtap="close_remark"></view>
  77 + <view class="rem_pop;">
  78 + <view style="text-align: right;"bindtap="close_remark"><text class="iconfont icon-close" style="font-size: 40rpx;"></text></view>
  79 + <view style="padding: 0 16rpx;">
  80 + <view class="fs32">活动说明:</view>
  81 + <view class="fs30">{{pop_remark_text}}</view>
  82 + </view>
  83 + </view>
  84 +</view>
71 85 \ No newline at end of file
... ...
packageA/pages/myGift/myGift.wxss
... ... @@ -164,4 +164,28 @@ page {
164 164 color: #bbb;
165 165 text-align: center;
166 166 font-size: 22rpx;
167   -}
168 167 \ No newline at end of file
  168 +}
  169 +.lb_remark{
  170 + position: absolute;
  171 + bottom: 0;
  172 + left: 0;
  173 + width: 100%;
  174 + height: 50rpx;
  175 + line-height: 50rpx;
  176 + font-size: 30rpx;
  177 + color: #333;
  178 + padding-left: 10rpx;
  179 + background-color: rgba(250,250,250,0.5);
  180 +}
  181 +
  182 +.rem_pop{
  183 + position: fixed;
  184 + top: 30%;
  185 + left: 6%;
  186 + width: 88%;
  187 + margin: 0 auto;
  188 + height: 460rpx;
  189 + background-color: #fff;
  190 + z-index: 100; border-radius: 10rpx;
  191 + padding: 10rpx;
  192 +}
... ...
packageA/pages/myGiftDetails/myGiftDetails.js
... ... @@ -11,7 +11,7 @@ Page({
11 11 data: {
12 12 qr_code_object: {
13 13 val: "12121",
14   - content: "请将二维码展示给核销员,服务更快捷!"
  14 + content: "当前核销码仅限当面使用!"
15 15 },
16 16 },
17 17  
... ... @@ -72,7 +72,7 @@ Page({
72 72 if(res.data.code==0 && res.data.data && res.data.data.pageData && res.data.data.pageData.length>0){
73 73 var da= res.data.data.pageData[0]
74 74 self.setData({ details:da, });
75   -
  75 + console.log(da);
76 76 //礼包有俩种类型
77 77 if(da.lbtype==1){
78 78 app.request.promiseGet('/api/weshop/libao/libaoList/page', {
... ... @@ -94,6 +94,7 @@ Page({
94 94 },
95 95 isShowLoading: true,
96 96 }).then(function(res) {
  97 + console.log(res);
97 98 if(res.data.code==0){
98 99 self.setData({
99 100 list: res.data.data,
... ... @@ -150,6 +151,7 @@ Page({
150 151 },
151 152 isShowLoading: true,
152 153 }).then(function(res) {
  154 + console.log(res);
153 155 // console.log('res4-->', res);
154 156 if(res.data.code==0 && res.data.data) {
155 157 self.setData({
... ... @@ -290,6 +292,7 @@ Page({
290 292 getApp().request.get("/api/weshop/libao/libaoListvip/getLibaoCode",{
291 293 data:data,
292 294 success:function (res){
  295 + console.log(res);
293 296 if(res.data.code==0){
294 297 th.data.qr_code_object.val=res.data.data;
295 298 var qc_com = th.selectComponent("#qrcode"); //组件的id
... ...
packageA/pages/myGiftDetails/myGiftDetails.wxml
... ... @@ -3,7 +3,17 @@
3 3 <!-- 图片 -->
4 4 <view><image src="{{imghost + (details.lburl ? details.lburl:'miniapp/images/default_g_img.gif')}}" class="img" mode="widthFix"/></view>
5 5  
6   - <view wx:if="{{index==1}}" class="fs26 exp_title">兑换结束时间:{{filter.format_time(details.expdate,1)}}</view>
  6 + <!-- 未买 -->
  7 + <block wx:if="{{index==0}}">
  8 + <view class="fs26 exp_title">活动结束时间:{{filter.format_time(details.endtime,1)}}</view>
  9 + </block>
  10 + <!-- 已买 -->
  11 + <block wx:else>
  12 + <view wx:if="{{details.lbtype==1}}"class="fs26 exp_title">兑换结束时间:{{filter.format_time(details.expdate,1)}}</view>
  13 + </block>
  14 +
  15 +
  16 +
7 17 <!-- 描述-->
8 18 <view class="desc-container">
9 19 <!-- 标题 -->
... ... @@ -30,7 +40,7 @@
30 40 <view class="fs24 c-a4">已售{{details.salenum}}件</view>
31 41 </view>
32 42 <!-- 时间 -->
33   - <view class="date">活动截止日期 {{details.expdate ? filter.format_time(details.expdate):filter.format_time(details.endtime)}}</view>
  43 + <!-- <view class="date">活动结束日期 {{filter.format_time(details.endtime)}}</view> -->
34 44 </view>
35 45  
36 46  
... ... @@ -71,16 +81,40 @@
71 81 </view>
72 82  
73 83 <view wx:if="{{details.lbtype==2}}" class="flex" style="flex-wrap: wrap;">
74   - <block wx:for="{{list}}">
  84 + <block wx:for="{{list}}" wx:for-index="f_idx">
75 85 <block wx:for="{{item.goods_num-0}}" wx:for-item="nitem" wx:for-index="idx">
76 86 <view class="lb_quan" style="background-image: url({{imghost}}/miniapp/images/yhq_{{index%2+1}}.png)">
77 87 <view class="flex fs28 fir_view">
78   - <view>满1000.00使用</view>
79   - <view class="fs38" style="text-align: right">¥1000</view>
  88 + <view>满{{item.condition}}使用</view>
  89 + <view class="fs8" style="text-align: right">¥{{item.money}}</view>
80 90 </view>
81   - <view style="font-size: 16rpx; text-align: center">活动结束日期: 2022-06-02 00:00:00 </view>
  91 +
  92 +
  93 + <view style="font-size: 16rpx; text-align: center"> {{index==0?'活动结束日期':'截至时间'}}:
  94 +
  95 + <block wx:if="{{item.endtype<1}}">
  96 + <block wx:if="{{item.use_end_time}}">
  97 + {{filter.format_time(item.use_end_time,1)}}
  98 + </block>
  99 + <block wx:else>
  100 + 不限
  101 + </block>
  102 + </block>
  103 +
  104 + <block wx:else>
  105 + <block wx:if="{{item.days>0}}">
  106 + 有效期{{item.days}}天
  107 + </block>
  108 + <block wx:else>
  109 + 不限
  110 + </block>
  111 +
  112 + </block>
  113 + </view>
  114 +
  115 +
82 116 </view>
83   - </block>
  117 + </block>
84 118 </block>
85 119 </view>
86 120  
... ... @@ -106,7 +140,7 @@
106 140 <view wx:if="{{details.lbprice>0}}" bindtap="GetBuyPrice" class="btn pink">立即购买</view>
107 141 </block>
108 142 <block wx:else>
109   - <view wx:if="{{details.isget}}" data-type="1" class="btn" style="background-color:#aaa;color: #fff">已领</view>
  143 + <view wx:if="{{details.isget}}" data-type="1" class="btn" style="background-color:#aaa;color: #fff">已领</view>
110 144 <view wx:else bindtap="show_get_quan" data-type="1" class="btn red">一键领取优惠券→</view>
111 145 </block>
112 146 </view>
... ...
packageB/components/painter/lib/downloader.js 0 → 100644
  1 +/**
  2 + * LRU 文件存储,使用该 downloader 可以让下载的文件存储在本地,下次进入小程序后可以直接使用
  3 + * 详细设计文档可查看 https://juejin.im/post/5b42d3ede51d4519277b6ce3
  4 + */
  5 +const util = require('./util');
  6 +
  7 +const SAVED_FILES_KEY = 'savedFiles';
  8 +const KEY_TOTAL_SIZE = 'totalSize';
  9 +const KEY_PATH = 'path';
  10 +const KEY_TIME = 'time';
  11 +const KEY_SIZE = 'size';
  12 +
  13 +// 可存储总共为 6M,目前小程序可允许的最大本地存储为 10M
  14 +let MAX_SPACE_IN_B = 6 * 1024 * 1024;
  15 +let savedFiles = {};
  16 +
  17 +export default class Dowloader {
  18 + constructor() {
  19 + // app 如果设置了最大存储空间,则使用 app 中的
  20 + if (getApp().PAINTER_MAX_LRU_SPACE) {
  21 + MAX_SPACE_IN_B = getApp().PAINTER_MAX_LRU_SPACE;
  22 + }
  23 + wx.getStorage({
  24 + key: SAVED_FILES_KEY,
  25 + success: function (res) {
  26 + if (res.data) {
  27 + savedFiles = res.data;
  28 + }
  29 + },
  30 + });
  31 + }
  32 +
  33 + /**
  34 + * 下载文件,会用 lru 方式来缓存文件到本地
  35 + * @param {String} url 文件的 url
  36 + */
  37 + download(url, lru) {
  38 + return new Promise((resolve, reject) => {
  39 + if (!(url && util.isValidUrl(url))) {
  40 + resolve(url);
  41 + return;
  42 + }
  43 + if (!lru) {
  44 + // 无 lru 情况下直接判断 临时文件是否存在,不存在重新下载
  45 + wx.getFileInfo({
  46 + filePath: url,
  47 + success: () => {
  48 + resolve(url);
  49 + },
  50 + fail: () => {
  51 + downloadFile(url, lru).then((path) => {
  52 + resolve(path);
  53 + }, () => {
  54 + reject();
  55 + });
  56 + },
  57 + })
  58 + return
  59 + }
  60 +
  61 + const file = getFile(url);
  62 +
  63 + if (file) {
  64 + // 检查文件是否正常,不正常需要重新下载
  65 + wx.getSavedFileInfo({
  66 + filePath: file[KEY_PATH],
  67 + success: (res) => {
  68 + resolve(file[KEY_PATH]);
  69 + },
  70 + fail: (error) => {
  71 + console.error(`the file is broken, redownload it, ${JSON.stringify(error)}`);
  72 + downloadFile(url, lru).then((path) => {
  73 + resolve(path);
  74 + }, () => {
  75 + reject();
  76 + });
  77 + },
  78 + });
  79 + } else {
  80 + downloadFile(url, lru).then((path) => {
  81 + resolve(path);
  82 + }, () => {
  83 + reject();
  84 + });
  85 + }
  86 + });
  87 + }
  88 +}
  89 +
  90 +function downloadFile(url, lru) {
  91 + return new Promise((resolve, reject) => {
  92 + wx.downloadFile({
  93 + url: url,
  94 + success: function (res) {
  95 + if (res.statusCode !== 200) {
  96 + console.error(`downloadFile ${url} failed res.statusCode is not 200`);
  97 + reject();
  98 + return;
  99 + }
  100 + const {
  101 + tempFilePath
  102 + } = res;
  103 + wx.getFileInfo({
  104 + filePath: tempFilePath,
  105 + success: (tmpRes) => {
  106 + const newFileSize = tmpRes.size;
  107 + lru ? doLru(newFileSize).then(() => {
  108 + saveFile(url, newFileSize, tempFilePath).then((filePath) => {
  109 + resolve(filePath);
  110 + });
  111 + }, () => {
  112 + resolve(tempFilePath);
  113 + }) : resolve(tempFilePath);
  114 + },
  115 + fail: (error) => {
  116 + // 文件大小信息获取失败,则此文件也不要进行存储
  117 + console.error(`getFileInfo ${res.tempFilePath} failed, ${JSON.stringify(error)}`);
  118 + resolve(res.tempFilePath);
  119 + },
  120 + });
  121 + },
  122 + fail: function (error) {
  123 + console.error(`downloadFile failed, ${JSON.stringify(error)} `);
  124 + reject();
  125 + },
  126 + });
  127 + });
  128 +}
  129 +
  130 +function saveFile(key, newFileSize, tempFilePath) {
  131 + return new Promise((resolve, reject) => {
  132 + wx.saveFile({
  133 + tempFilePath: tempFilePath,
  134 + success: (fileRes) => {
  135 + const totalSize = savedFiles[KEY_TOTAL_SIZE] ? savedFiles[KEY_TOTAL_SIZE] : 0;
  136 + savedFiles[key] = {};
  137 + savedFiles[key][KEY_PATH] = fileRes.savedFilePath;
  138 + savedFiles[key][KEY_TIME] = new Date().getTime();
  139 + savedFiles[key][KEY_SIZE] = newFileSize;
  140 + savedFiles['totalSize'] = newFileSize + totalSize;
  141 + wx.setStorage({
  142 + key: SAVED_FILES_KEY,
  143 + data: savedFiles,
  144 + });
  145 + resolve(fileRes.savedFilePath);
  146 + },
  147 + fail: (error) => {
  148 + console.error(`saveFile ${key} failed, then we delete all files, ${JSON.stringify(error)}`);
  149 + // 由于 saveFile 成功后,res.tempFilePath 处的文件会被移除,所以在存储未成功时,我们还是继续使用临时文件
  150 + resolve(tempFilePath);
  151 + // 如果出现错误,就直接情况本地的所有文件,因为你不知道是不是因为哪次lru的某个文件未删除成功
  152 + reset();
  153 + },
  154 + });
  155 + });
  156 +}
  157 +
  158 +/**
  159 + * 清空所有下载相关内容
  160 + */
  161 +function reset() {
  162 + wx.removeStorage({
  163 + key: SAVED_FILES_KEY,
  164 + success: () => {
  165 + wx.getSavedFileList({
  166 + success: (listRes) => {
  167 + removeFiles(listRes.fileList);
  168 + },
  169 + fail: (getError) => {
  170 + console.error(`getSavedFileList failed, ${JSON.stringify(getError)}`);
  171 + },
  172 + });
  173 + },
  174 + });
  175 +}
  176 +
  177 +function doLru(size) {
  178 + if (size > MAX_SPACE_IN_B) {
  179 + return Promise.reject()
  180 + }
  181 + return new Promise((resolve, reject) => {
  182 + let totalSize = savedFiles[KEY_TOTAL_SIZE] ? savedFiles[KEY_TOTAL_SIZE] : 0;
  183 +
  184 + if (size + totalSize <= MAX_SPACE_IN_B) {
  185 + resolve();
  186 + return;
  187 + }
  188 + // 如果加上新文件后大小超过最大限制,则进行 lru
  189 + const pathsShouldDelete = [];
  190 + // 按照最后一次的访问时间,从小到大排序
  191 + const allFiles = JSON.parse(JSON.stringify(savedFiles));
  192 + delete allFiles[KEY_TOTAL_SIZE];
  193 + const sortedKeys = Object.keys(allFiles).sort((a, b) => {
  194 + return allFiles[a][KEY_TIME] - allFiles[b][KEY_TIME];
  195 + });
  196 +
  197 + for (const sortedKey of sortedKeys) {
  198 + totalSize -= savedFiles[sortedKey].size;
  199 + pathsShouldDelete.push(savedFiles[sortedKey][KEY_PATH]);
  200 + delete savedFiles[sortedKey];
  201 + if (totalSize + size < MAX_SPACE_IN_B) {
  202 + break;
  203 + }
  204 + }
  205 +
  206 + savedFiles['totalSize'] = totalSize;
  207 +
  208 + wx.setStorage({
  209 + key: SAVED_FILES_KEY,
  210 + data: savedFiles,
  211 + success: () => {
  212 + // 保证 storage 中不会存在不存在的文件数据
  213 + if (pathsShouldDelete.length > 0) {
  214 + removeFiles(pathsShouldDelete);
  215 + }
  216 + resolve();
  217 + },
  218 + fail: (error) => {
  219 + console.error(`doLru setStorage failed, ${JSON.stringify(error)}`);
  220 + reject();
  221 + },
  222 + });
  223 + });
  224 +}
  225 +
  226 +function removeFiles(pathsShouldDelete) {
  227 + for (const pathDel of pathsShouldDelete) {
  228 + let delPath = pathDel;
  229 + if (typeof pathDel === 'object') {
  230 + delPath = pathDel.filePath;
  231 + }
  232 + wx.removeSavedFile({
  233 + filePath: delPath,
  234 + fail: (error) => {
  235 + console.error(`removeSavedFile ${pathDel} failed, ${JSON.stringify(error)}`);
  236 + },
  237 + });
  238 + }
  239 +}
  240 +
  241 +function getFile(key) {
  242 + if (!savedFiles[key]) {
  243 + return;
  244 + }
  245 + savedFiles[key]['time'] = new Date().getTime();
  246 + wx.setStorage({
  247 + key: SAVED_FILES_KEY,
  248 + data: savedFiles,
  249 + });
  250 + return savedFiles[key];
  251 +}
0 252 \ No newline at end of file
... ...
packageB/components/painter/lib/gradient.js 0 → 100644
  1 +/* eslint-disable */
  2 +// 当ctx传入当前文件,const grd = ctx.createCircularGradient() 和
  3 +// const grd = this.ctx.createLinearGradient() 无效,因此只能分开处理
  4 +// 先分析,在外部创建grd,再传入使用就可以
  5 +
  6 +!(function () {
  7 +
  8 + var api = {
  9 + isGradient: function(bg) {
  10 + if (bg && (bg.startsWith('linear') || bg.startsWith('radial'))) {
  11 + return true;
  12 + }
  13 + return false;
  14 + },
  15 +
  16 + doGradient: function(bg, width, height, ctx) {
  17 + if (bg.startsWith('linear')) {
  18 + linearEffect(width, height, bg, ctx);
  19 + } else if (bg.startsWith('radial')) {
  20 + radialEffect(width, height, bg, ctx);
  21 + }
  22 + },
  23 + }
  24 +
  25 + function analizeGrad(string) {
  26 + const colorPercents = string.substring(0, string.length - 1).split("%,");
  27 + const colors = [];
  28 + const percents = [];
  29 + for (let colorPercent of colorPercents) {
  30 + colors.push(colorPercent.substring(0, colorPercent.lastIndexOf(" ")).trim());
  31 + percents.push(colorPercent.substring(colorPercent.lastIndexOf(" "), colorPercent.length) / 100);
  32 + }
  33 + return {colors: colors, percents: percents};
  34 + }
  35 +
  36 + function radialEffect(width, height, bg, ctx) {
  37 + const colorPer = analizeGrad(bg.match(/radial-gradient\((.+)\)/)[1]);
  38 + const grd = ctx.createRadialGradient(0, 0, 0, 0, 0, width < height ? height / 2 : width / 2);
  39 + for (let i = 0; i < colorPer.colors.length; i++) {
  40 + grd.addColorStop(colorPer.percents[i], colorPer.colors[i]);
  41 + }
  42 + ctx.fillStyle = grd;
  43 + //ctx.fillRect(-(width / 2), -(height / 2), width, height);
  44 + }
  45 +
  46 + function analizeLinear(bg, width, height) {
  47 + const direction = bg.match(/([-]?\d{1,3})deg/);
  48 + const dir = direction && direction[1] ? parseFloat(direction[1]) : 0;
  49 + let coordinate;
  50 + switch (dir) {
  51 + case 0: coordinate = [0, -height / 2, 0, height / 2]; break;
  52 + case 90: coordinate = [width / 2, 0, -width / 2, 0]; break;
  53 + case -90: coordinate = [-width / 2, 0, width / 2, 0]; break;
  54 + case 180: coordinate = [0, height / 2, 0, -height / 2]; break;
  55 + case -180: coordinate = [0, -height / 2, 0, height / 2]; break;
  56 + default:
  57 + let x1 = 0;
  58 + let y1 = 0;
  59 + let x2 = 0;
  60 + let y2 = 0;
  61 + if (direction[1] > 0 && direction[1] < 90) {
  62 + x1 = (width / 2) - ((width / 2) * Math.tan((90 - direction[1]) * Math.PI * 2 / 360) - height / 2) * Math.sin(2 * (90 - direction[1]) * Math.PI * 2 / 360) / 2;
  63 + y2 = Math.tan((90 - direction[1]) * Math.PI * 2 / 360) * x1;
  64 + x2 = -x1;
  65 + y1 = -y2;
  66 + } else if (direction[1] > -180 && direction[1] < -90) {
  67 + x1 = -(width / 2) + ((width / 2) * Math.tan((90 - direction[1]) * Math.PI * 2 / 360) - height / 2) * Math.sin(2 * (90 - direction[1]) * Math.PI * 2 / 360) / 2;
  68 + y2 = Math.tan((90 - direction[1]) * Math.PI * 2 / 360) * x1;
  69 + x2 = -x1;
  70 + y1 = -y2;
  71 + } else if (direction[1] > 90 && direction[1] < 180) {
  72 + x1 = (width / 2) + (-(width / 2) * Math.tan((90 - direction[1]) * Math.PI * 2 / 360) - height / 2) * Math.sin(2 * (90 - direction[1]) * Math.PI * 2 / 360) / 2;
  73 + y2 = Math.tan((90 - direction[1]) * Math.PI * 2 / 360) * x1;
  74 + x2 = -x1;
  75 + y1 = -y2;
  76 + } else {
  77 + x1 = -(width / 2) - (-(width / 2) * Math.tan((90 - direction[1]) * Math.PI * 2 / 360) - height / 2) * Math.sin(2 * (90 - direction[1]) * Math.PI * 2 / 360) / 2;
  78 + y2 = Math.tan((90 - direction[1]) * Math.PI * 2 / 360) * x1;
  79 + x2 = -x1;
  80 + y1 = -y2;
  81 + }
  82 + coordinate = [x1, y1, x2, y2];
  83 + break;
  84 + }
  85 + return coordinate;
  86 + }
  87 +
  88 + function linearEffect(width, height, bg, ctx) {
  89 + const param = analizeLinear(bg, width, height);
  90 + const grd = ctx.createLinearGradient(param[0], param[1], param[2], param[3]);
  91 + const content = bg.match(/linear-gradient\((.+)\)/)[1];
  92 + const colorPer = analizeGrad(content.substring(content.indexOf(',') + 1));
  93 + for (let i = 0; i < colorPer.colors.length; i++) {
  94 + grd.addColorStop(colorPer.percents[i], colorPer.colors[i]);
  95 + }
  96 + ctx.fillStyle = grd
  97 + //ctx.fillRect(-(width / 2), -(height / 2), width, height);
  98 + }
  99 +
  100 + module.exports = { api }
  101 +
  102 +})();
... ...
packageB/components/painter/lib/pen.js 0 → 100644
  1 +const QR = require('./qrcode.js');
  2 +const GD = require('./gradient.js');
  3 +
  4 +export default class Painter {
  5 + constructor(ctx, data) {
  6 + this.ctx = ctx;
  7 + this.data = data;
  8 + this.globalWidth = {};
  9 + this.globalHeight = {};
  10 + }
  11 +
  12 + isMoving = false
  13 + movingCache = {}
  14 + paint(callback, isMoving, movingCache) {
  15 + this.style = {
  16 + width: this.data.width.toPx(),
  17 + height: this.data.height.toPx(),
  18 + };
  19 + if (isMoving) {
  20 + this.isMoving = true
  21 + this.movingCache = movingCache
  22 + }
  23 + this._background();
  24 + for (const view of this.data.views) {
  25 + this._drawAbsolute(view);
  26 + }
  27 + this.ctx.draw(false, () => {
  28 + callback && callback(this.callbackInfo);
  29 + });
  30 + }
  31 +
  32 + _background() {
  33 + this.ctx.save();
  34 + const {
  35 + width,
  36 + height,
  37 + } = this.style;
  38 + const bg = this.data.background;
  39 + this.ctx.translate(width / 2, height / 2);
  40 +
  41 + this._doClip(this.data.borderRadius, width, height);
  42 + if (!bg) {
  43 + // 如果未设置背景,则默认使用透明色
  44 + this.ctx.fillStyle = 'transparent';
  45 + this.ctx.fillRect(-(width / 2), -(height / 2), width, height);
  46 + } else if (bg.startsWith('#') || bg.startsWith('rgba') || bg.toLowerCase() === 'transparent') {
  47 + // 背景填充颜色
  48 + this.ctx.fillStyle = bg;
  49 + this.ctx.fillRect(-(width / 2), -(height / 2), width, height);
  50 + } else if (GD.api.isGradient(bg)) {
  51 + GD.api.doGradient(bg, width, height, this.ctx);
  52 + this.ctx.fillRect(-(width / 2), -(height / 2), width, height);
  53 + } else {
  54 + // 背景填充图片
  55 + this.ctx.drawImage(bg, -(width / 2), -(height / 2), width, height);
  56 + }
  57 + this.ctx.restore();
  58 + }
  59 +
  60 + _drawAbsolute(view) {
  61 + if (!(view && view.type)) {
  62 + // 过滤无效 view
  63 + return
  64 + }
  65 + // 证明 css 为数组形式,需要合并
  66 + if (view.css && view.css.length) {
  67 + /* eslint-disable no-param-reassign */
  68 + view.css = Object.assign(...view.css);
  69 + }
  70 + switch (view.type) {
  71 + case 'image':
  72 + this._drawAbsImage(view);
  73 + break;
  74 + case 'text':
  75 + this._fillAbsText(view);
  76 + break;
  77 + case 'rect':
  78 + this._drawAbsRect(view);
  79 + break;
  80 + case 'qrcode':
  81 + this._drawQRCode(view);
  82 + break;
  83 + default:
  84 + break;
  85 + }
  86 + }
  87 +
  88 + _border({
  89 + borderRadius = 0,
  90 + width,
  91 + height,
  92 + borderWidth = 0,
  93 + borderStyle = 'solid'
  94 + }) {
  95 + let r1 = 0,
  96 + r2 = 0,
  97 + r3 = 0,
  98 + r4 = 0
  99 + const minSize = Math.min(width, height);
  100 + if (borderRadius) {
  101 + const border = borderRadius.split(/\s+/)
  102 + if (border.length === 4) {
  103 + r1 = Math.min(border[0].toPx(false, minSize), width / 2, height / 2);
  104 + r2 = Math.min(border[1].toPx(false, minSize), width / 2, height / 2);
  105 + r3 = Math.min(border[2].toPx(false, minSize), width / 2, height / 2);
  106 + r4 = Math.min(border[3].toPx(false, minSize), width / 2, height / 2);
  107 + } else {
  108 + r1 = r2 = r3 = r4 = Math.min(borderRadius && borderRadius.toPx(false, minSize), width / 2, height / 2);
  109 + }
  110 + }
  111 + const lineWidth = borderWidth && borderWidth.toPx(false, minSize);
  112 + this.ctx.lineWidth = lineWidth;
  113 + if (borderStyle === 'dashed') {
  114 + this.ctx.setLineDash([lineWidth * 4 / 3, lineWidth * 4 / 3]);
  115 + // this.ctx.lineDashOffset = 2 * lineWidth
  116 + } else if (borderStyle === 'dotted') {
  117 + this.ctx.setLineDash([lineWidth, lineWidth]);
  118 + }
  119 + const notSolid = borderStyle !== 'solid'
  120 + this.ctx.beginPath();
  121 +
  122 + notSolid && r1 === 0 && this.ctx.moveTo(-width / 2 - lineWidth, -height / 2 - lineWidth / 2) // 顶边虚线规避重叠规则
  123 + r1 !== 0 && this.ctx.arc(-width / 2 + r1, -height / 2 + r1, r1 + lineWidth / 2, 1 * Math.PI, 1.5 * Math.PI); //左上角圆弧
  124 + this.ctx.lineTo(r2 === 0 ? notSolid ? width / 2 : width / 2 + lineWidth / 2 : width / 2 - r2, -height / 2 - lineWidth / 2); // 顶边线
  125 +
  126 + notSolid && r2 === 0 && this.ctx.moveTo(width / 2 + lineWidth / 2, -height / 2 - lineWidth) // 右边虚线规避重叠规则
  127 + r2 !== 0 && this.ctx.arc(width / 2 - r2, -height / 2 + r2, r2 + lineWidth / 2, 1.5 * Math.PI, 2 * Math.PI); // 右上角圆弧
  128 + this.ctx.lineTo(width / 2 + lineWidth / 2, r3 === 0 ? notSolid ? height / 2 : height / 2 + lineWidth / 2 : height / 2 - r3); // 右边线
  129 +
  130 + notSolid && r3 === 0 && this.ctx.moveTo(width / 2 + lineWidth, height / 2 + lineWidth / 2) // 底边虚线规避重叠规则
  131 + r3 !== 0 && this.ctx.arc(width / 2 - r3, height / 2 - r3, r3 + lineWidth / 2, 0, 0.5 * Math.PI); // 右下角圆弧
  132 + this.ctx.lineTo(r4 === 0 ? notSolid ? -width / 2 : -width / 2 - lineWidth / 2 : -width / 2 + r4, height / 2 + lineWidth / 2); // 底边线
  133 +
  134 + notSolid && r4 === 0 && this.ctx.moveTo(-width / 2 - lineWidth / 2, height / 2 + lineWidth) // 左边虚线规避重叠规则
  135 + r4 !== 0 && this.ctx.arc(-width / 2 + r4, height / 2 - r4, r4 + lineWidth / 2, 0.5 * Math.PI, 1 * Math.PI); // 左下角圆弧
  136 + this.ctx.lineTo(-width / 2 - lineWidth / 2, r1 === 0 ? notSolid ? -height / 2 : -height / 2 - lineWidth / 2 : -height / 2 + r1); // 左边线
  137 + notSolid && r1 === 0 && this.ctx.moveTo(-width / 2 - lineWidth, -height / 2 - lineWidth / 2) // 顶边虚线规避重叠规则
  138 +
  139 + if (!notSolid) {
  140 + this.ctx.closePath();
  141 + }
  142 + }
  143 +
  144 + /**
  145 + * 根据 borderRadius 进行裁减
  146 + */
  147 + _doClip(borderRadius, width, height, borderStyle) {
  148 + if (borderRadius && width && height) {
  149 + // 防止在某些机型上周边有黑框现象,此处如果直接设置 fillStyle 为透明,在 Android 机型上会导致被裁减的图片也变为透明, iOS 和 IDE 上不会
  150 + // globalAlpha 在 1.9.90 起支持,低版本下无效,但把 fillStyle 设为了 white,相对默认的 black 要好点
  151 + this.ctx.globalAlpha = 0;
  152 + this.ctx.fillStyle = 'white';
  153 + this._border({
  154 + borderRadius,
  155 + width,
  156 + height,
  157 + borderStyle
  158 + })
  159 + this.ctx.fill();
  160 + // 在 ios 的 6.6.6 版本上 clip 有 bug,禁掉此类型上的 clip,也就意味着,在此版本微信的 ios 设备下无法使用 border 属性
  161 + if (!(getApp().systemInfo &&
  162 + getApp().systemInfo.version <= '6.6.6' &&
  163 + getApp().systemInfo.platform === 'ios')) {
  164 + this.ctx.clip();
  165 + }
  166 + this.ctx.globalAlpha = 1;
  167 + }
  168 + }
  169 +
  170 + /**
  171 + * 画边框
  172 + */
  173 + _doBorder(view, width, height) {
  174 + if (!view.css) {
  175 + return;
  176 + }
  177 + const {
  178 + borderRadius,
  179 + borderWidth,
  180 + borderColor,
  181 + borderStyle
  182 + } = view.css;
  183 + if (!borderWidth) {
  184 + return;
  185 + }
  186 + this.ctx.save();
  187 + this._preProcess(view, true);
  188 + this.ctx.strokeStyle = (borderColor || 'black');
  189 + this._border({
  190 + borderRadius,
  191 + width,
  192 + height,
  193 + borderWidth,
  194 + borderStyle
  195 + })
  196 + this.ctx.stroke();
  197 + this.ctx.restore();
  198 + }
  199 +
  200 + _preProcess(view, notClip) {
  201 + let width = 0;
  202 + let height;
  203 + let extra;
  204 + const paddings = this._doPaddings(view);
  205 + switch (view.type) {
  206 + case 'text': {
  207 + const textArray = view.text.split('\n');
  208 + // 处理多个连续的'\n'
  209 + for (let i = 0; i < textArray.length; ++i) {
  210 + if (textArray[i] === '') {
  211 + textArray[i] = ' ';
  212 + }
  213 + }
  214 + const fontWeight = view.css.fontWeight || '400';
  215 + const textStyle = view.css.textStyle || 'normal';
  216 + if (!view.css.fontSize) {
  217 + view.css.fontSize = '20rpx';
  218 + }
  219 + this.ctx.font = `${textStyle} ${fontWeight} ${view.css.fontSize.toPx()}px "${view.css.fontFamily || 'sans-serif'}"`;
  220 + // 计算行数
  221 + let lines = 0;
  222 + const linesArray = [];
  223 + for (let i = 0; i < textArray.length; ++i) {
  224 + const textLength = this.ctx.measureText(textArray[i]).width;
  225 + const minWidth = view.css.fontSize.toPx() + paddings[1] + paddings[3];
  226 + let partWidth = view.css.width ? view.css.width.toPx(false, this.style.width) - paddings[1] - paddings[3] : textLength;
  227 + if (partWidth < minWidth) {
  228 + partWidth = minWidth;
  229 + }
  230 + const calLines = Math.ceil(textLength / partWidth);
  231 + // 取最长的作为 width
  232 + width = partWidth > width ? partWidth : width;
  233 + lines += calLines;
  234 + linesArray[i] = calLines;
  235 + }
  236 + lines = view.css.maxLines < lines ? view.css.maxLines : lines;
  237 + const lineHeight = view.css.lineHeight ? view.css.lineHeight.toPx() : view.css.fontSize.toPx();
  238 + height = lineHeight * lines;
  239 + extra = {
  240 + lines: lines,
  241 + lineHeight: lineHeight,
  242 + textArray: textArray,
  243 + linesArray: linesArray,
  244 + };
  245 + break;
  246 + }
  247 + case 'image': {
  248 + // image的长宽设置成auto的逻辑处理
  249 + const ratio = getApp().systemInfo.pixelRatio ? getApp().systemInfo.pixelRatio : 2;
  250 + // 有css却未设置width或height,则默认为auto
  251 + if (view.css) {
  252 + if (!view.css.width) {
  253 + view.css.width = 'auto';
  254 + }
  255 + if (!view.css.height) {
  256 + view.css.height = 'auto';
  257 + }
  258 + }
  259 + if (!view.css || (view.css.width === 'auto' && view.css.height === 'auto')) {
  260 + width = Math.round(view.sWidth / ratio);
  261 + height = Math.round(view.sHeight / ratio);
  262 + } else if (view.css.width === 'auto') {
  263 + height = view.css.height.toPx(false, this.style.height);
  264 + width = view.sWidth / view.sHeight * height;
  265 + } else if (view.css.height === 'auto') {
  266 + width = view.css.width.toPx(false, this.style.width);
  267 + height = view.sHeight / view.sWidth * width;
  268 + } else {
  269 + width = view.css.width.toPx(false, this.style.width);
  270 + height = view.css.height.toPx(false, this.style.height);
  271 + }
  272 + break;
  273 + }
  274 + default:
  275 + if (!(view.css.width && view.css.height)) {
  276 + console.error('You should set width and height');
  277 + return;
  278 + }
  279 + width = view.css.width.toPx(false, this.style.width);
  280 + height = view.css.height.toPx(false, this.style.height);
  281 + break;
  282 + }
  283 + let x;
  284 + if (view.css && view.css.right) {
  285 + if (typeof view.css.right === 'string') {
  286 + x = this.style.width - view.css.right.toPx(true, this.style.width);
  287 + } else {
  288 + // 可以用数组方式,把文字长度计算进去
  289 + // [right, 文字id, 乘数(默认 1)]
  290 + const rights = view.css.right;
  291 + x = this.style.width - rights[0].toPx(true, this.style.width) - this.globalWidth[rights[1]] * (rights[2] || 1);
  292 + }
  293 + } else if (view.css && view.css.left) {
  294 + if (typeof view.css.left === 'string') {
  295 + x = view.css.left.toPx(true, this.style.width);
  296 + } else {
  297 + const lefts = view.css.left;
  298 + x = lefts[0].toPx(true, this.style.width) + this.globalWidth[lefts[1]] * (lefts[2] || 1);
  299 + }
  300 + } else {
  301 + x = 0;
  302 + }
  303 + //const y = view.css && view.css.bottom ? this.style.height - height - view.css.bottom.toPx(true) : (view.css && view.css.top ? view.css.top.toPx(true) : 0);
  304 + let y;
  305 + if (view.css && view.css.bottom) {
  306 + y = this.style.height - height - view.css.bottom.toPx(true, this.style.height);
  307 + } else {
  308 + if (view.css && view.css.top) {
  309 + if (typeof view.css.top === 'string') {
  310 + y = view.css.top.toPx(true, this.style.height);
  311 + } else {
  312 + const tops = view.css.top;
  313 + y = tops[0].toPx(true, this.style.height) + this.globalHeight[tops[1]] * (tops[2] || 1);
  314 + }
  315 + } else {
  316 + y = 0
  317 + }
  318 + }
  319 +
  320 + const angle = view.css && view.css.rotate ? this._getAngle(view.css.rotate) : 0;
  321 + // 当设置了 right 时,默认 align 用 right,反之用 left
  322 + const align = view.css && view.css.align ? view.css.align : (view.css && view.css.right ? 'right' : 'left');
  323 + const verticalAlign = view.css && view.css.verticalAlign ? view.css.verticalAlign : 'top';
  324 + // 记录绘制时的画布
  325 + let xa = 0;
  326 + switch (align) {
  327 + case 'center':
  328 + xa = x;
  329 + break;
  330 + case 'right':
  331 + xa = x - width / 2;
  332 + break;
  333 + default:
  334 + xa = x + width / 2;
  335 + break;
  336 + }
  337 + let ya = 0;
  338 + switch (verticalAlign) {
  339 + case 'center':
  340 + ya = y;
  341 + break;
  342 + case 'bottom':
  343 + ya = y - height / 2;
  344 + break;
  345 + default:
  346 + ya = y + height / 2;
  347 + break;
  348 + }
  349 + this.ctx.translate(xa, ya);
  350 + // 记录该 view 的有效点击区域
  351 + // TODO ,旋转和裁剪的判断
  352 + // 记录在真实画布上的左侧
  353 + let left = x
  354 + if (align === 'center') {
  355 + left = x - width / 2
  356 + } else if (align === 'right') {
  357 + left = x - width
  358 + }
  359 + var top = y;
  360 + if (verticalAlign === 'center') {
  361 + top = y - height / 2;
  362 + } else if (verticalAlign === 'bottom') {
  363 + top = y - height
  364 + }
  365 + if (view.rect) {
  366 + view.rect.left = left;
  367 + view.rect.top = top;
  368 + view.rect.right = left + width;
  369 + view.rect.bottom = top + height;
  370 + view.rect.x = view.css && view.css.right ? x - width : x;
  371 + view.rect.y = y;
  372 + } else {
  373 + view.rect = {
  374 + left: left,
  375 + top: top,
  376 + right: left + width,
  377 + bottom: top + height,
  378 + x: view.css && view.css.right ? x - width : x,
  379 + y: y
  380 + };
  381 + }
  382 +
  383 + view.rect.left = view.rect.left - paddings[3];
  384 + view.rect.top = view.rect.top - paddings[0];
  385 + view.rect.right = view.rect.right + paddings[1];
  386 + view.rect.bottom = view.rect.bottom + paddings[2];
  387 + if (view.type === 'text') {
  388 + view.rect.minWidth = view.css.fontSize.toPx() + paddings[1] + paddings[3];
  389 + }
  390 +
  391 + this.ctx.rotate(angle);
  392 + if (!notClip && view.css && view.css.borderRadius && view.type !== 'rect') {
  393 + this._doClip(view.css.borderRadius, width, height, view.css.borderStyle);
  394 + }
  395 + this._doShadow(view);
  396 + if (view.id) {
  397 + this.globalWidth[view.id] = width;
  398 + this.globalHeight[view.id] = height;
  399 + }
  400 + return {
  401 + width: width,
  402 + height: height,
  403 + x: x,
  404 + y: y,
  405 + extra: extra,
  406 + };
  407 + }
  408 +
  409 + _doPaddings(view) {
  410 + const {
  411 + padding,
  412 + } = view.css ? view.css : {};
  413 + let pd = [0, 0, 0, 0];
  414 + if (padding) {
  415 + const pdg = padding.split(/\s+/);
  416 + if (pdg.length === 1) {
  417 + const x = pdg[0].toPx();
  418 + pd = [x, x, x, x];
  419 + }
  420 + if (pdg.length === 2) {
  421 + const x = pdg[0].toPx();
  422 + const y = pdg[1].toPx();
  423 + pd = [x, y, x, y];
  424 + }
  425 + if (pdg.length === 3) {
  426 + const x = pdg[0].toPx();
  427 + const y = pdg[1].toPx();
  428 + const z = pdg[2].toPx();
  429 + pd = [x, y, z, y];
  430 + }
  431 + if (pdg.length === 4) {
  432 + const x = pdg[0].toPx();
  433 + const y = pdg[1].toPx();
  434 + const z = pdg[2].toPx();
  435 + const a = pdg[3].toPx();
  436 + pd = [x, y, z, a];
  437 + }
  438 + }
  439 + return pd;
  440 + }
  441 +
  442 + // 画文字的背景图片
  443 + _doBackground(view) {
  444 + this.ctx.save();
  445 + const {
  446 + width: rawWidth,
  447 + height: rawHeight,
  448 + } = this._preProcess(view, true);
  449 +
  450 + const {
  451 + background,
  452 + } = view.css;
  453 + let pd = this._doPaddings(view);
  454 + const width = rawWidth + pd[1] + pd[3];
  455 + const height = rawHeight + pd[0] + pd[2];
  456 +
  457 + this._doClip(view.css.borderRadius, width, height, view.css.borderStyle)
  458 + if (GD.api.isGradient(background)) {
  459 + GD.api.doGradient(background, width, height, this.ctx);
  460 + } else {
  461 + this.ctx.fillStyle = background;
  462 + }
  463 + this.ctx.fillRect(-(width / 2), -(height / 2), width, height);
  464 +
  465 + this.ctx.restore();
  466 + }
  467 +
  468 + _drawQRCode(view) {
  469 + this.ctx.save();
  470 + const {
  471 + width,
  472 + height,
  473 + } = this._preProcess(view);
  474 + QR.api.draw(view.content, this.ctx, -width / 2, -height / 2, width, height, view.css.background, view.css.color);
  475 + this.ctx.restore();
  476 + this._doBorder(view, width, height);
  477 + }
  478 +
  479 + _drawAbsImage(view) {
  480 + if (!view.url) {
  481 + return;
  482 + }
  483 + this.ctx.save();
  484 + const {
  485 + width,
  486 + height,
  487 + } = this._preProcess(view);
  488 + // 获得缩放到图片大小级别的裁减框
  489 + let rWidth = view.sWidth;
  490 + let rHeight = view.sHeight;
  491 + let startX = 0;
  492 + let startY = 0;
  493 + // 绘画区域比例
  494 + const cp = width / height;
  495 + // 原图比例
  496 + const op = view.sWidth / view.sHeight;
  497 + if (cp >= op) {
  498 + rHeight = rWidth / cp;
  499 + startY = Math.round((view.sHeight - rHeight) / 2);
  500 + } else {
  501 + rWidth = rHeight * cp;
  502 + startX = Math.round((view.sWidth - rWidth) / 2);
  503 + }
  504 + if (view.css && view.css.mode === 'scaleToFill') {
  505 + this.ctx.drawImage(view.url, -(width / 2), -(height / 2), width, height);
  506 + } else {
  507 + this.ctx.drawImage(view.url, startX, startY, rWidth, rHeight, -(width / 2), -(height / 2), width, height);
  508 + view.rect.startX = startX / view.sWidth;
  509 + view.rect.startY = startY / view.sHeight;
  510 + view.rect.endX = (startX + rWidth) / view.sWidth;
  511 + view.rect.endY = (startY + rHeight) / view.sHeight;
  512 + }
  513 + this.ctx.restore();
  514 + this._doBorder(view, width, height);
  515 + }
  516 +
  517 + callbackInfo = {}
  518 + _fillAbsText(view) {
  519 + if (!view.text) {
  520 + return;
  521 + }
  522 + if (view.css.background) {
  523 + // 生成背景
  524 + this._doBackground(view);
  525 + }
  526 + this.ctx.save();
  527 + const {
  528 + width,
  529 + height,
  530 + extra,
  531 + } = this._preProcess(view, view.css.background && view.css.borderRadius);
  532 + this.ctx.fillStyle = (view.css.color || 'black');
  533 + if (this.isMoving && JSON.stringify(this.movingCache) !== JSON.stringify({})) {
  534 + this.globalWidth[view.id] = this.movingCache.globalWidth
  535 + this.ctx.textAlign = view.css.textAlign ? view.css.textAlign : 'left';
  536 + for (const i of this.movingCache.lineArray) {
  537 + const {
  538 + measuredWith,
  539 + text,
  540 + x,
  541 + y,
  542 + textDecoration
  543 + } = i
  544 + if (view.css.textStyle === 'stroke') {
  545 + this.ctx.strokeText(text, x, y, measuredWith);
  546 + } else {
  547 + this.ctx.fillText(text, x, y, measuredWith);
  548 + }
  549 + if (textDecoration) {
  550 + const fontSize = view.css.fontSize.toPx();
  551 + this.ctx.lineWidth = fontSize / 13;
  552 + this.ctx.beginPath();
  553 + this.ctx.moveTo(...textDecoration.moveTo);
  554 + this.ctx.lineTo(...textDecoration.lineTo);
  555 + this.ctx.closePath();
  556 + this.ctx.strokeStyle = view.css.color;
  557 + this.ctx.stroke();
  558 + }
  559 + }
  560 + } else {
  561 + const {
  562 + lines,
  563 + lineHeight,
  564 + textArray,
  565 + linesArray,
  566 + } = extra;
  567 + // 如果设置了id,则保留 text 的长度
  568 + if (view.id) {
  569 + let textWidth = 0;
  570 + for (let i = 0; i < textArray.length; ++i) {
  571 + const _w = this.ctx.measureText(textArray[i]).width
  572 + textWidth = _w > textWidth ? _w : textWidth;
  573 + }
  574 + this.globalWidth[view.id] = width ? (textWidth < width ? textWidth : width) : textWidth;
  575 + if (!this.isMoving) {
  576 + Object.assign(this.callbackInfo, {
  577 + globalWidth: this.globalWidth[view.id]
  578 + })
  579 + }
  580 + }
  581 + let lineIndex = 0;
  582 + for (let j = 0; j < textArray.length; ++j) {
  583 + const preLineLength = Math.ceil(textArray[j].length / linesArray[j]);
  584 + let start = 0;
  585 + let alreadyCount = 0;
  586 +
  587 + for (let i = 0; i < linesArray[j]; ++i) {
  588 + // 绘制行数大于最大行数,则直接跳出循环
  589 + if (lineIndex >= lines) {
  590 + break;
  591 + }
  592 + alreadyCount = preLineLength;
  593 + let text = textArray[j].substr(start, alreadyCount);
  594 + let measuredWith = this.ctx.measureText(text).width;
  595 + // 如果测量大小小于width一个字符的大小,则进行补齐,如果测量大小超出 width,则进行减除
  596 + // 如果已经到文本末尾,也不要进行该循环
  597 + while ((start + alreadyCount <= textArray[j].length) && (width - measuredWith > view.css.fontSize.toPx() || measuredWith - width > view.css.fontSize.toPx())) {
  598 + if (measuredWith < width) {
  599 + text = textArray[j].substr(start, ++alreadyCount);
  600 + } else {
  601 + if (text.length <= 1) {
  602 + // 如果只有一个字符时,直接跳出循环
  603 + break;
  604 + }
  605 + text = textArray[j].substr(start, --alreadyCount);
  606 + // break;
  607 + }
  608 + measuredWith = this.ctx.measureText(text).width;
  609 + }
  610 + start += text.length
  611 + // 如果是最后一行了,发现还有未绘制完的内容,则加...
  612 + if (lineIndex === lines - 1 && (j < textArray.length - 1 || start < textArray[j].length)) {
  613 + while (this.ctx.measureText(`${text}...`).width > width) {
  614 + if (text.length <= 1) {
  615 + // 如果只有一个字符时,直接跳出循环
  616 + break;
  617 + }
  618 + text = text.substring(0, text.length - 1);
  619 + }
  620 + text += '...';
  621 + measuredWith = this.ctx.measureText(text).width;
  622 + }
  623 + this.ctx.textAlign = view.css.textAlign ? view.css.textAlign : 'left';
  624 + let x;
  625 + let lineX;
  626 + switch (view.css.textAlign) {
  627 + case 'center':
  628 + x = 0;
  629 + lineX = x - measuredWith / 2;
  630 + break;
  631 + case 'right':
  632 + x = (width / 2);
  633 + lineX = x - measuredWith;
  634 + break;
  635 + default:
  636 + x = -(width / 2);
  637 + lineX = x;
  638 + break;
  639 + }
  640 + const y = -(height / 2) + (lineIndex === 0 ? view.css.fontSize.toPx() : (view.css.fontSize.toPx() + lineIndex * lineHeight));
  641 + lineIndex++;
  642 + if (view.css.textStyle === 'stroke') {
  643 + this.ctx.strokeText(text, x, y, measuredWith);
  644 + } else {
  645 + this.ctx.fillText(text, x, y, measuredWith);
  646 + }
  647 + const fontSize = view.css.fontSize.toPx();
  648 + let textDecoration;
  649 + if (view.css.textDecoration) {
  650 + this.ctx.lineWidth = fontSize / 13;
  651 + this.ctx.beginPath();
  652 + if (/\bunderline\b/.test(view.css.textDecoration)) {
  653 + this.ctx.moveTo(lineX, y);
  654 + this.ctx.lineTo(lineX + measuredWith, y);
  655 + textDecoration = {
  656 + moveTo: [lineX, y],
  657 + lineTo: [lineX + measuredWith, y]
  658 + }
  659 + }
  660 + if (/\boverline\b/.test(view.css.textDecoration)) {
  661 + this.ctx.moveTo(lineX, y - fontSize);
  662 + this.ctx.lineTo(lineX + measuredWith, y - fontSize);
  663 + textDecoration = {
  664 + moveTo: [lineX, y - fontSize],
  665 + lineTo: [lineX + measuredWith, y - fontSize]
  666 + }
  667 + }
  668 + if (/\bline-through\b/.test(view.css.textDecoration)) {
  669 + this.ctx.moveTo(lineX, y - fontSize / 3);
  670 + this.ctx.lineTo(lineX + measuredWith, y - fontSize / 3);
  671 + textDecoration = {
  672 + moveTo: [lineX, y - fontSize / 3],
  673 + lineTo: [lineX + measuredWith, y - fontSize / 3]
  674 + }
  675 + }
  676 + this.ctx.closePath();
  677 + this.ctx.strokeStyle = view.css.color;
  678 + this.ctx.stroke();
  679 + }
  680 + if (!this.isMoving) {
  681 + this.callbackInfo.lineArray ? this.callbackInfo.lineArray.push({
  682 + text,
  683 + x,
  684 + y,
  685 + measuredWith,
  686 + textDecoration
  687 + }) : this.callbackInfo.lineArray = [{
  688 + text,
  689 + x,
  690 + y,
  691 + measuredWith,
  692 + textDecoration
  693 + }]
  694 + }
  695 + }
  696 + }
  697 + }
  698 + this.ctx.restore();
  699 + this._doBorder(view, width, height);
  700 + }
  701 +
  702 + _drawAbsRect(view) {
  703 + this.ctx.save();
  704 + const {
  705 + width,
  706 + height,
  707 + } = this._preProcess(view);
  708 + if (GD.api.isGradient(view.css.color)) {
  709 + GD.api.doGradient(view.css.color, width, height, this.ctx);
  710 + } else {
  711 + this.ctx.fillStyle = view.css.color;
  712 + }
  713 + const {
  714 + borderRadius,
  715 + borderStyle,
  716 + borderWidth
  717 + } = view.css
  718 + this._border({
  719 + borderRadius,
  720 + width,
  721 + height,
  722 + borderWidth,
  723 + borderStyle
  724 + })
  725 + this.ctx.fill();
  726 + this.ctx.restore();
  727 + this._doBorder(view, width, height);
  728 + }
  729 +
  730 + // shadow 支持 (x, y, blur, color), 不支持 spread
  731 + // shadow:0px 0px 10px rgba(0,0,0,0.1);
  732 + _doShadow(view) {
  733 + if (!view.css || !view.css.shadow) {
  734 + return;
  735 + }
  736 + const box = view.css.shadow.replace(/,\s+/g, ',').split(/\s+/);
  737 + if (box.length > 4) {
  738 + console.error('shadow don\'t spread option');
  739 + return;
  740 + }
  741 + this.ctx.shadowOffsetX = parseInt(box[0], 10);
  742 + this.ctx.shadowOffsetY = parseInt(box[1], 10);
  743 + this.ctx.shadowBlur = parseInt(box[2], 10);
  744 + this.ctx.shadowColor = box[3];
  745 + }
  746 +
  747 + _getAngle(angle) {
  748 + return Number(angle) * Math.PI / 180;
  749 + }
  750 +}
... ...
packageB/components/painter/lib/qrcode.js 0 → 100644
  1 +/* eslint-disable */
  2 +!(function () {
  3 +
  4 + // alignment pattern
  5 + var adelta = [
  6 + 0, 11, 15, 19, 23, 27, 31,
  7 + 16, 18, 20, 22, 24, 26, 28, 20, 22, 24, 24, 26, 28, 28, 22, 24, 24,
  8 + 26, 26, 28, 28, 24, 24, 26, 26, 26, 28, 28, 24, 26, 26, 26, 28, 28
  9 + ];
  10 +
  11 + // version block
  12 + var vpat = [
  13 + 0xc94, 0x5bc, 0xa99, 0x4d3, 0xbf6, 0x762, 0x847, 0x60d,
  14 + 0x928, 0xb78, 0x45d, 0xa17, 0x532, 0x9a6, 0x683, 0x8c9,
  15 + 0x7ec, 0xec4, 0x1e1, 0xfab, 0x08e, 0xc1a, 0x33f, 0xd75,
  16 + 0x250, 0x9d5, 0x6f0, 0x8ba, 0x79f, 0xb0b, 0x42e, 0xa64,
  17 + 0x541, 0xc69
  18 + ];
  19 +
  20 + // final format bits with mask: level << 3 | mask
  21 + var fmtword = [
  22 + 0x77c4, 0x72f3, 0x7daa, 0x789d, 0x662f, 0x6318, 0x6c41, 0x6976, //L
  23 + 0x5412, 0x5125, 0x5e7c, 0x5b4b, 0x45f9, 0x40ce, 0x4f97, 0x4aa0, //M
  24 + 0x355f, 0x3068, 0x3f31, 0x3a06, 0x24b4, 0x2183, 0x2eda, 0x2bed, //Q
  25 + 0x1689, 0x13be, 0x1ce7, 0x19d0, 0x0762, 0x0255, 0x0d0c, 0x083b //H
  26 + ];
  27 +
  28 + // 4 per version: number of blocks 1,2; data width; ecc width
  29 + var eccblocks = [
  30 + 1, 0, 19, 7, 1, 0, 16, 10, 1, 0, 13, 13, 1, 0, 9, 17,
  31 + 1, 0, 34, 10, 1, 0, 28, 16, 1, 0, 22, 22, 1, 0, 16, 28,
  32 + 1, 0, 55, 15, 1, 0, 44, 26, 2, 0, 17, 18, 2, 0, 13, 22,
  33 + 1, 0, 80, 20, 2, 0, 32, 18, 2, 0, 24, 26, 4, 0, 9, 16,
  34 + 1, 0, 108, 26, 2, 0, 43, 24, 2, 2, 15, 18, 2, 2, 11, 22,
  35 + 2, 0, 68, 18, 4, 0, 27, 16, 4, 0, 19, 24, 4, 0, 15, 28,
  36 + 2, 0, 78, 20, 4, 0, 31, 18, 2, 4, 14, 18, 4, 1, 13, 26,
  37 + 2, 0, 97, 24, 2, 2, 38, 22, 4, 2, 18, 22, 4, 2, 14, 26,
  38 + 2, 0, 116, 30, 3, 2, 36, 22, 4, 4, 16, 20, 4, 4, 12, 24,
  39 + 2, 2, 68, 18, 4, 1, 43, 26, 6, 2, 19, 24, 6, 2, 15, 28,
  40 + 4, 0, 81, 20, 1, 4, 50, 30, 4, 4, 22, 28, 3, 8, 12, 24,
  41 + 2, 2, 92, 24, 6, 2, 36, 22, 4, 6, 20, 26, 7, 4, 14, 28,
  42 + 4, 0, 107, 26, 8, 1, 37, 22, 8, 4, 20, 24, 12, 4, 11, 22,
  43 + 3, 1, 115, 30, 4, 5, 40, 24, 11, 5, 16, 20, 11, 5, 12, 24,
  44 + 5, 1, 87, 22, 5, 5, 41, 24, 5, 7, 24, 30, 11, 7, 12, 24,
  45 + 5, 1, 98, 24, 7, 3, 45, 28, 15, 2, 19, 24, 3, 13, 15, 30,
  46 + 1, 5, 107, 28, 10, 1, 46, 28, 1, 15, 22, 28, 2, 17, 14, 28,
  47 + 5, 1, 120, 30, 9, 4, 43, 26, 17, 1, 22, 28, 2, 19, 14, 28,
  48 + 3, 4, 113, 28, 3, 11, 44, 26, 17, 4, 21, 26, 9, 16, 13, 26,
  49 + 3, 5, 107, 28, 3, 13, 41, 26, 15, 5, 24, 30, 15, 10, 15, 28,
  50 + 4, 4, 116, 28, 17, 0, 42, 26, 17, 6, 22, 28, 19, 6, 16, 30,
  51 + 2, 7, 111, 28, 17, 0, 46, 28, 7, 16, 24, 30, 34, 0, 13, 24,
  52 + 4, 5, 121, 30, 4, 14, 47, 28, 11, 14, 24, 30, 16, 14, 15, 30,
  53 + 6, 4, 117, 30, 6, 14, 45, 28, 11, 16, 24, 30, 30, 2, 16, 30,
  54 + 8, 4, 106, 26, 8, 13, 47, 28, 7, 22, 24, 30, 22, 13, 15, 30,
  55 + 10, 2, 114, 28, 19, 4, 46, 28, 28, 6, 22, 28, 33, 4, 16, 30,
  56 + 8, 4, 122, 30, 22, 3, 45, 28, 8, 26, 23, 30, 12, 28, 15, 30,
  57 + 3, 10, 117, 30, 3, 23, 45, 28, 4, 31, 24, 30, 11, 31, 15, 30,
  58 + 7, 7, 116, 30, 21, 7, 45, 28, 1, 37, 23, 30, 19, 26, 15, 30,
  59 + 5, 10, 115, 30, 19, 10, 47, 28, 15, 25, 24, 30, 23, 25, 15, 30,
  60 + 13, 3, 115, 30, 2, 29, 46, 28, 42, 1, 24, 30, 23, 28, 15, 30,
  61 + 17, 0, 115, 30, 10, 23, 46, 28, 10, 35, 24, 30, 19, 35, 15, 30,
  62 + 17, 1, 115, 30, 14, 21, 46, 28, 29, 19, 24, 30, 11, 46, 15, 30,
  63 + 13, 6, 115, 30, 14, 23, 46, 28, 44, 7, 24, 30, 59, 1, 16, 30,
  64 + 12, 7, 121, 30, 12, 26, 47, 28, 39, 14, 24, 30, 22, 41, 15, 30,
  65 + 6, 14, 121, 30, 6, 34, 47, 28, 46, 10, 24, 30, 2, 64, 15, 30,
  66 + 17, 4, 122, 30, 29, 14, 46, 28, 49, 10, 24, 30, 24, 46, 15, 30,
  67 + 4, 18, 122, 30, 13, 32, 46, 28, 48, 14, 24, 30, 42, 32, 15, 30,
  68 + 20, 4, 117, 30, 40, 7, 47, 28, 43, 22, 24, 30, 10, 67, 15, 30,
  69 + 19, 6, 118, 30, 18, 31, 47, 28, 34, 34, 24, 30, 20, 61, 15, 30
  70 + ];
  71 +
  72 + // Galois field log table
  73 + var glog = [
  74 + 0xff, 0x00, 0x01, 0x19, 0x02, 0x32, 0x1a, 0xc6, 0x03, 0xdf, 0x33, 0xee, 0x1b, 0x68, 0xc7, 0x4b,
  75 + 0x04, 0x64, 0xe0, 0x0e, 0x34, 0x8d, 0xef, 0x81, 0x1c, 0xc1, 0x69, 0xf8, 0xc8, 0x08, 0x4c, 0x71,
  76 + 0x05, 0x8a, 0x65, 0x2f, 0xe1, 0x24, 0x0f, 0x21, 0x35, 0x93, 0x8e, 0xda, 0xf0, 0x12, 0x82, 0x45,
  77 + 0x1d, 0xb5, 0xc2, 0x7d, 0x6a, 0x27, 0xf9, 0xb9, 0xc9, 0x9a, 0x09, 0x78, 0x4d, 0xe4, 0x72, 0xa6,
  78 + 0x06, 0xbf, 0x8b, 0x62, 0x66, 0xdd, 0x30, 0xfd, 0xe2, 0x98, 0x25, 0xb3, 0x10, 0x91, 0x22, 0x88,
  79 + 0x36, 0xd0, 0x94, 0xce, 0x8f, 0x96, 0xdb, 0xbd, 0xf1, 0xd2, 0x13, 0x5c, 0x83, 0x38, 0x46, 0x40,
  80 + 0x1e, 0x42, 0xb6, 0xa3, 0xc3, 0x48, 0x7e, 0x6e, 0x6b, 0x3a, 0x28, 0x54, 0xfa, 0x85, 0xba, 0x3d,
  81 + 0xca, 0x5e, 0x9b, 0x9f, 0x0a, 0x15, 0x79, 0x2b, 0x4e, 0xd4, 0xe5, 0xac, 0x73, 0xf3, 0xa7, 0x57,
  82 + 0x07, 0x70, 0xc0, 0xf7, 0x8c, 0x80, 0x63, 0x0d, 0x67, 0x4a, 0xde, 0xed, 0x31, 0xc5, 0xfe, 0x18,
  83 + 0xe3, 0xa5, 0x99, 0x77, 0x26, 0xb8, 0xb4, 0x7c, 0x11, 0x44, 0x92, 0xd9, 0x23, 0x20, 0x89, 0x2e,
  84 + 0x37, 0x3f, 0xd1, 0x5b, 0x95, 0xbc, 0xcf, 0xcd, 0x90, 0x87, 0x97, 0xb2, 0xdc, 0xfc, 0xbe, 0x61,
  85 + 0xf2, 0x56, 0xd3, 0xab, 0x14, 0x2a, 0x5d, 0x9e, 0x84, 0x3c, 0x39, 0x53, 0x47, 0x6d, 0x41, 0xa2,
  86 + 0x1f, 0x2d, 0x43, 0xd8, 0xb7, 0x7b, 0xa4, 0x76, 0xc4, 0x17, 0x49, 0xec, 0x7f, 0x0c, 0x6f, 0xf6,
  87 + 0x6c, 0xa1, 0x3b, 0x52, 0x29, 0x9d, 0x55, 0xaa, 0xfb, 0x60, 0x86, 0xb1, 0xbb, 0xcc, 0x3e, 0x5a,
  88 + 0xcb, 0x59, 0x5f, 0xb0, 0x9c, 0xa9, 0xa0, 0x51, 0x0b, 0xf5, 0x16, 0xeb, 0x7a, 0x75, 0x2c, 0xd7,
  89 + 0x4f, 0xae, 0xd5, 0xe9, 0xe6, 0xe7, 0xad, 0xe8, 0x74, 0xd6, 0xf4, 0xea, 0xa8, 0x50, 0x58, 0xaf
  90 + ];
  91 +
  92 + // Galios field exponent table
  93 + var gexp = [
  94 + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1d, 0x3a, 0x74, 0xe8, 0xcd, 0x87, 0x13, 0x26,
  95 + 0x4c, 0x98, 0x2d, 0x5a, 0xb4, 0x75, 0xea, 0xc9, 0x8f, 0x03, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0,
  96 + 0x9d, 0x27, 0x4e, 0x9c, 0x25, 0x4a, 0x94, 0x35, 0x6a, 0xd4, 0xb5, 0x77, 0xee, 0xc1, 0x9f, 0x23,
  97 + 0x46, 0x8c, 0x05, 0x0a, 0x14, 0x28, 0x50, 0xa0, 0x5d, 0xba, 0x69, 0xd2, 0xb9, 0x6f, 0xde, 0xa1,
  98 + 0x5f, 0xbe, 0x61, 0xc2, 0x99, 0x2f, 0x5e, 0xbc, 0x65, 0xca, 0x89, 0x0f, 0x1e, 0x3c, 0x78, 0xf0,
  99 + 0xfd, 0xe7, 0xd3, 0xbb, 0x6b, 0xd6, 0xb1, 0x7f, 0xfe, 0xe1, 0xdf, 0xa3, 0x5b, 0xb6, 0x71, 0xe2,
  100 + 0xd9, 0xaf, 0x43, 0x86, 0x11, 0x22, 0x44, 0x88, 0x0d, 0x1a, 0x34, 0x68, 0xd0, 0xbd, 0x67, 0xce,
  101 + 0x81, 0x1f, 0x3e, 0x7c, 0xf8, 0xed, 0xc7, 0x93, 0x3b, 0x76, 0xec, 0xc5, 0x97, 0x33, 0x66, 0xcc,
  102 + 0x85, 0x17, 0x2e, 0x5c, 0xb8, 0x6d, 0xda, 0xa9, 0x4f, 0x9e, 0x21, 0x42, 0x84, 0x15, 0x2a, 0x54,
  103 + 0xa8, 0x4d, 0x9a, 0x29, 0x52, 0xa4, 0x55, 0xaa, 0x49, 0x92, 0x39, 0x72, 0xe4, 0xd5, 0xb7, 0x73,
  104 + 0xe6, 0xd1, 0xbf, 0x63, 0xc6, 0x91, 0x3f, 0x7e, 0xfc, 0xe5, 0xd7, 0xb3, 0x7b, 0xf6, 0xf1, 0xff,
  105 + 0xe3, 0xdb, 0xab, 0x4b, 0x96, 0x31, 0x62, 0xc4, 0x95, 0x37, 0x6e, 0xdc, 0xa5, 0x57, 0xae, 0x41,
  106 + 0x82, 0x19, 0x32, 0x64, 0xc8, 0x8d, 0x07, 0x0e, 0x1c, 0x38, 0x70, 0xe0, 0xdd, 0xa7, 0x53, 0xa6,
  107 + 0x51, 0xa2, 0x59, 0xb2, 0x79, 0xf2, 0xf9, 0xef, 0xc3, 0x9b, 0x2b, 0x56, 0xac, 0x45, 0x8a, 0x09,
  108 + 0x12, 0x24, 0x48, 0x90, 0x3d, 0x7a, 0xf4, 0xf5, 0xf7, 0xf3, 0xfb, 0xeb, 0xcb, 0x8b, 0x0b, 0x16,
  109 + 0x2c, 0x58, 0xb0, 0x7d, 0xfa, 0xe9, 0xcf, 0x83, 0x1b, 0x36, 0x6c, 0xd8, 0xad, 0x47, 0x8e, 0x00
  110 + ];
  111 +
  112 + // Working buffers:
  113 + // data input and ecc append, image working buffer, fixed part of image, run lengths for badness
  114 + var strinbuf = [], eccbuf = [], qrframe = [], framask = [], rlens = [];
  115 + // Control values - width is based on version, last 4 are from table.
  116 + var version, width, neccblk1, neccblk2, datablkw, eccblkwid;
  117 + var ecclevel = 2;
  118 + // set bit to indicate cell in qrframe is immutable. symmetric around diagonal
  119 + function setmask(x, y) {
  120 + var bt;
  121 + if (x > y) {
  122 + bt = x;
  123 + x = y;
  124 + y = bt;
  125 + }
  126 + // y*y = 1+3+5...
  127 + bt = y;
  128 + bt *= y;
  129 + bt += y;
  130 + bt >>= 1;
  131 + bt += x;
  132 + framask[bt] = 1;
  133 + }
  134 +
  135 + // enter alignment pattern - black to qrframe, white to mask (later black frame merged to mask)
  136 + function putalign(x, y) {
  137 + var j;
  138 +
  139 + qrframe[x + width * y] = 1;
  140 + for (j = -2; j < 2; j++) {
  141 + qrframe[(x + j) + width * (y - 2)] = 1;
  142 + qrframe[(x - 2) + width * (y + j + 1)] = 1;
  143 + qrframe[(x + 2) + width * (y + j)] = 1;
  144 + qrframe[(x + j + 1) + width * (y + 2)] = 1;
  145 + }
  146 + for (j = 0; j < 2; j++) {
  147 + setmask(x - 1, y + j);
  148 + setmask(x + 1, y - j);
  149 + setmask(x - j, y - 1);
  150 + setmask(x + j, y + 1);
  151 + }
  152 + }
  153 +
  154 + //========================================================================
  155 + // Reed Solomon error correction
  156 + // exponentiation mod N
  157 + function modnn(x) {
  158 + while (x >= 255) {
  159 + x -= 255;
  160 + x = (x >> 8) + (x & 255);
  161 + }
  162 + return x;
  163 + }
  164 +
  165 + var genpoly = [];
  166 +
  167 + // Calculate and append ECC data to data block. Block is in strinbuf, indexes to buffers given.
  168 + function appendrs(data, dlen, ecbuf, eclen) {
  169 + var i, j, fb;
  170 +
  171 + for (i = 0; i < eclen; i++)
  172 + strinbuf[ecbuf + i] = 0;
  173 + for (i = 0; i < dlen; i++) {
  174 + fb = glog[strinbuf[data + i] ^ strinbuf[ecbuf]];
  175 + if (fb != 255) /* fb term is non-zero */
  176 + for (j = 1; j < eclen; j++)
  177 + strinbuf[ecbuf + j - 1] = strinbuf[ecbuf + j] ^ gexp[modnn(fb + genpoly[eclen - j])];
  178 + else
  179 + for (j = ecbuf; j < ecbuf + eclen; j++)
  180 + strinbuf[j] = strinbuf[j + 1];
  181 + strinbuf[ecbuf + eclen - 1] = fb == 255 ? 0 : gexp[modnn(fb + genpoly[0])];
  182 + }
  183 + }
  184 +
  185 + //========================================================================
  186 + // Frame data insert following the path rules
  187 +
  188 + // check mask - since symmetrical use half.
  189 + function ismasked(x, y) {
  190 + var bt;
  191 + if (x > y) {
  192 + bt = x;
  193 + x = y;
  194 + y = bt;
  195 + }
  196 + bt = y;
  197 + bt += y * y;
  198 + bt >>= 1;
  199 + bt += x;
  200 + return framask[bt];
  201 + }
  202 +
  203 + //========================================================================
  204 + // Apply the selected mask out of the 8.
  205 + function applymask(m) {
  206 + var x, y, r3x, r3y;
  207 +
  208 + switch (m) {
  209 + case 0:
  210 + for (y = 0; y < width; y++)
  211 + for (x = 0; x < width; x++)
  212 + if (!((x + y) & 1) && !ismasked(x, y))
  213 + qrframe[x + y * width] ^= 1;
  214 + break;
  215 + case 1:
  216 + for (y = 0; y < width; y++)
  217 + for (x = 0; x < width; x++)
  218 + if (!(y & 1) && !ismasked(x, y))
  219 + qrframe[x + y * width] ^= 1;
  220 + break;
  221 + case 2:
  222 + for (y = 0; y < width; y++)
  223 + for (r3x = 0, x = 0; x < width; x++ , r3x++) {
  224 + if (r3x == 3)
  225 + r3x = 0;
  226 + if (!r3x && !ismasked(x, y))
  227 + qrframe[x + y * width] ^= 1;
  228 + }
  229 + break;
  230 + case 3:
  231 + for (r3y = 0, y = 0; y < width; y++ , r3y++) {
  232 + if (r3y == 3)
  233 + r3y = 0;
  234 + for (r3x = r3y, x = 0; x < width; x++ , r3x++) {
  235 + if (r3x == 3)
  236 + r3x = 0;
  237 + if (!r3x && !ismasked(x, y))
  238 + qrframe[x + y * width] ^= 1;
  239 + }
  240 + }
  241 + break;
  242 + case 4:
  243 + for (y = 0; y < width; y++)
  244 + for (r3x = 0, r3y = ((y >> 1) & 1), x = 0; x < width; x++ , r3x++) {
  245 + if (r3x == 3) {
  246 + r3x = 0;
  247 + r3y = !r3y;
  248 + }
  249 + if (!r3y && !ismasked(x, y))
  250 + qrframe[x + y * width] ^= 1;
  251 + }
  252 + break;
  253 + case 5:
  254 + for (r3y = 0, y = 0; y < width; y++ , r3y++) {
  255 + if (r3y == 3)
  256 + r3y = 0;
  257 + for (r3x = 0, x = 0; x < width; x++ , r3x++) {
  258 + if (r3x == 3)
  259 + r3x = 0;
  260 + if (!((x & y & 1) + !(!r3x | !r3y)) && !ismasked(x, y))
  261 + qrframe[x + y * width] ^= 1;
  262 + }
  263 + }
  264 + break;
  265 + case 6:
  266 + for (r3y = 0, y = 0; y < width; y++ , r3y++) {
  267 + if (r3y == 3)
  268 + r3y = 0;
  269 + for (r3x = 0, x = 0; x < width; x++ , r3x++) {
  270 + if (r3x == 3)
  271 + r3x = 0;
  272 + if (!(((x & y & 1) + (r3x && (r3x == r3y))) & 1) && !ismasked(x, y))
  273 + qrframe[x + y * width] ^= 1;
  274 + }
  275 + }
  276 + break;
  277 + case 7:
  278 + for (r3y = 0, y = 0; y < width; y++ , r3y++) {
  279 + if (r3y == 3)
  280 + r3y = 0;
  281 + for (r3x = 0, x = 0; x < width; x++ , r3x++) {
  282 + if (r3x == 3)
  283 + r3x = 0;
  284 + if (!(((r3x && (r3x == r3y)) + ((x + y) & 1)) & 1) && !ismasked(x, y))
  285 + qrframe[x + y * width] ^= 1;
  286 + }
  287 + }
  288 + break;
  289 + }
  290 + return;
  291 + }
  292 +
  293 + // Badness coefficients.
  294 + var N1 = 3, N2 = 3, N3 = 40, N4 = 10;
  295 +
  296 + // Using the table of the length of each run, calculate the amount of bad image
  297 + // - long runs or those that look like finders; called twice, once each for X and Y
  298 + function badruns(length) {
  299 + var i;
  300 + var runsbad = 0;
  301 + for (i = 0; i <= length; i++)
  302 + if (rlens[i] >= 5)
  303 + runsbad += N1 + rlens[i] - 5;
  304 + // BwBBBwB as in finder
  305 + for (i = 3; i < length - 1; i += 2)
  306 + if (rlens[i - 2] == rlens[i + 2]
  307 + && rlens[i + 2] == rlens[i - 1]
  308 + && rlens[i - 1] == rlens[i + 1]
  309 + && rlens[i - 1] * 3 == rlens[i]
  310 + // white around the black pattern? Not part of spec
  311 + && (rlens[i - 3] == 0 // beginning
  312 + || i + 3 > length // end
  313 + || rlens[i - 3] * 3 >= rlens[i] * 4 || rlens[i + 3] * 3 >= rlens[i] * 4)
  314 + )
  315 + runsbad += N3;
  316 + return runsbad;
  317 + }
  318 +
  319 + // Calculate how bad the masked image is - blocks, imbalance, runs, or finders.
  320 + function badcheck() {
  321 + var x, y, h, b, b1;
  322 + var thisbad = 0;
  323 + var bw = 0;
  324 +
  325 + // blocks of same color.
  326 + for (y = 0; y < width - 1; y++)
  327 + for (x = 0; x < width - 1; x++)
  328 + if ((qrframe[x + width * y] && qrframe[(x + 1) + width * y]
  329 + && qrframe[x + width * (y + 1)] && qrframe[(x + 1) + width * (y + 1)]) // all black
  330 + || !(qrframe[x + width * y] || qrframe[(x + 1) + width * y]
  331 + || qrframe[x + width * (y + 1)] || qrframe[(x + 1) + width * (y + 1)])) // all white
  332 + thisbad += N2;
  333 +
  334 + // X runs
  335 + for (y = 0; y < width; y++) {
  336 + rlens[0] = 0;
  337 + for (h = b = x = 0; x < width; x++) {
  338 + if ((b1 = qrframe[x + width * y]) == b)
  339 + rlens[h]++;
  340 + else
  341 + rlens[++h] = 1;
  342 + b = b1;
  343 + bw += b ? 1 : -1;
  344 + }
  345 + thisbad += badruns(h);
  346 + }
  347 +
  348 + // black/white imbalance
  349 + if (bw < 0)
  350 + bw = -bw;
  351 +
  352 + var big = bw;
  353 + var count = 0;
  354 + big += big << 2;
  355 + big <<= 1;
  356 + while (big > width * width)
  357 + big -= width * width, count++;
  358 + thisbad += count * N4;
  359 +
  360 + // Y runs
  361 + for (x = 0; x < width; x++) {
  362 + rlens[0] = 0;
  363 + for (h = b = y = 0; y < width; y++) {
  364 + if ((b1 = qrframe[x + width * y]) == b)
  365 + rlens[h]++;
  366 + else
  367 + rlens[++h] = 1;
  368 + b = b1;
  369 + }
  370 + thisbad += badruns(h);
  371 + }
  372 + return thisbad;
  373 + }
  374 +
  375 + function genframe(instring) {
  376 + var x, y, k, t, v, i, j, m;
  377 +
  378 + // find the smallest version that fits the string
  379 + t = instring.length;
  380 + version = 0;
  381 + do {
  382 + version++;
  383 + k = (ecclevel - 1) * 4 + (version - 1) * 16;
  384 + neccblk1 = eccblocks[k++];
  385 + neccblk2 = eccblocks[k++];
  386 + datablkw = eccblocks[k++];
  387 + eccblkwid = eccblocks[k];
  388 + k = datablkw * (neccblk1 + neccblk2) + neccblk2 - 3 + (version <= 9);
  389 + if (t <= k)
  390 + break;
  391 + } while (version < 40);
  392 +
  393 + // FIXME - insure that it fits insted of being truncated
  394 + width = 17 + 4 * version;
  395 +
  396 + // allocate, clear and setup data structures
  397 + v = datablkw + (datablkw + eccblkwid) * (neccblk1 + neccblk2) + neccblk2;
  398 + for (t = 0; t < v; t++)
  399 + eccbuf[t] = 0;
  400 + strinbuf = instring.slice(0);
  401 +
  402 + for (t = 0; t < width * width; t++)
  403 + qrframe[t] = 0;
  404 +
  405 + for (t = 0; t < (width * (width + 1) + 1) / 2; t++)
  406 + framask[t] = 0;
  407 +
  408 + // insert finders - black to frame, white to mask
  409 + for (t = 0; t < 3; t++) {
  410 + k = 0;
  411 + y = 0;
  412 + if (t == 1)
  413 + k = (width - 7);
  414 + if (t == 2)
  415 + y = (width - 7);
  416 + qrframe[(y + 3) + width * (k + 3)] = 1;
  417 + for (x = 0; x < 6; x++) {
  418 + qrframe[(y + x) + width * k] = 1;
  419 + qrframe[y + width * (k + x + 1)] = 1;
  420 + qrframe[(y + 6) + width * (k + x)] = 1;
  421 + qrframe[(y + x + 1) + width * (k + 6)] = 1;
  422 + }
  423 + for (x = 1; x < 5; x++) {
  424 + setmask(y + x, k + 1);
  425 + setmask(y + 1, k + x + 1);
  426 + setmask(y + 5, k + x);
  427 + setmask(y + x + 1, k + 5);
  428 + }
  429 + for (x = 2; x < 4; x++) {
  430 + qrframe[(y + x) + width * (k + 2)] = 1;
  431 + qrframe[(y + 2) + width * (k + x + 1)] = 1;
  432 + qrframe[(y + 4) + width * (k + x)] = 1;
  433 + qrframe[(y + x + 1) + width * (k + 4)] = 1;
  434 + }
  435 + }
  436 +
  437 + // alignment blocks
  438 + if (version > 1) {
  439 + t = adelta[version];
  440 + y = width - 7;
  441 + for (; ;) {
  442 + x = width - 7;
  443 + while (x > t - 3) {
  444 + putalign(x, y);
  445 + if (x < t)
  446 + break;
  447 + x -= t;
  448 + }
  449 + if (y <= t + 9)
  450 + break;
  451 + y -= t;
  452 + putalign(6, y);
  453 + putalign(y, 6);
  454 + }
  455 + }
  456 +
  457 + // single black
  458 + qrframe[8 + width * (width - 8)] = 1;
  459 +
  460 + // timing gap - mask only
  461 + for (y = 0; y < 7; y++) {
  462 + setmask(7, y);
  463 + setmask(width - 8, y);
  464 + setmask(7, y + width - 7);
  465 + }
  466 + for (x = 0; x < 8; x++) {
  467 + setmask(x, 7);
  468 + setmask(x + width - 8, 7);
  469 + setmask(x, width - 8);
  470 + }
  471 +
  472 + // reserve mask-format area
  473 + for (x = 0; x < 9; x++)
  474 + setmask(x, 8);
  475 + for (x = 0; x < 8; x++) {
  476 + setmask(x + width - 8, 8);
  477 + setmask(8, x);
  478 + }
  479 + for (y = 0; y < 7; y++)
  480 + setmask(8, y + width - 7);
  481 +
  482 + // timing row/col
  483 + for (x = 0; x < width - 14; x++)
  484 + if (x & 1) {
  485 + setmask(8 + x, 6);
  486 + setmask(6, 8 + x);
  487 + }
  488 + else {
  489 + qrframe[(8 + x) + width * 6] = 1;
  490 + qrframe[6 + width * (8 + x)] = 1;
  491 + }
  492 +
  493 + // version block
  494 + if (version > 6) {
  495 + t = vpat[version - 7];
  496 + k = 17;
  497 + for (x = 0; x < 6; x++)
  498 + for (y = 0; y < 3; y++ , k--)
  499 + if (1 & (k > 11 ? version >> (k - 12) : t >> k)) {
  500 + qrframe[(5 - x) + width * (2 - y + width - 11)] = 1;
  501 + qrframe[(2 - y + width - 11) + width * (5 - x)] = 1;
  502 + }
  503 + else {
  504 + setmask(5 - x, 2 - y + width - 11);
  505 + setmask(2 - y + width - 11, 5 - x);
  506 + }
  507 + }
  508 +
  509 + // sync mask bits - only set above for white spaces, so add in black bits
  510 + for (y = 0; y < width; y++)
  511 + for (x = 0; x <= y; x++)
  512 + if (qrframe[x + width * y])
  513 + setmask(x, y);
  514 +
  515 + // convert string to bitstream
  516 + // 8 bit data to QR-coded 8 bit data (numeric or alphanum, or kanji not supported)
  517 + v = strinbuf.length;
  518 +
  519 + // string to array
  520 + for (i = 0; i < v; i++)
  521 + eccbuf[i] = strinbuf.charCodeAt(i);
  522 + strinbuf = eccbuf.slice(0);
  523 +
  524 + // calculate max string length
  525 + x = datablkw * (neccblk1 + neccblk2) + neccblk2;
  526 + if (v >= x - 2) {
  527 + v = x - 2;
  528 + if (version > 9)
  529 + v--;
  530 + }
  531 +
  532 + // shift and repack to insert length prefix
  533 + i = v;
  534 + if (version > 9) {
  535 + strinbuf[i + 2] = 0;
  536 + strinbuf[i + 3] = 0;
  537 + while (i--) {
  538 + t = strinbuf[i];
  539 + strinbuf[i + 3] |= 255 & (t << 4);
  540 + strinbuf[i + 2] = t >> 4;
  541 + }
  542 + strinbuf[2] |= 255 & (v << 4);
  543 + strinbuf[1] = v >> 4;
  544 + strinbuf[0] = 0x40 | (v >> 12);
  545 + }
  546 + else {
  547 + strinbuf[i + 1] = 0;
  548 + strinbuf[i + 2] = 0;
  549 + while (i--) {
  550 + t = strinbuf[i];
  551 + strinbuf[i + 2] |= 255 & (t << 4);
  552 + strinbuf[i + 1] = t >> 4;
  553 + }
  554 + strinbuf[1] |= 255 & (v << 4);
  555 + strinbuf[0] = 0x40 | (v >> 4);
  556 + }
  557 + // fill to end with pad pattern
  558 + i = v + 3 - (version < 10);
  559 + while (i < x) {
  560 + strinbuf[i++] = 0xec;
  561 + // buffer has room if (i == x) break;
  562 + strinbuf[i++] = 0x11;
  563 + }
  564 +
  565 + // calculate and append ECC
  566 +
  567 + // calculate generator polynomial
  568 + genpoly[0] = 1;
  569 + for (i = 0; i < eccblkwid; i++) {
  570 + genpoly[i + 1] = 1;
  571 + for (j = i; j > 0; j--)
  572 + genpoly[j] = genpoly[j]
  573 + ? genpoly[j - 1] ^ gexp[modnn(glog[genpoly[j]] + i)] : genpoly[j - 1];
  574 + genpoly[0] = gexp[modnn(glog[genpoly[0]] + i)];
  575 + }
  576 + for (i = 0; i <= eccblkwid; i++)
  577 + genpoly[i] = glog[genpoly[i]]; // use logs for genpoly[] to save calc step
  578 +
  579 + // append ecc to data buffer
  580 + k = x;
  581 + y = 0;
  582 + for (i = 0; i < neccblk1; i++) {
  583 + appendrs(y, datablkw, k, eccblkwid);
  584 + y += datablkw;
  585 + k += eccblkwid;
  586 + }
  587 + for (i = 0; i < neccblk2; i++) {
  588 + appendrs(y, datablkw + 1, k, eccblkwid);
  589 + y += datablkw + 1;
  590 + k += eccblkwid;
  591 + }
  592 + // interleave blocks
  593 + y = 0;
  594 + for (i = 0; i < datablkw; i++) {
  595 + for (j = 0; j < neccblk1; j++)
  596 + eccbuf[y++] = strinbuf[i + j * datablkw];
  597 + for (j = 0; j < neccblk2; j++)
  598 + eccbuf[y++] = strinbuf[(neccblk1 * datablkw) + i + (j * (datablkw + 1))];
  599 + }
  600 + for (j = 0; j < neccblk2; j++)
  601 + eccbuf[y++] = strinbuf[(neccblk1 * datablkw) + i + (j * (datablkw + 1))];
  602 + for (i = 0; i < eccblkwid; i++)
  603 + for (j = 0; j < neccblk1 + neccblk2; j++)
  604 + eccbuf[y++] = strinbuf[x + i + j * eccblkwid];
  605 + strinbuf = eccbuf;
  606 +
  607 + // pack bits into frame avoiding masked area.
  608 + x = y = width - 1;
  609 + k = v = 1; // up, minus
  610 + /* inteleaved data and ecc codes */
  611 + m = (datablkw + eccblkwid) * (neccblk1 + neccblk2) + neccblk2;
  612 + for (i = 0; i < m; i++) {
  613 + t = strinbuf[i];
  614 + for (j = 0; j < 8; j++ , t <<= 1) {
  615 + if (0x80 & t)
  616 + qrframe[x + width * y] = 1;
  617 + do { // find next fill position
  618 + if (v)
  619 + x--;
  620 + else {
  621 + x++;
  622 + if (k) {
  623 + if (y != 0)
  624 + y--;
  625 + else {
  626 + x -= 2;
  627 + k = !k;
  628 + if (x == 6) {
  629 + x--;
  630 + y = 9;
  631 + }
  632 + }
  633 + }
  634 + else {
  635 + if (y != width - 1)
  636 + y++;
  637 + else {
  638 + x -= 2;
  639 + k = !k;
  640 + if (x == 6) {
  641 + x--;
  642 + y -= 8;
  643 + }
  644 + }
  645 + }
  646 + }
  647 + v = !v;
  648 + } while (ismasked(x, y));
  649 + }
  650 + }
  651 +
  652 + // save pre-mask copy of frame
  653 + strinbuf = qrframe.slice(0);
  654 + t = 0; // best
  655 + y = 30000; // demerit
  656 + // for instead of while since in original arduino code
  657 + // if an early mask was "good enough" it wouldn't try for a better one
  658 + // since they get more complex and take longer.
  659 + for (k = 0; k < 8; k++) {
  660 + applymask(k); // returns black-white imbalance
  661 + x = badcheck();
  662 + if (x < y) { // current mask better than previous best?
  663 + y = x;
  664 + t = k;
  665 + }
  666 + if (t == 7)
  667 + break; // don't increment i to a void redoing mask
  668 + qrframe = strinbuf.slice(0); // reset for next pass
  669 + }
  670 + if (t != k) // redo best mask - none good enough, last wasn't t
  671 + applymask(t);
  672 +
  673 + // add in final mask/ecclevel bytes
  674 + y = fmtword[t + ((ecclevel - 1) << 3)];
  675 + // low byte
  676 + for (k = 0; k < 8; k++ , y >>= 1)
  677 + if (y & 1) {
  678 + qrframe[(width - 1 - k) + width * 8] = 1;
  679 + if (k < 6)
  680 + qrframe[8 + width * k] = 1;
  681 + else
  682 + qrframe[8 + width * (k + 1)] = 1;
  683 + }
  684 + // high byte
  685 + for (k = 0; k < 7; k++ , y >>= 1)
  686 + if (y & 1) {
  687 + qrframe[8 + width * (width - 7 + k)] = 1;
  688 + if (k)
  689 + qrframe[(6 - k) + width * 8] = 1;
  690 + else
  691 + qrframe[7 + width * 8] = 1;
  692 + }
  693 + return qrframe;
  694 + }
  695 +
  696 +
  697 +
  698 +
  699 + var _canvas = null;
  700 +
  701 + var api = {
  702 +
  703 + get ecclevel() {
  704 + return ecclevel;
  705 + },
  706 +
  707 + set ecclevel(val) {
  708 + ecclevel = val;
  709 + },
  710 +
  711 + get size() {
  712 + return _size;
  713 + },
  714 +
  715 + set size(val) {
  716 + _size = val
  717 + },
  718 +
  719 + get canvas() {
  720 + return _canvas;
  721 + },
  722 +
  723 + set canvas(el) {
  724 + _canvas = el;
  725 + },
  726 +
  727 + getFrame: function (string) {
  728 + return genframe(string);
  729 + },
  730 + //这里的utf16to8(str)是对Text中的字符串进行转码,让其支持中文
  731 + utf16to8: function (str) {
  732 + var out, i, len, c;
  733 +
  734 + out = "";
  735 + len = str.length;
  736 + for (i = 0; i < len; i++) {
  737 + c = str.charCodeAt(i);
  738 + if ((c >= 0x0001) && (c <= 0x007F)) {
  739 + out += str.charAt(i);
  740 + } else if (c > 0x07FF) {
  741 + out += String.fromCharCode(0xE0 | ((c >> 12) & 0x0F));
  742 + out += String.fromCharCode(0x80 | ((c >> 6) & 0x3F));
  743 + out += String.fromCharCode(0x80 | ((c >> 0) & 0x3F));
  744 + } else {
  745 + out += String.fromCharCode(0xC0 | ((c >> 6) & 0x1F));
  746 + out += String.fromCharCode(0x80 | ((c >> 0) & 0x3F));
  747 + }
  748 + }
  749 + return out;
  750 + },
  751 + /**
  752 + * 新增$this参数,传入组件的this,兼容在组件中生成
  753 + * @param bg 目前只能设置颜色值
  754 + */
  755 + draw: function (str, ctx, startX, startY, cavW, cavH, bg, color, $this, ecc) {
  756 + var that = this;
  757 + ecclevel = ecc || ecclevel;
  758 + if (!ctx) {
  759 + console.warn('No canvas provided to draw QR code in!')
  760 + return;
  761 + }
  762 + var size = Math.min(cavW, cavH);
  763 + str = that.utf16to8(str);//增加中文显示
  764 +
  765 + var frame = that.getFrame(str);
  766 + var px = size / width;
  767 + if (bg) {
  768 + ctx.fillStyle = bg;
  769 + ctx.fillRect(startX, startY, cavW, cavW);
  770 + }
  771 + ctx.fillStyle = color || 'black';
  772 + for (var i = 0; i < width; i++) {
  773 + for (var j = 0; j < width; j++) {
  774 + if (frame[j * width + i]) {
  775 + ctx.fillRect(startX + px * i, startY + px * j, px, px);
  776 + }
  777 + }
  778 + }
  779 + }
  780 + }
  781 + module.exports = { api }
  782 + // exports.draw = api;
  783 +
  784 +})();
0 785 \ No newline at end of file
... ...
packageB/components/painter/lib/util.js 0 → 100644
  1 +
  2 +function isValidUrl(url) {
  3 + return /(ht|f)tp(s?):\/\/([^ \\/]*\.)+[^ \\/]*(:[0-9]+)?\/?/.test(url);
  4 +}
  5 +
  6 +/**
  7 + * 深度对比两个对象是否一致
  8 + * from: https://github.com/epoberezkin/fast-deep-equal
  9 + * @param {Object} a 对象a
  10 + * @param {Object} b 对象b
  11 + * @return {Boolean} 是否相同
  12 + */
  13 +/* eslint-disable */
  14 +function equal(a, b) {
  15 + if (a === b) return true;
  16 +
  17 + if (a && b && typeof a == 'object' && typeof b == 'object') {
  18 + var arrA = Array.isArray(a)
  19 + , arrB = Array.isArray(b)
  20 + , i
  21 + , length
  22 + , key;
  23 +
  24 + if (arrA && arrB) {
  25 + length = a.length;
  26 + if (length != b.length) return false;
  27 + for (i = length; i-- !== 0;)
  28 + if (!equal(a[i], b[i])) return false;
  29 + return true;
  30 + }
  31 +
  32 + if (arrA != arrB) return false;
  33 +
  34 + var dateA = a instanceof Date
  35 + , dateB = b instanceof Date;
  36 + if (dateA != dateB) return false;
  37 + if (dateA && dateB) return a.getTime() == b.getTime();
  38 +
  39 + var regexpA = a instanceof RegExp
  40 + , regexpB = b instanceof RegExp;
  41 + if (regexpA != regexpB) return false;
  42 + if (regexpA && regexpB) return a.toString() == b.toString();
  43 +
  44 + var keys = Object.keys(a);
  45 + length = keys.length;
  46 +
  47 + if (length !== Object.keys(b).length)
  48 + return false;
  49 +
  50 + for (i = length; i-- !== 0;)
  51 + if (!Object.prototype.hasOwnProperty.call(b, keys[i])) return false;
  52 +
  53 + for (i = length; i-- !== 0;) {
  54 + key = keys[i];
  55 + if (!equal(a[key], b[key])) return false;
  56 + }
  57 +
  58 + return true;
  59 + }
  60 +
  61 + return a!==a && b!==b;
  62 +}
  63 +
  64 +module.exports = {
  65 + isValidUrl,
  66 + equal
  67 +};
  68 +
... ...
packageB/components/painter/lib/wx-canvas.js 0 → 100644
  1 +// @ts-check
  2 +export default class WxCanvas {
  3 + ctx;
  4 + type;
  5 + canvasId;
  6 + canvasNode;
  7 + stepList = [];
  8 + canvasPrototype = {};
  9 +
  10 + constructor(type, ctx, canvasId, isNew, canvasNode) {
  11 + this.ctx = ctx;
  12 + this.canvasId = canvasId;
  13 + this.type = type;
  14 + if (isNew) {
  15 + this.canvasNode = canvasNode || {};
  16 + }
  17 + }
  18 +
  19 + set width(w) {
  20 + if (this.canvasNode) this.canvasNode.width = w;
  21 + }
  22 +
  23 + get width() {
  24 + if (this.canvasNode) return this.canvasNode.width;
  25 + return 0;
  26 + }
  27 +
  28 + set height(h) {
  29 + if (this.canvasNode) this.canvasNode.height = h;
  30 + }
  31 +
  32 + get height() {
  33 + if (this.canvasNode) return this.canvasNode.height;
  34 + return 0;
  35 + }
  36 +
  37 + set lineWidth(args) {
  38 + this.canvasPrototype.lineWidth = args;
  39 + this.stepList.push({
  40 + action: "lineWidth",
  41 + args,
  42 + actionType: "set",
  43 + });
  44 + }
  45 +
  46 + get lineWidth() {
  47 + return this.canvasPrototype.lineWidth;
  48 + }
  49 +
  50 + set lineCap(args) {
  51 + this.canvasPrototype.lineCap = args;
  52 + this.stepList.push({
  53 + action: "lineCap",
  54 + args,
  55 + actionType: "set",
  56 + });
  57 + }
  58 +
  59 + get lineCap() {
  60 + return this.canvasPrototype.lineCap;
  61 + }
  62 +
  63 + set lineJoin(args) {
  64 + this.canvasPrototype.lineJoin = args;
  65 + this.stepList.push({
  66 + action: "lineJoin",
  67 + args,
  68 + actionType: "set",
  69 + });
  70 + }
  71 +
  72 + get lineJoin() {
  73 + return this.canvasPrototype.lineJoin;
  74 + }
  75 +
  76 + set miterLimit(args) {
  77 + this.canvasPrototype.miterLimit = args;
  78 + this.stepList.push({
  79 + action: "miterLimit",
  80 + args,
  81 + actionType: "set",
  82 + });
  83 + }
  84 +
  85 + get miterLimit() {
  86 + return this.canvasPrototype.miterLimit;
  87 + }
  88 +
  89 + set lineDashOffset(args) {
  90 + this.canvasPrototype.lineDashOffset = args;
  91 + this.stepList.push({
  92 + action: "lineDashOffset",
  93 + args,
  94 + actionType: "set",
  95 + });
  96 + }
  97 +
  98 + get lineDashOffset() {
  99 + return this.canvasPrototype.lineDashOffset;
  100 + }
  101 +
  102 + set font(args) {
  103 + this.canvasPrototype.font = args;
  104 + this.ctx.font = args;
  105 + this.stepList.push({
  106 + action: "font",
  107 + args,
  108 + actionType: "set",
  109 + });
  110 + }
  111 +
  112 + get font() {
  113 + return this.canvasPrototype.font;
  114 + }
  115 +
  116 + set textAlign(args) {
  117 + this.canvasPrototype.textAlign = args;
  118 + this.stepList.push({
  119 + action: "textAlign",
  120 + args,
  121 + actionType: "set",
  122 + });
  123 + }
  124 +
  125 + get textAlign() {
  126 + return this.canvasPrototype.textAlign;
  127 + }
  128 +
  129 + set textBaseline(args) {
  130 + this.canvasPrototype.textBaseline = args;
  131 + this.stepList.push({
  132 + action: "textBaseline",
  133 + args,
  134 + actionType: "set",
  135 + });
  136 + }
  137 +
  138 + get textBaseline() {
  139 + return this.canvasPrototype.textBaseline;
  140 + }
  141 +
  142 + set fillStyle(args) {
  143 + this.canvasPrototype.fillStyle = args;
  144 + this.stepList.push({
  145 + action: "fillStyle",
  146 + args,
  147 + actionType: "set",
  148 + });
  149 + }
  150 +
  151 + get fillStyle() {
  152 + return this.canvasPrototype.fillStyle;
  153 + }
  154 +
  155 + set strokeStyle(args) {
  156 + this.canvasPrototype.strokeStyle = args;
  157 + this.stepList.push({
  158 + action: "strokeStyle",
  159 + args,
  160 + actionType: "set",
  161 + });
  162 + }
  163 +
  164 + get strokeStyle() {
  165 + return this.canvasPrototype.strokeStyle;
  166 + }
  167 +
  168 + set globalAlpha(args) {
  169 + this.canvasPrototype.globalAlpha = args;
  170 + this.stepList.push({
  171 + action: "globalAlpha",
  172 + args,
  173 + actionType: "set",
  174 + });
  175 + }
  176 +
  177 + get globalAlpha() {
  178 + return this.canvasPrototype.globalAlpha;
  179 + }
  180 +
  181 + set globalCompositeOperation(args) {
  182 + this.canvasPrototype.globalCompositeOperation = args;
  183 + this.stepList.push({
  184 + action: "globalCompositeOperation",
  185 + args,
  186 + actionType: "set",
  187 + });
  188 + }
  189 +
  190 + get globalCompositeOperation() {
  191 + return this.canvasPrototype.globalCompositeOperation;
  192 + }
  193 +
  194 + set shadowColor(args) {
  195 + this.canvasPrototype.shadowColor = args;
  196 + this.stepList.push({
  197 + action: "shadowColor",
  198 + args,
  199 + actionType: "set",
  200 + });
  201 + }
  202 +
  203 + get shadowColor() {
  204 + return this.canvasPrototype.shadowColor;
  205 + }
  206 +
  207 + set shadowOffsetX(args) {
  208 + this.canvasPrototype.shadowOffsetX = args;
  209 + this.stepList.push({
  210 + action: "shadowOffsetX",
  211 + args,
  212 + actionType: "set",
  213 + });
  214 + }
  215 +
  216 + get shadowOffsetX() {
  217 + return this.canvasPrototype.shadowOffsetX;
  218 + }
  219 +
  220 + set shadowOffsetY(args) {
  221 + this.canvasPrototype.shadowOffsetY = args;
  222 + this.stepList.push({
  223 + action: "shadowOffsetY",
  224 + args,
  225 + actionType: "set",
  226 + });
  227 + }
  228 +
  229 + get shadowOffsetY() {
  230 + return this.canvasPrototype.shadowOffsetY;
  231 + }
  232 +
  233 + set shadowBlur(args) {
  234 + this.canvasPrototype.shadowBlur = args;
  235 + this.stepList.push({
  236 + action: "shadowBlur",
  237 + args,
  238 + actionType: "set",
  239 + });
  240 + }
  241 +
  242 + get shadowBlur() {
  243 + return this.canvasPrototype.shadowBlur;
  244 + }
  245 +
  246 + save() {
  247 + this.stepList.push({
  248 + action: "save",
  249 + args: null,
  250 + actionType: "func",
  251 + });
  252 + }
  253 +
  254 + restore() {
  255 + this.stepList.push({
  256 + action: "restore",
  257 + args: null,
  258 + actionType: "func",
  259 + });
  260 + }
  261 +
  262 + setLineDash(...args) {
  263 + this.canvasPrototype.lineDash = args;
  264 + this.stepList.push({
  265 + action: "setLineDash",
  266 + args,
  267 + actionType: "func",
  268 + });
  269 + }
  270 +
  271 + moveTo(...args) {
  272 + this.stepList.push({
  273 + action: "moveTo",
  274 + args,
  275 + actionType: "func",
  276 + });
  277 + }
  278 +
  279 + closePath() {
  280 + this.stepList.push({
  281 + action: "closePath",
  282 + args: null,
  283 + actionType: "func",
  284 + });
  285 + }
  286 +
  287 + lineTo(...args) {
  288 + this.stepList.push({
  289 + action: "lineTo",
  290 + args,
  291 + actionType: "func",
  292 + });
  293 + }
  294 +
  295 + quadraticCurveTo(...args) {
  296 + this.stepList.push({
  297 + action: "quadraticCurveTo",
  298 + args,
  299 + actionType: "func",
  300 + });
  301 + }
  302 +
  303 + bezierCurveTo(...args) {
  304 + this.stepList.push({
  305 + action: "bezierCurveTo",
  306 + args,
  307 + actionType: "func",
  308 + });
  309 + }
  310 +
  311 + arcTo(...args) {
  312 + this.stepList.push({
  313 + action: "arcTo",
  314 + args,
  315 + actionType: "func",
  316 + });
  317 + }
  318 +
  319 + arc(...args) {
  320 + this.stepList.push({
  321 + action: "arc",
  322 + args,
  323 + actionType: "func",
  324 + });
  325 + }
  326 +
  327 + rect(...args) {
  328 + this.stepList.push({
  329 + action: "rect",
  330 + args,
  331 + actionType: "func",
  332 + });
  333 + }
  334 +
  335 + scale(...args) {
  336 + this.stepList.push({
  337 + action: "scale",
  338 + args,
  339 + actionType: "func",
  340 + });
  341 + }
  342 +
  343 + rotate(...args) {
  344 + this.stepList.push({
  345 + action: "rotate",
  346 + args,
  347 + actionType: "func",
  348 + });
  349 + }
  350 +
  351 + translate(...args) {
  352 + this.stepList.push({
  353 + action: "translate",
  354 + args,
  355 + actionType: "func",
  356 + });
  357 + }
  358 +
  359 + transform(...args) {
  360 + this.stepList.push({
  361 + action: "transform",
  362 + args,
  363 + actionType: "func",
  364 + });
  365 + }
  366 +
  367 + setTransform(...args) {
  368 + this.stepList.push({
  369 + action: "setTransform",
  370 + args,
  371 + actionType: "func",
  372 + });
  373 + }
  374 +
  375 + clearRect(...args) {
  376 + this.stepList.push({
  377 + action: "clearRect",
  378 + args,
  379 + actionType: "func",
  380 + });
  381 + }
  382 +
  383 + fillRect(...args) {
  384 + this.stepList.push({
  385 + action: "fillRect",
  386 + args,
  387 + actionType: "func",
  388 + });
  389 + }
  390 +
  391 + strokeRect(...args) {
  392 + this.stepList.push({
  393 + action: "strokeRect",
  394 + args,
  395 + actionType: "func",
  396 + });
  397 + }
  398 +
  399 + fillText(...args) {
  400 + this.stepList.push({
  401 + action: "fillText",
  402 + args,
  403 + actionType: "func",
  404 + });
  405 + }
  406 +
  407 + strokeText(...args) {
  408 + this.stepList.push({
  409 + action: "strokeText",
  410 + args,
  411 + actionType: "func",
  412 + });
  413 + }
  414 +
  415 + beginPath() {
  416 + this.stepList.push({
  417 + action: "beginPath",
  418 + args: null,
  419 + actionType: "func",
  420 + });
  421 + }
  422 +
  423 + fill() {
  424 + this.stepList.push({
  425 + action: "fill",
  426 + args: null,
  427 + actionType: "func",
  428 + });
  429 + }
  430 +
  431 + stroke() {
  432 + this.stepList.push({
  433 + action: "stroke",
  434 + args: null,
  435 + actionType: "func",
  436 + });
  437 + }
  438 +
  439 + drawFocusIfNeeded(...args) {
  440 + this.stepList.push({
  441 + action: "drawFocusIfNeeded",
  442 + args,
  443 + actionType: "func",
  444 + });
  445 + }
  446 +
  447 + clip() {
  448 + this.stepList.push({
  449 + action: "clip",
  450 + args: null,
  451 + actionType: "func",
  452 + });
  453 + }
  454 +
  455 + isPointInPath(...args) {
  456 + this.stepList.push({
  457 + action: "isPointInPath",
  458 + args,
  459 + actionType: "func",
  460 + });
  461 + }
  462 +
  463 + drawImage(...args) {
  464 + this.stepList.push({
  465 + action: "drawImage",
  466 + args,
  467 + actionType: "func",
  468 + });
  469 + }
  470 +
  471 + addHitRegion(...args) {
  472 + this.stepList.push({
  473 + action: "addHitRegion",
  474 + args,
  475 + actionType: "func",
  476 + });
  477 + }
  478 +
  479 + removeHitRegion(...args) {
  480 + this.stepList.push({
  481 + action: "removeHitRegion",
  482 + args,
  483 + actionType: "func",
  484 + });
  485 + }
  486 +
  487 + clearHitRegions(...args) {
  488 + this.stepList.push({
  489 + action: "clearHitRegions",
  490 + args,
  491 + actionType: "func",
  492 + });
  493 + }
  494 +
  495 + putImageData(...args) {
  496 + this.stepList.push({
  497 + action: "putImageData",
  498 + args,
  499 + actionType: "func",
  500 + });
  501 + }
  502 +
  503 + getLineDash() {
  504 + return this.canvasPrototype.lineDash;
  505 + }
  506 +
  507 + createLinearGradient(...args) {
  508 + return this.ctx.createLinearGradient(...args);
  509 + }
  510 +
  511 + createRadialGradient(...args) {
  512 + if (this.type === "2d") {
  513 + return this.ctx.createRadialGradient(...args);
  514 + } else {
  515 + return this.ctx.createCircularGradient(...args.slice(3, 6));
  516 + }
  517 + }
  518 +
  519 + createPattern(...args) {
  520 + return this.ctx.createPattern(...args);
  521 + }
  522 +
  523 + measureText(...args) {
  524 + return this.ctx.measureText(...args);
  525 + }
  526 +
  527 + createImageData(...args) {
  528 + return this.ctx.createImageData(...args);
  529 + }
  530 +
  531 + getImageData(...args) {
  532 + return this.ctx.getImageData(...args);
  533 + }
  534 +
  535 + async draw(reserve, func) {
  536 + const realstepList = this.stepList.slice();
  537 + this.stepList.length = 0;
  538 + if (this.type === "mina") {
  539 + if (realstepList.length > 0) {
  540 + for (const step of realstepList) {
  541 + this.implementMinaStep(step);
  542 + }
  543 + this.ctx.draw(reserve, func);
  544 + realstepList.length = 0;
  545 + }
  546 + } else if (this.type === "2d") {
  547 + if (!reserve) {
  548 + this.ctx.clearRect(0, 0, this.canvasNode.width, this.canvasNode.height);
  549 + }
  550 + if (realstepList.length > 0) {
  551 + for (const step of realstepList) {
  552 + await this.implement2DStep(step);
  553 + }
  554 + realstepList.length = 0;
  555 + }
  556 + if (func) {
  557 + func();
  558 + }
  559 + }
  560 + realstepList.length = 0;
  561 + }
  562 +
  563 + implementMinaStep(step) {
  564 + switch (step.action) {
  565 + case "textAlign": {
  566 + this.ctx.setTextAlign(step.args);
  567 + break;
  568 + }
  569 + case "textBaseline": {
  570 + this.ctx.setTextBaseline(step.args);
  571 + break;
  572 + }
  573 + default: {
  574 + if (step.actionType === "set") {
  575 + this.ctx[step.action] = step.args;
  576 + } else if (step.actionType === "func") {
  577 + if (step.args) {
  578 + this.ctx[step.action](...step.args);
  579 + } else {
  580 + this.ctx[step.action]();
  581 + }
  582 + }
  583 + break;
  584 + }
  585 + }
  586 + }
  587 +
  588 + implement2DStep(step) {
  589 + return new Promise((resolve) => {
  590 + if (step.action === "drawImage") {
  591 + const img = this.canvasNode.createImage();
  592 + img.src = step.args[0];
  593 + img.onload = () => {
  594 + this.ctx.drawImage(img, ...step.args.slice(1));
  595 + resolve();
  596 + };
  597 + } else {
  598 + if (step.actionType === "set") {
  599 + this.ctx[step.action] = step.args;
  600 + } else if (step.actionType === "func") {
  601 + if (step.args) {
  602 + this.ctx[step.action](...step.args);
  603 + } else {
  604 + this.ctx[step.action]();
  605 + }
  606 + }
  607 + resolve();
  608 + }
  609 + });
  610 + }
  611 +}
... ...
packageB/components/painter/painter.js 0 → 100644
  1 +import Pen from './lib/pen';
  2 +import Downloader from './lib/downloader';
  3 +import WxCanvas from './lib/wx-canvas';
  4 +
  5 +const util = require('./lib/util');
  6 +
  7 +const downloader = new Downloader();
  8 +
  9 +// 最大尝试的绘制次数
  10 +const MAX_PAINT_COUNT = 5;
  11 +const ACTION_DEFAULT_SIZE = 24;
  12 +const ACTION_OFFSET = '2rpx';
  13 +Component({
  14 + canvasWidthInPx: 0,
  15 + canvasHeightInPx: 0,
  16 + canvasNode: null,
  17 + paintCount: 0,
  18 + currentPalette: {},
  19 + movingCache: {},
  20 + outterDisabled: false,
  21 + isDisabled: false,
  22 + needClear: false,
  23 + /**
  24 + * 组件的属性列表
  25 + */
  26 + properties: {
  27 + use2D: {
  28 + type: Boolean,
  29 + },
  30 + customStyle: {
  31 + type: String,
  32 + },
  33 + // 运行自定义选择框和删除缩放按钮
  34 + customActionStyle: {
  35 + type: Object,
  36 + },
  37 + palette: {
  38 + type: Object,
  39 + observer: function (newVal, oldVal) {
  40 + if (this.isNeedRefresh(newVal, oldVal)) {
  41 + this.paintCount = 0;
  42 + this.startPaint();
  43 + }
  44 + },
  45 + },
  46 + dancePalette: {
  47 + type: Object,
  48 + observer: function (newVal, oldVal) {
  49 + if (!this.isEmpty(newVal) && !this.properties.use2D) {
  50 + this.initDancePalette(newVal);
  51 + }
  52 + },
  53 + },
  54 + // 缩放比,会在传入的 palette 中统一乘以该缩放比
  55 + scaleRatio: {
  56 + type: Number,
  57 + value: 1
  58 + },
  59 + widthPixels: {
  60 + type: Number,
  61 + value: 0
  62 + },
  63 + // 启用脏检查,默认 false
  64 + dirty: {
  65 + type: Boolean,
  66 + value: false,
  67 + },
  68 + LRU: {
  69 + type: Boolean,
  70 + value: true,
  71 + },
  72 + action: {
  73 + type: Object,
  74 + observer: function (newVal, oldVal) {
  75 + if (newVal && !this.isEmpty(newVal) && !this.properties.use2D) {
  76 + this.doAction(newVal, (callbackInfo) => {
  77 + this.movingCache = callbackInfo
  78 + }, false, true)
  79 + }
  80 + },
  81 + },
  82 + disableAction: {
  83 + type: Boolean,
  84 + observer: function (isDisabled) {
  85 + this.outterDisabled = isDisabled
  86 + this.isDisabled = isDisabled
  87 + }
  88 + },
  89 + clearActionBox: {
  90 + type: Boolean,
  91 + observer: function (needClear) {
  92 + if (needClear && !this.needClear) {
  93 + if (this.frontContext) {
  94 + setTimeout(() => {
  95 + this.frontContext.draw();
  96 + }, 100);
  97 + this.touchedView = {};
  98 + this.prevFindedIndex = this.findedIndex
  99 + this.findedIndex = -1;
  100 + }
  101 + }
  102 + this.needClear = needClear
  103 + }
  104 + },
  105 + },
  106 +
  107 + data: {
  108 + picURL: '',
  109 + showCanvas: true,
  110 + painterStyle: '',
  111 + },
  112 +
  113 + methods: {
  114 +
  115 + /**
  116 + * 判断一个 object 是否为 空
  117 + * @param {object} object
  118 + */
  119 + isEmpty(object) {
  120 + for (const i in object) {
  121 + return false;
  122 + }
  123 + return true;
  124 + },
  125 +
  126 + isNeedRefresh(newVal, oldVal) {
  127 + if (!newVal || this.isEmpty(newVal) || (this.data.dirty && util.equal(newVal, oldVal))) {
  128 + return false;
  129 + }
  130 + return true;
  131 + },
  132 +
  133 + getBox(rect, type) {
  134 + const boxArea = {
  135 + type: 'rect',
  136 + css: {
  137 + height: `${rect.bottom - rect.top}px`,
  138 + width: `${rect.right - rect.left}px`,
  139 + left: `${rect.left}px`,
  140 + top: `${rect.top}px`,
  141 + borderWidth: '4rpx',
  142 + borderColor: '#1A7AF8',
  143 + color: 'transparent'
  144 + }
  145 + }
  146 + if (type === 'text') {
  147 + boxArea.css = Object.assign({}, boxArea.css, {
  148 + borderStyle: 'dashed'
  149 + })
  150 + }
  151 + if (this.properties.customActionStyle && this.properties.customActionStyle.border) {
  152 + boxArea.css = Object.assign({}, boxArea.css, this.properties.customActionStyle.border)
  153 + }
  154 + Object.assign(boxArea, {
  155 + id: 'box'
  156 + })
  157 + return boxArea
  158 + },
  159 +
  160 + getScaleIcon(rect, type) {
  161 + let scaleArea = {}
  162 + const {
  163 + customActionStyle
  164 + } = this.properties
  165 + if (customActionStyle && customActionStyle.scale) {
  166 + scaleArea = {
  167 + type: 'image',
  168 + url: type === 'text' ? customActionStyle.scale.textIcon : customActionStyle.scale.imageIcon,
  169 + css: {
  170 + height: `${2 * ACTION_DEFAULT_SIZE}rpx`,
  171 + width: `${2 * ACTION_DEFAULT_SIZE}rpx`,
  172 + borderRadius: `${ACTION_DEFAULT_SIZE}rpx`,
  173 + }
  174 + }
  175 + } else {
  176 + scaleArea = {
  177 + type: 'rect',
  178 + css: {
  179 + height: `${2 * ACTION_DEFAULT_SIZE}rpx`,
  180 + width: `${2 * ACTION_DEFAULT_SIZE}rpx`,
  181 + borderRadius: `${ACTION_DEFAULT_SIZE}rpx`,
  182 + color: '#0000ff',
  183 + }
  184 + }
  185 + }
  186 + scaleArea.css = Object.assign({}, scaleArea.css, {
  187 + align: 'center',
  188 + left: `${rect.right + ACTION_OFFSET.toPx()}px`,
  189 + top: type === 'text' ? `${rect.top - ACTION_OFFSET.toPx() - scaleArea.css.height.toPx() / 2}px` : `${rect.bottom - ACTION_OFFSET.toPx() - scaleArea.css.height.toPx() / 2}px`
  190 + })
  191 + Object.assign(scaleArea, {
  192 + id: 'scale'
  193 + })
  194 + return scaleArea
  195 + },
  196 +
  197 + getDeleteIcon(rect) {
  198 + let deleteArea = {}
  199 + const {
  200 + customActionStyle
  201 + } = this.properties
  202 + if (customActionStyle && customActionStyle.scale) {
  203 + deleteArea = {
  204 + type: 'image',
  205 + url: customActionStyle.delete.icon,
  206 + css: {
  207 + height: `${2 * ACTION_DEFAULT_SIZE}rpx`,
  208 + width: `${2 * ACTION_DEFAULT_SIZE}rpx`,
  209 + borderRadius: `${ACTION_DEFAULT_SIZE}rpx`,
  210 + }
  211 + }
  212 + } else {
  213 + deleteArea = {
  214 + type: 'rect',
  215 + css: {
  216 + height: `${2 * ACTION_DEFAULT_SIZE}rpx`,
  217 + width: `${2 * ACTION_DEFAULT_SIZE}rpx`,
  218 + borderRadius: `${ACTION_DEFAULT_SIZE}rpx`,
  219 + color: '#0000ff',
  220 + }
  221 + }
  222 + }
  223 + deleteArea.css = Object.assign({}, deleteArea.css, {
  224 + align: 'center',
  225 + left: `${rect.left - ACTION_OFFSET.toPx()}px`,
  226 + top: `${rect.top - ACTION_OFFSET.toPx() - deleteArea.css.height.toPx() / 2}px`
  227 + })
  228 + Object.assign(deleteArea, {
  229 + id: 'delete'
  230 + })
  231 + return deleteArea
  232 + },
  233 +
  234 + doAction(action, callback, isMoving, overwrite) {
  235 + if (this.properties.use2D) {
  236 + return;
  237 + }
  238 + let newVal = null
  239 + if (action) {
  240 + newVal = action.view
  241 + }
  242 + if (newVal && newVal.id && this.touchedView.id !== newVal.id) {
  243 + // 带 id 的动作给撤回时使用,不带 id,表示对当前选中对象进行操作
  244 + const {
  245 + views
  246 + } = this.currentPalette;
  247 + for (let i = 0; i < views.length; i++) {
  248 + if (views[i].id === newVal.id) {
  249 + // 跨层回撤,需要重新构建三层关系
  250 + this.touchedView = views[i];
  251 + this.findedIndex = i;
  252 + this.sliceLayers();
  253 + break
  254 + }
  255 + }
  256 + }
  257 +
  258 + const doView = this.touchedView
  259 +
  260 + if (!doView || this.isEmpty(doView)) {
  261 + return
  262 + }
  263 + if (newVal && newVal.css) {
  264 + if (overwrite) {
  265 + doView.css = newVal.css
  266 + } else if (Array.isArray(doView.css) && Array.isArray(newVal.css)) {
  267 + doView.css = Object.assign({}, ...doView.css, ...newVal.css)
  268 + } else if (Array.isArray(doView.css)) {
  269 + doView.css = Object.assign({}, ...doView.css, newVal.css)
  270 + } else if (Array.isArray(newVal.css)) {
  271 + doView.css = Object.assign({}, doView.css, ...newVal.css)
  272 + } else {
  273 + doView.css = Object.assign({}, doView.css, newVal.css)
  274 + }
  275 + }
  276 + if (newVal && newVal.rect) {
  277 + doView.rect = newVal.rect;
  278 + }
  279 + if (newVal && newVal.url && doView.url && newVal.url !== doView.url) {
  280 + downloader.download(newVal.url, this.properties.LRU).then((path) => {
  281 + if (newVal.url.startsWith('https')) {
  282 + doView.originUrl = newVal.url
  283 + }
  284 + doView.url = path;
  285 + wx.getImageInfo({
  286 + src: path,
  287 + success: (res) => {
  288 + doView.sHeight = res.height
  289 + doView.sWidth = res.width
  290 + this.reDraw(doView, callback, isMoving)
  291 + },
  292 + fail: () => {
  293 + this.reDraw(doView, callback, isMoving)
  294 + }
  295 + })
  296 + }).catch((error) => {
  297 + // 未下载成功,直接绘制
  298 + console.error(error)
  299 + this.reDraw(doView, callback, isMoving)
  300 + })
  301 + } else {
  302 + (newVal && newVal.text && doView.text && newVal.text !== doView.text) && (doView.text = newVal.text);
  303 + (newVal && newVal.content && doView.content && newVal.content !== doView.content) && (doView.content = newVal.content);
  304 + this.reDraw(doView, callback, isMoving)
  305 + }
  306 + },
  307 +
  308 + reDraw(doView, callback, isMoving) {
  309 + const draw = {
  310 + width: this.currentPalette.width,
  311 + height: this.currentPalette.height,
  312 + views: this.isEmpty(doView) ? [] : [doView]
  313 + }
  314 + const pen = new Pen(this.globalContext, draw);
  315 +
  316 + if (isMoving && doView.type === 'text') {
  317 + pen.paint((callbackInfo) => {
  318 + callback && callback(callbackInfo);
  319 + this.triggerEvent('viewUpdate', {
  320 + view: this.touchedView
  321 + });
  322 + }, true, this.movingCache);
  323 + } else {
  324 + // 某些机型(华为 P20)非移动和缩放场景下,只绘制一遍会偶然性图片绘制失败
  325 + // if (!isMoving && !this.isScale) {
  326 + // pen.paint()
  327 + // }
  328 + pen.paint((callbackInfo) => {
  329 + callback && callback(callbackInfo);
  330 + this.triggerEvent('viewUpdate', {
  331 + view: this.touchedView
  332 + });
  333 + })
  334 + }
  335 +
  336 + const {
  337 + rect,
  338 + css,
  339 + type
  340 + } = doView
  341 +
  342 + this.block = {
  343 + width: this.currentPalette.width,
  344 + height: this.currentPalette.height,
  345 + views: this.isEmpty(doView) ? [] : [this.getBox(rect, doView.type)]
  346 + }
  347 + if (css && css.scalable) {
  348 + this.block.views.push(this.getScaleIcon(rect, type))
  349 + }
  350 + if (css && css.deletable) {
  351 + this.block.views.push(this.getDeleteIcon(rect))
  352 + }
  353 + const topBlock = new Pen(this.frontContext, this.block)
  354 + topBlock.paint();
  355 + },
  356 +
  357 + isInView(x, y, rect) {
  358 + return (x > rect.left &&
  359 + y > rect.top &&
  360 + x < rect.right &&
  361 + y < rect.bottom
  362 + )
  363 + },
  364 +
  365 + isInDelete(x, y) {
  366 + for (const view of this.block.views) {
  367 + if (view.id === 'delete') {
  368 + return (x > view.rect.left &&
  369 + y > view.rect.top &&
  370 + x < view.rect.right &&
  371 + y < view.rect.bottom)
  372 + }
  373 + }
  374 + return false
  375 + },
  376 +
  377 + isInScale(x, y) {
  378 + for (const view of this.block.views) {
  379 + if (view.id === 'scale') {
  380 + return (x > view.rect.left &&
  381 + y > view.rect.top &&
  382 + x < view.rect.right &&
  383 + y < view.rect.bottom)
  384 + }
  385 + }
  386 + return false
  387 + },
  388 +
  389 + touchedView: {},
  390 + findedIndex: -1,
  391 + onClick() {
  392 + const x = this.startX
  393 + const y = this.startY
  394 + const totalLayerCount = this.currentPalette.views.length
  395 + let canBeTouched = []
  396 + let isDelete = false
  397 + let deleteIndex = -1
  398 + for (let i = totalLayerCount - 1; i >= 0; i--) {
  399 + const view = this.currentPalette.views[i]
  400 + const {
  401 + rect
  402 + } = view
  403 + if (this.touchedView && this.touchedView.id && this.touchedView.id === view.id && this.isInDelete(x, y, rect)) {
  404 + canBeTouched.length = 0
  405 + deleteIndex = i
  406 + isDelete = true
  407 + break
  408 + }
  409 + if (this.isInView(x, y, rect)) {
  410 + canBeTouched.push({
  411 + view,
  412 + index: i
  413 + })
  414 + }
  415 + }
  416 + this.touchedView = {}
  417 + if (canBeTouched.length === 0) {
  418 + this.findedIndex = -1
  419 + } else {
  420 + let i = 0
  421 + const touchAble = canBeTouched.filter(item => Boolean(item.view.id))
  422 + if (touchAble.length === 0) {
  423 + this.findedIndex = canBeTouched[0].index
  424 + } else {
  425 + for (i = 0; i < touchAble.length; i++) {
  426 + if (this.findedIndex === touchAble[i].index) {
  427 + i++
  428 + break
  429 + }
  430 + }
  431 + if (i === touchAble.length) {
  432 + i = 0
  433 + }
  434 + this.touchedView = touchAble[i].view
  435 + this.findedIndex = touchAble[i].index
  436 + this.triggerEvent('viewClicked', {
  437 + view: this.touchedView
  438 + })
  439 + }
  440 + }
  441 + if (this.findedIndex < 0 || (this.touchedView && !this.touchedView.id)) {
  442 + // 证明点击了背景 或无法移动的view
  443 + this.frontContext.draw();
  444 + if (isDelete) {
  445 + this.triggerEvent('touchEnd', {
  446 + view: this.currentPalette.views[deleteIndex],
  447 + index: deleteIndex,
  448 + type: 'delete'
  449 + })
  450 + this.doAction()
  451 + } else if (this.findedIndex < 0) {
  452 + this.triggerEvent('viewClicked', {})
  453 + }
  454 + this.findedIndex = -1
  455 + this.prevFindedIndex = -1
  456 + } else if (this.touchedView && this.touchedView.id) {
  457 + this.sliceLayers();
  458 + }
  459 + },
  460 +
  461 + sliceLayers() {
  462 + const bottomLayers = this.currentPalette.views.slice(0, this.findedIndex)
  463 + const topLayers = this.currentPalette.views.slice(this.findedIndex + 1)
  464 + const bottomDraw = {
  465 + width: this.currentPalette.width,
  466 + height: this.currentPalette.height,
  467 + background: this.currentPalette.background,
  468 + views: bottomLayers
  469 + }
  470 + const topDraw = {
  471 + width: this.currentPalette.width,
  472 + height: this.currentPalette.height,
  473 + views: topLayers
  474 + }
  475 + if (this.prevFindedIndex < this.findedIndex) {
  476 + new Pen(this.bottomContext, bottomDraw).paint();
  477 + this.doAction(null, (callbackInfo) => {
  478 + this.movingCache = callbackInfo
  479 + })
  480 + new Pen(this.topContext, topDraw).paint();
  481 + } else {
  482 + new Pen(this.topContext, topDraw).paint();
  483 + this.doAction(null, (callbackInfo) => {
  484 + this.movingCache = callbackInfo
  485 + })
  486 + new Pen(this.bottomContext, bottomDraw).paint();
  487 + }
  488 + this.prevFindedIndex = this.findedIndex
  489 + },
  490 +
  491 + startX: 0,
  492 + startY: 0,
  493 + startH: 0,
  494 + startW: 0,
  495 + isScale: false,
  496 + startTimeStamp: 0,
  497 + onTouchStart(event) {
  498 + if (this.isDisabled) {
  499 + return
  500 + }
  501 + const {
  502 + x,
  503 + y
  504 + } = event.touches[0]
  505 + this.startX = x
  506 + this.startY = y
  507 + this.startTimeStamp = new Date().getTime()
  508 + if (this.touchedView && !this.isEmpty(this.touchedView)) {
  509 + const {
  510 + rect
  511 + } = this.touchedView
  512 + if (this.isInScale(x, y, rect)) {
  513 + this.isScale = true
  514 + this.movingCache = {}
  515 + this.startH = rect.bottom - rect.top
  516 + this.startW = rect.right - rect.left
  517 + } else {
  518 + this.isScale = false
  519 + }
  520 + } else {
  521 + this.isScale = false
  522 + }
  523 + },
  524 +
  525 + onTouchEnd(e) {
  526 + if (this.isDisabled) {
  527 + return
  528 + }
  529 + const current = new Date().getTime()
  530 + if ((current - this.startTimeStamp) <= 500 && !this.hasMove) {
  531 + !this.isScale && this.onClick(e)
  532 + } else if (this.touchedView && !this.isEmpty(this.touchedView)) {
  533 + this.triggerEvent('touchEnd', {
  534 + view: this.touchedView,
  535 + })
  536 + }
  537 + this.hasMove = false
  538 + },
  539 +
  540 + onTouchCancel(e) {
  541 + if (this.isDisabled) {
  542 + return
  543 + }
  544 + this.onTouchEnd(e)
  545 + },
  546 +
  547 + hasMove: false,
  548 + onTouchMove(event) {
  549 + if (this.isDisabled) {
  550 + return
  551 + }
  552 + this.hasMove = true
  553 + if (!this.touchedView || (this.touchedView && !this.touchedView.id)) {
  554 + return
  555 + }
  556 + const {
  557 + x,
  558 + y
  559 + } = event.touches[0]
  560 + const offsetX = x - this.startX
  561 + const offsetY = y - this.startY
  562 + const {
  563 + rect,
  564 + type
  565 + } = this.touchedView
  566 + let css = {}
  567 + if (this.isScale) {
  568 + const newW = this.startW + offsetX > 1 ? this.startW + offsetX : 1
  569 + if (this.touchedView.css && this.touchedView.css.minWidth) {
  570 + if (newW < this.touchedView.css.minWidth.toPx()) {
  571 + return
  572 + }
  573 + }
  574 + if (this.touchedView.rect && this.touchedView.rect.minWidth) {
  575 + if (newW < this.touchedView.rect.minWidth) {
  576 + return
  577 + }
  578 + }
  579 + const newH = this.startH + offsetY > 1 ? this.startH + offsetY : 1
  580 + css = {
  581 + width: `${newW}px`,
  582 + }
  583 + if (type !== 'text') {
  584 + if (type === 'image') {
  585 + css.height = `${(newW) * this.startH / this.startW }px`
  586 + } else {
  587 + css.height = `${newH}px`
  588 + }
  589 + }
  590 + } else {
  591 + this.startX = x
  592 + this.startY = y
  593 + css = {
  594 + left: `${rect.x + offsetX}px`,
  595 + top: `${rect.y + offsetY}px`,
  596 + right: undefined,
  597 + bottom: undefined
  598 + }
  599 + }
  600 + this.doAction({
  601 + view: {
  602 + css
  603 + }
  604 + }, (callbackInfo) => {
  605 + if (this.isScale) {
  606 + this.movingCache = callbackInfo
  607 + }
  608 + }, !this.isScale)
  609 + },
  610 +
  611 + initScreenK() {
  612 + if (!(getApp() && getApp().systemInfo && getApp().systemInfo.screenWidth)) {
  613 + try {
  614 + getApp().systemInfo = wx.getSystemInfoSync();
  615 + } catch (e) {
  616 + console.error(`Painter get system info failed, ${JSON.stringify(e)}`);
  617 + return;
  618 + }
  619 + }
  620 + this.screenK = 0.5;
  621 + if (getApp() && getApp().systemInfo && getApp().systemInfo.screenWidth) {
  622 + this.screenK = getApp().systemInfo.screenWidth / 750;
  623 + }
  624 + setStringPrototype(this.screenK, this.properties.scaleRatio);
  625 + },
  626 +
  627 + initDancePalette() {
  628 + if (this.properties.use2D) {
  629 + return;
  630 + }
  631 + this.isDisabled = true;
  632 + this.initScreenK();
  633 + this.downloadImages(this.properties.dancePalette).then(async (palette) => {
  634 + this.currentPalette = palette
  635 + const {
  636 + width,
  637 + height
  638 + } = palette;
  639 +
  640 + if (!width || !height) {
  641 + console.error(`You should set width and height correctly for painter, width: ${width}, height: ${height}`);
  642 + return;
  643 + }
  644 + this.setData({
  645 + painterStyle: `width:${width.toPx()}px;height:${height.toPx()}px;`,
  646 + });
  647 + this.frontContext || (this.frontContext = await this.getCanvasContext(this.properties.use2D, 'front'));
  648 + this.bottomContext || (this.bottomContext = await this.getCanvasContext(this.properties.use2D, 'bottom'));
  649 + this.topContext || (this.topContext = await this.getCanvasContext(this.properties.use2D, 'top'));
  650 + this.globalContext || (this.globalContext = await this.getCanvasContext(this.properties.use2D, 'k-canvas'));
  651 + new Pen(this.bottomContext, palette, this.properties.use2D).paint(() => {
  652 + this.isDisabled = false;
  653 + this.isDisabled = this.outterDisabled;
  654 + this.triggerEvent('didShow');
  655 + });
  656 + this.globalContext.draw();
  657 + this.frontContext.draw();
  658 + this.topContext.draw();
  659 + });
  660 + this.touchedView = {};
  661 + },
  662 +
  663 + startPaint() {
  664 + this.initScreenK();
  665 +
  666 + this.downloadImages(this.properties.palette).then(async (palette) => {
  667 + const {
  668 + width,
  669 + height
  670 + } = palette;
  671 +
  672 + if (!width || !height) {
  673 + console.error(`You should set width and height correctly for painter, width: ${width}, height: ${height}`);
  674 + return;
  675 + }
  676 +
  677 + let needScale = false;
  678 + // 生成图片时,根据设置的像素值重新绘制
  679 + if (width.toPx() !== this.canvasWidthInPx) {
  680 + this.canvasWidthInPx = width.toPx();
  681 + needScale = this.properties.use2D;
  682 + }
  683 + if (this.properties.widthPixels) {
  684 + setStringPrototype(this.screenK, this.properties.widthPixels / this.canvasWidthInPx)
  685 + this.canvasWidthInPx = this.properties.widthPixels
  686 + }
  687 +
  688 + if (this.canvasHeightInPx !== height.toPx()) {
  689 + this.canvasHeightInPx = height.toPx();
  690 + needScale = needScale || this.properties.use2D;
  691 + }
  692 + this.setData({
  693 + photoStyle: `width:${this.canvasWidthInPx}px;height:${this.canvasHeightInPx}px;`,
  694 + });
  695 + if (!this.photoContext) {
  696 + this.photoContext = await this.getCanvasContext(this.properties.use2D, 'photo');
  697 + }
  698 + if (needScale) {
  699 + const scale = getApp().systemInfo.pixelRatio;
  700 + this.photoContext.width = this.canvasWidthInPx * scale;
  701 + this.photoContext.height = this.canvasHeightInPx * scale;
  702 + this.photoContext.scale(scale, scale);
  703 + }
  704 + new Pen(this.photoContext, palette).paint(() => {
  705 + this.saveImgToLocal();
  706 + });
  707 + setStringPrototype(this.screenK, this.properties.scaleRatio);
  708 + });
  709 + },
  710 +
  711 + downloadImages(palette) {
  712 + return new Promise((resolve, reject) => {
  713 + let preCount = 0;
  714 + let completeCount = 0;
  715 + const paletteCopy = JSON.parse(JSON.stringify(palette));
  716 + if (paletteCopy.background) {
  717 + preCount++;
  718 + downloader.download(paletteCopy.background, this.properties.LRU).then((path) => {
  719 + paletteCopy.background = path;
  720 + completeCount++;
  721 + if (preCount === completeCount) {
  722 + resolve(paletteCopy);
  723 + }
  724 + }, () => {
  725 + completeCount++;
  726 + if (preCount === completeCount) {
  727 + resolve(paletteCopy);
  728 + }
  729 + });
  730 + }
  731 + if (paletteCopy.views) {
  732 + for (const view of paletteCopy.views) {
  733 + if (view && view.type === 'image' && view.url) {
  734 + preCount++;
  735 + /* eslint-disable no-loop-func */
  736 + downloader.download(view.url, this.properties.LRU).then((path) => {
  737 + view.originUrl = view.url;
  738 + view.url = path;
  739 + wx.getImageInfo({
  740 + src: path,
  741 + success: (res) => {
  742 + // 获得一下图片信息,供后续裁减使用
  743 + view.sWidth = res.width;
  744 + view.sHeight = res.height;
  745 + },
  746 + fail: (error) => {
  747 + // 如果图片坏了,则直接置空,防止坑爹的 canvas 画崩溃了
  748 + view.url = "";
  749 + // console.error(`getImageInfo ${view.url} failed, ${JSON.stringify(error)}`);
  750 + },
  751 + complete: () => {
  752 + completeCount++;
  753 + if (preCount === completeCount) {
  754 + resolve(paletteCopy);
  755 + }
  756 + },
  757 + });
  758 + }, () => {
  759 + completeCount++;
  760 + if (preCount === completeCount) {
  761 + resolve(paletteCopy);
  762 + }
  763 + });
  764 + }
  765 + }
  766 + }
  767 + if (preCount === 0) {
  768 + resolve(paletteCopy);
  769 + }
  770 + });
  771 + },
  772 +
  773 + saveImgToLocal() {
  774 + const that = this;
  775 + setTimeout(() => {
  776 + wx.canvasToTempFilePath({
  777 + canvasId: 'photo',
  778 + canvas: that.properties.use2D ? that.canvasNode : null,
  779 + destWidth: that.canvasWidthInPx * getApp().systemInfo.pixelRatio,
  780 + destHeight: that.canvasHeightInPx * getApp().systemInfo.pixelRatio,
  781 + success: function (res) {
  782 + that.getImageInfo(res.tempFilePath);
  783 + },
  784 + fail: function (error) {
  785 + console.error(`canvasToTempFilePath failed, ${JSON.stringify(error)}`);
  786 + that.triggerEvent('imgErr', {
  787 + error: error
  788 + });
  789 + },
  790 + }, this);
  791 + }, 300);
  792 + },
  793 +
  794 +
  795 + getCanvasContext(use2D, id) {
  796 + const that = this;
  797 + return new Promise(resolve => {
  798 + if (use2D) {
  799 + const query = wx.createSelectorQuery().in(that);
  800 + const selectId = `#${id}`;
  801 + query.select(selectId)
  802 + .fields({ node: true, size: true })
  803 + .exec((res) => {
  804 + that.canvasNode = res[0].node;
  805 + const ctx = that.canvasNode.getContext('2d');
  806 + const wxCanvas = new WxCanvas('2d', ctx, id, true, that.canvasNode);
  807 + resolve(wxCanvas);
  808 + });
  809 + } else {
  810 + const temp = wx.createCanvasContext(id, that);
  811 + resolve(new WxCanvas('mina', temp, id, true));
  812 + }
  813 + })
  814 + },
  815 +
  816 + getImageInfo(filePath) {
  817 + const that = this;
  818 + wx.getImageInfo({
  819 + src: filePath,
  820 + success: (infoRes) => {
  821 + if (that.paintCount > MAX_PAINT_COUNT) {
  822 + const error = `The result is always fault, even we tried ${MAX_PAINT_COUNT} times`;
  823 + console.error(error);
  824 + that.triggerEvent('imgErr', {
  825 + error: error
  826 + });
  827 + return;
  828 + }
  829 + // 比例相符时才证明绘制成功,否则进行强制重绘制
  830 + if (Math.abs((infoRes.width * that.canvasHeightInPx - that.canvasWidthInPx * infoRes.height) / (infoRes.height * that.canvasHeightInPx)) < 0.01) {
  831 + that.triggerEvent('imgOK', {
  832 + path: filePath
  833 + });
  834 + } else {
  835 + that.startPaint();
  836 + }
  837 + that.paintCount++;
  838 + },
  839 + fail: (error) => {
  840 + console.error(`getImageInfo failed, ${JSON.stringify(error)}`);
  841 + that.triggerEvent('imgErr', {
  842 + error: error
  843 + });
  844 + },
  845 + });
  846 + },
  847 + },
  848 +});
  849 +
  850 +
  851 +function setStringPrototype(screenK, scale) {
  852 + /* eslint-disable no-extend-native */
  853 + /**
  854 + * 是否支持负数
  855 + * @param {Boolean} minus 是否支持负数
  856 + * @param {Number} baseSize 当设置了 % 号时,设置的基准值
  857 + */
  858 + String.prototype.toPx = function toPx(minus, baseSize) {
  859 + if (this === '0') {
  860 + return 0
  861 + }
  862 + let reg;
  863 + if (minus) {
  864 + reg = /^-?[0-9]+([.]{1}[0-9]+){0,1}(rpx|px|%)$/g;
  865 + } else {
  866 + reg = /^[0-9]+([.]{1}[0-9]+){0,1}(rpx|px|%)$/g;
  867 + }
  868 + const results = reg.exec(this);
  869 + if (!this || !results) {
  870 + console.error(`The size: ${this} is illegal`);
  871 + return 0;
  872 + }
  873 + const unit = results[2];
  874 + const value = parseFloat(this);
  875 +
  876 + let res = 0;
  877 + if (unit === 'rpx') {
  878 + res = Math.round(value * (screenK || 0.5) * (scale || 1));
  879 + } else if (unit === 'px') {
  880 + res = Math.round(value * (scale || 1));
  881 + } else if (unit === '%') {
  882 + res = Math.round(value * baseSize / 100);
  883 + }
  884 + return res;
  885 + };
  886 +}
0 887 \ No newline at end of file
... ...
packageB/components/painter/painter.json 0 → 100644
  1 +{
  2 + "component": true,
  3 + "usingComponents": {}
  4 +}
0 5 \ No newline at end of file
... ...
packageB/components/painter/painter.wxml 0 → 100644
  1 +<view style='position: relative;{{customStyle}};{{painterStyle}}'>
  2 + <block wx:if="{{!use2D}}">
  3 + <canvas canvas-id="photo" style="{{photoStyle}};position: absolute; left: -9999px; top: -9999rpx;" />
  4 + <canvas canvas-id="bottom" style="{{painterStyle}};position: absolute;" />
  5 + <canvas canvas-id="k-canvas" style="{{painterStyle}};position: absolute;" />
  6 + <canvas canvas-id="top" style="{{painterStyle}};position: absolute;" />
  7 + <canvas
  8 + canvas-id="front"
  9 + style="{{painterStyle}};position: absolute;"
  10 + bindtouchstart="onTouchStart"
  11 + bindtouchmove="onTouchMove"
  12 + bindtouchend="onTouchEnd"
  13 + bindtouchcancel="onTouchCancel"
  14 + disable-scroll="{{true}}" />
  15 + </block>
  16 + <block wx:if="{{use2D}}">
  17 + <canvas type="2d" id="photo" style="{{photoStyle}};" />
  18 + <!-- <canvas type="2d" id="bottom" style="{{painterStyle}};position: absolute;" />
  19 + <canvas type="2d" id="k-canvas" style="{{painterStyle}};position: absolute;" />
  20 + <canvas type="2d" id="top" style="{{painterStyle}};position: absolute;" />
  21 + <canvas
  22 + type="2d"
  23 + id="front"
  24 + style="{{painterStyle}};position: absolute;"
  25 + bindtouchstart="onTouchStart"
  26 + bindtouchmove="onTouchMove"
  27 + bindtouchend="onTouchEnd"
  28 + bindtouchcancel="onTouchCancel"
  29 + disable-scroll="{{true}}" /> -->
  30 + </block>
  31 +</view>
... ...
packageB/images/luckDraw/jiang.png 0 → 100644

19.6 KB

packageB/pages/luckactivity/index/index.wxml
... ... @@ -20,7 +20,7 @@
20 20 <block wx:for="{{list.pageData}}">
21 21 <view class="tab-item" bindtap="goto" data-id="{{item.id}}" data-title="{{item.act_name}}">
22 22 <view class="img-container">
23   - <image wx:if="{{item.imageurl}}" src="{{imghost + item.imageurl}}" class="img"></image>
  23 + <image wx:if="{{item.imageurl}}" src="{{imghost + item.imageurl}}" class="img" mode="aspectFit"></image>
24 24 <text class="iconfont icon-zhuanpan" wx:else></text>
25 25 </view>
26 26 <view class="desc-container">
... ...
packageB/pages/luckactivity/luckinfo/luckinfo.js
  1 +var util = require("../../../../utils/util.js");
1 2 var WxParse = require('../../../../utils/wxParse/wxParse.js');
2 3 const app = getApp();
3 4 let imghost = app.globalData.setting.imghost;
4 5 let self = null;
  6 +let imgDraw = {
  7 + "width": "554px",
  8 + "height": "899px",
  9 + "background": imghost + "miniapp/images/share_bg.png",
  10 + "views": [
  11 + { //0.头像
  12 + "type": "image",
  13 + // "url": "",
  14 + "css": {
  15 + "background": "white",
  16 + "width": "80px",
  17 + "height": "80px",
  18 + "top": "24px",
  19 + "left": "40px",
  20 + "borderRadius": "80px",
  21 + }
  22 + },
  23 + { //1.昵称
  24 + "type": "text",
  25 + "text": "",
  26 + "css": {
  27 + "color": "#000000",
  28 + "width": "400px",
  29 + "top": "25px",
  30 + "left": "140px",
  31 + "fontSize": "26px",
  32 + "maxLines": "1",
  33 + }
  34 + },
  35 + { //2.强烈推荐
  36 + "type": "text",
  37 + "text": "强烈推荐",
  38 + "css": {
  39 + "color": "#fff",
  40 + "background": "#FF6768",
  41 + "width": "105px",
  42 + "height": "26px",
  43 + "lineHeight": "26px",
  44 + "top": "70px",
  45 + "left": "140px",
  46 + "borderRadius": "10px",
  47 + "fontSize": "18px",
  48 + "textAlign": "center"
  49 +
  50 + }
  51 + },
  52 + { //3.分享标题
  53 + "type": "text",
  54 + "text": "",
  55 + "css": {
  56 + "width": "554px",
  57 + "padding": "20px",
  58 + "left": "20px",
  59 + "top": "160px",
  60 + "fontSize": "28px",
  61 + "textAlign": "left",
  62 + "maxLines": "1",
  63 + }
  64 + },
  65 + { //4.分享内容
  66 + "type": "text",
  67 + // "text": "",
  68 + "css": {
  69 + "color": "#000000",
  70 + "width": "554px",
  71 + "padding": "20px",
  72 + "left": "20px",
  73 + "top": "190px",
  74 + "fontSize": "26px",
  75 + "textAlign": "center",
  76 + "maxLines": "1",
  77 + }
  78 + },
  79 + { //5.分享图片
  80 + "type": "image",
  81 + "url": "/packageB/images/luckDraw/jiang.png",
  82 + "css": {
  83 + "width": "auto",
  84 + "height": "350px",
  85 + "top": "230px",
  86 + "left": "277px",
  87 + "align": "center",
  88 + "mode": "aspectFill",
  89 + }
  90 + },
  91 + { //6
  92 + "type": "image",
  93 + "url": "/images/share/s_gou.png",
  94 + "css": {
  95 + "width": "30px",
  96 + "height": "30px",
  97 + "top": "620px",
  98 + "left": "18px",
  99 + "rotate": "0",
  100 + "borderRadius": "30px",
  101 + }
  102 + },
  103 + { //7
  104 + "type": "text",
  105 + "text": "正品保障",
  106 + "css": {
  107 + "color": "red",
  108 + "width": "110px",
  109 + "top": "620px",
  110 + "left": "52px",
  111 + "fontSize": "22px",
  112 + }
  113 + },
  114 + { //8
  115 + "type": "image",
  116 + "url": "/images/share/s_gou.png",
  117 + "css": {
  118 + "width": "30px",
  119 + "height": "30px",
  120 + "top": "620px",
  121 + "left": "208px",
  122 + "borderRadius": "30px",
  123 + }
  124 + },
  125 + { //9
  126 + "type": "text",
  127 + "text": "纯实体店",
  128 + "css": {
  129 + "color": "red",
  130 + "width": "129px",
  131 + "top": "620px",
  132 + "left": "243px",
  133 + "fontSize": "22px",
  134 + }
  135 + },
  136 + { //10
  137 + "type": "image",
  138 + "url": "/images/share/s_gou.png",
  139 + "css": {
  140 + "width": "30px",
  141 + "height": "30px",
  142 + "top": "620px",
  143 + "left": "410px",
  144 + "borderRadius": "30px",
  145 + }
  146 + },
  147 + { //11
  148 + "type": "text",
  149 + "text": "官方验证",
  150 + "css": {
  151 + "color": "red",
  152 + "width": "121px",
  153 + "top": "620px",
  154 + "left": "450px",
  155 + "fontSize": "22px",
  156 + }
  157 + },
  158 + { //12.横线
  159 + "type": "rect",
  160 + "css": {
  161 + "background": "#f0f0f0",
  162 + "width": "554px",
  163 + "height": "1px",
  164 + "top": "676px",
  165 + "left": "0px",
  166 + }
  167 + },
  168 + { //13
  169 + "type": "text",
  170 + "text": "特惠活动时间仅限",
  171 + "css": {
  172 + "color": "#000000",
  173 + "width": "245px",
  174 + "top": "730px",
  175 + "left": "28px",
  176 + "fontSize": "24px",
  177 + "textAlign": "left"
  178 + }
  179 + },
  180 + { //14.时间
  181 + "type": "text",
  182 + // "text": "",
  183 + "css": {
  184 + "width": "377px",
  185 + "top": "770px",
  186 + "left": "28px",
  187 + "fontSize": "24px",
  188 + }
  189 + },
  190 + { //15
  191 + "type": "text",
  192 + "text": "长按识别小程序码有惊喜哦!",
  193 + "css": {
  194 + "color": "#7c7c7c",
  195 + "width": "348px",
  196 + "top": "810px",
  197 + "left": "27px",
  198 + "fontSize": "24px",
  199 + }
  200 + },
  201 +
  202 + { //16.码
  203 + "type": "image",
  204 + // "url": "",
  205 + "css": {
  206 + "width": "150px",
  207 + "height": "150px",
  208 + "top": "705px",
  209 + "left": "380px",
  210 + "mode": "scaleToFill"
  211 + }
  212 + },
  213 +
  214 + ]
  215 + };
  216 +
5 217  
6 218 Page({
7 219 data: {
  220 + imgDraw: imgDraw,
8 221 start: false,
9 222 list: null,
10 223 isLoading: false, // 检测是否已经发送请求,防止重复发送请求
... ... @@ -12,6 +225,8 @@ Page({
12 225 pageNum: 1, // 当前页数
13 226 imghost: imghost,
14 227 num: 3,
  228 + canStart: false,
  229 +
15 230  
16 231 prizes: [],
17 232 defaultConfig: {
... ... @@ -57,9 +272,16 @@ Page({
57 272 },
58 273  
59 274 onLoad(options) {
  275 + // wx.showLoading();
  276 + // this.setData({
  277 + // showMask2: true,
  278 + // });
60 279 // console.log('imghost+++++', imghost);
61 280 self = this;
  281 + let first_leader = null;
62 282 this.data.options = options;
  283 +
  284 +
63 285 // this.setData({
64 286 // options,
65 287 // imghost,
... ... @@ -68,28 +290,58 @@ Page({
68 290 wx.setNavigationBarTitle({
69 291 title: options.title,
70 292 });
  293 +
  294 +
71 295 app.isLogin().then(function(data) {//进入页面前已经授权登录成功
72 296 self.setData({
73 297 userInfo: data,
74   - // imghost,
75 298 });
76 299 });
  300 +
  301 +
  302 +
  303 + //从分享的跳转过来
  304 + if (options.id == undefined || options.id == null || options.id == '') {
  305 + var scene = decodeURIComponent(options.scene);
  306 + scene = scene.split('_');
  307 + first_leader = scene[0];
  308 + this.data.options.id = scene[1];
  309 + };
  310 +
  311 + if(first_leader) {
  312 + // console.log("log---", first_leader);
  313 + app.globalData.first_leader = first_leader;
  314 + //调用接口判断是不是会员
  315 + app.request.promiseGet("/api/weshop/shoppingGuide/get/" + app.globalData.setting.stoid +"/" + first_leader,{}).then(res=>{
  316 + if(res.data.code==0){
  317 + app.globalData.guide_id = res.data.data.id;
  318 + }
  319 + })
  320 + };
  321 +
  322 +
  323 +
  324 +
  325 +
77 326 },
78 327  
79 328 onShow() {
  329 + // console.log('show~~`');
80 330 if(app.globalData.userInfo) {
81 331 if(!this.data.isLogin) {
82   -
83 332 this.setData({
84 333 userInfo: app.globalData.userInfo,
85 334 isLogin: true,
  335 + 'imgDraw.views[0].url': app.globalData.userInfo.head_pic,//头像
  336 + 'imgDraw.views[1].text': app.globalData.userInfo.nickname,//昵称
86 337 });
87   -
88 338 // console.log('imghost', this.data.imghost);
89 339 let user_id = app.globalData.userInfo.user_id;
90 340 let store_id = app.globalData.setting.stoid;
91 341 let id = this.data.options.id;
92 342 let url = `/api/weshop/marketing/marketingLuckForm/getLuckInfo/${store_id}/${id}/${user_id}`;
  343 +
  344 +
93 345  
94 346  
95 347 app.request.get(url, {
... ... @@ -110,27 +362,89 @@ Page({
110 362 // console.log('luckInfo', res.data.data);
111 363 let luckInfo = res.data.data;
112 364  
113   -
  365 + self.setData({
  366 + 'imgDraw.views[3].text': self.data.luckInfo.act_name,//分享标题
  367 + // 'imgDraw.views[4].text': '快来一起抽奖吧,精美奖品等着你!',//分享内容
  368 + 'imgDraw.views[14].text': util.formar_no_full(self.data.luckInfo.begindate) + ' 至 ' + util.formar_no_full(self.data.luckInfo.enddate),//活动时间
  369 + });
  370 +
  371 +
  372 + let luckStyle = null;
114 373 if(luckInfo && luckInfo.template_type != null && luckInfo.template_type == 1) { //获取模板
115   - let url = `/api/weshop/marketing/marketingLuckTemplate/get/${store_id}/${luckInfo.template_id}`;
  374 + let url = `/api/weshop/marketing/marketingLuckTemplate/get/0/${luckInfo.template_id}`;
116 375 app.request.get(url, {
117 376 success: function(res) {
118   - // console.log('prizes//////', res.data.data);
119   - self.setData({
120   - template: res.data.data,
121   - bannerUrl: imghost + ((res.data.data&&res.data.data.bannerUrl) ? res.data.data.bannerUrl:'miniapp/images/luckDraw/bg.png'), //背景图
122   - 'blocks[0].imgs[0].src': imghost + ((res.data.data&&res.data.data.wheelBaseUrl) ? res.data.data.wheelBaseUrl:'miniapp/images/luckDraw/weel.png'), //转盘
123   - 'buttons[0].imgs[0].src': imghost + ((res.data.data&&res.data.data.wheelPointerUrl) ? res.data.data.wheelPointerUrl:'miniapp/images/luckDraw/pointer.png'), //指针
124   - });
  377 + let template = null;
  378 + if(res.data.code == 0) {
  379 + template = res.data.data;
  380 + self.setData({
  381 + template,
  382 + bannerUrl: imghost + template.bannerUrl, //背景图
  383 + 'blocks[0].imgs[0].src': imghost + ((template&&template.wheelBaseUrl) ? template.wheelBaseUrl:'miniapp/images/luckDraw/weel.png?v=2'), //转盘
  384 + 'buttons[0].imgs[0].src': imghost + ((template&&template.wheelPointerUrl) ? template.wheelPointerUrl:'miniapp/images/luckDraw/pointer.png?v=2'), //指针
  385 + 'imgDraw.views[3].text': template.title, //分享标题
  386 + 'imgDraw.views[5].url': imghost + (template&&template.share_image ? template.share_image:self.data.luckInfo.imageurl), //分享图片
  387 + });
  388 +
  389 + let color = template&&template.colorCode ? template.colorCode:'#da104b';
  390 + luckStyle = `background: ${color} url(${self.data.bannerUrl}) no-repeat;`;
  391 + self.setData({
  392 + luckStyle,
  393 + });
  394 + // self.setData({
  395 + // template: res.data.data,
  396 + // bannerUrl: imghost + res.data.data.bannerUrl, //背景图
  397 + // //bannerUrl: imghost + ((res.data.data&&res.data.data.bannerUrl) ? res.data.data.bannerUrl:'miniapp/images/luckDraw/bg.png?v=2'), //背景图
  398 + // 'blocks[0].imgs[0].src': imghost + res.data.data&&res.data.data.wheelBaseUrl) ? res.data.data.wheelBaseUrl:'miniapp/images/luckDraw/weel.png?v=2'), //转盘
  399 + // 'buttons[0].imgs[0].src': imghost + ((res.data.data&&res.data.data.wheelPointerUrl) ? res.data.data.wheelPointerUrl:'miniapp/images/luckDraw/pointer.png?v=2'), //指针
  400 + // 'imgDraw.views[3].text': (res.data.data&&res.data.data.title) ? res.data.data.title : self.data.luckInfo.act_name,//分享标题
  401 + // // 'imgDraw.views[4].text': (res.data.data&&res.data.data.share_content) ? res.data.data.share_content : '快来一起抽奖吧,精美奖品等着你!',//分享内容
  402 + // 'imgDraw.views[5].url': (res.data.data&&res.data.data.share_image) ? (imghost + res.data.data.share_image):(self.data.luckInfo.imageurl ? (imghost + self.data.luckInfo.imageurl):'/packpageB/images/luckDraw/jiang.png'),//分享图片
  403 + // 'imgDraw.views[14].text': util.formar_no_full(self.data.luckInfo.begindate) + ' 至 ' + util.formar_no_full(self.data.luckInfo.enddate),//活动时间
  404 + // });
  405 + } else {
  406 + luckStyle = `background: #da104b url(${imghost + 'miniapp/images/luckDraw/bg.png?v=2'}) no-repeat;`;
  407 + self.setData({
  408 + luckStyle,
  409 + 'imgDraw.views[5].url': self.data.luckInfo.imageurl ? (imghost + self.data.luckInfo.imageurl):'/packageB/images/luckDraw/jiang.png', //分享图片
  410 + //'blocks[0].imgs[0].src': imghost + ((res.data.data&&res.data.data.wheelBaseUrl) ? res.data.data.wheelBaseUrl:'miniapp/images/luckDraw/weel.png?v=2'), //转盘
  411 + //'buttons[0].imgs[0].src': imghost + ((res.data.data&&res.data.data.wheelPointerUrl) ? res.data.data.wheelPointerUrl:'miniapp/images/luckDraw/pointer.png?v=2'), //指针
  412 + });
  413 + // let color = template&&template.colorCode ? template.colorCode:'#da104b';
  414 +
  415 + // self.setData({
  416 + // luckStyle,
  417 + // });
  418 + };
  419 +
125 420 },
126 421 });
127 422 } else {
  423 +
  424 + if(luckInfo && luckInfo.imageurl) {
  425 + self.setData({
  426 + 'imgDraw.views[5].url': imghost + self.data.luckInfo.imageurl, //分享图片
  427 + });
  428 + };
  429 +
128 430 if(luckInfo && luckInfo.store_bannerUrl) {
129 431 self.setData({
130 432 bannerUrl: imghost + luckInfo.store_bannerUrl,
  433 + custom: true,
  434 + });
  435 + } else {
  436 + self.setData({
  437 + bannerUrl: imghost + 'miniapp/images/luckDraw/bg.png?v=2',
  438 + custom: false,
131 439 });
132 440 };
133   -
  441 +
  442 + let color = self.data.custom ? '#f0f0f0':'#da104b';
  443 + luckStyle = `background: ${color} url(${self.data.bannerUrl}) no-repeat;`;
  444 + self.setData({
  445 + luckStyle,
  446 + });
  447 +
134 448 };
135 449  
136 450  
... ... @@ -139,7 +453,6 @@ Page({
139 453 title: self.data.luckInfo.msgInfo,
140 454 icon: 'none',
141 455 });
142   - // return;
143 456 };
144 457  
145 458 },
... ... @@ -157,7 +470,7 @@ Page({
157 470 self.setData({
158 471 award,
159 472 });
160   - console.log('award', award);
  473 + // console.log('award', award);
161 474 self.prizeLayout(award);
162 475  
163 476 },
... ... @@ -178,8 +491,8 @@ Page({
178 491 self.setData({
179 492 record: res.data.data.pageData,
180 493 });
181   - };
182   - },
  494 + }
  495 + },
183 496 });
184 497  
185 498  
... ... @@ -201,6 +514,24 @@ Page({
201 514 },
202 515 });
203 516  
  517 + let mainUrl = app.globalData.setting.url;
  518 + // let stoid = app.globalData.setting.stoid;
  519 + let cj_id = this.data.options.id;
  520 + // let user_id = app.globalData.userInfo.user_id;
  521 +
  522 + wx.getImageInfo({
  523 + src: `${mainUrl}/api/wx/open/app/user/getWeAppEwm/${store_id}?sceneValue=${user_id}_${cj_id}&pageValue=pages/index/index/index`,
  524 + success (res) {
  525 + if(res.code != -1) {
  526 + self.setData({
  527 + 'imgDraw.views[16].url': res.path,
  528 + });
  529 + };
  530 +
  531 + }
  532 + });
  533 +
  534 +
204 535 };
205 536 };
206 537 },
... ... @@ -493,129 +824,184 @@ Page({
493 824 return;
494 825 };
495 826  
496   -
497   - if(this.data.luckInfo.user_LuckNumDay > 0 || this.data.luckInfo.vip_act_num == 0) {
498   - // console.log('start choujiang');
499   - // let start = false;
500   - if(!this.data.start) {
501   - this.data.start = true;
502   - // 获取抽奖组件实例
503   - const $lucky = this.selectComponent('#myLucky');
504   - // 调用play方法开始旋转
505   - $lucky.play();
  827 + // 获取积分
  828 + app.request.promisePost('/api/weshop/marketing/marketingLuckForm/startLuckIntegral', {
  829 + isShowLoading: false,
  830 + data: {
  831 + storeId: app.globalData.setting.stoid,
  832 + userId: app.globalData.userInfo.user_id,
  833 + LuckId: this.data.options.id,
  834 + },
  835 + })
  836 + .then(function(res) {
  837 + if(res.data.code == -1) {
  838 + //积分不足,弹出提示
  839 + self.data.luckInfo.msgInfo = res.data.msg
  840 + wx.showToast({
  841 + title: res.data.msg,
  842 + icon: 'none',
  843 + });
  844 + return;
  845 + };
  846 +
  847 + if(res.data.code == 0) {
506 848  
507   - // 获取抽奖结果
508   - app.request.post('/api/weshop/marketing/marketingLuckForm/startLuck', {
509   - isShowLoading: false,
510   - data: {
511   - storeId: app.globalData.setting.stoid,
512   - userId: app.globalData.userInfo.user_id,
513   - LuckId: this.data.options.id,
514   - },
515   - success: function(res) {
  849 + if(self.data.luckInfo.user_LuckNumDay > 0 || self.data.luckInfo.vip_act_num == 0) {
  850 + // console.log('start choujiang');
  851 + // let start = false;
  852 + if(!self.data.start) {
  853 + self.data.start = true;
  854 + // 获取抽奖组件实例
  855 + const $lucky = self.selectComponent('#myLucky');
  856 + // 调用play方法开始旋转
  857 + $lucky.play();
516 858  
517   - if(res.data.code == 0) {
518   - console.log('开始摇奖', res.data.data);
519   - if(self.data.luckInfo.vip_act_num != 0) {
520   - self.setData({
521   - 'luckInfo.user_LuckNumDay': self.data.luckInfo.user_LuckNumDay - 1,
522   - // isActive: true,
523   - });
524   - };
525   -
526   - self.setData({
527   - // 'luckInfo.user_LuckNumDay': self.data.luckInfo.user_LuckNumDay - 1,
528   - isActive: true,
529   - });
530   - // console.log('请求成功', res.data.data);
531   - let luckyId = res.data.data.id;
532   - let indexArr = self.luckyIndex(self.data.prizes, luckyId);
533   - // console.log('抽奖奖品id', luckyId);
534   - // console.log('奖品列表', self.data.prizes);
535   - // console.log('奖品对应的索引数组', indexArr);
536   - let random = Math.random() * indexArr.length >> 0;
537   - // console.log('random', random);
538   - let index = indexArr[random];
539   - setTimeout(() => {
540   - $lucky.stop(index);
541   - self.data.start = false;
542   - }, 3000);
  859 + // 获取抽奖结果
  860 + app.request.post('/api/weshop/marketing/marketingLuckForm/startLuck', {
  861 + isShowLoading: false,
  862 + data: {
  863 + storeId: app.globalData.setting.stoid,
  864 + userId: app.globalData.userInfo.user_id,
  865 + LuckId: self.data.options.id,
  866 + },
  867 + success: function(res) {
  868 +
  869 + if(res.data.code == 0) {
  870 + // console.log('开始摇奖', res.data.data);
  871 + if(self.data.luckInfo.vip_act_num != 0) {
  872 + self.setData({
  873 + 'luckInfo.user_LuckNumDay': self.data.luckInfo.user_LuckNumDay - 1,
  874 + // isActive: true,
  875 + });
  876 + };
  877 +
  878 + self.setData({
  879 + // 'luckInfo.user_LuckNumDay': self.data.luckInfo.user_LuckNumDay - 1,
  880 + isActive: true,
  881 + wow: res.data.data,
  882 + });
  883 + // console.log('wow', self.data.wow);
  884 + // console.log('请求成功', res.data.data);
  885 + let luckyId = res.data.data.id;
  886 + let indexArr = self.luckyIndex(self.data.prizes, luckyId);
  887 + // console.log('抽奖奖品id', luckyId);
  888 + // console.log('奖品列表', self.data.prizes);
  889 + // console.log('奖品对应的索引数组', indexArr);
  890 + let random = Math.random() * indexArr.length >> 0;
  891 + // console.log('random', random);
  892 + let index = indexArr[random];
  893 + setTimeout(() => {
  894 + $lucky.stop(index);
  895 + self.data.start = false;
  896 + }, 3000);
  897 +
  898 +
  899 + //获取兑奖记录
  900 + // app.request.get('/api/weshop/marketing/marketingLuckRecord/page', {
  901 + // isShowLoading: false,
  902 + // data: {
  903 + // store_id: app.globalData.setting.stoid,
  904 + // user_id: app.globalData.userInfo.user_id,
  905 + // luck_formid: self.data.options.id,
  906 + // luck_state: 1
  907 + // },
  908 + // success: function(res) {
  909 + // if(res.data.code == 0) {
  910 + // // console.log('res===>', res.data.data.pageData);
  911 + // self.setData({
  912 + // record: res.data.data.pageData,
  913 + // });
  914 + // };
  915 + // },
  916 + // });
  917 +
  918 +
  919 + } else {
  920 + let thxIndexArr = self.data.thxIndexArr;
  921 + const random = Math.random() * thxIndexArr.length >> 0;
  922 + const index = thxIndexArr[random];
  923 + // console.log('谢谢参与数组', thxIndexArr);
  924 + // console.log('请求出错产生谢谢参与的随机数', index);
  925 + setTimeout(() => {
  926 + $lucky.stop(index);
  927 + self.data.start = false;
  928 + }, 3000);
  929 +
  930 +
  931 +
  932 +
  933 + if(res.data.code == -1) {
  934 + wx.showToast({
  935 + title: res.data.msg,
  936 + icon: 'none',
  937 + });
  938 + self.data.luckInfo.msgInfo = res.data.msg;
  939 + return;
  940 + // self.data.start = true;
  941 + };
  942 +
  943 +
  944 + if(res.data.code == -2 && self.data.luckInfo.vip_act_num != 0) {
  945 + self.setData({
  946 + 'luckInfo.user_LuckNumDay': self.data.luckInfo.user_LuckNumDay - 1,
  947 + });
  948 + };
  949 +
  950 +
  951 + };
  952 +
543 953  
  954 + },
544 955  
545   - //获取兑奖记录
546   - // app.request.get('/api/weshop/marketing/marketingLuckRecord/page', {
547   - // isShowLoading: false,
548   - // data: {
549   - // store_id: app.globalData.setting.stoid,
550   - // user_id: app.globalData.userInfo.user_id,
551   - // luck_formid: self.data.options.id,
552   - // luck_state: 1
553   - // },
554   - // success: function(res) {
555   - // if(res.data.code == 0) {
556   - // // console.log('res===>', res.data.data.pageData);
557   - // self.setData({
558   - // record: res.data.data.pageData,
559   - // });
560   - // };
561   - // },
562   - // });
  956 + fail: function(res) {
  957 + // console.log('出错');
  958 + wx.showToast({
  959 + title: '数据请求失败',
  960 + icon: 'error',
  961 + });
  962 + let thxIndexArr = self.data.thxIndexArr;
  963 + const random = Math.random() * thxIndexArr.length >> 0;
  964 + const index = thxIndexArr[random];
  965 + setTimeout(() => {
  966 + $lucky.stop(index);
  967 + self.data.start = false;
  968 + }, 3000);
  969 + },
563 970  
564 971  
565   - } else {
566   - // console.log('请求出错');
567   - if(self.data.luckInfo.vip_act_num != 0) {
568   - self.setData({
569   - 'luckInfo.user_LuckNumDay': self.data.luckInfo.user_LuckNumDay - 1,
570   - });
571   - };
572 972  
573   - let thxIndexArr = self.data.thxIndexArr;
574   - const random = Math.random() * thxIndexArr.length >> 0;
575   - const index = thxIndexArr[random];
576   - // console.log('谢谢参与数组', thxIndexArr);
577   - // console.log('请求出错产生谢谢参与的随机数', index);
578   - setTimeout(() => {
579   - $lucky.stop(index);
580   - self.data.start = false;
581   - }, 3000);
582   - };
583   - },
584   -
585   - fail: function(res) {
586   - // console.log('出错');
587   - wx.showToast({
588   - title: '数据请求失败',
589   - icon: 'error',
590 973 });
591   - let thxIndexArr = self.data.thxIndexArr;
592   - const random = Math.random() * thxIndexArr.length >> 0;
593   - const index = thxIndexArr[random];
594   - setTimeout(() => {
595   - $lucky.stop(index);
596   - self.data.start = false;
597   - }, 3000);
598   - },
  974 +
  975 + }
599 976  
600   - });
  977 +
  978 + } else {
  979 + wx.showToast({
  980 + title: '你今天的抽奖次数已用完啦!~',
  981 + icon: 'none',
  982 + });
  983 + };
601 984  
602   - }
603   -
604   -
605   - } else {
606   - wx.showToast({
607   - title: '你今天的抽奖次数已用完啦!~',
608   - icon: 'none',
609   - });
610   - };
  985 + };
  986 + });
  987 +
  988 +
  989 +
  990 +
  991 +
611 992  
612 993 },
613 994 end (event) {
614 995 // 中奖奖品详情
615   - // console.log('zjiangla~~',event.detail.lbtype);
  996 + console.log('抽奖结果:',event.detail);
616 997 let no_luck_urltype = this.data.luckInfo.no_luck_urltype;
617   - let lbtype;
  998 + let lbtype = null;
  999 + // let good_id = null;
618 1000 let resultTitle = event.detail.fonts[0].text.replace('\n','');
  1001 + // if(event.detail.id) {
  1002 + // console.log('~~~~~~----++++++',event.detail.id);
  1003 + // good_id = event.detail.id;
  1004 + // };
619 1005 if(event.detail.lbtype == 5) {
620 1006 lbtype = 5;
621 1007 } else {
... ... @@ -627,13 +1013,15 @@ Page({
627 1013 showResult: true,
628 1014 showMask: true,
629 1015 resultTitle,
  1016 + showPopup: false,
630 1017 currentLbtype: lbtype,
  1018 + // good_id,
631 1019 });
632 1020  
633 1021  
634 1022  
635 1023  
636   - if(no_luck_urltype == 1) {
  1024 + if(no_luck_urltype == 1 && resultTitle == '谢谢参与') {
637 1025 if(this.data.luckInfo.no_luck_weappurl) {
638 1026 let num = this.data.num;
639 1027 let url = this.data.luckInfo.no_luck_weappurl;
... ... @@ -649,8 +1037,47 @@ Page({
649 1037 }, 1000);
650 1038  
651 1039 };
  1040 +
  1041 + };
  1042 +
  1043 +
  1044 + if(self.data.luckInfo.give_user) {
  1045 + if(resultTitle == '谢谢参与') {
  1046 + if(self.data.luckInfo.give_type == 1) {
  1047 + if(self.data.luckInfo.give_integral > 0) {
  1048 + wx.showToast({
  1049 + title: `获得游戏奖励积分${self.data.luckInfo.give_integral}`,
  1050 + icon: 'none',
  1051 + });
  1052 + };
  1053 + } else if((self.data.luckInfo.give_type == 2)) {
  1054 + if(self.data.luckInfo.give_growth > 0) {
  1055 + wx.showToast({
  1056 + title: `获得游戏奖励成长值${self.data.luckInfo.give_growth}`,
  1057 + icon: 'none',
  1058 + });
  1059 + };
  1060 + };
  1061 + };
  1062 + } else {
  1063 + if(self.data.luckInfo.give_type == 1) {
  1064 + if(self.data.luckInfo.give_integral > 0) {
  1065 + wx.showToast({
  1066 + title: `获得游戏奖励积分${self.data.luckInfo.give_integral}`,
  1067 + icon: 'none',
  1068 + });
  1069 + };
  1070 + } else if((self.data.luckInfo.give_type == 2)) {
  1071 + if(self.data.luckInfo.give_growth > 0) {
  1072 + wx.showToast({
  1073 + title: `获得游戏奖励成长值${self.data.luckInfo.give_growth}`,
  1074 + icon: 'none',
  1075 + });
  1076 + };
  1077 + };
652 1078 };
653 1079  
  1080 +
654 1081 },
655 1082  
656 1083 showPopup() {
... ... @@ -786,6 +1213,14 @@ Page({
786 1213 goto(e) {
787 1214 let url = '';
788 1215 let type = e.currentTarget.dataset.type;
  1216 + let ordersn = null;
  1217 + let buyreceive_id = null;
  1218 + if(e.currentTarget.dataset.ordersn) {
  1219 + ordersn = e.currentTarget.dataset.ordersn;
  1220 + };
  1221 + if(e.currentTarget.dataset.buyreceiveid) {
  1222 + buyreceive_id = e.currentTarget.dataset.buyreceiveid;
  1223 + };
789 1224 switch(type) {
790 1225 case 1: {
791 1226 url = '/pages/user/integral/integral';
... ... @@ -804,7 +1239,7 @@ Page({
804 1239 break;
805 1240 };
806 1241 case 6: {
807   - url = '/packageA/pages/myGift/myGift';
  1242 + url = `/pages/giftpack/giftpacklist/giftpacklist?isBuy=0&orderSn=${ordersn}&lbId=${buyreceive_id}`;
808 1243 break;
809 1244 };
810 1245 };
... ... @@ -812,20 +1247,30 @@ Page({
812 1247 },
813 1248  
814 1249 showQr(e) {
  1250 + let id = null;
815 1251 let store_id = app.globalData.setting.stoid;
816   - let id = e.currentTarget.dataset.id;
  1252 + if(e && e.currentTarget.dataset.id) {
  1253 + id = e.currentTarget.dataset.id;
  1254 + } else {
  1255 + id = this.data.wow.record_id;
  1256 + };
817 1257 let url = `/api/weshop/marketing/marketingLuckList/updateGoodsVerifyCode/${store_id}/${id}`;
  1258 + // console.log('good_id', id, url);
818 1259 app.request.put(url, {
819 1260 success: function(res) {
820 1261 if(res.data.code == 0) {
821 1262 let data = res.data.data;
822   - console.log('data!!!!', data);
823 1263 let barcode = self.selectComponent("#qrcode");
824 1264 barcode.open({val: data});
825 1265 self.setData({
826 1266 hiddenCanvas: true,
827 1267 showPopup: false,
828 1268 });
  1269 + } else {
  1270 + wx.showToast({
  1271 + title: res.data.msg,
  1272 + icon: 'none',
  1273 + });
829 1274 };
830 1275 },
831 1276  
... ... @@ -843,6 +1288,31 @@ Page({
843 1288 this.setData({
844 1289 showResult: false,
845 1290 });
846   - this.showPopup();
  1291 + this.showQr();
  1292 + },
  1293 +
  1294 + showPoster() {
  1295 + this.setData({
  1296 + hiddenCanvas: true,
  1297 + showMask: true,
  1298 + showPoster: true,
  1299 + });
  1300 + },
  1301 +
  1302 + closePoster() {
  1303 + this.setData({
  1304 + showMask: false,
  1305 + showPoster: false,
  1306 + hiddenCanvas: false,
  1307 + });
  1308 + },
  1309 +
  1310 +
  1311 +
  1312 + onImgOK(e) {
  1313 + this.setData({
  1314 + myimg: e.detail.path,
  1315 + });
847 1316 },
  1317 +
848 1318 })
849 1319 \ No newline at end of file
... ...
packageB/pages/luckactivity/luckinfo/luckinfo.json
... ... @@ -2,7 +2,8 @@
2 2 "usingComponents": {
3 3 "lucky-wheel":"/packageB/miniprogram_npm/mini-luck-draw/lucky-wheel/index",
4 4 "qrcode": "/components/my-qrcode/my-qrcode",
5   - "nodata": "/components/nodata/nodata"
  5 + "nodata": "/components/nodata/nodata",
  6 + "painter": "/packageB/components/painter/painter"
6 7 },
7 8 "enablePullDownRefresh": false,
8 9 "navigationBarTitleText": "幸运大转盘"
... ...
packageB/pages/luckactivity/luckinfo/luckinfo.wxml
1 1 <wxs module="filter" src="../../../../utils/filter.wxs"></wxs>
2 2 <wxs module="tool" src="./tool.wxs"></wxs>
3   -<view class="luck-container" style="background: {{template.colorCode ? template.colorCode:'#8102FD'}} url({{bannerUrl ? bannerUrl:(imghost + 'miniapp/images/luckDraw/bg.png')}}) no-repeat;">
4   -<!-- <view class="luck-container" style="background: url({{ bannerUrl}}) no-repeat;"> -->
  3 +<view class="luck-container {{!template&&custom ? 'on':''}}" style="{{luckStyle}}">
  4 +<!-- <view class="luck-container {{!template&&custom ? 'on':''}}" style="background: {{template&&template.colorCode ? template.colorCode:(custom ? '#f0f0f0':'#da104b')}} url({{bannerUrl ? bannerUrl:''}}) no-repeat;"> -->
5 5 <!-- 中奖人员 -->
6 6 <view class="swiper-container" wx:if="{{nameList && nameList.length != 0}}">
7 7 <swiper class="swiper" autoplay="true" circular="true" vertical="true" interval="3000">
... ... @@ -36,17 +36,17 @@
36 36 hiddenCanvas="{{hiddenCanvas}}"
37 37 />
38 38 </view>
39   - <view class="fs28 white t-c pdt10" wx:if="{{luckInfo.vip_act_num == 0}}">今天你有 <text class="fs50 c-yellow">不限次</text> 抽奖机会</view>
40   - <view class="fs28 white t-c pdt10" wx:else>今天你还有 <text class="fs50 c-yellow">{{filter.show_default(luckInfo.user_LuckNumDay, '0')}}</text> 次抽奖机会</view>
  39 + <view class="weel-txt fs28 white t-c pdt10" wx:if="{{luckInfo.vip_act_num == 0}}">今天你有 <text class="fs50 c-yellow cs">不限次</text> 抽奖机会</view>
  40 + <view class="weel-txt fs28 white t-c pdt10" wx:else>今天你还有 <text class="fs50 c-yellow cs">{{filter.show_default(luckInfo.user_LuckNumDay < 0 ? 0:luckInfo.user_LuckNumDay, '0')}}</text> 次抽奖机会</view>
41 41 <view class="tip-to-down expand-transition">
42 42 <text></text>
43 43 <text></text>
44 44 </view>
45 45 </view>
46 46 <!-- 奖品展示 -->
47   - <view wx:if="{{award}}">
  47 + <view wx:if="{{award && award.length != 0}}">
48 48 <view class="badge-container"><image src="{{imghost + 'miniapp/images/luckDraw/badge.png'}}" class="badge prizes" lazy-load></image></view>
49   - <view class="list br12 bg-white">
  49 + <view class="panel list br12 bg-white">
50 50 <view class="list-item" wx:for="{{award}}">
51 51 <view class="img-container">
52 52 <image wx:if="{{item.luck_goods_img}}" src="{{imghost + item.luck_goods_img}}" class="img" mode="aspectFit"></image>
... ... @@ -63,28 +63,24 @@
63 63 </view>
64 64 </view>
65 65 <!-- 活动展示 -->
66   - <view wx:if="{{luckInfo.remark}}">
  66 + <view>
67 67 <view class="badge-container"><image src="{{imghost + 'miniapp/images/luckDraw/badge.png'}}" class="badge activity" lazy-load></image></view>
68   - <view class="bg-white br12 pd20 fs28">
  68 + <view class="panel bg-white br12 pd20 fs28">
69 69 <!-- {{luckInfo.remark}} -->
70 70 <import src="../../../../utils/wxParse/wxParse.wxml"/>
71   - <template is="wxParse" data="{{wxParseData:content.nodes}}"/>
  71 + <!-- <template is="wxParse" data="{{wxParseData:content.nodes}}"/> -->
72 72 <!-- 时间 -->
73   - <!-- <view class="bdb">
74   - <view class="">
  73 + <view class="bdt">
  74 + <!-- <view class=""> -->
75 75 <view class="txt-red">活动时间:</view>
76   - <view class="fs28 pdv20">187606546456</view>
77   - </view>
78   - <view>
79   - <view class="txt-red">兑换时间:</view>
80   - <view class="fs28 pdv20">-</view>
81   - </view>
82   - </view> -->
  76 + <view class="fs28 pdv20">{{filter.format_time(luckInfo.begindate, 1) + ' 至 ' + filter.format_time(luckInfo.enddate, 1)}}</view>
  77 + <!-- </view> -->
  78 + </view>
83 79 <!-- 规则 -->
84   - <!-- <view class="bdb">
85   - <view class="txt-red pdt20">活动规则:</view>
86   - <view class="fs28 pdv20">-</view>
87   - </view> -->
  80 + <view class="bdt" wx:if="{{luckInfo.remark}}">
  81 + <view class="txt-red pdt20">活动说明:</view>
  82 + <view class="fs28 pdv20"><template is="wxParse" data="{{wxParseData:content.nodes}}"/></view>
  83 + </view>
88 84 <!-- 电话 -->
89 85 <!-- <view class="bdb">
90 86 <view class="txt-red pdt20">联系电话:</view>
... ... @@ -121,14 +117,17 @@
121 117 </view>
122 118 </view> -->
123 119 <!-- 技术支持 -->
124   - <view class="t-c">
  120 + <view class="logo-container t-c">
125 121 <!-- <view class="pdt20 fs26 text-underline">帮美店免费开通这个玩法</view> -->
126   - <view class="flex ai_c fs24 jc-center pdv20 white"><image src="{{imghost + 'miniapp/images/luckDraw/logo.png'}}" class="logo" lazy-load></image>提供技术支持</view>
  122 + <view class="flex ai_c fs24 jc-center pdv20 white"><image src="{{imghost + 'miniapp/images/luckDraw/logo.png?v=3'}}" class="logo" lazy-load></image>提供技术支持</view>
127 123 </view>
128 124 </view>
129 125  
  126 +<!-- 分享按钮 -->
  127 +<view class="circle-container zhuanfa" bindtap="showPoster"><text class="iconfont icon-zhuanfa1"></text></view>
  128 +
130 129 <!-- 悬浮按钮 -->
131   -<view class="gift-container {{((record && record.length != 0) || isActive) ? 'active':''}}" bindtap="showPopup"><text class="iconfont icon-liwu"></text></view>
  130 +<view class="circle-container gift {{((record && record.length != 0) || isActive) ? 'active':''}}" bindtap="showPopup"><text class="iconfont icon-liwu"></text></view>
132 131  
133 132 <!-- 弹窗 -->
134 133 <view class="popup-container" wx:if="{{showPopup}}">
... ... @@ -142,10 +141,11 @@
142 141 <view class="ellipsis-2 fs28">{{item.luck_name}}</view>
143 142 <view class="pdt20">
144 143 <view class="fs26 xc-black3">价值:<text class="rmb">{{item.luck_goods_price}}</text></view>
145   - <view class="flex ai_c jc_fe fs26 xc-black3 ">
  144 + <view class="flex ai_c {{item.luck_type == 5 ? 'jc_sb':'jc_fe'}} fs26 xc-black3 ">
146 145 <!-- <view style="visibility: {{item.luck_type == 5 ? 'visible':'hidden'}};">兑换状态:{{item.state == 0 ? '未兑换':'已兑换'}}</view> -->
147 146 <!-- <view style="">兑换状态:{{item.state == 0 ? '未兑换':'已兑换'}}</view> -->
148   - <view class="btn" bindtap="{{item.luck_type == 5 ? (item.state == 0 ? 'showQr':''):'goto'}}" data-type="{{item.luck_type}}" data-id="{{item.id}}">{{item.luck_type == 5 ? (item.state == 1 ? '已兑换':'兑换'):'查看'}}</view>
  147 + <view class="fs24 c-a" wx:if="{{item.luck_type == 5}}">兑换截止时间:{{filter.show_default(item.changeDate, '不限')}}</view>
  148 + <view class="btn" bindtap="{{item.luck_type == 5 ? (item.state == 0 ? 'showQr':''):'goto'}}" data-type="{{item.luck_type}}" data-id="{{item.id}}" data-ordersn="{{item.order_sn}}" data-buyreceiveid="{{item.buyreceive_id}}">{{item.luck_type == 5 ? (item.state == 1 ? '已兑换':'兑换'):'查看'}}</view>
149 149 </view>
150 150 </view>
151 151 </view>
... ... @@ -164,25 +164,45 @@
164 164 <block wx:if="{{resultTitle == '谢谢参与'}}">
165 165 <view class="bold c-tb fs40">{{luckInfo.no_luck_name}}</view>
166 166 <view class="pdt10">{{luckInfo.no_luck_remark}}</view>
167   - <view class="img-container2"><image src="{{imghost + (luckInfo.no_luck_img ? luckInfo.no_luck_img:'miniapp/images/luckDraw/gift.png')}}" class="img" mode="aspectFit"></image></view>
168   - <view class="pdt40 fs26 c9" wx:if="{{luckInfo.no_luck_urltype == 1 && luckInfo.no_luck_weappurl}}">{{num}}s后自动跳转...</view>
  167 + <view class="img-container2"><image src="{{imghost + (luckInfo.no_luck_img ? luckInfo.no_luck_img:'/miniapp/images/luckDraw/nolockimg.png')}}" class="img" mode="aspectFit"></image></view>
  168 + <view class="pdt40 fs26 c9 t-c" wx:if="{{(luckInfo.no_luck_urltype == 1) && luckInfo.no_luck_weappurl}}">{{num}}s后自动跳转...</view>
169 169 </block>
170 170 <block wx:else>
171 171 <view class="bold c-tb fs40">恭喜你获得</view>
172 172 <view class="pdt10">{{resultTitle}} </view>
173   - <view class="img-container2"><image src="{{imghost + 'miniapp/images/luckDraw/gift.png'}}" class="img" mode="aspectFit"></image></view>
  173 + <view class="img-container2">
  174 + <!-- <image src="{{imghost + 'miniapp/images/luckDraw/gift.png'}}" class="img" mode="aspectFit"></image> -->
  175 + <image wx:if="{{wow.luck_goods_img}}" src="{{imghost + wow.luck_goods_img}}" class="img" mode="aspectFit"></image>
  176 + <image src="{{imghost + tool.showDefaultImg(wow.lbtype)}}" class="img" mode="aspectFit" wx:else></image>
  177 + </view>
174 178 </block>
175 179 </view>
176 180  
177 181 <view class="pdt40" wx:if="{{currentLbtype == 5}}">
178   - <view class="btn btn2" bindtap="clickReceive">立即领取</view>
  182 + <view class="btn btn2" bindtap="clickReceive">立即兑换</view>
179 183 </view>
  184 +
  185 +
180 186 <!-- <view class="note">注:未领取就关闭弹窗视为主动放弃奖品。</view> -->
181 187 </view>
182 188 </view>
183 189  
184 190  
  191 +<!-- 海报 -->
  192 + <view class="poster-container" wx:if="{{showPoster}}">
  193 + <view class="t-r pdb20 white2"><text class="iconfont icon-close fs40" bindtap="closePoster"></text></view>
  194 + <image src="{{myimg}}" class="poster" show-menu-by-longpress></image>
  195 + <view class="pdt10 fs26 white2"><text class="iconfont icon-zhiwen"></text> 长按图片保存至相册</view>
  196 + </view>
  197 +
  198 +
185 199 <!-- 遮罩层 -->
186 200 <view class="mask" wx:if="{{showMask}}"></view>
187 201  
188   -<qrcode id="qrcode" bind:close="closeQr"></qrcode>
189 202 \ No newline at end of file
  203 +<!-- 遮罩层2 -->
  204 +<!-- <cover-view class="mask2"></cover-view> -->
  205 +
  206 +<qrcode id="qrcode" bind:close="closeQr"></qrcode>
  207 +
  208 +
  209 +<painter style="position: absolute; top: -9999rpx;" palette="{{imgDraw}}" bind:imgOK="onImgOK" />
190 210 \ No newline at end of file
... ...
packageB/pages/luckactivity/luckinfo/luckinfo.wxss
... ... @@ -13,7 +13,7 @@ page,
13 13  
14 14 .luck-container {
15 15 background-size: 100% auto !important;
16   - padding: 50% 20rpx 0;
  16 + padding: 42% 20rpx 0;
17 17 }
18 18  
19 19 .weel-container {
... ... @@ -68,7 +68,7 @@ page,
68 68 width: 140rpx;
69 69 height: 140rpx;
70 70 margin-right: 20rpx;
71   - background-color: #f5f5f5;
  71 + /* background-color: #f5f5f5; */
72 72 }
73 73  
74 74 .img {
... ... @@ -113,12 +113,12 @@ page,
113 113 }
114 114  
115 115 .logo {
116   - width: 120rpx;
117   - height: 40rpx;
  116 + width: 132rpx;
  117 + height: 37rpx;
118 118 margin-right: 10rpx;
119 119 }
120 120  
121   -.gift-container {
  121 +.circle-container {
122 122 background-color: rgba(44, 44, 44, 0.2);
123 123 width: 100rpx;
124 124 height: 100rpx;
... ... @@ -126,14 +126,21 @@ page,
126 126 color: white;
127 127 position: fixed;
128 128 right: 20rpx;
129   - bottom: 20rpx;
130 129 display: flex;
131 130 justify-content: center;
132 131 align-items: center;
133 132 z-index: 1;
134 133 }
135 134  
136   -.gift-container.active::after {
  135 +.circle-container.gift {
  136 + bottom: 20rpx;
  137 +}
  138 +
  139 +.circle-container.zhuanfa {
  140 + bottom: 160rpx;
  141 +}
  142 +
  143 +.circle-container.active::after {
137 144 content: '';
138 145 position: absolute;
139 146 width: 14rpx;
... ... @@ -145,7 +152,8 @@ page,
145 152 right: 10rpx;
146 153 }
147 154  
148   -.icon-liwu {
  155 +.icon-liwu,
  156 +.icon-zhuanfa1 {
149 157 font-size: 40rpx;
150 158 }
151 159  
... ... @@ -161,7 +169,7 @@ page,
161 169 width: 6rem;
162 170 z-index: 2;
163 171 -webkit-transform: translate(0, -50%); */
164   - transform: translate(0, -50%);
  172 + /* transform: translate(0, -50%); */
165 173 /* color: #fff;
166 174 font: normal 400 20px/1 'Josefin Sans', sans-serif;
167 175 letter-spacing: .1em;
... ... @@ -175,9 +183,10 @@ page,
175 183 left: 50%;
176 184 width: 1rem;
177 185 height: 1rem;
178   - margin-left: -12px;
179   - border-left: 1px solid #fff;
180   - border-bottom: 1px solid #fff;
  186 + /* transform: translateX(-50%); */
  187 + margin-left: -13rpx;
  188 + border-left: 2rpx solid #fff;
  189 + border-bottom: 2rpx solid #fff;
181 190 -webkit-transform: rotate(-45deg);
182 191 transform: rotate(-45deg);
183 192 -webkit-animation: sdb07 2s infinite;
... ... @@ -190,7 +199,7 @@ page,
190 199 animation-delay: 0s;
191 200 }
192 201 .tip-to-down text:nth-of-type(2) {
193   - top: 16px;
  202 + top: 32rpx;
194 203 -webkit-animation-delay: .15s;
195 204 animation-delay: .15s;
196 205 }
... ... @@ -311,9 +320,7 @@ page,
311 320 color: #ff2d4b;
312 321 }
313 322  
314   -.bdb {
315   - border-bottom: 2rpx solid #ebedf0;
316   -}
  323 +
317 324  
318 325 .c-yellow {
319 326 color: yellow;
... ... @@ -327,7 +334,7 @@ page,
327 334 width: 100%;
328 335 height: 100%;
329 336 top: 0;
330   - background-color: rgba(0,0,0,.5);
  337 + background-color: rgba(0,0,0,.7);
331 338 z-index: 1;
332 339 }
333 340  
... ... @@ -428,3 +435,50 @@ page,
428 435 padding: 0 10rpx;
429 436 }
430 437  
  438 +.bdt ~ .bdt {
  439 + border-top: 2rpx solid #ebedf0;
  440 +}
  441 +
  442 +.poster-container {
  443 + text-align: center;
  444 + color: white;
  445 + position: fixed;
  446 + top: 50%;
  447 + left: 50%;
  448 + transform: translate(-50%, -50%);
  449 + z-index: 9;
  450 +}
  451 +
  452 +.poster {
  453 + width: 554rpx;
  454 + height: 899rpx;
  455 + /* border-radius: 16rpx; */
  456 + margin: 0 auto;
  457 + /* background-color: pink; */
  458 +}
  459 +
  460 +
  461 +.luck-container.on .weel-txt {
  462 + color: black;
  463 +}
  464 +
  465 +.luck-container.on .badge,
  466 +.luck-container.on .logo-container,
  467 +.luck-container.on .tip-to-down {
  468 + -webkit-filter: brightness(60%);
  469 + filter: brightness(60%);
  470 +}
  471 +
  472 +.luck-container.on .panel {
  473 + box-shadow: 0 0 24rpx #e7e9eb;
  474 +}
  475 +
  476 +.luck-container.on .cs {
  477 + color: #ff5000;
  478 +}
  479 +
  480 +
  481 +
  482 +
  483 +
  484 +
... ...
packageB/pages/user/binding_info/binding_info.js 0 → 100644
  1 +// packageB/pages/user/binding_info/binding_info.js
  2 +Page({
  3 +
  4 + /**
  5 + * 页面的初始数据
  6 + */
  7 + data: {
  8 +
  9 + },
  10 +
  11 + /**
  12 + * 生命周期函数--监听页面加载
  13 + */
  14 + onLoad: function (options) {
  15 +
  16 + },
  17 +
  18 + /**
  19 + * 生命周期函数--监听页面初次渲染完成
  20 + */
  21 + onReady: function () {
  22 +
  23 + },
  24 +
  25 + /**
  26 + * 生命周期函数--监听页面显示
  27 + */
  28 + onShow: function () {
  29 +
  30 + },
  31 +
  32 + /**
  33 + * 生命周期函数--监听页面隐藏
  34 + */
  35 + onHide: function () {
  36 +
  37 + },
  38 +
  39 + /**
  40 + * 生命周期函数--监听页面卸载
  41 + */
  42 + onUnload: function () {
  43 +
  44 + },
  45 +
  46 + /**
  47 + * 页面相关事件处理函数--监听用户下拉动作
  48 + */
  49 + onPullDownRefresh: function () {
  50 +
  51 + },
  52 +
  53 + /**
  54 + * 页面上拉触底事件的处理函数
  55 + */
  56 + onReachBottom: function () {
  57 +
  58 + },
  59 +
  60 + /**
  61 + * 用户点击右上角分享
  62 + */
  63 + onShareAppMessage: function () {
  64 +
  65 + }
  66 +})
0 67 \ No newline at end of file
... ...
packageB/pages/user/binding_info/binding_info.json 0 → 100644
  1 +{
  2 + "usingComponents": {}
  3 +}
0 4 \ No newline at end of file
... ...
packageB/pages/user/binding_info/binding_info.wxml 0 → 100644
  1 +<!--packageB/pages/user/binding_info/binding_info.wxml-->
  2 +<text>packageB/pages/user/binding_info/binding_info.wxml</text>
... ...
packageB/pages/user/binding_info/binding_info.wxss 0 → 100644
  1 +/* packageB/pages/user/binding_info/binding_info.wxss */
0 2 \ No newline at end of file
... ...
packageB/pages/zuhegou/index/index.js 0 → 100644
  1 +
  2 +const app = getApp();
  3 +let self = null;
  4 +
  5 +let imgDraw = {
  6 + "width": "650px",
  7 + "height": "843px",
  8 + "background": "https://mshopimg.yolipai.net/miniapp/images/zhg/bg-zuhegou.jpg",
  9 + "views": [
  10 + { // 头像
  11 + "type": "image",
  12 + "url": "https://desk-fd.zol-img.com.cn/t_s960x600c5/g5/M00/0F/08/ChMkJlauzXWIDrXBAAdCg2xP7oYAAH9FQOpVAIAB0Kb342.jpg",
  13 + "css": {
  14 + "width": "100px",
  15 + "height": "100px",
  16 + "top": "20px",
  17 + "left": "275px",
  18 + "borderRadius": "100px",
  19 + "mode": "scaleToFill",
  20 + "borderWidth": "2px",
  21 + "borderColor": "#fff",
  22 + }
  23 + },
  24 + { //昵称
  25 + "type": "text",
  26 + "text": "我是店铺",
  27 + "css": {
  28 + "width": "650px",
  29 + "color": "#fff",
  30 + "top": "136px",
  31 + "fontSize": "26px",
  32 + "maxLines": "1",
  33 + "textAlign": "center",
  34 + }
  35 + },
  36 + { //10元任选3件
  37 + "type": "text",
  38 + "text": "10元任选3件",
  39 + "css": {
  40 + "color": "#fff",
  41 + "width": "650px",
  42 + "top": "270px",
  43 + "fontSize": "70px",
  44 + "maxLines": "1",
  45 + "textAlign": "center",
  46 + "fontWeight": "bold",
  47 + }
  48 + },
  49 + { //活动时间
  50 + "type": "text",
  51 + "text": "活动时间:2021.07.06 - 2021.07.08",
  52 + "css": {
  53 + "color": "#333",
  54 + "width": "650px",
  55 + "top": "440px",
  56 + "fontSize": "26px",
  57 + "fontWeight": "normal",
  58 + "maxLines": "1",
  59 + "textAlign": "center"
  60 + }
  61 + },
  62 + { // 码
  63 + "type": "qrcode",
  64 + "content": "二维码地址",
  65 + "css": {
  66 + "color": "#000",
  67 + "width": "200px",
  68 + "height": "200px",
  69 + "top": "525px",
  70 + "left": "225px",
  71 + }
  72 + },
  73 + { // 扫码提示
  74 + "type": "text",
  75 + "text": "长按扫码即可参与活动",
  76 + "css": {
  77 + "color": "#666",
  78 + "width": "650px",
  79 + "top": "750px",
  80 + "fontSize": "26px",
  81 + "textAlign": "center"
  82 + }
  83 + },
  84 + ]
  85 +};
  86 +
  87 +
  88 +Page({
  89 +
  90 + /**
  91 + * 页面的初始数据
  92 + */
  93 + data: {
  94 + showRule: false,
  95 + showMask: false,
  96 + showNum: false,
  97 + haveAdded: false,
  98 + imgDraw: imgDraw,
  99 + },
  100 +
  101 + /**
  102 + * 生命周期函数--监听页面加载
  103 + */
  104 + onLoad: function (options) {
  105 + self = this;
  106 + },
  107 +
  108 + /**
  109 + * 生命周期函数--监听页面初次渲染完成
  110 + */
  111 + onReady: function () {
  112 +
  113 + },
  114 +
  115 + /**
  116 + * 生命周期函数--监听页面显示
  117 + */
  118 + onShow: function () {
  119 +
  120 + },
  121 +
  122 + /**
  123 + * 生命周期函数--监听页面隐藏
  124 + */
  125 + onHide: function () {
  126 +
  127 + },
  128 +
  129 + /**
  130 + * 生命周期函数--监听页面卸载
  131 + */
  132 + onUnload: function () {
  133 +
  134 + },
  135 +
  136 + /**
  137 + * 页面相关事件处理函数--监听用户下拉动作
  138 + */
  139 + onPullDownRefresh: function () {
  140 +
  141 + },
  142 +
  143 + /**
  144 + * 页面上拉触底事件的处理函数
  145 + */
  146 + onReachBottom: function () {
  147 +
  148 + },
  149 +
  150 + /**
  151 + * 用户点击右上角分享
  152 + */
  153 + onShareAppMessage: function () {
  154 +
  155 + },
  156 +
  157 + /**
  158 + * 点击规则详情,弹出规则
  159 + */
  160 + showRule() {
  161 + this.setData({
  162 + type: 0, //控制显示规则详情还是提示信息,0规则详情,1提示信息
  163 + showRule: true,
  164 + showMask: true,
  165 + });
  166 + },
  167 +
  168 + /**
  169 + * 点击关闭按钮关闭规则详情弹窗
  170 + */
  171 + closeRule() {
  172 + this.setData({
  173 + showRule: false,
  174 + showMask: false,
  175 + });
  176 + },
  177 +
  178 + /**
  179 + * 点击提示信息
  180 + */
  181 + showInfo() {
  182 + this.setData({
  183 + type: 1,
  184 + showRule: true,
  185 + showMask: true,
  186 + });
  187 + },
  188 +
  189 + /**
  190 + * 加入购物车
  191 + */
  192 + addToCart() {
  193 + let haveAdded = !this.data.haveAdded;
  194 + let title = '';
  195 + if(haveAdded) {
  196 + title = '加入购物车成功';
  197 + this.setData({
  198 + num: 1,
  199 + showNum: true,
  200 + haveAdded,
  201 + });
  202 + wx.showToast({
  203 + title: title,
  204 + icon: 'success',
  205 + });
  206 + } else {
  207 + wx.showModal({
  208 + title: '温馨提示',
  209 + content: '确定将该商品移出购物车?',
  210 + success (res) {
  211 + if (res.confirm) {
  212 + console.log('用户点击确定');
  213 + title = '移除购物车成功';
  214 + self.setData({
  215 + showNum: false,
  216 + haveAdded: false,
  217 + });
  218 + wx.showToast({
  219 + title: title,
  220 + icon: 'success',
  221 + });
  222 + } else if (res.cancel) {
  223 + console.log('用户点击取消')
  224 + self.setData({
  225 + haveAdded: true,
  226 + });
  227 + }
  228 + }
  229 + })
  230 +
  231 + }
  232 +
  233 + },
  234 +
  235 + /**
  236 + * 增加数量
  237 + */
  238 + add() {
  239 + this.setData({
  240 + num: ++this.data.num,
  241 + });
  242 + },
  243 +
  244 + /**
  245 + * 减少数量
  246 + */
  247 + sub() {
  248 + let num = this.data.num;
  249 + if(num >= 2) {
  250 + this.setData({
  251 + num: --this.data.num,
  252 + });
  253 + };
  254 + if(num == 1) {
  255 + // this.setData({
  256 + // showNum: false,
  257 + // haveAdded: false,
  258 + // });
  259 + wx.showModal({
  260 + title: '温馨提示',
  261 + content: '确定将该商品移出购物车?',
  262 + success (res) {
  263 + if (res.confirm) {
  264 + console.log('用户点击确定');
  265 + // title = '移除购物车成功';
  266 + self.setData({
  267 + showNum: false,
  268 + haveAdded: false,
  269 + });
  270 + wx.showToast({
  271 + title: '移除购物车成功',
  272 + icon: 'success',
  273 + });
  274 + } else if (res.cancel) {
  275 + console.log('用户点击取消')
  276 + self.setData({
  277 + haveAdded: true,
  278 + });
  279 + }
  280 + }
  281 + })
  282 + }
  283 + },
  284 +
  285 + /**
  286 + * 分享
  287 + */
  288 + share() {
  289 + this.setData({
  290 + showMask: true,
  291 + showPoster: true,
  292 + });
  293 + },
  294 +
  295 + /**
  296 + * 关闭海报
  297 + */
  298 + closePoster() {
  299 + this.setData({
  300 + showMask: false,
  301 + showPoster: false,
  302 + });
  303 + },
  304 +
  305 + onImgOK(e) {
  306 + console.log(e.detail.path);
  307 + this.setData({
  308 + myimg: e.detail.path,
  309 + });
  310 + },
  311 +})
0 312 \ No newline at end of file
... ...
packageB/pages/zuhegou/index/index.json 0 → 100644
  1 +{
  2 + "usingComponents": {
  3 + "catch": "/components/catch/catch",
  4 + "nodata": "/components/nodata/nodata",
  5 + "painter": "/packageB/components/painter/painter"
  6 + },
  7 + "enablePullDownRefresh": false,
  8 + "navigationBarTitleText": "组合购"
  9 +}
0 10 \ No newline at end of file
... ...
packageB/pages/zuhegou/index/index.wxml 0 → 100644
  1 +<view class="container">
  2 + <view class="flex jc_sb">
  3 + <view class="white">以下商品10元任选3件</view>
  4 + <view class="rule-container" bindtap="showRule">规则详情<text class="iconfont icon-arrow_right"></text></view>
  5 + </view>
  6 + <view class="countdown-container">距结束还剩 1天<text class="num-box">12</text>:<text class="num-box">12</text>:<text class="num-box">00</text></view>
  7 + <!-- 商品列表 -->
  8 + <view class="list-container">
  9 + <view class="list">
  10 +
  11 + <view class="list-item">
  12 + <view class="img-container"><image src="../../../images/luckDraw/yhq.png" mode="aspectFit" class="img-block"></image></view>
  13 + <view class="pdl20 flex f1 fdc jc_sb">
  14 + <view>
  15 + <view class="fs30 ellipsis-2">商品名称商品名称</view>
  16 + <view class="num-container" wx:if="{{showNum}}">
  17 + <text class="num-box c-dedfe3" bindtap="sub">-</text>
  18 + <text class="num-box">{{num}}</text>
  19 + <text class="num-box" bindtap="add">+</text>
  20 + </view>
  21 + </view>
  22 +
  23 + <view class="flex jc_sb ai_end pdt12">
  24 + <view>
  25 + <text class="rmb fs30 c-red">0.01</text>
  26 + <text class="rmb fs20 line-through cb">200.00</text>
  27 + </view>
  28 + <view class="c-red pdr10 {{haveAdded ? 'active':''}}" bindtap="addToCart"><text class="iconfont icon-gouwuche fs60"></text></view>
  29 + </view>
  30 + </view>
  31 + </view>
  32 +
  33 +
  34 + <!-- <nodata nodataContainer="t-c" wx:if="{{list.pageData.length == 0}}"></nodata> -->
  35 + <nodata nodataContainer="t-c"></nodata>
  36 + </view>
  37 +
  38 + <view class="noMore">没有更多了</view>
  39 +
  40 +
  41 + </view>
  42 + <!-- 底部栏 -->
  43 + <view class="bar-container">
  44 + <view class="t-c bg-fcfb c-fa8b2b fs28 pd20">再买2件,下单立享【10元任选3件】</view>
  45 + <view class="flex jc_sb ai_c pd20">
  46 + <view class="fs30">合计:<text class="rmb c-red fs40">0.01</text><text class="iconfont icon-info cb fs24 mgl10" bindtap="showInfo"></text></view>
  47 + <view class="btn-container">去购物车</view>
  48 + </view>
  49 + </view>
  50 + <!-- 分享 -->
  51 + <view class="share-container" bindtap="share">
  52 + <text class="iconfont icon-zhuanfa fs40"></text>
  53 + <view class="fs22 c-8">分享</view>
  54 + </view>
  55 +
  56 +
  57 + <!-- 规则详情和提示信息弹窗 -->
  58 + <view class="rule-pop-container" wx:if="{{showRule}}">
  59 + <view class="pop-title">{{!type ? '规则详情':'提示'}}<text class="iconfont icon-guan" bindtap="closeRule"></text></view>
  60 + <block wx:if="{{!type}}">
  61 + <view class="pdt40">
  62 + <view class="pdb20">活动时间</view>
  63 + <view class="">2020.12.11 18:00:00 至 2020.12.11 18:00:00</view>
  64 + </view>
  65 + <view class="pdt40">
  66 + <view class="pdb20">活动内容</view>
  67 + <view class="">
  68 + <view class="pdb10">1、活动商品范围内,任选3件仅需10元;</view>
  69 + <view class="">2、此优惠可无限叠加,买得越多优惠越多;</view>
  70 + </view>
  71 + </view>
  72 + <view class="pdt40 pdb20">
  73 + <view class="pdb20">优惠叠加</view>
  74 + <view class="">不可与其他优惠活动同时使用</view>
  75 + </view>
  76 + </block>
  77 + <block wx:else>
  78 + <view class="pdt40 pdb20">
  79 +
  80 + <!-- <view class="pdb20">优惠叠加</view> -->
  81 +
  82 + <view class="">合计金额及提示仅为初步预估,请以最终下单金额为准。</view>
  83 + </view>
  84 + </block>
  85 + <view class="pdv20">
  86 + <view class="btn" bindtap="closeRule">我知道了</view>
  87 + </view>
  88 + </view>
  89 +
  90 + <!-- 遮罩层 -->
  91 + <view class="mask" wx:if="{{showMask}}"></view>
  92 +
  93 + <!-- 海报 -->
  94 + <view class="poster-container" wx:if="{{showPoster}}">
  95 + <view class="t-r pdb20 white2"><text class="iconfont icon-close fs40" bindtap="closePoster"></text></view>
  96 + <image src="{{myimg}}" class="poster" show-menu-by-longpress></image>
  97 + <view class="pdt10 fs26 white2"><text class="iconfont icon-zhiwen"></text> 长按图片保存至相册</view>
  98 + </view>
  99 +
  100 +</view>
  101 +
  102 +<painter style="position: absolute; top: -9999rpx;" palette="{{imgDraw}}" bind:imgOK="onImgOK" />
  103 +
  104 +<!-- 活动异常提醒 -->
  105 +<!-- <catch>当前活动已结束</catch> -->
  106 +
  107 +
  108 +
... ...
packageB/pages/zuhegou/index/index.wxss 0 → 100644
  1 +/* packageB//pages/zuhegou/index/index.wxss */
  2 +page {
  3 + background: #f5f5f5 linear-gradient(to bottom, #FB5A2F, #FA7958, #f5f5f5 26%) no-repeat;
  4 +}
  5 +.container {
  6 + padding: 20rpx 20rpx 240rpx 20rpx;
  7 +}
  8 +.countdown-container {
  9 + font-size: 26rpx;
  10 + padding-top: 10rpx;
  11 + color: white;
  12 +}
  13 +
  14 +.num-box {
  15 + display: inline-block;
  16 + background-color: rgba(255,255,255,.2);
  17 + box-sizing: border-box;
  18 + min-width: 40rpx;
  19 + padding: 4rpx;
  20 + margin: 0 8rpx;
  21 + border-radius: 6rpx;
  22 + text-align: center;
  23 +}
  24 +
  25 +.rule-container {
  26 + font-size: 24rpx;
  27 + background-color: rgba(255,255,255,.2);
  28 + padding: 10rpx 5rpx 10rpx 20rpx;
  29 + border-radius: 26rpx 0 0 26rpx;
  30 + margin-right: -20rpx;
  31 + color: white;
  32 +}
  33 +
  34 +.icon-arrow_right {
  35 + font-size: 24rpx;
  36 +}
  37 +
  38 +.list-container {
  39 + padding-top: 30rpx;
  40 +}
  41 +
  42 +.list {
  43 + border-radius: 10rpx;
  44 + background-color: white;
  45 +}
  46 +
  47 +.list-item {
  48 + padding: 20rpx;
  49 + display: flex;
  50 +}
  51 +
  52 +.img-container {
  53 + width: 200rpx;
  54 + height: 200rpx;
  55 + background-color: #f0f0f0;
  56 + border-radius: 8rpx;
  57 +}
  58 +
  59 +.num-container {
  60 + font-size: 28rpx;
  61 + padding-top: 10rpx;
  62 + text-align: right;
  63 +}
  64 +
  65 +.num-container .num-box {
  66 + background-color: #f3f3f3;
  67 +}
  68 +
  69 +
  70 +
  71 +.noMore {
  72 + padding: 20rpx;
  73 + color: #bbb;
  74 + text-align: center;
  75 + font-size: 26rpx;
  76 +}
  77 +
  78 +.rmb::before {
  79 + content: '¥';
  80 + font-size: 22rpx;
  81 +}
  82 +
  83 +.bar-container {
  84 + position: fixed;
  85 + left: 0;
  86 + bottom: 0;
  87 + width: 100%;
  88 + background-color: white;
  89 +}
  90 +
  91 +.bg-fcfb {
  92 + background-color: #FCFBE5;
  93 +}
  94 +
  95 +.c-fa8b2b {
  96 + color: #FA8B2B;
  97 +}
  98 +
  99 +.c-8 {
  100 + color: #888;
  101 +}
  102 +
  103 +.c-dedfe3 {
  104 + color: #DEDFE3;
  105 +}
  106 +
  107 +.btn-container {
  108 + padding: 16rpx 40rpx;
  109 + background-color: red;
  110 + color: white;
  111 + font-size: 30rpx;
  112 + border-radius: 36rpx;
  113 + background: -webkit-linear-gradient(left,#ff5000,#ff2000) no-repeat;
  114 +}
  115 +
  116 +.share-container {
  117 + position: fixed;
  118 + right: 20rpx;
  119 + bottom: 200rpx;
  120 + width: 100rpx;
  121 + height: 100rpx;
  122 + border-radius: 50%;
  123 + background-color: white;
  124 + display: flex;
  125 + flex-direction: column;
  126 + justify-content: center;
  127 + align-items: center;
  128 + box-shadow: 0 0 16rpx #CCC;
  129 +}
  130 +
  131 +.mask {
  132 + position: fixed;
  133 + top: 0;
  134 + bottom: 0;
  135 + left: 0;
  136 + right: 0;
  137 + background-color: rgba(0,0,0,.6);
  138 +}
  139 +
  140 +.rule-pop-container {
  141 + position: fixed;
  142 + left: 0;
  143 + bottom: 0;
  144 + width: 100%;
  145 + background-color: white;
  146 + z-index: 1;
  147 + border-radius: 16rpx 16rpx 0 0;
  148 + padding: 0 40rpx;
  149 + box-sizing: border-box;
  150 + font-size: 28rpx;
  151 + color: #444;
  152 +}
  153 +
  154 +.pop-title {
  155 + padding: 20rpx 0;
  156 + text-align: center;
  157 + font-size: 32rpx;
  158 + position: relative;
  159 +}
  160 +.icon-guan {
  161 + position: absolute;
  162 + right: 0;
  163 + font-size: 26rpx;
  164 + top: 50%;
  165 + transform: translateY(-50%);
  166 + color: #ccc;
  167 +}
  168 +
  169 +.btn {
  170 + color: white;
  171 + padding: 20rpx 0;
  172 + text-align: center;
  173 + border-radius: 40rpx;
  174 + background: -webkit-linear-gradient(left,#ff5000,#ff2000) no-repeat;
  175 +}
  176 +
  177 +.active {
  178 + color: #ccc;
  179 +}
  180 +
  181 +.poster-container {
  182 + text-align: center;
  183 + color: white;
  184 + position: fixed;
  185 + top: 50%;
  186 + left: 50%;
  187 + transform: translate(-50%, -50%);
  188 +}
  189 +
  190 +.poster {
  191 + width: 650rpx;
  192 + height: 843rpx;
  193 + border-radius: 16rpx;
  194 + margin: 0 auto;
  195 +}
  196 +
  197 +.white2 {
  198 + color: rgba(255,255,255,.8);
  199 +}
0 200 \ No newline at end of file
... ...
pages/giftpack/festival/festival.js
... ... @@ -175,21 +175,20 @@ Page({
175 175 }
176 176 },
177 177 function (res) {
178   -
179 178 }
180   -
181 179 )
182   -
183 180 }
184 181 },
185 182 //获取节日有礼信息
186 183 is_festival: function(e) {
187 184 var th = this;
188 185 var url = "/api/weshop/marketing/holiday/act/judge";
  186 + console.log(th.data.getActId);
189 187 getApp().request.promiseGet(url, {
190 188 data: {
191 189 storeId: a.stoid, //商家ID
192   - userId: d.user_id //用户ID
  190 + userId: d.user_id, //用户ID
  191 + id:th.data.getActId
193 192 }
194 193 }).then(res => {
195 194 if (res.data.code == 0) {
... ... @@ -197,7 +196,6 @@ Page({
197 196 bimg: res.data.data.actImg,
198 197 actFontColor: res.data.data.actFontColor, //字体颜色
199 198 actBgColor: res.data.data.actBgColor, //背景颜色
200   -
201 199 })
202 200 }
203 201 })
... ...
pages/giftpack/festival/festival.wxml
1 1 <view style="background-color:{{actBgColor==undefined?'#FFB72D':actBgColor}}">
2 2 <view class="image_box">
3   - <image src="{{iurl+bimg}}" lazy-load="true"></image>
  3 + <image src="{{iurl+bimg?bimg:'/miniapp/images/default_g_img.gif'}}" binderror="bind_bnerr1" data-errorimg="bimg" lazy-load="true"></image>
4 4 </view>
5 5 <block wx:if="{{itemShow}}">
6 6 <view class="top rel">
... ...
pages/goods/goodsInfo/goodsInfo.js
... ... @@ -253,9 +253,9 @@ Page({
253 253  
254 254 //------初始化加载----------
255 255 onLoad: function(t) {
256   - wx.setNavigationBarTitle({
257   - title: t.title,
258   - })
  256 +
  257 +
  258 +
259 259 var ee = this,
260 260 that = ee,
261 261 th = ee,
... ... @@ -773,7 +773,11 @@ Page({
773 773 });
774 774 }
775 775 }
776   -
  776 + //动态获取商品名称
  777 + wx.setNavigationBarTitle({
  778 + title: t.data.data.goods_name,
  779 + })
  780 +
777 781 //-- 把商品的赋值 --
778 782 ee.data.fir_goods=JSON.parse(JSON.stringify(t.data.data));
779 783 ee.check_is_youhui(ee.data.gid);
... ... @@ -2098,7 +2102,6 @@ Page({
2098 2102 async get_sku(stoid, gd, g_id, is_normal, func) {
2099 2103 var tt = this,arrdata=null;
2100 2104 var now=ut.gettimestamp();
2101   -
2102 2105 await getApp().request.promiseGet("/api/weshop/goods/page", {
2103 2106 data: {
2104 2107 store_id: o.stoid,
... ... @@ -4210,10 +4213,10 @@ Page({
4210 4213 if(th.data.poster){
4211 4214 var erm_x= parseFloat(th.data.poster.ewm_x)*2;
4212 4215 var erm_y= parseFloat(th.data.poster.ewm_y)*2;
4213   - context.drawImage(vpath, erm_x * unit, erm_y * unit, 120 * unit, 120 * unit);
  4216 + context.drawImage(vpath, erm_x * unit, erm_y * unit, 136 * unit, 136 * unit);
4214 4217 }else{
4215 4218 //---二维吗图---
4216   - context.drawImage(vpath, 410 * unit, 726 * unit, 115 * unit, 125 * unit);
  4219 + context.drawImage(vpath, 390 * unit, 726 * unit, 136 * unit, 136 * unit);
4217 4220 }
4218 4221  
4219 4222 break;
... ... @@ -4243,10 +4246,10 @@ Page({
4243 4246 if(th.data.poster){
4244 4247 var erm_x= parseFloat(th.data.poster.ewm_x)*2;
4245 4248 var erm_y= parseFloat(th.data.poster.ewm_y)*2;
4246   - context.drawImage(vpath, erm_x * unit, erm_y * unit, 120 * unit, 120 * unit);
  4249 + context.drawImage(vpath, erm_x * unit, erm_y * unit, 135 * unit, 135 * unit);
4247 4250 }else{
4248 4251 //---二维吗图---
4249   - context.drawImage(vpath, 420 * unit, 726 * unit, 120 * unit, 120 * unit);
  4252 + context.drawImage(vpath, 390 * unit, 726 * unit, 135 * unit, 135 * unit);
4250 4253 }
4251 4254 break;
4252 4255  
... ... @@ -4290,10 +4293,10 @@ Page({
4290 4293 if(th.data.poster){
4291 4294 var erm_x= parseFloat(th.data.poster.ewm_x)*2;
4292 4295 var erm_y= parseFloat(th.data.poster.ewm_y)*2;
4293   - context.drawImage(vpath, erm_x * unit, erm_y * unit, 120 * unit, 120 * unit);
  4296 + context.drawImage(vpath, erm_x * unit, erm_y * unit, 136 * unit, 136 * unit);
4294 4297 }else{
4295 4298 //---二维吗图---
4296   - context.drawImage(vpath, 420 * unit, 726 * unit, 120 * unit, 120 * unit);
  4299 + context.drawImage(vpath, 390 * unit, 726 * unit, 136 * unit, 136 * unit);
4297 4300 }
4298 4301 break
4299 4302 case 3: //阶梯团的展示
... ... @@ -4334,7 +4337,7 @@ Page({
4334 4337 context.setFillStyle("black")
4335 4338 context.fillText("快来和我一起拼团吧!", 40 * unit, 820 * unit);
4336 4339 //context.font = 'normal bold 18px sans-serif';
4337   - context.setFontSize(22 * unit)
  4340 + context.setFontSize(21 * unit)
4338 4341 context.fillText("长按识别二维码,立即参团", 40 * unit, 850 * unit);
4339 4342  
4340 4343  
... ... @@ -4342,10 +4345,10 @@ Page({
4342 4345 if(th.data.poster){
4343 4346 var erm_x= parseFloat(th.data.poster.ewm_x)*2;
4344 4347 var erm_y= parseFloat(th.data.poster.ewm_y)*2;
4345   - context.drawImage(vpath, erm_x * unit, erm_y * unit, 120 * unit, 120 * unit);
  4348 + context.drawImage(vpath, erm_x * unit, erm_y * unit, 136 * unit, 136 * unit);
4346 4349 }else{
4347 4350 //---二维吗图---
4348   - context.drawImage(vpath, 420 * unit, 726 * unit, 120 * unit, 120 * unit);
  4351 + context.drawImage(vpath, 390 * unit, 726 * unit, 136 * unit, 136 * unit);
4349 4352 }
4350 4353 break
4351 4354  
... ...
pages/index/index/index.js
... ... @@ -978,15 +978,25 @@ Page({
978 978 var giftBagId = res.data.data.gifBagId; //礼包id
979 979 var nav_url = "/pages/giftpack/festival/festival?actId=" + actid + '&' + 'actType=' + 3 + '&' + 'giftBagId=' + giftBagId;
980 980 var swiperimage = th.data.swiperimage;
981   - var actBoundImg = res.data.data.actBoundImg;
  981 + var actBoundImg = res.data.data.actBoundImg?res.data.data.actBoundImg:'/miniapp/images/default_g_img.gif';
982 982  
983 983 th.data.holiday_image= res.data.data.actImg;
984 984 th.data.holiday_url=nav_url;
985 985  
986 986 var img = {
987 987 image: actBoundImg,
988   - nav_url: nav_url
  988 + nav_url: nav_url,
  989 + id:res.data.data.id,
  990 + type:'festival'
989 991 }
  992 +
  993 + for(var i in swiperimage){
  994 + var item=swiperimage[i];
  995 + if(item.id ==img.id && item.type==img.type){
  996 + return false;
  997 + }
  998 + }
  999 +
990 1000 swiperimage.unshift(img);
991 1001 th.setData({
992 1002 swiperimage: swiperimage,
... ...
pages/index/index/index.wxml
... ... @@ -9,7 +9,7 @@
9 9 <!--普通界面-->
10 10 <wxs module="filter" src="../../../utils/filter.wxs"></wxs>
11 11  
12   -<view class="container rel" wx:if="{{ishow}}">
  12 +<view class="container rel nor" wx:if="{{ishow}}">
13 13 <block wx:if="{{banner}}">
14 14 <image class="xc-top-img abs" src="{{url}}/miniapp/images/top-img.png"></image>
15 15 </block>
... ...
pages/index/index/index.wxss
... ... @@ -9,7 +9,6 @@
9 9 z-index: 99;
10 10 }
11 11  
12   -
13 12 .search-box {
14 13 /* position: fixed;
15 14 top: 0;
... ... @@ -976,6 +975,10 @@ page {
976 975  
977 976 .container {
978 977 overflow: hidden;
  978 + /* padding-top: 140rpx; */
  979 +}
  980 +
  981 +.container.nor{
979 982 padding-top: 140rpx;
980 983 }
981 984  
... ...
pages/user/binding_info/binding_info.js deleted
1   -var e = getApp(),app=e, a = e.request, t = e.globalData.setting,os=t, i = require("../../../utils/common.js");
2   -
3   -Page({
4   - data: {
5   - url: t.url,
6   - iurl: t.imghost,
7   - nickName: "",
8   - userHeadPic: "",
9   - isRegist: !1,
10   - bindMobile: "",
11   - bindCode: "",
12   - regMobile: "",
13   - regCode: "",
14   - regPwd: "",
15   - isAgree: !1,
16   - canGetCode: !1,
17   -
18   - config:null,
19   -
20   - store: null,
21   - imghots: os.imghost,
22   - gettime:0,
23   - },
24   - onLoad: function(e) {
25   - var th=this;
26   - app.getConfig(function (e) {
27   - th.setData({ store: e });
28   - })
29   - app.getConfig2(function (e) {
30   - var cf = JSON.parse(e.sms_send_type);
31   - th.setData({ config: cf });
32   - console.log(th.data.config);
33   - })
34   -
35   -
36   - },
37   - account: function() {
38   - this.setData({
39   - isRegist: !1
40   - });
41   - },
42   - regist: function() {
43   - this.setData({
44   - isRegist: !0
45   - });
46   - },
47   - setMobile: function(e) {
48   - this.data.bindMobile = e.detail.value;
49   - },
50   - setCode: function(e) {
51   - this.data.bindCode = e.detail.value;
52   - },
53   -
54   - //---获取短信验证码---
55   - getCode: function(t) {
56   - var th=this;
57   - if ("" != this.data.bindMobile) {
58   - var s = this;
59   - a.post("/api/weshop/smslog/sendsms", {
60   - data: {
61   - mobile: this.data.bindMobile,
62   - store_id: os.stoid,
63   - wxopenid: app.globalData.openid,
64   - },
65   - success: function(e) {
66   - if(e.data.code==0){
67   - th.setData({ gettime: th.data.config.time_out, canGetCode:1});
68   - th.setInt();
69   - }else{
70   - e.showWarning(e.data.msg);
71   - }
72   - }
73   - });
74   - } else e.showWarning("请输入手机号码");
75   - },
76   -
77   - //----发送验证码的推送时间倒计时---
78   - setInt:function(){
79   - var th=this;
80   - var it=setInterval(function(){
81   - var ti = th.data.gettime-1;
82   - if (ti<=0){
83   - th.setData({ gettime:0, canGetCode: !1 });
84   - clearInterval(it);
85   - }
86   - else{
87   - th.setData({ gettime: ti,});
88   - }
89   - },1000);
90   - },
91   -
92   - setRegMobile: function(e) {
93   - this.data.regMobile = e.detail.value;
94   - },
95   - setRegPwd: function(e) {
96   - this.data.regPwd = e.detail.value;
97   - },
98   - setRegCode: function(e) {
99   - this.data.regCode = e.detail.value;
100   - },
101   - getRegCode: function(t) {
102   - if ("" != this.data.regMobile) {
103   - var s = this;
104   - a.post("/Home/Api/checkRegMobile", {
105   - data: {
106   - mobile: this.data.regMobile
107   - },
108   - success: function(e) {
109   - i.sendBindSmsCode(s.data.regMobile);
110   - }
111   - });
112   - } else e.showWarning("请输入手机号码");
113   - },
114   - check: function() {
115   - this.setData({
116   - isAgree: !this.data.isAgree
117   - });
118   - },
119   - bindAccount: function() {
120   - var t = this;
121   - var r = getApp().globalData.getu;
122   - var openid = getApp().globalData.openid;
123   -
124   - "" != this.data.bindMobile ? "" != this.data.bindCode ? a.get("/api/weshop/users/thirdLogin", {
125   - data: {
126   - mobile: t.data.bindMobile,
127   - code: t.data.bindCode,
128   - openid: openid,
129   - nickname: r.nickName,
130   - head_pic: r.avatarUrl,
131   - sex: r.gender,
132   - store_id:os.stoid,
133   - },
134   - success: function(a) {
135   - if(a.data.code==0){
136   - wx.setStorageSync("isAuth", !0),
137   - e.globalData.userInfo = a.data.data,
138   - e.globalData.user_id = e.globalData.userInfo.user_id, e.globalData.userInfo.head_pic = i.getFullUrl(e.globalData.userInfo.head_pic),
139   - "function" == typeof cb && cb(e.globalData.userInfo, e.globalData.wechatUser);
140   - e.showWarning("绑定成功");
141   - setTimeout(function(){
142   - wx.navigateTo({
143   - url: '/pages/user/index/index',
144   - })
145   - },1000);
146   - }else{
147   - e.showWarning("请输入验证码")
148   - }
149   - }
150   - }) : e.showWarning("请输入验证码") : e.showWarning("请输入手机号码");
151   - },
152   -
153   - bindReg: function() {
154   - var t = this;
155   - if( "" != this.data.regMobile ){
156   - e.showWarning("请输入手机号码"); return false;
157   - }else if( "" != this.data.regCode){
158   - e.showWarning("请输入验证码"); return false;
159   - }else {
160   - var openid = getApp().globalData.openid;
161   - var r = getApp().globalData.getu;
162   - a.post("/api/weshop/users/thirdLogin", {
163   - data: {
164   - mobile: t.data.regMobile,
165   - verify_code: t.data.regCode,
166   - openid: openid,
167   - nickname: r.nickName,
168   - head_pic: r.avatarUrl,
169   - sex: r.gender,
170   - },
171   - success: function(a) {
172   - console.log("thirdLogin");
173   - console.log(e);
174   - if (e.data.code == 0) {
175   - app.globalData.user_id = e.data.data.user_id;
176   - } else {
177   - return app.showWarning("授权登入失败!");
178   - }
179   - wx.setStorageSync("isAuth", !0), a.globalData.userInfo = e.data.data, a.globalData.userInfo.head_pic = t.getFullUrl(a.globalData.userInfo.head_pic);
180   - wx.navigateBack({ delta: 1 })
181   - }
182   - })
183   - }
184   - }
185   -});
186   -
187   -function randomNum(min, max) {
188   - return Math.floor(Math.random() * (max - min) + min);
189   -}
190   -/**生成一个随机色**/
191   -function randomColor(min, max) {
192   - var r = randomNum(min, max);
193   - var g = randomNum(min, max);
194   - var b = randomNum(min, max);
195   - return "rgb(" + r + "," + g + "," + b + ")";
196   -}
197   -
198   -/**绘制验证码图片**/
199   -function drawPic(that) {
200   - ctx = wx.createCanvasContext('canvas');
201   - /**绘制背景色**/
202   - ctx.fillStyle = randomColor(180, 240); //颜色若太深可能导致看不清
203   - ctx.fillRect(0, 0, 90, 28)
204   - /**绘制文字**/
205   - var arr;
206   - var text = '';
207   - var str = 'ABCEFGHJKLMNPQRSTWXY123456789';
208   - for (var i = 0; i < 4; i++) {
209   - var txt = str[randomNum(0, str.length)];
210   - ctx.fillStyle = randomColor(50, 160); //随机生成字体颜色
211   - ctx.font = randomNum(20, 26) + 'px SimHei'; //随机生成字体大小
212   - var x = 5 + i * 20;
213   - var y = randomNum(20, 25);
214   - var deg = randomNum(-20, 20);
215   - //修改坐标原点和旋转角度
216   - ctx.translate(x, y);
217   - ctx.rotate(deg * Math.PI / 180);
218   - ctx.fillText(txt, 5, 0);
219   - text = text + txt;
220   - //恢复坐标原点和旋转角度
221   - ctx.rotate(-deg * Math.PI / 180);
222   - ctx.translate(-x, -y);
223   - }
224   - /**绘制干扰线**/
225   - for (var i = 0; i < 4; i++) {
226   - ctx.strokeStyle = randomColor(40, 180);
227   - ctx.beginPath();
228   - ctx.moveTo(randomNum(0, 90), randomNum(0, 28));
229   - ctx.lineTo(randomNum(0, 90), randomNum(0, 28));
230   - ctx.stroke();
231   - }
232   - /**绘制干扰点**/
233   - for (var i = 0; i < 20; i++) {
234   - ctx.fillStyle = randomColor(0, 255);
235   - ctx.beginPath();
236   - ctx.arc(randomNum(0, 90), randomNum(0, 28), 1, 0, 2 * Math.PI);
237   - ctx.fill();
238   - }
239   - ctx.draw(false, function () {
240   - that.setData({
241   - text: text
242   - })
243   - });
244   -}
245 0 \ No newline at end of file
pages/user/binding_info/binding_info.wxml deleted
1   -<view>
2   - <view class="binding-top" style="background-image:url('{{iurl}}/miniapp/images/binding-bj.png')">
3   - <view class="user-logo">
4   - <image src="{{imghots+store.store_logo}}"></image>
5   - </view>
6   - <view class="user-text">
7   - <text>{{store.store_name}}</text>
8   -
9   - </view>
10   - <view class="userbj-cover">
11   - <image src="{{iurl}}/miniapp/images/white-cover.png"></image>
12   - </view>
13   - </view>
14   - <view class="binding-container">
15   - <!-- <view class="binding-tips">
16   - <text>为了给您更好地服务,请关注一个TPshop账号
17   -若还没有TPshop账号,则注册后默认完成关联</text>
18   - </view> -->
19   - <view>
20   - <!-- <view class="correlation-cont">
21   - <view bindtap="account" class="connect-item {{isRegist?'':'tp-list-bg'}}">关联已有账号</view>
22   - <view bindtap="regist" class="connect-item {{isRegist?'tp-list-bg':''}}">注册并关联账号</view>
23   - </view> -->
24   -
25   - <view class="correlation-input-wrap">
26   - <view class="items-warp" hidden="{{isRegist}}">
27   - <view class="item_cont">
28   - <image src="{{iurl}}/miniapp/images/numb.png"></image>
29   - <text>手机号码</text>
30   - <input bindinput="setMobile" id="username" name="username" placeholder="请输入手机号码" type="number"></input>
31   - </view>
32   -
33   - <view class="item_cont ">
34   - <image src="{{iurl}}/miniapp/images/code.png"></image>
35   - <text decode="{{true}}" space="{{true}}">验&nbsp;证&nbsp;&nbsp;码</text>
36   - <input bindinput="setCode" id="password" name="password" placeholder="请输入验证码" type="number"></input>
37   - <button wx:if="{{canGetCode}}" class="tp-get-gode btn-disable">
38   - {{gettime>0?gettime:""}}秒后重发
39   - </button>
40   - <button wx:else bindtap="getCode" class="tp-get-gode"> 获取验证码</button>
41   - </view>
42   - <view class="item-cont">
43   - <button bindtap="bindAccount" class="correlation-submit">立即绑定</button>
44   - </view>
45   - </view>
46   - <view class="items-warp" hidden="{{!isRegist}}">
47   - <view class="item_cont">
48   - <image src="{{iurl}}/miniapp/images/numb.png"></image>
49   - <text>手机号码</text>
50   - <input bindinput="setRegMobile" id="username" name="username" placeholder="请输入手机号码" type="number"></input>
51   - </view>
52   - <view class="item_cont ">
53   - <image src="{{iurl}}/miniapp/images/password.png"></image>
54   - <text>设置密码</text>
55   - <input bindinput="setRegPwd" id="username" name="username" placeholder="字母和数字组成的6-16位字符" type="password"></input>
56   - </view>
57   - <view class="item_cont">
58   - <image src="{{iurl}}/miniapp/images/code.png"></image>
59   - <text decode="{{true}}" space="{{true}}">验&nbsp;证&nbsp;&nbsp;码</text>
60   - <input bindinput="setRegCode" id="password" name="password" placeholder="请输入验证码" type="number"></input>
61   - <button bindtap="getRegCode" class="tp-get-gode">获取验证码</button>
62   - </view>
63   - <view class="item-cont">
64   - <button bindtap="bindReg" class="correlation-submit">立即绑定</button>
65   - </view>
66   - </view>
67   - </view>
68   - </view>
69   - <view class="bingding-agreement" hidden="{{!isRegist}}">
70   - <checkbox bindtap="check" checked="{{isAgree}}"></checkbox>
71   - <label>我已阅读并同意</label>
72   - <navigator>《TPshop商城用户注册协议》</navigator>
73   - </view>
74   - </view>
75   -</view>
76   -
77   -
pages/user/binding_info/binding_info.wxss deleted
1   -page {
2   - background-color: #fff;
3   -}
4   -
5   -.binding-top {
6   - width: 100%;
7   - height: 450rpx;
8   - text-align: center;
9   - position: relative;
10   - overflow: hidden;
11   -}
12   -
13   -.user-logo {
14   - width: 190rpx;
15   - height: 190rpx;
16   - border-radius: 50%;
17   - border: 2px solid #fff;
18   - overflow: hidden;
19   - position: absolute;
20   - left: 50%;
21   - margin-left: -95rpx;
22   - top: 60rpx;
23   -}
24   -
25   -.user-logo image {
26   - width: 100%;
27   - height: 100%;
28   -}
29   -
30   -.user-text {
31   - margin-top: 142px;
32   -}
33   -
34   -.user-text text {
35   - display: block;
36   - margin-top: 16rpx;
37   - color: #fff;
38   -}
39   -
40   -.userbj-cover {
41   - width: 100%;
42   - height: 46rpx;
43   - position: absolute;
44   - left: 0;
45   - bottom: 0;
46   - z-index: 20;
47   -}
48   -
49   -.userbj-cover image {
50   - width: 100%;
51   - height: 46rpx;
52   -}
53   -
54   -.binding-container {
55   - width: 100%;
56   - padding-top: 15px;
57   -}
58   -
59   -.binding-tips {
60   - font-size: 14px;
61   - color: #666;
62   - text-align: center;
63   - letter-spacing: 2rpx;
64   -}
65   -
66   -.correlation-cont {
67   - width: 600rpx;
68   - margin: 0 auto;
69   - margin-top: 40rpx;
70   - overflow: hidden;
71   -}
72   -
73   -.connect-item {
74   - width: 296rpx;
75   - height: 78rpx;
76   - line-height: 78rpx;
77   - font-size: 16px;
78   - text-align: center;
79   - border: 1px solid #b7b7b7;
80   - float: left;
81   -}
82   -
83   -.correlation-cont .connect-item:first-child {
84   - border-bottom-left-radius: 30px;
85   - border-top-left-radius: 30px;
86   -}
87   -
88   -.correlation-cont .connect-item:last-child {
89   - border-bottom-right-radius: 30px;
90   - border-top-right-radius: 30px;
91   -}
92   -
93   -.tp-list-bg {
94   - color: #fff;
95   - background: #e23435;
96   - border: 1px solid #e23435!important;
97   -}
98   -
99   -.correlation-input-wrap {
100   - margin-top: 56rpx;
101   - width: 100%;
102   -}
103   -
104   -.item_cont {
105   - width: 660rpx;
106   - height: 96rpx;
107   - margin: 0 auto;
108   - position: relative;
109   - line-height: 96rpx;
110   - border-bottom: 1px solid #e6e6e6;
111   -}
112   -
113   -.item_cont image {
114   - width: 48rpx;
115   - height: 48rpx;
116   - vertical-align: middle;
117   -}
118   -
119   -.item_cont text {
120   - font-size: 16px;
121   - vertical-align: middle;
122   - color: #666;
123   - margin-left: 16rpx;
124   -}
125   -
126   -.item_cont input {
127   - border: 0px;
128   - font-size: 16px;
129   - height: 50rpx;
130   - line-height: 50rpx;
131   - display: inline-block;
132   - vertical-align: middle;
133   - width: 432rpx;
134   - margin-left: 30rpx;
135   -}
136   -
137   -.tp-get-gode {
138   - position: absolute;
139   - right: 0;
140   - top: 20rpx;
141   - border-radius: 30rpx;
142   - background-color: #f05052;
143   - color: #fff;
144   - height: 56rpx;
145   - width: 140rpx;
146   - font-size: 22rpx;
147   - line-height: 56rpx;
148   - z-index: 50;
149   -}
150   -.tp-get-gode.btn-disable{
151   - background-color: #e6e6e6;
152   - color: #999;
153   -}
154   -
155   -.correlation-submit {
156   - width: 660rpx;
157   - height: 96rpx;
158   - line-height: 96rpx;
159   - background: #db261e;
160   - border: none;
161   - border-radius: 6px;
162   - color: #ffffff;
163   - font-size: 20px;
164   - margin-top: 40rpx;
165   -}
166   -
167   -.bingding-agreement {
168   - width: 660rpx;
169   - margin: 0 auto;
170   - margin-top: 20rpx;
171   - font-size: 14px;
172   - margin-bottom: 30px;
173   -}
174   -
175   -.bingding-agreement label {
176   - vertical-align: middle;
177   - color: #333;
178   - margin-left: 10rpx;
179   -}
180   -
181   -.bingding-agreement navigator {
182   - vertical-align: middle;
183   - color: #0094ca;
184   - display: inline-block;
185   -}
186   -
187   -checkbox .wx-checkbox-input {
188   - border-radius: 50%;
189   - width: 36rpx;
190   - height: 36rpx;
191   -}
192   -
193   -checkbox .wx-checkbox-input.wx-checkbox-input-checked {
194   - border: none;
195   - background: red;
196   - width: 40rpx;
197   - height: 40rpx;
198   -}
199   -
200   -checkbox .wx-checkbox-input.wx-checkbox-input-checked::before {
201   - border-radius: 50%;
202   - width: 36rpx;
203   - height: 36rpx;
204   - line-height: 36rpx;
205   - text-align: center;
206   - font-size: 30rpx;
207   - color: #fff;
208   - background: transparent;
209   - transform: translate(-50%,-50%) scale(1);
210   -}
211 0 \ No newline at end of file
pages/user/order_detail/order_detail.js
... ... @@ -19,10 +19,11 @@ Page({
19 19  
20 20 getApp().getConfig2(function (e) {
21 21  
22   - th.setData({conf: e,sales_rules:e.sales_rules });
  22 + th.setData({conf: e,sales_rules:e.sales_rules, userInfo: getApp().globalData.userInfo});
23 23 //--- 看后台是不是有开通等级卡 ---
24 24 if(e.switch_list){
25 25 var s_list=JSON.parse(e.switch_list);
  26 + th.setData({sys_switch: s_list});
26 27 var is_open_offline=s_list.is_pricing_open;
27 28 var user=getApp().globalData.userInfo;
28 29 //如果后台有开启等级价的功能
... ...
pages/user/order_detail/order_detail.wxml
... ... @@ -52,7 +52,19 @@
52 52 </view>
53 53 <view class="order-operate">
54 54 <view bindtap="checkTeam" class="contact-us check-btn" wx:if="{{optionIsGoup}}">查看拼团详情</view>
55   - <view bindtap="contactService" class="contact-us goods-btn">联系客服</view>
  55 + <view>
  56 + <!-- <button wx:if="{{sys_switch.weapp_customertype}}" class="custom-service cart-ico new_split" open-type="contact" session-from="wechat|{{userInfo.user_id}}|{{userInfo.nickname}}|{{userInfo.head_pic}}"> -->
  57 + <!-- <image class="cs-img" src="{{iurl}}/miniapp/images/custom-service.png"></image>
  58 + <view></view> -->
  59 + <!-- </button> -->
  60 + <button wx:if="{{sys_switch.weapp_customertype}}" class="contact-us goods-btn" open-type="contact" session-from="wechat|{{userInfo.user_id}}|{{userInfo.nickname}}|{{userInfo.head_pic}}">联系客服</button>
  61 + <!-- <view wx:else class="custom-service cart-ico new_split" bindtap="contactService">
  62 + <image class="cs-img" src="{{iurl}}/miniapp/images/custom-service.png"></image>
  63 + <view>联系客服</view>
  64 + </view> -->
  65 + <view wx:else bindtap="contactService" class="contact-us goods-btn">联系客服</view>
  66 + </view>
  67 + <!-- <view bindtap="contactService" class="contact-us goods-btn">联系客服</view> -->
56 68 <view bindtap="cancelOrder" class="cancel-order goods-btn" data-id="{{order.order_id}}"
57 69 hidden="{{!(order.order_status==0&&order.pay_status==0)}}">取消订单</view>
58 70 </view>
... ...
pages/user/order_detail/order_detail.wxss
... ... @@ -170,4 +170,9 @@
170 170 background-color: #f23030;
171 171 /* margin-left: 2rpx; */
172 172 margin-right: 8rpx
  173 +}
  174 +
  175 +
  176 +.contact-us.goods-btn::after {
  177 + content: none;
173 178 }
174 179 \ No newline at end of file
... ...
project.config.json
... ... @@ -21,6 +21,7 @@
21 21 "checkSiteMap": true,
22 22 "uploadWithSourceMap": true,
23 23 "compileHotReLoad": false,
  24 + "lazyloadPlaceholderEnable": false,
24 25 "useMultiFrameRuntime": true,
25 26 "useApiHook": true,
26 27 "useApiHostProcess": false,
... ... @@ -30,12 +31,11 @@
30 31 "outputPath": ""
31 32 },
32 33 "useIsolateContext": true,
33   - "useCompilerModule": false,
34   - "userConfirmedUseCompilerModuleSwitch": false,
35 34 "userConfirmedBundleSwitch": false,
36 35 "packNpmManually": false,
37 36 "packNpmRelationList": [],
38   - "minifyWXSS": true
  37 + "minifyWXSS": true,
  38 + "showES6CompileOption": false
39 39 },
40 40 "compileType": "miniprogram",
41 41 "libVersion": "2.16.0",
... ...