From 87d91489775af7d75ca15296d497389d6f200f2d Mon Sep 17 00:00:00 2001 From: Kiyan Date: Thu, 4 May 2017 13:08:03 +0800 Subject: [PATCH] =?UTF-8?q?=E8=AE=A2=E5=8D=95=E8=AF=A6=E6=83=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/app.json | 2 +- app/app.wxss | 1 + app/images/Shop-icon.png | Bin 1608 -> 0 bytes app/images/chat_phone_normal.png | Bin 0 -> 1036 bytes app/images/icon_hongbao.png | Bin 0 -> 699 bytes app/images/icon_jian.png | Bin 0 -> 749 bytes app/images/shop-512.png | Bin 0 -> 2488 bytes app/pages/index/index.js | 14 -- app/pages/order/constant.js | 2 +- app/pages/order/quasi.wxml | 15 +- app/pages/order/quasi.wxss | 11 +- app/pages/order/show.js | 123 +++++++--- app/pages/order/show.wxml | 136 ++++++++++- app/pages/order/show.wxss | 111 +++++++++ app/utils/WxValidate.js | 378 +++++++++++++++++++++++++++++++ app/utils/coordtransform.js | 153 +++++++++++++ app/utils/countdown.js | 26 +++ app/utils/qqmap-wx-jssdk.min.js | 2 + app/utils/timeago.min.js | 1 + app/utils/util.js | 186 +++++++++++++-- 20 files changed, 1079 insertions(+), 82 deletions(-) delete mode 100644 app/images/Shop-icon.png create mode 100644 app/images/chat_phone_normal.png create mode 100644 app/images/icon_hongbao.png create mode 100644 app/images/icon_jian.png create mode 100644 app/images/shop-512.png create mode 100644 app/utils/WxValidate.js create mode 100644 app/utils/coordtransform.js create mode 100644 app/utils/countdown.js create mode 100644 app/utils/qqmap-wx-jssdk.min.js create mode 100644 app/utils/timeago.min.js diff --git a/app/app.json b/app/app.json index 2695222..c0e8771 100644 --- a/app/app.json +++ b/app/app.json @@ -1,12 +1,12 @@ { "pages": [ "pages/order/show", + "pages/order/quasi", "pages/order/list", "pages/index/index", "pages/address/list", "pages/address/add", "pages/address/select", - "pages/order/quasi", "pages/shop/show", "pages/mine/mine", "pages/index/address", diff --git a/app/app.wxss b/app/app.wxss index 33c79ed..9ead761 100644 --- a/app/app.wxss +++ b/app/app.wxss @@ -23,6 +23,7 @@ page { } .trangle { + position: relative; padding-right: 15px; } diff --git a/app/images/Shop-icon.png b/app/images/Shop-icon.png deleted file mode 100644 index 2aae60d57ffdf3c5ae8668df0c2698dece0775bd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1608 zcmeAS@N?(olHy`uVBq!ia0vp^8X(NU1|)m_?Z^dEk|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+m=!ZaB1$5BeXNr6bM+EIYV;~{3xK*A7;Nk-3KEmEQ%e+* zQqwc@Y?a>c-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxR5#hc&_u!9QqR!T z(8R(}N5ROz&{*HVSl`fC*U-qyz|zXlQ~?TIxIyg#@@$ndN=gc>^!3Zj z%k|2Q_413-^$jg8E%gnI^o@*kfhu&1EAvVcD|GXUm0>2hq!uR^WfqiV=I1GZOiWD5 zFD$Tv3bSNU;+l1ennz|zM-B0$V)JVzP|XC=H|jx7ncO3BHWAB;NpiyW)Z+ZoqGVvir744~DzI`cN=+=uFAB-e&w+(vKt_H^esM;Afr7KMf<|~|UP^v> zu_jo#udkJ7UU5lcUUI6Zi>(sS0KLr26e|luOG6hER|_L2ClfUI2$*<4On9mVa^UGcH4m8Bi-4*6wOV5z0|V1uPZ!6K zid%1H#CG@wiX1<0D11pZRY_m&0*|SUCzr8Lhevr(bJB^7B{Mv-jxp=cd!ih#>booG zk*mf}tt>YEQ|#F_x!CAH$`V-_ z-NpM&A81PO@-?dl$s5VnoM1{8Dhg}nP1ye{^?7AlTw+z)ZL10Fy=(aMoqHT5pkGuqqS=38aA zYL};x=#iZ!XO=JpH?BMo@}OQIqT@tG?)%xg?pt-IC|}rP^IZ9#`Nn?T`~PDW-Fh~a z?RjL*zWWcn{Z`aH^ocv2{jjQEHE7jagLrf1xyLdaYikN be-;S_k69B~*L7M|fy#DIS3j3^P627(m!jDs zgvthqqVXjP(gxFP5G@F;u9cPAf5HF4;js4|Q196%?!yoCtiA7D|GW2IYn`?KvR1D7 zqj24Un4p*-kK?)nt_t$`d`aLCcnv;*(_n;UfRKmR6%ks>KxBf zK_h4ZGZb@H4>Hj%-h+SD!g z0bC1WpTIHAU@>?L+CZkMf+S=&g&31YQJoZHnH;uv)6tY5W0G0^h?s2C6Ke(qZPwWT zV_he~BiAy$^nsKAFz-AI)Nc;^0tzm*3=k7;Ew_bETMFA;+Da?~#DptoAdAoY3R^sr zujHge%L{_&_;#*Dj>1+z+hNN?f)ZJn);U*#75N2+2#^aD?)r; zZ&1n4vr`#K((cmovN)|^6z6V(VUGDXY1^TgyPmeI;fU&%gNQHcW9#2-4N?;Zwp24au+q=F!)MZ1 zsR1JubBj6V3P^~`?E`=5OSWwjuQ_)c*xL)75n0)7ws8MKbpc?j`Y)@}MUPyk@JyB2 ze$6D!xS_I=;DiXVJ+~<8xqVyO><4sPv&Zg-_)@rwUo2ZFEyDRZ6!lbuJ8TK;U(`qa z!V6!zlp)(6Dr76>=2BF(v&6#x59AEGa)XC2o(f)awa%*QzaVq-SUyz+nwBhpr2?sN z?Mjjfv(y&diX=Eh@X8_ro`7_2VSlh~9JLyYQLKi-r0G(qO0tT1`K&ZLSjlG?b7{;d zxDI@zFgf7+Si#3B#;3AZ-cB)djJySBB3{c#7RX1RSuvae7x}s$ur;VI+Kdt85SPxR zScA*L#=H-iit7%<1jPh-9M>J_Zhixh%B}5-(faZL0000%}IB4PrFnS}NJeU|0zk#7wPh33c!AQJ# zR8zLL5bau7Udp23@%gVa&9qGG7Rb&0&$$sV(Gs8S) z7MZuqXU1W67!r75?32hWia9f4js9+W2a!9;++~&+R}ncZu2}OPdK^fUC-yOynb*wT z5z4h=PxM01zCfZJ9Ae&wAlDA`9_lE{fjQ=vK}iW5=Cq<>+x=r+dvJ?9=PCWB7omcl z=&f9bgidr>z9SQos;siJ%R13UKu+3q=E+;lhXQ)ZzN$+g(Xb>X|CeYjZ&5j&ioU3O zBTb;1wP?5W#JFhLO8G8rMSX6jX>;K=ZNHi(&(4J>>OH6Wn@8m2tcFWxQI**%w6QQr zTZIhOKd^M=2<3P!tckVJ!=0Vn*FU&uD|cA@;RJ0yo1(3k8QNaTQvF?)c0Tf(_`=wV z2>$0W)Q~|Ib1)ZcV6A`kJGf}b^hA52$3}GhxE}(`(d`Gk!;_nXzWE7D?2N-qGq*oJwP7$&R1# z@1jl=hC1(qcc4oUD3#XAMJ^D5M6g8AlAZ$PP7mKu~rH?(Ltsb0XYd=2DLvnaA82~ htZPuv6%GTc+aHGoML@i99s2+P002ovPDHLkV1nwcQilKl literal 0 HcmV?d00001 diff --git a/app/images/icon_jian.png b/app/images/icon_jian.png new file mode 100644 index 0000000000000000000000000000000000000000..012b44eac7634c0d8cc791906bf36fd324bacffc GIT binary patch literal 749 zcmeAS@N?(olHy`uVBq!ia0vp^S|H593?x6vT4n;N_5hy{S0Mf0-=7L7KK_4u$G@8D z|9QFpf#A;F|KGp=zkC^F^1FBcPoDZeWy=4j&p_O*TmSDr@PE~+|MTa=?R~;J`99Do zx+Ot=!3^w zi(`nz>A9f~s}?H=sN`PB7QVG??-LgBHK!c+?EYTAFS_HvtYgbw{<+{kvw!Z~Sg~Vi z5qIyd@7}cPR8sB#$Bnv=3pYPydHSrd^T!eU2S0^=riOpyUQxEX_*wQr@ekjM&)u0` zBltA&*qu-Q8&vOHpH$yvl=&m{gLXx?*n7RT*PK2r>x)Ty z`gY)5(HZ3f84JbL8#vc5NjU#cpmy!*+*@pC?o8VMrt%;2O20}EhAZzkX=jJkELgQ5 zu;P`+Ha&^lDQW?W8J27-IMaI|Ev$+?NBENC`w#3XtF^sk7dpTC_+)y3g6@_lHUW&b z*Df|~SdjC4CDZ&R!kJN0Y$57S+rD&m<;|?* zEK0O4acetcwbU_TLSuj0nbz8y&wlW}yW=lwEFpjYQkkdkiyE8xH#2v-?>h9{&^$3K zmzA&DJ6W~H{OiIkX17JvF702jU}b5~_1`bfanBT+f39yKYpj3iXS;_top`@UOgj9w z?Z(sPM{>2(+ka~-Czt+K*kyI^+kNR-+j|~Gv;DcW_2a&R<1+iIBx83!`o~=UE2*eY T$0r|{SQtEA{an^LB{Ts5iJpOH literal 0 HcmV?d00001 diff --git a/app/images/shop-512.png b/app/images/shop-512.png new file mode 100644 index 0000000000000000000000000000000000000000..421d2ded10174160d037ce7d94ae848e505f3428 GIT binary patch literal 2488 zcmaJ@c|25mA3jo&wYta_(?r%Wn~51SwwWPi>}t9p)6BtO7BeG5UB$g|ElEh02!*Rf zmqe6GiL7zUmMpDy3KyZgqnqyg$J={8pL2f8=Xsv*_WW^ToE&UrrBtN=0FbrYLvj(V zTC1<5gy{PUNJ|qfDgrW9;L7n4gwS{(V8!4Z0U>rQnlI=A(iovZ4Imx>#CI^=r~)d* z9!KY}jA*MEBO!|`Vgmr)Ldd1j13&@f2&=!vg472GqhFf*0aM0xVEKg9urHY(7p%fPU4*iT114a46&}L=ZrL{*x4y;shab zcpwC0gn`i!NMncz)(D9~8k-^wAt(eA4M(8iNHh$I!XdCYBnI;Bfr_H>7(O@`lFheR zq7wn?ClGLPaCk^ah*1dIh{N-RBe7U49D#zPP%se!#t&r+XhIm9zjIB21oG)TCRf1Z zupz68v?H8g0Rbw?^q&$~-0!k%{|71S#SwWRO~B!~aX5i%U3Bu}2snH{4i`csLUa!>*$hqy zU+*iNLc!Uw`2rf74%(3jP?3NUlgYplO^~}uHfRhQu^Wp-l1;2pSS*Q*CZlXjQ3z`r z>oqQkLl0(wY{43r@h^Ax54o#OU~xr}Ng$7T6lB=&I4sE5igC;z=YsyB-Zw7e$GI5) zkP8ZGm7DOzc-o2I-N_2| zzLV8cgo~5@szyph2c4Cu%Bf)fW*@C|YlZaLXsh4W=VwCGA+(HF8EVv;q%!BZxSWd$ z&oyl}#W2Ww2Q?RMlL|T~uZ&GD1)Z41&Swwx|FSd}J!0)7KGgCu9X)h>s5zbQlg(nW zFz(vh$nE+8Ey;D=_yIA6bZJ+^w>HjHu6m(%as&QM@ucyuL#E}?nLf%<`|_S#tLQ`` zwv8NhYdfV|is%Y@S%rx2REWzTXkYP%TRQts{3Y?kEr2LC1M|FL>HFK%IaGvcJmrP2VULe2VQo&pXl zbJF2Tplg%KQlN^&=+@{0j|~J}h?p5Zwzs|(RV#fc=Zkbx$FtT5Ou2G!^>l+U%f)$V zR54H|uF3lE4;4j*L2sY!?!UHB21{w9CntEB8*lKY1O^Zy0!#+@9$i_(OEtB;%H^#C z6IPpBYk0|z5Zw-UWbdWVHno4=x~P#s8juktl+>BDBlRSgGvD>je>O?PY})>TbTfwo z?1<}L=h<6d)Ke+D{wgyD9G6O)m$2fhBIG&`IXpO?`Oy;?$;*x%e42L4asQzbpHkk? zf#GD`(r152pIm95Z|dC?)dZZ|D2YF6QL5J7BQb1nw&HAMx^m*r{+Rf<`pXn-P6|r5)|>cG|@I)#|IIxw-h>KW!&Ak=0rC z3*DylA-uLL5skk1G%o26r(v(5(0+RSVOM=c`hD_bA@#c6*??@Y-(zDRWvlc^@2P`b zjZ#%rRj=I{s2-nDamjE>&F?v8X}5o(Eqy$H&lwZ@tkv1Ca6u}ZPEAq4qE_Uf;SYdb zl7sSM3Eq!Tde7xkOTsl}Vz4VG?OjYp1I^6V?v^J`v8Yqq(XR*dnL+4?PBzkp?`2aZ!BCrq)Bd>3Z* zpZagpo{j7Z}VPeWBZ5=hs8$5e8C%Wg}Joj{A zP|?mKGL9GaHX+}tKQH%a4cA!M@3R$+sx~lNZmW;i1g{n82WihvA zhY!oZ4+YkZ#4h0#atpYMNbCrbJK37CoYJ{X7M1JZ zn18}3?r7^9+^8HXdr3#Wc}C1Q#Wweoi5O}{e9=*SI*Rutdb+C#SnhWM+;?eeSUTUS zOKr6R8Ww^!C4P?AEWTx#bTv7l_F!fBUsYoFHef89TDYlF>6a>MoiQm{?L*U#+w!iQ zzv@*>w!PqVa|AyWbRC~*ds}Kbm2u*j#l@MWO59ub1zsrXZ+e);xi|gpo6ARolg=9r z$e(FcEQ)MM?jmce&CG>i&o_Bxw7gIKu$b8ENmU%YR*;a_AAI-uOl8=Zqi&){M{w<~ ns35cUkI1sqb3HL9q!B>u - + {{info.seller_name}} @@ -52,7 +52,9 @@ - 商城优惠 + + 商城优惠 + -¥{{info.cut_money}} @@ -63,8 +65,8 @@ 总计¥{{info.order_price}} 优惠¥{{info.cut_money}} - 实付 - ¥{{info.pay_price}} + + 实付 ¥{{info.pay_price}} @@ -74,9 +76,10 @@ 已优惠¥{{info.cut_money}} - 待支付 ¥{{info.pay_price}} + 待支付 + ¥{{info.pay_price}} - \ No newline at end of file diff --git a/app/pages/order/quasi.wxss b/app/pages/order/quasi.wxss index 2e68e15..61be79d 100644 --- a/app/pages/order/quasi.wxss +++ b/app/pages/order/quasi.wxss @@ -26,8 +26,8 @@ .quasi-goods__img { margin-top: -2px; - width: 20px; - height: 20px; + width: 18px; + height: 18px; vertical-align: middle; } @@ -48,6 +48,13 @@ flex: 2; } +.quasi-goods__item-name-icon { + margin: -2px 5px 0 0; + height: 21px; + width: 21px; + vertical-align: middle; +} + .quasi-goods__item-name_grey { color: #999; } diff --git a/app/pages/order/show.js b/app/pages/order/show.js index 4fca748..fcf3e3a 100644 --- a/app/pages/order/show.js +++ b/app/pages/order/show.js @@ -1,41 +1,54 @@ // pages/order/show.js +import Countdown from '../../utils/countdown' +import { countdownFormat } from '../../utils/util' Page({ data: { + activeNavIndex: 1, + tabNavs: ['订单状态', '订单详情'], + statusImgs: { + '1': '/images/status/order_status_money_icon_current@2x.png', + '2': '/images/status/order_status_shop_icon_current@2x.png', + '3': '/images/status/order_status_rider_icon_current@2x.png', + '4': '/images/status/order_status_service_icon_current@2x.png', + '5': '/images/status/order_status_service_icon_fail_current@2x.png', + '6': '/images/status/order_status_service_icon_fail_current@2x.png', + '7': '/images/status/order_status_service_icon_fail_current@2x.png' + }, info: { - "order_id": "1370", - "order_no": "2017042815510158201158862546", - "day_sn": "1", + "order_id": "1375", + "order_no": "2017050316304632448020041071", + "day_sn": "4", "seller_id": "2", "user_id": "4", - "state": "5", - "add_time": "1493365861", - "order_price": "42.98", - "pay_price": "34.98", - "goods_price": "22.98", + "state": "3", + "add_time": "1493800246", + "order_price": "30.00", + "pay_price": "22.00", + "goods_price": "20.00", "cut_money": "8.00", "coupon_money": "0.00", - "packing_fee": "2.00", - "delivery_fee": "18.00", + "packing_fee": "0.00", + "delivery_fee": "10.00", "receiver": "test4", - "receiver_addr": "龙华大厦", - "receiver_gps": "120.69101,28.002974", - "receiver_phone": "13000000005", - "receive_time": "1493369461", - "distance": "7.177", - "remark": null, + "receiver_addr": "电商大厦", + "receiver_gps": "120.737561,27.979617", + "receiver_phone": "13000000004", + "receive_time": "1493803846", + "distance": "1.707", + "remark": "", "is_reviews": "0", "is_delete": "0", "delivery_order_id": "0", - "title": "鸡腿饭(大)", + "title": "鸡翅饭", "receiver_city": "330300", - "take_time": null, + "take_time": "1493800254", "remind_time": "0", - "pay_type": null, + "pay_type": "3", "sys_settle_no": null, "settle_no": null, "commision": "0.00", "user_coupon_id": null, - "real_delivery_fee": "18.00", + "real_delivery_fee": "10.00", "cut_delivery_fee": "0.00", "service_money": "0.00", "seller_name": "鲜极道", @@ -43,46 +56,53 @@ Page({ "delivery_phone": "13906641410", "goods": [ { - "goods_id": "29", - "sub_id": "50", + "goods_id": "32", + "sub_id": "0", "seller_id": "2", - "detail": "鸡腿饭 xx", - "sales": "46", + "detail": "鸡翅饭 xx", + "sales": "43", "praise": "0", "state": "1", - "commision": "3.00", - "goods_name": "鸡腿饭(大)", - "price": "22.98", - "packing_fee": "2.00", - "stock": "74", + "commision": null, + "goods_name": "鸡翅饭", + "price": "20.00", + "packing_fee": "0.00", + "stock": "54", "is_delete": "0", - "pic_url": "http://test.storesystem.cn/Uploadfile/Img/seller_goods/1461034075146103407535640.jpg", + "pic_url": null, "num": "1", - "price_sum": "22.98" + "price_sum": "20.00" } ], "expire_time": 0, "left_time": 0, "flow": [ { - "time": "1493365861", + "time": "1493800246", "state": "1", "status": "订单提交成功,待支付", "remark": "" }, { - "time": "1493366164", - "state": "5", - "status": "订单已取消", + "time": "1493800252", + "state": "2", + "status": "支付成功,等待商家接单", + "remark": "" + }, + { + "time": "1493800254", + "state": "3", + "status": "商家已接单", "remark": "" } ], + "run_order_id": "6408", "localphone": "13906641410" - } - + }, }, onLoad: function (options) { // 页面初始化 options为页面跳转所带来的参数 + this.initCountdown(287) }, onReady: function () { // 页面渲染完成 @@ -95,5 +115,34 @@ Page({ }, onUnload: function () { // 页面关闭 + if (this.countdown) { + this.countdown.stop() + } + }, + tabChange(e) { + var {current} = e.detail + this.setData({ + activeNavIndex: current + }) + }, + navChange(e) { + var {id} = e.currentTarget + this.setData({ + activeNavIndex: id + }) + }, + + initCountdown(count) { + this.setData({ + count + }) + var countdown = new Countdown(this, 'count') + countdown.start((count) => { + this.setData({ + countLabel: countdownFormat(count) + }) + }) + this.countdown = countdown } + }) \ No newline at end of file diff --git a/app/pages/order/show.wxml b/app/pages/order/show.wxml index c629335..cfeacac 100644 --- a/app/pages/order/show.wxml +++ b/app/pages/order/show.wxml @@ -2,19 +2,141 @@ - + 订单状态 - - 订单详情 + + - + - + + + {{item.status}} + + {{item.time}} + + + + 支付剩余时间 + {{countLabel}} + + + 取消订单 + 立即付款 + - - 详情 + + 订单详情 + + + + + {{info.seller_name}} + + + 爱跑腿专送 + + + + + {{item.goods_name}} + x{{item.num}} + ¥{{item.price_sum}} + + + + + 餐盒费 + + ¥{{info.packing_fee}} + + + 配送费 + + ¥{{info.delivery_fee}} + + + + + + 商城优惠 + + + -¥{{info.cut_money}} + + + + + + 总计¥{{info.order_price}} 优惠¥{{info.cut_money}} + + + + 实付 ¥{{info.pay_price}} + + + + + + 配送信息 + + + + 期望时间 + + 立即配送 + + + + 配送地址 + + + + {{info.receiver}} {{info.receiver_phone}} + + + {{info.receiver_addr}} + + + + + + 配送服务 + + + 爱跑腿专送 + + + + 订单信息 + + + + 订单号码 + + + {{info.order_no}} + + + + + 订单时间 + + + {{info.add_time}} + + + + + 支付方式 + + + 在线支付 + + + \ No newline at end of file diff --git a/app/pages/order/show.wxss b/app/pages/order/show.wxss index f74402d..590a846 100644 --- a/app/pages/order/show.wxss +++ b/app/pages/order/show.wxss @@ -1,4 +1,5 @@ /* pages/order/show.wxss */ +@import './quasi.wxss'; .tab { display: flex; @@ -8,6 +9,7 @@ } .tab__navbar { + position: relative; display: flex; color: #999; border-bottom: 1rpx solid #e8e8e8; @@ -33,3 +35,112 @@ .tab-swiper { flex: 1; } + +.tab__swiper-item { + position: absolute; + overflow: auto; +} + + +/* flow-list */ +.flow-item { + position: relative; + margin-left: 50px; + padding: 10px 0; +} + +.flow-item:not(:first-child) { + border-top: 1rpx solid #e8e8e8; +} + +.flow-item::before { + content: ''; + position: absolute; + left: -25px; + top: 50%; + width: 5px; + height: 5px; + background-color: #ff5801; + border-radius: 50%; + transform: translate(-50%, -50%); +} + +.flow-item:not(:last-child)::after { + content: ''; + position: absolute; + left: -25px; + top: 50%; + height: 100%; + border-left: 2rpx solid #ff5801; + transform: translateX(-50%); +} + +.flow-item__time { + position: absolute; + top: 10px; + right: 10px; + color: #999; + font-size: 0.8em; +} + +.flow-item__img { + position: absolute; + top: 50%; + left: -25px; + width:20px; + height: 20px; + border: 5px solid #fff; + transform: translate(-50%, -50%); + z-index: 1; +} + + +/* actionbar*/ +.actionbar { + display: flex; + position: absolute; + left: 0; + bottom: 0; + height: 50px; + width: 100%; + border-top: 1rpx solid #e8e8e8; +} + +.actionbar-btn_action { + flex: 1; + line-height: 50px; + text-align: center; +} + +.actionbar-btn_primary { + background-color: #ff5801; + color: #fff; +} + +/* order-show_left-time*/ +.order-show__left-time { + position: absolute; + bottom: 60px; + left: 10px; + font-size: 0.8em; +} + +.phone { + position: absolute; + top: 5px; + right: 8px; +} +.phone__icon { + width: 26px; + height: 26px; +} + + +.tab__swiper-item_detail { + background-color: #f8f8f8; +} + +.weui-cell__hd { + min-width: 5em; + color: #999; +} \ No newline at end of file diff --git a/app/utils/WxValidate.js b/app/utils/WxValidate.js new file mode 100644 index 0000000..82497bf --- /dev/null +++ b/app/utils/WxValidate.js @@ -0,0 +1,378 @@ +/** + * 创建验证字段的工厂函数 + * + * @param {Object} rules 验证字段的规则 + * @param {Object} messages 验证字段的提示信息 + * + */ +class WxValidate { + constructor(rules = {}, messages = {}) { + Object.assign(this, { + rules, + messages, + }) + this.__init() + } + + /** + * __init + */ + __init() { + this.__initMethods() + this.__initDefaults() + this.__initErrorList() + } + + /** + * 初始化错误信息 + */ + __initErrorList() { + this.errorList = [] + } + + /** + * 初始化默认提示信息 + */ + __initDefaults() { + this.defaults = { + messages: { + required: '这是必填字段。', + email: '请输入有效的电子邮件地址。', + tel: '请输入11位的手机号码。', + url: '请输入有效的网址。', + date: '请输入有效的日期。', + dateISO: '请输入有效的日期(ISO),例如:2009-06-23,1998/01/22。', + number: '请输入有效的数字。', + digits: '只能输入数字。', + idcard: '请输入18位的有效身份证。', + equalTo: this.formatTpl('输入值必须和 {0} 相同。'), + contains: this.formatTpl('输入值必须包含 {0}。'), + minlength: this.formatTpl('最少要输入 {0} 个字符。'), + maxlength: this.formatTpl('最多可以输入 {0} 个字符。'), + rangelength: this.formatTpl('请输入长度在 {0} 到 {1} 之间的字符。'), + min: this.formatTpl('请输入不小于 {0} 的数值。'), + max: this.formatTpl('请输入不大于 {0} 的数值。'), + range: this.formatTpl('请输入范围在 {0} 到 {1} 之间的数值。'), + } + } + } + + /** + * 初始化默认验证方法 + */ + __initMethods() { + const that = this + that.methods = { + /** + * 验证必填元素 + */ + required(value, param) { + if (!that.depend(param)) { + return 'dependency-mismatch' + } + return value.length > 0 + }, + /** + * 验证电子邮箱格式 + */ + email(value) { + return that.optional(value) || /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/.test(value) + }, + /** + * 验证手机格式 + */ + tel(value) { + return that.optional(value) || /^1[34578]\d{9}$/.test(value) + }, + /** + * 验证URL格式 + */ + url(value) { + return that.optional(value) || /^(?:(?:(?:https?|ftp):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})).?)(?::\d{2,5})?(?:[/?#]\S*)?$/i.test(value) + }, + /** + * 验证日期格式 + */ + date(value) { + return that.optional(value) || !/Invalid|NaN/.test(new Date(value).toString()) + }, + /** + * 验证ISO类型的日期格式 + */ + dateISO(value) { + return that.optional(value) || /^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])$/.test(value) + }, + /** + * 验证十进制数字 + */ + number(value) { + return that.optional(value) || /^(?:-?\d+|-?\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/.test(value) + }, + /** + * 验证整数 + */ + digits(value) { + return that.optional(value) || /^\d+$/.test(value) + }, + /** + * 验证身份证号码 + */ + idcard(value) { + return that.optional(value) || /^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/.test(value) + }, + /** + * 验证两个输入框的内容是否相同 + */ + equalTo(value, param) { + return that.optional(value) || value === that.scope.detail.value[param] + }, + /** + * 验证是否包含某个值 + */ + contains(value, param) { + return that.optional(value) || value.indexOf(param) >= 0 + }, + /** + * 验证最小长度 + */ + minlength(value, param) { + return that.optional(value) || value.length >= param + }, + /** + * 验证最大长度 + */ + maxlength(value, param) { + return that.optional(value) || value.length <= param + }, + /** + * 验证一个长度范围[min, max] + */ + rangelength(value, param) { + return that.optional(value) || (value.length >= param[0] && value.length <= param[1]) + }, + /** + * 验证最小值 + */ + min(value, param) { + return that.optional(value) || value >= param + }, + /** + * 验证最大值 + */ + max(value, param) { + return that.optional(value) || value <= param + }, + /** + * 验证一个值范围[min, max] + */ + range(value, param) { + return that.optional(value) || (value >= param[0] && value <= param[1]) + }, + } + } + + /** + * 添加自定义验证方法 + * @param {String} name 方法名 + * @param {Function} method 函数体,接收两个参数(value, param),value表示元素的值,param表示参数 + * @param {String} message 提示信息 + */ + addMethod(name, method, message) { + this.methods[name] = method + this.defaults.messages[name] = message !== undefined ? message : this.defaults.messages[name] + } + + /** + * 判断验证方法是否存在 + */ + isValidMethod(value) { + let methods = [] + for(let method in this.methods) { + if (method && typeof this.methods[method] === 'function') { + methods.push(method) + } + } + return methods.indexOf(value) !== -1 + } + + /** + * 格式化提示信息模板 + */ + formatTpl(source, params) { + const that = this + if (arguments.length === 1) { + return function() { + let args = Array.from(arguments) + args.unshift(source) + return that.formatTpl.apply(this, args) + } + } + if (params === undefined) { + return source + } + if (arguments.length > 2 && params.constructor !== Array) { + params = Array.from(arguments).slice(1) + } + if (params.constructor !== Array) { + params = [ params ] + } + params.forEach(function(n, i) { + source = source.replace(new RegExp("\\{" + i + "\\}", "g"), function() { + return n + }) + }) + return source + } + + /** + * 判断规则依赖是否存在 + */ + depend(param) { + switch(typeof param) { + case 'boolean': + param = param + break + case 'string': + param = !!param.length + break + case 'function': + param = param() + default: + param = !0 + } + return param + } + + /** + * 判断输入值是否为空 + */ + optional(value) { + return !this.methods.required(value) && 'dependency-mismatch' + } + + /** + * 获取自定义字段的提示信息 + * @param {String} param 字段名 + * @param {Object} rule 规则 + */ + customMessage(param, rule) { + const params = this.messages[param] + const isObject = typeof params === 'object' + if (params && isObject) return params[rule.method] + } + + /** + * 获取某个指定字段的提示信息 + * @param {String} param 字段名 + * @param {Object} rule 规则 + */ + defaultMessage(param, rule) { + let message = this.customMessage(param, rule) || this.defaults.messages[rule.method] + let type = typeof message + + if (type === 'undefined') { + message = `Warning: No message defined for ${rule.method}.` + } else if (type === 'function') { + message = message.call(this, rule.parameters) + } + + return message + } + + /** + * 缓存错误信息 + * @param {String} param 字段名 + * @param {Object} rule 规则 + * @param {String} value 元素的值 + */ + formatTplAndAdd(param, rule, value) { + let msg = this.defaultMessage(param, rule) + + this.errorList.push({ + param: param, + msg: msg, + value: value, + }) + } + + /** + * 验证某个指定字段的规则 + * @param {String} param 字段名 + * @param {Object} rules 规则 + * @param {Object} event 表单数据对象 + */ + checkParam(param, rules, event) { + + // 缓存表单数据对象 + this.scope = event + + // 缓存字段对应的值 + const data = event.detail.value + const value = data[param] || '' + + // 遍历某个指定字段的所有规则,依次验证规则,否则缓存错误信息 + for(let method in rules) { + + // 判断验证方法是否存在 + if (this.isValidMethod(method)) { + + // 缓存规则的属性及值 + const rule = { + method: method, + parameters: rules[method] + } + + // 调用验证方法 + const result = this.methods[method](value, rule.parameters) + + // 若result返回值为dependency-mismatch,则说明该字段的值为空或非必填字段 + if (result === 'dependency-mismatch') { + continue + } + + // 判断是否通过验证,否则缓存错误信息,跳出循环 + if (!result) { + this.formatTplAndAdd(param, rule, value) + break + } + } + } + } + + /** + * 验证所有字段的规则,返回验证是否通过 + * @param {Object} event 表单数据对象 + */ + checkForm(event) { + this.errorList = [] + + for (let param in this.rules) { + this.checkParam(param, this.rules[param], event) + } + + return this.valid() + } + + /** + * 返回验证是否通过 + */ + valid() { + return this.size() === 0 + } + + /** + * 返回错误信息的个数 + */ + size() { + return this.errorList.length + } + + /** + * 返回所有错误信息 + */ + validationErrors() { + return this.errorList + } +} + +export default WxValidate \ No newline at end of file diff --git a/app/utils/coordtransform.js b/app/utils/coordtransform.js new file mode 100644 index 0000000..be1a7d4 --- /dev/null +++ b/app/utils/coordtransform.js @@ -0,0 +1,153 @@ +/** + * Created by Wandergis on 2015/7/8. + * 提供了百度坐标(BD09)、国测局坐标(火星坐标,GCJ02)、和WGS84坐标系之间的转换 + */ +//UMD魔法代码 +// if the module has no dependencies, the above pattern can be simplified to +(function (root, factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define([], factory); + } else if (typeof module === 'object' && module.exports) { + // Node. Does not work with strict CommonJS, but + // only CommonJS-like environments that support module.exports, + // like Node. + module.exports = factory(); + } else { + // Browser globals (root is window) + root.coordtransform = factory(); + } +}(this, function () { + //定义一些常量 + var x_PI = 3.14159265358979324 * 3000.0 / 180.0; + var PI = 3.1415926535897932384626; + var a = 6378245.0; + var ee = 0.00669342162296594323; + /** + * 百度坐标系 (BD-09) 与 火星坐标系 (GCJ-02)的转换 + * 即 百度 转 谷歌、高德 + * @param bd_lon + * @param bd_lat + * @returns {*[]} + */ + var bd09togcj02 = function bd09togcj02(bd_lon, bd_lat) { + var bd_lon = +bd_lon; + var bd_lat = +bd_lat; + var x = bd_lon - 0.0065; + var y = bd_lat - 0.006; + var z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * x_PI); + var theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * x_PI); + var gg_lng = z * Math.cos(theta); + var gg_lat = z * Math.sin(theta); + return [gg_lng, gg_lat] + }; + + /** + * 火星坐标系 (GCJ-02) 与百度坐标系 (BD-09) 的转换 + * 即谷歌、高德 转 百度 + * @param lng + * @param lat + * @returns {*[]} + */ + var gcj02tobd09 = function gcj02tobd09(lng, lat) { + var lat = +lat; + var lng = +lng; + var z = Math.sqrt(lng * lng + lat * lat) + 0.00002 * Math.sin(lat * x_PI); + var theta = Math.atan2(lat, lng) + 0.000003 * Math.cos(lng * x_PI); + var bd_lng = z * Math.cos(theta) + 0.0065; + var bd_lat = z * Math.sin(theta) + 0.006; + return [bd_lng, bd_lat] + }; + + /** + * WGS84转GCj02 + * @param lng + * @param lat + * @returns {*[]} + */ + var wgs84togcj02 = function wgs84togcj02(lng, lat) { + var lat = +lat; + var lng = +lng; + if (out_of_china(lng, lat)) { + return [lng, lat] + } else { + var dlat = transformlat(lng - 105.0, lat - 35.0); + var dlng = transformlng(lng - 105.0, lat - 35.0); + var radlat = lat / 180.0 * PI; + var magic = Math.sin(radlat); + magic = 1 - ee * magic * magic; + var sqrtmagic = Math.sqrt(magic); + dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * PI); + dlng = (dlng * 180.0) / (a / sqrtmagic * Math.cos(radlat) * PI); + var mglat = lat + dlat; + var mglng = lng + dlng; + return [mglng, mglat] + } + }; + + /** + * GCJ02 转换为 WGS84 + * @param lng + * @param lat + * @returns {*[]} + */ + var gcj02towgs84 = function gcj02towgs84(lng, lat) { + var lat = +lat; + var lng = +lng; + if (out_of_china(lng, lat)) { + return [lng, lat] + } else { + var dlat = transformlat(lng - 105.0, lat - 35.0); + var dlng = transformlng(lng - 105.0, lat - 35.0); + var radlat = lat / 180.0 * PI; + var magic = Math.sin(radlat); + magic = 1 - ee * magic * magic; + var sqrtmagic = Math.sqrt(magic); + dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * PI); + dlng = (dlng * 180.0) / (a / sqrtmagic * Math.cos(radlat) * PI); + var mglat = lat + dlat; + var mglng = lng + dlng; + return [lng * 2 - mglng, lat * 2 - mglat] + } + }; + + var transformlat = function transformlat(lng, lat) { + var lat = +lat; + var lng = +lng; + var ret = -100.0 + 2.0 * lng + 3.0 * lat + 0.2 * lat * lat + 0.1 * lng * lat + 0.2 * Math.sqrt(Math.abs(lng)); + ret += (20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) * 2.0 / 3.0; + ret += (20.0 * Math.sin(lat * PI) + 40.0 * Math.sin(lat / 3.0 * PI)) * 2.0 / 3.0; + ret += (160.0 * Math.sin(lat / 12.0 * PI) + 320 * Math.sin(lat * PI / 30.0)) * 2.0 / 3.0; + return ret + }; + + var transformlng = function transformlng(lng, lat) { + var lat = +lat; + var lng = +lng; + var ret = 300.0 + lng + 2.0 * lat + 0.1 * lng * lng + 0.1 * lng * lat + 0.1 * Math.sqrt(Math.abs(lng)); + ret += (20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) * 2.0 / 3.0; + ret += (20.0 * Math.sin(lng * PI) + 40.0 * Math.sin(lng / 3.0 * PI)) * 2.0 / 3.0; + ret += (150.0 * Math.sin(lng / 12.0 * PI) + 300.0 * Math.sin(lng / 30.0 * PI)) * 2.0 / 3.0; + return ret + }; + + /** + * 判断是否在国内,不在国内则不做偏移 + * @param lng + * @param lat + * @returns {boolean} + */ + var out_of_china = function out_of_china(lng, lat) { + var lat = +lat; + var lng = +lng; + // 纬度3.86~53.55,经度73.66~135.05 + return !(lng > 73.66 && lng < 135.05 && lat > 3.86 && lat < 53.55); + }; + + return { + bd09togcj02: bd09togcj02, + gcj02tobd09: gcj02tobd09, + wgs84togcj02: wgs84togcj02, + gcj02towgs84: gcj02towgs84 + } +})); diff --git a/app/utils/countdown.js b/app/utils/countdown.js new file mode 100644 index 0000000..fb78c56 --- /dev/null +++ b/app/utils/countdown.js @@ -0,0 +1,26 @@ +export default class Countdown { + constructor(page, prop) { + this.page = page + this.prop = prop + } + + start(cb) { + var that = this; + var {page, prop} = that + var second = page.data[prop] + if (second <= 0) { + return + } + cb && cb(second) + that.timer = setTimeout(function () { + page.setData({ + [prop]: second - 1 + }); + that.start(cb); + }, 1000) + } + + stop() { + clearTimeout(this.timer) + } +} \ No newline at end of file diff --git a/app/utils/qqmap-wx-jssdk.min.js b/app/utils/qqmap-wx-jssdk.min.js new file mode 100644 index 0000000..3323249 --- /dev/null +++ b/app/utils/qqmap-wx-jssdk.min.js @@ -0,0 +1,2 @@ +var _createClass=function(){function a(e,c){for(var b=0;b=l[i]&&i(0===i?9:1)&&(i+=1),d[n](t,i)[a].replace("%s",t)}function r(e,n){return n=n?t(n):new Date,(n-t(e))/1e3}function i(t){for(var e=1,n=0,r=Math.abs(t);t>=l[n]&&n1&&(n+="s"),[t+" "+n+" ago","in "+t+" "+n]},zh_CN:function(t,e){if(0===e)return["刚刚","片刻后"];var n=s[parseInt(e/2)];return[t+n+"前",t+n+"后"]}},l=[60,60,24,7,365/7/12,12],h=6,p="datetime";return u.register=function(t,e){d[t]=e},u}); \ No newline at end of file diff --git a/app/utils/util.js b/app/utils/util.js index c5cccf3..dfc8ca1 100644 --- a/app/utils/util.js +++ b/app/utils/util.js @@ -1,21 +1,179 @@ -function formatTime(date) { - var year = date.getFullYear() - var month = date.getMonth() + 1 - var day = date.getDate() +'use strict'; +import timeago from './timeago.min' +import QQMapWX from './qqmap-wx-jssdk.min' +import { gcj02tobd09 } from './coordtransform' +// import { host } from '../config' - var hour = date.getHours() - var minute = date.getMinutes() - var second = date.getSeconds() +const qqmap = new QQMapWX({ + key: 'FPOBZ-UT2K2-ZFYUC-CX67E-IOOYS-7XFQ6' +}); - - return [year, month, day].map(formatNumber).join('/') + ' ' + [hour, minute, second].map(formatNumber).join(':') +function resolveAdInfo(adInfo) { + const {city, district, adcode} = adInfo + return { + city, district, + district_id: adcode, + city_id: adcode.replace(/\d{2}$/, '00') + } } -function formatNumber(n) { - n = n.toString() - return n[1] ? n : '0' + n +// 解析地址 +export function reverseGeocoder(options) { + const { + location, success, complete + } = options + qqmap.reverseGeocoder({ + location, + success: function (res) { + var address = resolveAdInfo(res.result.ad_info) + success && success(address) + }, + fail: function (err) { + console.log(err) + }, + complete + }) } -module.exports = { - formatTime: formatTime +// 获取当前地理位置 +export function getCurrentAddress(options) { + const { + success, complete + } = options + wx.getLocation({ + type: 'gcj02', + success(res) { + getAddressFromLocation({ + location: { + latitude: res.latitude, + longitude: res.longitude, + }, + success, complete + }) + } + }) } + +// 根据坐标获取地址信息 +export function getAddressFromLocation(options) { + const {location, success} = options + getPois({ + location, + success(pois) { + var poi = pois[0] + if (poi) { + var address = Object.assign({ + address_name: poi.title, + location, + }, resolveAdInfo(poi.ad_info)) + + success && success(address) + } + } + }) +} + +// 获取兴趣点 +export function getPois(options) { + const { + location, success, complete + } = options + qqmap.reverseGeocoder({ + location, + get_poi: 1, + success: function (res) { + success && success(res.result.pois) + }, + fail: function (err) { + console.log(err) + }, + complete + }) +} + +export function getPrevPage() { + const pages = getCurrentPages() + return pages[pages.length - 2] +} + +export function fetch(options) { + wx.request({ + url: `https://${host}/${options.url}`, + data: Object.assign(options.data, { + 'app_v': 'ipaotui_mini' + }), + method: options.method || 'POST', + header: { + 'content-type': 'application/x-www-form-urlencoded' + }, + success: function (res) { + const data = res.data + if (data.State == 'Success') { + options.success && options.success(data.data) + } else { + alert(data.info) + options.error && options.error(data.info) + } + options.complete && options.complete() + } + }) +} + +// 提示框 +export function alert(content, callback) { + wx.showModal({ + title: '提示', + content: content, + showCancel: false, + success: callback + }) +} +// 确认框 +export function confirm(options) { + const { + content, confirmText, + ok, + } = options + wx.showModal({ + content, + confirmText, + cancelText: '关闭', + success(res) { + if (res.confirm) { + ok && ok() + } + } + }) +} + +// 加载提示 +export function showLoading() { + wx.showToast({ + icon: 'loading', + duration: 10000, + title: '加载中...', + mask: true, + }) +} +export function hideLoading() { + wx.hideToast() +} + +// 时间格式化 +export function datetimeFormat(unix_timestamp) { + return new timeago().format(new Date(unix_timestamp * 1000), 'zh_CN'); +} + +// 坐标格式化 +export function coordFormat(location) { + // gcj02 转 bd09 + return gcj02tobd09(location.longitude, location.latitude).join(',') +} + +// 倒计时格式化 +export function countdownFormat(count) { + var seconds = count % 60 + count = Math.floor(count / 60) + var minutes = count % 60 + return `${minutes}分钟${seconds}秒` +} \ No newline at end of file