order-create.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474
  1. <template>
  2. <view class="order-create">
  3. <tui-skeleton v-if="isRequest" :loadingType="3" :isLoading="true"></tui-skeleton>
  4. <!-- 地址选择 -->
  5. <order-choose-address class="sticky-top" :addressInfo="addressInfo"></order-choose-address>
  6. <!-- 供应商商品列表 -->
  7. <view class="shop-list">
  8. <view class="section" v-for="(shopInfo, index) in shopList" :key="shopInfo.shopId">
  9. <order-supplier-area
  10. :shopInfo="shopInfo"
  11. :submitType="submitType"
  12. @countChange="onCountChange"
  13. ></order-supplier-area>
  14. <view class="comment">
  15. <text>留言:</text>
  16. <input placeholder="请输入内容" placeholder-class="placeholder" v-model="shopInfo.note" />
  17. </view>
  18. <tui-divider :height="48" v-if="index < shopList.length - 1"></tui-divider>
  19. </view>
  20. </view>
  21. <!-- 优惠券 -->
  22. <view class="cell-section" @click="couponVisiable = true">
  23. <tui-list-cell :arrow="true" :padding="cellPadding" :unlined="true">
  24. <view class="cell-content">
  25. <text>优惠券</text> <text class="reduce tip">-¥{{ couponAmount | priceFormat }}</text>
  26. </view>
  27. </tui-list-cell>
  28. </view>
  29. <!-- 分享减免 -->
  30. <view class="cell-section" @click="$refs.sharePopup.open()">
  31. <tui-list-cell :arrow="false" :padding="cellPadding" :unlined="true">
  32. <button class="cell-content share-btn">
  33. <text>金额满99元,分享可立减20元</text> <text class="reduce tip">点击分享</text>
  34. </button>
  35. </tui-list-cell>
  36. </view>
  37. <!-- 运费 -->
  38. <view class="cell-section">
  39. <tui-list-cell :arrow="false" :padding="cellPadding" :unlined="true">
  40. <view class="cell-content"> <text>运费</text> <text class="tip postage">免邮</text> </view>
  41. </tui-list-cell>
  42. </view>
  43. <!-- 提交订单 -->
  44. <order-submit :orderInfo="orderInfo" @submit="onSubmit"></order-submit>
  45. <!-- 优惠券列表 -->
  46. <cm-coupon-popup
  47. :visiable="couponVisiable"
  48. :list="receiveCouponList"
  49. :hasTabs="false"
  50. :hasConfirm="true"
  51. :hasSafeArea="true"
  52. :hasCheckedNone="true"
  53. :checkedNone="checkedNone"
  54. @close="onCouponPopupClose"
  55. @couponClick="onCouponClick"
  56. @checkedNone="onCheckedNone"
  57. ></cm-coupon-popup>
  58. <!-- 分享 -->
  59. <cm-share-popup ref="sharePopup"></cm-share-popup>
  60. </view>
  61. </template>
  62. <script>
  63. import { orderConfirm, orderSubmit } from '@/services/api/order.js'
  64. import { fetchAddressList } from '@/services/api/user.js'
  65. import { initFormatCouponList, splitCouponList, chooseBestCoupon } from '@/common/business.helper.js'
  66. import { mapGetters } from 'vuex'
  67. import wechatPayMixins from '@/pages/views/order/mixins/wechatPay.js'
  68. export default {
  69. mixins: [wechatPayMixins],
  70. data() {
  71. return {
  72. isRequest: true,
  73. submitType: 'cart', // 订单提交来源 cart product shareBuy
  74. // 确认订单参数信息
  75. confirmParams: {
  76. userId: '',
  77. cartIds: '',
  78. productId: '',
  79. productCount: '',
  80. heUserId: '',
  81. collageFlag: 0
  82. },
  83. // 订单提交参数
  84. submitParams: {
  85. userId: 0,
  86. orderInfo: [], //提交的商品信息
  87. addressId: 0,
  88. cartType: 0,
  89. payInfo: {
  90. orderShouldPayFee: 0
  91. },
  92. discountInfo: null
  93. },
  94. // 地址
  95. addressList: [],
  96. addressInfo: null,
  97. // 商品信息
  98. shopList: [],
  99. // 优惠券
  100. couponVisiable: false,
  101. receiveCouponList: [],
  102. currentCoupon: null,
  103. checkedNone: true,
  104. notUseCouponList: [],
  105. canUseCouponList: [],
  106. // 拼团
  107. collageFlag: 0, //拼团标识:0不参与拼团,1参与拼团
  108. collageId: 0, //拼团id:参与拼团,若拼团id为空则发起拼团,不为空则与他人拼团
  109. // 分享抵扣
  110. shareReductStatus: false,
  111. reduction: null,
  112. reductionUserId: 0, //分享抵扣用户id
  113. shareData: {
  114. type: 0
  115. },
  116. allCount: 0, // 全部商品数量
  117. // 统计价格(接口返回)
  118. totalPrice: 0
  119. }
  120. },
  121. computed: {
  122. ...mapGetters(['userId']),
  123. cellPadding() {
  124. return '24rpx 24rpx'
  125. },
  126. // 优惠券金额
  127. couponAmount() {
  128. if (this.currentCoupon) {
  129. return this.currentCoupon.couponAmount
  130. } else {
  131. return 0
  132. }
  133. },
  134. // 减免金额
  135. discountedPrice() {
  136. return this.couponAmount
  137. },
  138. // 支付金额
  139. payAllPrice() {
  140. const price = this.totalPrice - this.discountedPrice
  141. if (price < 0) {
  142. return 0
  143. }
  144. return price
  145. },
  146. orderInfo() {
  147. return {
  148. payAllPrice: this.payAllPrice,
  149. discountedPrice: this.discountedPrice,
  150. allCount: this.allCount
  151. }
  152. }
  153. },
  154. onLoad(options) {
  155. this.initOptions(options)
  156. this.orderPaySuccess() // 支付回调
  157. },
  158. onShow() {
  159. this.resetAddress()
  160. },
  161. beforeDestroy() {
  162. uni.removeStorageSync('COMMIT_CART_INFO')
  163. uni.removeStorageSync('COMMIT_PRODUCT_INFO')
  164. uni.removeStorageSync('CHOOSE_ADDRESS')
  165. },
  166. methods: {
  167. // 支付成功回调
  168. orderPaySuccess() {
  169. this.$on('orderPaySuccess', orderInfo => {
  170. if (this.collageFlag === 1) {
  171. uni.redirectTo({ url: `share-buy/share-buy-detail?collageId=${this.collageId}` })
  172. } else {
  173. uni.setStorageSync('PAY_ORDER_INFO', orderInfo)
  174. this.$router.redirectTo('order/pay-success')
  175. }
  176. })
  177. },
  178. // 商品数量变化
  179. onCountChange(value) {
  180. this.confirmParams.productCount = value
  181. this.initOrderInfo()
  182. },
  183. // 初始化参数信息
  184. initOptions(options) {
  185. this.submitType = options.type
  186. this.confirmParams.userId = this.userId
  187. if (this.submitType === 'product' || this.submitType === 'shareBuy') {
  188. const productInfo = uni.getStorageSync('COMMIT_PRODUCT_INFO')
  189. this.submitParams.cartType = 2 // 从商品详情 / 拼单入口提交
  190. this.confirmParams.productCount = productInfo.productCount
  191. this.confirmParams.productId = productInfo.productId
  192. this.confirmParams.heUserId = productInfo.heUserId || 0
  193. this.confirmParams.collageFlag = this.collageFlag = productInfo.collageFlag
  194. this.collageId = parseInt(productInfo.collageId) || 0
  195. this.allCount = productInfo.allCount
  196. } else {
  197. const cartInfo = uni.getStorageSync('COMMIT_CART_INFO')
  198. this.submitParams.cartType = 1 // 从购物车提交
  199. this.confirmParams.cartIds = cartInfo.cartIds.join()
  200. this.allCount = cartInfo.allCount
  201. }
  202. this.initOrderInfo()
  203. // this.getUserAddress()
  204. },
  205. // 提交订单
  206. async onSubmit() {
  207. // 用户id
  208. this.submitParams.userId = this.userId
  209. // 校验地址信息
  210. if (!this.addressInfo) {
  211. this.$toast('请先添加收货地址~')
  212. return
  213. }
  214. this.submitParams.addressId = this.addressInfo.addressId
  215. // 优惠券,分享活动相关参数
  216. this.submitParams.discountInfo = this.getDiscountInfo()
  217. // 要支付的金额
  218. this.submitParams.payInfo.orderShouldPayFee = this.payAllPrice
  219. // 处理商品及留言信息
  220. this.submitParams.orderInfo = this.shopList.map(shop => {
  221. const productInfo = shop.productList.map(product => ({
  222. productId: product.productId,
  223. productNum: product.productCount,
  224. heUserId: product.heUserId
  225. }))
  226. return { shopId: shop.shopId, note: shop.note, productInfo }
  227. })
  228. // 提交订单
  229. console.log(this.submitParams)
  230. try {
  231. const res = await orderSubmit(this.submitParams)
  232. this.collageId = res.data.collageId
  233. if (parseFloat(res.data.payableAmount) === 0) {
  234. uni.setStorageSync('PAY_ORDER_INFO', res.data)
  235. this.$router.redirectTo('order/pay-success')
  236. } else {
  237. this.miniWxPayFor(res.data)
  238. }
  239. } catch (e) {
  240. console.log(e)
  241. }
  242. },
  243. // 优惠券,分享活动相关参数
  244. getDiscountInfo() {
  245. return {
  246. //优惠券ID
  247. couponId: this.currentCoupon ? this.currentCoupon.couponId : 0,
  248. //优惠券分享ID
  249. couponShareId: this.currentCoupon ? this.currentCoupon.couponShareId : 0,
  250. //拼团标识:0不参与拼团,1参与拼团
  251. collageFlag: this.collageFlag,
  252. //拼团id:参与拼团,若拼团id为空则发起拼团,不为空则与他人拼团
  253. collageId: this.collageId,
  254. //分享抵扣用户id
  255. reductionUserId: this.reductionUserId
  256. }
  257. },
  258. // 优惠券操作
  259. onCouponClick(coupon) {
  260. if (coupon.controlType === 'choose') {
  261. this.receiveCouponList.forEach(el => {
  262. if (coupon.couponId === el.couponId) {
  263. this.$set(el, 'checked', true)
  264. this.currentCoupon = el
  265. } else {
  266. this.$set(el, 'checked', false)
  267. }
  268. })
  269. this.checkedNone = false
  270. // this.couponVisiable = false
  271. // this.sortCouponList()
  272. }
  273. },
  274. // 不使用优惠券
  275. onCheckedNone() {
  276. this.receiveCouponList.forEach(el => {
  277. this.$set(el, 'checked', false)
  278. })
  279. this.currentCoupon = null
  280. this.checkedNone = true
  281. // this.sortCouponList()
  282. },
  283. // 优惠券列表关闭
  284. onCouponPopupClose() {
  285. this.couponVisiable = false
  286. this.sortCouponList()
  287. },
  288. // 初始化商品信息
  289. async initOrderInfo() {
  290. try {
  291. const res = await orderConfirm(this.confirmParams)
  292. this.totalPrice = res.data.totalPrice
  293. this.shopList = this.bindNoteMessage(res.data.shopList)
  294. this.initCouponList(res.data.receiveCouponList)
  295. } catch (e) {
  296. console.log(e)
  297. } finally {
  298. this.isRequest = false
  299. }
  300. },
  301. // 处理优惠券列表
  302. sortCouponList() {
  303. // 1将当前选中的优惠券从列表中删除
  304. // 2将当前选中的优惠券放入最前面
  305. // 3返回最新的优惠券列表
  306. // 4查找选中优惠券的索引
  307. if (this.currentCoupon) {
  308. const uniqueId = this.currentCoupon.uniqueId
  309. const index = this.canUseCouponList.findIndex(coupon => coupon.uniqueId === uniqueId)
  310. // 从列表中删除
  311. this.canUseCouponList.splice(index, 1)
  312. // 重新排序 将选中的优惠券放到最前面
  313. this.canUseCouponList = [
  314. this.currentCoupon,
  315. ...this.canUseCouponList.sort((a, b) => b.couponAmount - a.couponAmount)
  316. ]
  317. } else {
  318. this.canUseCouponList = this.canUseCouponList.sort((a, b) => b.couponAmount - a.couponAmount)
  319. }
  320. // 重新生成receiveCouponList
  321. this.receiveCouponList = [...this.canUseCouponList, ...this.notUseCouponList]
  322. console.log(this.receiveCouponList)
  323. },
  324. // 初始化优惠券列表
  325. initCouponList(couponList) {
  326. const allProductList = this.getAllProductList()
  327. let { canUseCouponList, notUseCouponList } = splitCouponList(couponList, allProductList)
  328. this.canUseCouponList = initFormatCouponList(canUseCouponList, 'choose', true)
  329. this.notUseCouponList = initFormatCouponList(notUseCouponList, 'buy', true)
  330. this.currentCoupon = this.canUseCouponList[0]
  331. if (this.currentCoupon) {
  332. this.checkedNone = false
  333. this.$set(this.currentCoupon, 'checked', true)
  334. }
  335. this.receiveCouponList = [...this.canUseCouponList, ...this.notUseCouponList]
  336. },
  337. // 获取全部商品
  338. getAllProductList() {
  339. const list = []
  340. this.shopList.forEach(shop => {
  341. list.push(...shop.productList)
  342. })
  343. return list
  344. },
  345. // 为共供应商绑定留言信息
  346. bindNoteMessage(shopList) {
  347. return shopList.map(item => {
  348. item.note = ''
  349. return item
  350. })
  351. },
  352. // 获取收货地址
  353. async getUserAddress() {
  354. try {
  355. const res = await fetchAddressList({ userId: this.userId })
  356. this.addressList = res.data.list
  357. if (res.data.list.length > 0) {
  358. this.addressInfo = res.data.list[0]
  359. console.log(this.addressInfo)
  360. }
  361. return res
  362. } catch (e) {
  363. console.log(e)
  364. }
  365. },
  366. // 初始化用户选中地址
  367. async resetAddress() {
  368. await this.getUserAddress()
  369. if (this.$router.checkRefreshType('chooseAddress') || this.$router.checkRefreshType('createAddressBack')) {
  370. const addressInfo = uni.getStorageSync('CHOOSE_ADDRESS')
  371. if (addressInfo) {
  372. this.addressInfo = this.addressList.find(address => address.addressId === addressInfo.addressId)
  373. }
  374. }
  375. }
  376. }
  377. }
  378. </script>
  379. <style lang="scss" scoped>
  380. .placeholder {
  381. font-size: 20rpx;
  382. }
  383. .order-create {
  384. padding-bottom: 100rpx;
  385. color: #333;
  386. .shop-list {
  387. background-color: #fff;
  388. padding: 24rpx;
  389. .section {
  390. .comment {
  391. @extend .cm-flex-between;
  392. margin-top: 24rpx;
  393. text {
  394. width: 80rpx;
  395. font-size: 24rpx;
  396. }
  397. input {
  398. flex: 1;
  399. background-color: #f7f7f7;
  400. padding: 4rpx 10rpx;
  401. font-size: 24rpx;
  402. }
  403. }
  404. }
  405. }
  406. .cell-section {
  407. margin: 16rpx 0;
  408. .cell-content {
  409. @extend .cm-flex-between;
  410. .tip {
  411. margin-right: 40rpx;
  412. }
  413. .reduce {
  414. color: #f83c6c;
  415. }
  416. .postage {
  417. color: #0062cc;
  418. margin-right: 0;
  419. }
  420. &.share-btn {
  421. padding: 0;
  422. margin: 0;
  423. background-color: transparent;
  424. font-size: 26rpx;
  425. line-height: inherit;
  426. .tip {
  427. margin-right: 0;
  428. }
  429. &::after {
  430. border: 0;
  431. }
  432. }
  433. }
  434. }
  435. }
  436. </style>