You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

419 lines
10 KiB

3 years ago
  1. <template>
  2. <view class="app column">
  3. <view class="main-wrap" :class="{show: loaded}">
  4. <view class="addr-sec" @click="navTo('/pages/address/list?choose=1&id='+addr.id)">
  5. <view v-if="!addr._id" class="addr-empty row fill">
  6. <text class="mix-icon icon-dizhi"></text>
  7. <text>请选择收货地址</text>
  8. </view>
  9. <view v-else class="addr-wrap">
  10. <text class="mix-icon icon-dizhi"></text>
  11. <view class="con column">
  12. <text class="addr">{{ addr.address.address }} {{ addr.address.room }}</text>
  13. <text class="name">{{ addr.name }} {{ addr.mobile }}</text>
  14. </view>
  15. </view>
  16. <text class="mix-icon icon-you"></text>
  17. <image class="bg" src="/static/icon/addr-line.png"></image>
  18. </view>
  19. <!-- 商品列表 -->
  20. <view class="goods-sec">
  21. <product-list :list="data.products"></product-list>
  22. </view>
  23. <!-- 价格信息 -->
  24. <view class="price-sec">
  25. <view class="cell row">
  26. <text class="tit fill">商品金额</text>
  27. <text class="price">{{ goodsTotal | price(2) }}</text>
  28. </view>
  29. <view class="cell row">
  30. <text class="tag"></text>
  31. <text class="tit fill">订单满减</text>
  32. <text class="price" :class="{red: fullReductionMoney > 0}">-{{ fullReductionMoney || 0 }}</text><!-- red -->
  33. </view>
  34. <view class="cell row" @click="showCouponPopup">
  35. <text class="tag red"></text>
  36. <text class="tit fill">优惠券</text>
  37. <text v-if="data.coupons.length === 0" class="price disabled">暂无可用</text>
  38. <template v-else>
  39. <text v-if="curCoupon._id" class="price red">-{{ curCoupon.coupon_money }}</text>
  40. <text v-else class="price red" style="font-weight: normal;">请选择优惠券</text>
  41. <text class="mix-icon icon-you"></text>
  42. </template>
  43. </view>
  44. <view class="cell row">
  45. <text class="tit fill">配送费</text>
  46. <text class="price">0</text>
  47. </view>
  48. <view class="total row b-t">
  49. <text class="price">{{ payTotal | price(2)}}</text>
  50. </view>
  51. </view>
  52. <view class="remarks column">
  53. <text class="title">订单备注</text>
  54. <textarea class="input" auto-height v-model="remarks" placeholder="选填,合理需求我们会尽量满足 .." placeholder-style="color: #999" />
  55. </view>
  56. <!-- 底部栏 -->
  57. <view class="bot-fill-view"></view>
  58. <view class="bottom row">
  59. <view class="fill">
  60. <text class="tip">实付款</text>
  61. <text class="price fill">{{ payTotal | price(2) }}</text>
  62. </view>
  63. <view class="btn center" @click="createOrder">
  64. <text>提交订单</text>
  65. </view>
  66. </view>
  67. </view>
  68. <!-- 优惠券弹窗 -->
  69. <coupon-select ref="couponSelect" :list="data.coupons" @confirm="onCheckCoupon"></coupon-select>
  70. <mix-loading v-if="isLoading" :type="loaded ? 1: 2" :mask="true"></mix-loading>
  71. </view>
  72. </template>
  73. <script>
  74. import productList from './components/product-list.vue'
  75. import couponSelect from './components/coupon-select.vue'
  76. export default {
  77. components: {
  78. productList,
  79. couponSelect
  80. },
  81. data() {
  82. return {
  83. remarks: '', //备注
  84. addr: {},//地址信息
  85. data: {
  86. products: [],
  87. coupons: []
  88. },
  89. curCoupon: {},
  90. payTotal: 0, //支付价格
  91. fullReductionMoney: 0, //满减金额
  92. }
  93. },
  94. computed: {
  95. //商品总价
  96. goodsTotal(){
  97. if(this.data.products.length === 0){
  98. return 0;
  99. }
  100. let total = 0;
  101. this.data.products.forEach(item=> {
  102. total += item.price * item.number;
  103. })
  104. return total;
  105. }
  106. },
  107. onLoad(options) {
  108. if(options.type === 'cart'){
  109. //购物车结算
  110. this.createType = 'cart';
  111. this.cartIds = options.ids;
  112. }else{
  113. this.createType = 'buyNow';
  114. this.buyData = JSON.parse(options.data);
  115. }
  116. this.loadData();
  117. },
  118. methods: {
  119. async loadData(){
  120. const operation = this.createType === 'cart' ? 'getCartConfirmData': 'getBuyNowConfirmData';
  121. const sendData = this.createType === 'cart' ? {
  122. ids: this.cartIds.split(',')
  123. } : this.buyData;
  124. const res = await this.$request('order', operation, sendData, {showLoading: true})
  125. this.addr = res.data.address;
  126. this.data = res.data;
  127. console.log(JSON.parse(JSON.stringify(res.data)));
  128. this.getOrderPayPrice();
  129. },
  130. //计算订单价格
  131. async getOrderPayPrice(){
  132. const res = await this.$request('order', 'getOrderPayPrice', {
  133. goods_price: this.goodsTotal,
  134. address_id: this.addr._id || '',
  135. coupon_id: this.curCoupon._id || ''
  136. }, {showLoading: this.payTotal > 0})
  137. this.payTotal = res.pay_price || 0;
  138. this.fullReductionMoney = res.full_reduction_money;
  139. },
  140. //创建订单
  141. createOrder(){
  142. this.$util.throttle(async ()=>{
  143. if(!this.addr._id){
  144. this.$util.msg('请选择收货地址');
  145. return;
  146. }
  147. this.isLoading = true;
  148. const data = this.getCreateData();
  149. const operation = this.createType === 'cart' ? 'addByCart': 'addBuyNow';
  150. const res = await this.$request('order', operation, data);
  151. this.isLoading = false;
  152. console.log(JSON.parse(JSON.stringify(res)));
  153. if(res.status === 1){
  154. if(this.createType === 'cart'){
  155. uni.$emit('refreshCart');//刷新购物车
  156. this.$store.dispatch('getCartCount');//刷新购物车数量个
  157. }
  158. uni.redirectTo({
  159. url: '/pages/wallet/pay?data=' + JSON.stringify({
  160. sourcePage: 'createOrder',
  161. ...res.data
  162. })
  163. })
  164. }else{
  165. this.$util.msg(res.msg);
  166. }
  167. })
  168. },
  169. //获取创建订单参数
  170. getCreateData(){
  171. const data = {
  172. remarks: this.remarks,
  173. address: this.addr,
  174. coupon_id: this.curCoupon._id || '',
  175. // #ifdef H5
  176. source_type: 1,
  177. // #endif
  178. // #ifdef APP-PLUS
  179. source_type: 2,
  180. // #endif
  181. // #ifdef MP-WEIXIN
  182. source_type: 3,
  183. // #endif
  184. }
  185. //购物车结算
  186. if(this.createType === 'cart'){
  187. data.ids = this.cartIds.split(',');
  188. }else{
  189. data.product = this.data.products[0]
  190. }
  191. return data;
  192. },
  193. //设置收货地址
  194. setAddress(addr){
  195. this.addr = addr;
  196. this.getOrderPayPrice();
  197. },
  198. //打开优惠券弹窗
  199. showCouponPopup(){
  200. if(this.data.coupons.length > 0){
  201. this.$refs.couponSelect.curCoupon = this.curCoupon;
  202. this.$refs.couponSelect.open();
  203. }
  204. },
  205. //优惠券选择回调
  206. onCheckCoupon(curCoupon){
  207. this.curCoupon = curCoupon;
  208. this.getOrderPayPrice();
  209. }
  210. }
  211. }
  212. </script>
  213. <style>
  214. page{
  215. background-color: #f7f7f7;
  216. }
  217. </style>
  218. <style scoped lang="scss">
  219. .b-b:after{
  220. left: 4rpx;
  221. right: 4rpx;
  222. border-color: #ececec;
  223. }
  224. .app{
  225. padding: 16rpx 24rpx 20rpx;
  226. }
  227. .main-wrap{
  228. opacity: 0;
  229. transition: .2s;
  230. &.show{
  231. opacity: 1;
  232. }
  233. }
  234. .addr-sec{
  235. display: flex;
  236. padding: 20rpx;
  237. background-color: #fff;
  238. border-radius: 10rpx;
  239. position: relative;
  240. overflow: hidden;
  241. .addr-empty{
  242. margin: 16rpx 0 24rpx;
  243. font-size: 30rpx;
  244. color: #666;
  245. .icon-dizhi{
  246. transform: translateY(0rpx);
  247. margin-right: 16rpx;
  248. }
  249. }
  250. .addr-wrap{
  251. display: flex;
  252. flex: 1;
  253. }
  254. .icon-dizhi{
  255. transform: translateY(6rpx);
  256. font-size: 32rpx;
  257. color: $base-color;
  258. }
  259. .icon-you{
  260. flex-shrink: 0;
  261. transform: translateY(50%);
  262. position: relative;
  263. top: -14rpx;
  264. font-size: 26rpx;
  265. color: #999;
  266. }
  267. .con{
  268. flex: 1;
  269. padding: 0 80rpx 10rpx 20rpx;;
  270. }
  271. .addr{
  272. margin-bottom: 16rpx;
  273. font-size: 30rpx;
  274. color: #333;
  275. line-height: 1.4;
  276. font-weight: 700;
  277. }
  278. .name{
  279. font-size: 28rpx;
  280. color: #999;
  281. }
  282. .bg{
  283. position: absolute;
  284. left: 0;
  285. bottom: 0;
  286. width: 100%;
  287. height: 4rpx;
  288. }
  289. }
  290. .goods-sec{
  291. margin-top: 16rpx;
  292. background-color: #fff;
  293. border-radius: 10rpx 10rpx 0 0;
  294. overflow: hidden;
  295. }
  296. .price-sec{
  297. padding-top: 14rpx;
  298. border-radius: 0 0 10rpx 10rpx;
  299. background-color: #fff;
  300. .cell{
  301. height: 68rpx;
  302. padding: 0 24rpx;
  303. font-size: 26rpx;
  304. color: #333;
  305. }
  306. .price{
  307. font-weight: 700;
  308. &.red{
  309. color: $base-color;
  310. }
  311. &.disabled{
  312. color: #999;
  313. font-weight: normal;
  314. }
  315. }
  316. .total{
  317. justify-content: flex-end;
  318. height: 80rpx;
  319. padding-right: 20rpx;
  320. margin-top: 16rpx;
  321. font-size: 30rpx;
  322. color: #333;
  323. .price:before{
  324. content: '小计:';
  325. font-weight: normal;
  326. }
  327. }
  328. .tag{
  329. padding: 6rpx 8rpx;
  330. margin-right: 8rpx;
  331. font-size: 20rpx;
  332. color: #fff;
  333. border-radius: 8rpx;
  334. background-color: orange;
  335. &.red{
  336. background-color: $base-color;
  337. }
  338. }
  339. .icon-you{
  340. margin-left: 8rpx;
  341. font-size: 20rpx;
  342. color: #999;
  343. }
  344. }
  345. .remarks{
  346. padding: 24rpx 24rpx;
  347. margin-top: 16rpx;
  348. border-radius: 12rpx;
  349. background-color: #fff;
  350. .title{
  351. margin-bottom: 24rpx;
  352. font-size: 30rpx;
  353. color: #333;
  354. font-weight: 700;
  355. }
  356. .input{
  357. flex: 1;
  358. min-height: 140rpx;
  359. font-size: 28rpx;
  360. color: #333;
  361. }
  362. }
  363. .bot-fill-view{
  364. width: 100%;
  365. height: 100rpx;
  366. box-sizing: content-box;
  367. padding-bottom: constant(safe-area-inset-bottom);
  368. padding-bottom: env(safe-area-inset-bottom);
  369. }
  370. .bottom{
  371. position: fixed;
  372. left: 0;
  373. bottom: 0;
  374. z-index: 90;
  375. width: 100%;
  376. height: 100rpx;
  377. background-color: #fff;
  378. box-shadow: 0 -2rpx 10rpx 0 rgba(0,0,0,.06);
  379. box-sizing: content-box;
  380. padding-bottom: constant(safe-area-inset-bottom);
  381. padding-bottom: env(safe-area-inset-bottom);
  382. .tip{
  383. margin-left: 24rpx;
  384. font-size: 28rpx;
  385. color: #999;
  386. }
  387. .price{
  388. margin-right: 30rpx;
  389. font-size: 36rpx;
  390. color: $base-color;
  391. font-weight: 700;
  392. text-align: right;
  393. }
  394. .btn{
  395. min-width: 180rpx;
  396. height: 70rpx;
  397. padding: 0 26rpx;
  398. margin-right: 20rpx;
  399. border-radius: 100rpx;
  400. background-color: $base-color;
  401. font-size: 30rpx;
  402. color: #fff;
  403. }
  404. }
  405. </style>